UNPKG

aws-cdk

Version:

AWS CDK Toolkit CLI, the command line tool for CDK apps

1,691 lines 301 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
    if (value !== null && value !== void 0) {
        if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
        var dispose, inner;
        if (async) {
            if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
            dispose = value[Symbol.asyncDispose];
        }
        if (dispose === void 0) {
            if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
            dispose = value[Symbol.dispose];
            if (async) inner = dispose;
        }
        if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
        if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
        env.stack.push({ value: value, dispose: dispose, async: async });
    }
    else if (async) {
        env.stack.push({ async: true });
    }
    return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
    return function (env) {
        function fail(e) {
            env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
            env.hasError = true;
        }
        var r, s = 0;
        function next() {
            while (r = env.stack.pop()) {
                try {
                    if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
                    if (r.dispose) {
                        var result = r.dispose.call(r.value);
                        if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
                    }
                    else s |= 1;
                }
                catch (e) {
                    fail(e);
                }
            }
            if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
            if (env.hasError) throw env.error;
        }
        return next();
    };
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
    var e = new Error(message);
    return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CdkToolkit = exports.AssetBuildTime = void 0;
exports.displayFlagsMessage = displayFlagsMessage;
const node_crypto_1 = require("node:crypto");
const path = __importStar(require("node:path"));
const node_util_1 = require("node:util");
const cxapi = __importStar(require("@aws-cdk/cloud-assembly-api"));
const cloud_assembly_schema_1 = require("@aws-cdk/cloud-assembly-schema");
const toolkit_lib_1 = require("@aws-cdk/toolkit-lib");
const chalk_1 = __importDefault(require("chalk"));
const chokidar = __importStar(require("chokidar"));
const handler_js_1 = require("chokidar/handler.js");
const fs = __importStar(require("fs-extra"));
const io_host_1 = require("./io-host");
const user_configuration_1 = require("./user-configuration");
const api_private_1 = require("../../lib/api-private");
const api_1 = require("../api");
const bootstrap_1 = require("../api/bootstrap");
const cloud_assembly_1 = require("../api/cloud-assembly");
const deploy_private_1 = require("../api/deploy-private");
const refactor_1 = require("../api/refactor");
const deploy_1 = require("../commands/deploy");
const list_stacks_1 = require("../commands/list-stacks");
const migrate_1 = require("../commands/migrate");
const cxapp_1 = require("../cxapp");
const util_1 = require("../util");
const collect_telemetry_1 = require("./telemetry/collect-telemetry");
const error_1 = require("./telemetry/error");
const messages_1 = require("./telemetry/messages");
const operations_1 = require("../commands/flags/operations");
// Must use a require() otherwise esbuild complains about calling a namespace
// eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/consistent-type-imports
const pLimit = require('p-limit');
/**
 * File events that we care about from chokidar.
 * In chokidar v4, EventName includes additional events like 'error', 'raw', 'ready', 'all'
 * that we need to filter out in the 'all' handler.
 */
const FILE_EVENTS = [handler_js_1.EVENTS.ADD, handler_js_1.EVENTS.ADD_DIR, handler_js_1.EVENTS.CHANGE, handler_js_1.EVENTS.UNLINK, handler_js_1.EVENTS.UNLINK_DIR];
/**
 * Type guard to check if an event is a file event we should process.
 */
function isFileEvent(event) {
    return FILE_EVENTS.includes(event);
}
/**
 * When to build assets
 */
var AssetBuildTime;
(function (AssetBuildTime) {
    /**
     * Build all assets before deploying the first stack
     *
     * This is intended for expensive Docker image builds; so that if the Docker image build
     * fails, no stacks are unnecessarily deployed (with the attendant wait time).
     */
    AssetBuildTime["ALL_BEFORE_DEPLOY"] = "all-before-deploy";
    /**
     * Build assets just-in-time, before publishing
     */
    AssetBuildTime["JUST_IN_TIME"] = "just-in-time";
})(AssetBuildTime || (exports.AssetBuildTime = AssetBuildTime = {}));
/**
 * Custom implementation of the public Toolkit to integrate with the legacy CdkToolkit
 *
 * This overwrites how an sdkProvider is acquired
 * in favor of the one provided directly to CdkToolkit.
 */
class InternalToolkit extends toolkit_lib_1.Toolkit {
    _sdkProvider;
    constructor(sdkProvider, options) {
        super(options);
        this._sdkProvider = sdkProvider;
    }
    /**
     * Access to the AWS SDK
     * @internal
     */
    async sdkProvider(_action) {
        return this._sdkProvider;
    }
}
/**
 * Toolkit logic
 *
 * The toolkit runs the `cloudExecutable` to obtain a cloud assembly and
 * deploys applies them to `cloudFormation`.
 */
class CdkToolkit {
    props;
    ioHost;
    toolkitStackName;
    toolkit;
    constructor(props) {
        this.props = props;
        this.ioHost = props.ioHost ?? io_host_1.CliIoHost.instance();
        this.toolkitStackName = props.toolkitStackName ?? api_1.DEFAULT_TOOLKIT_STACK_NAME;
        // We don't have the toolkit check unstable features. Instead, the error
        // messages the CLI give are slightly different, and so they need to be checked
        // separately. Instead, the Toolkit we use has all unstable features automatically
        // enabled.
        const iPromiseUnstablenessIsCheckedByTheCli = {
            'publish-assets': true,
            'diagnose': true,
            'flags': true,
            'orphan': true,
            'refactor': true,
            'validate': true,
        };
        this.toolkit = new InternalToolkit(props.sdkProvider, {
            assemblyFailureAt: this.validateMetadataFailAt(),
            color: true,
            emojis: true,
            ioHost: this.ioHost,
            toolkitStackName: this.toolkitStackName,
            unstableFeatures: Object.keys(iPromiseUnstablenessIsCheckedByTheCli),
        });
    }
    async metadata(stackName, json) {
        const env_1 = { stack: [], error: void 0, hasError: false };
        try {
            const _formatter = __addDisposableResource(env_1, this.ioHost.once(api_private_1.IO.CDK_TOOLKIT_I2901, (msg) => ({
                action: 'metadata',
                message: (0, util_1.serializeStructure)(msg.data.stacks[0]?.metadata ?? {}, json),
            })), false);
            await this.toolkit.list(this.props.cloudExecutable, {
                stacks: {
                    patterns: [stackName],
                    strategy: api_1.StackSelectionStrategy.PATTERN_MUST_MATCH_SINGLE,
                    expand: cloud_assembly_1.ExpandStackSelection.NONE,
                },
            });
        }
        catch (e_1) {
            env_1.error = e_1;
            env_1.hasError = true;
        }
        finally {
            __disposeResources(env_1);
        }
    }
    async acknowledge(noticeId) {
        const issueNumber = Number(noticeId);
        if (!Number.isInteger(issueNumber)) {
            throw new toolkit_lib_1.ToolkitError('InvalidAcknowledgementId', `Invalid notice ID '${noticeId}': 'cdk acknowledge' only accepts numeric notice IDs (e.g. 'cdk acknowledge 12345'). ` +
                'Scoped construct warnings such as \'@aws-cdk/aws-ecs:minHealthyPercent\' are acknowledged in code with ' +
                'Annotations.of(scope).acknowledgeWarning(\'<id>\').');
        }
        const acks = new Set(this.props.configuration.context.get('acknowledged-issue-numbers') ?? []);
        acks.add(issueNumber);
        this.props.configuration.context.set('acknowledged-issue-numbers', Array.from(acks));
        await this.props.configuration.saveContext();
    }
    async cliTelemetryStatus(args) {
        const canCollect = (0, collect_telemetry_1.canCollectTelemetry)(args, this.props.configuration.context);
        if (canCollect) {
            await this.ioHost.asIoHelper().defaults.info('CLI Telemetry is enabled. See https://docs.aws.amazon.com/cdk/v2/guide/cli-telemetry.html for ways to disable.');
        }
        else {
            await this.ioHost.asIoHelper().defaults.info('CLI Telemetry is disabled. See https://docs.aws.amazon.com/cdk/v2/guide/cli-telemetry.html for ways to enable.');
        }
    }
    async cliTelemetry(enable) {
        this.props.configuration.context.set('cli-telemetry', enable);
        await this.props.configuration.saveContext();
        await this.ioHost.asIoHelper().defaults.info(`Telemetry ${enable ? 'enabled' : 'disabled'}`);
    }
    async diff(options) {
        const assembly = await this.assembly();
        const stacks = await this.selectTopLevelOrMatchingStacks(assembly, options.stackNames, options.exclusively);
        await this.validateStacks(assembly, stacks);
        const strict = !!options.strict;
        const contextLines = options.contextLines || 3;
        const quiet = options.quiet || false;
        let diffs = 0;
        const parameterMap = buildParameterMap(options.parameters);
        if (options.templatePath !== undefined) {
            // Compare single stack against fixed template
            if (stacks.stackCount !== 1) {
                throw new toolkit_lib_1.ToolkitError('SingleStackRequired', 'Can only select one stack when comparing to fixed template. Use --exclusively to avoid selecting multiple stacks.');
            }
            if (!(await fs.pathExists(options.templatePath))) {
                throw new toolkit_lib_1.ToolkitError('TemplateNotFound', `There is no file at ${options.templatePath}`);
            }
            if (options.importExistingResources) {
                throw new toolkit_lib_1.ToolkitError('ImportWithTemplatePath', 'Can only use --import-existing-resources flag when comparing against deployed stacks.');
            }
            const template = (0, util_1.deserializeStructure)(await fs.readFile(options.templatePath, { encoding: 'utf-8' }));
            const formatter = new api_1.DiffFormatter({
                templateInfo: {
                    oldTemplate: template,
                    newTemplate: stacks.firstStack,
                },
            });
            if (options.securityOnly) {
                const securityDiff = formatter.formatSecurityDiff({ quiet });
                // Warn, count, and display the diff only if the reported changes are broadening permissions
                if (securityDiff.permissionChangeType === toolkit_lib_1.PermissionChangeType.BROADENING) {
                    await this.ioHost.asIoHelper().defaults.warn('This deployment will make potentially sensitive changes according to your current security approval level.\nPlease confirm you intend to make the following modifications:\n');
                    await this.ioHost.asIoHelper().defaults.info(securityDiff.formattedDiff);
                    diffs += securityDiff.numStacksWithChanges;
                }
            }
            else {
                const diff = formatter.formatStackDiff({
                    strict,
                    contextLines,
                    quiet,
                });
                diffs = diff.numStacksWithChanges;
                await this.ioHost.asIoHelper().defaults.info(diff.formattedDiff);
            }
        }
        else {
            const allMappings = options.includeMoves
                ? await (0, refactor_1.mappingsByEnvironment)(stacks.stackArtifacts, this.props.sdkProvider, true)
                : [];
            // Compare N stacks against deployed templates
            for (const stack of stacks.stackArtifacts) {
                const templateWithNestedStacks = await this.props.deployments.readCurrentTemplateWithNestedStacks(stack, options.compareAgainstProcessedTemplate);
                const currentTemplate = templateWithNestedStacks.deployedRootTemplate;
                const nestedStacks = templateWithNestedStacks.nestedStacks;
                const environment = await this.props.deployments.resolveEnvironment(stack);
                const migrator = new api_1.ResourceMigrator({
                    deployments: this.props.deployments,
                    ioHelper: (0, api_private_1.asIoHelper)(this.ioHost, 'diff'),
                });
                const resourcesToImport = await migrator.tryGetResources(environment);
                if (resourcesToImport) {
                    (0, api_1.removeNonImportResources)(stack);
                }
                const changeSet = (options.method !== 'template')
                    ? (await this.tryCreateDiffChangeSet(stack, options, parameterMap, resourcesToImport, quiet))?.changeSet
                    : undefined;
                const mappings = allMappings.find(m => m.environment.region === stack.environment.region && m.environment.account === stack.environment.account)?.mappings ?? {};
                const formatter = new api_1.DiffFormatter({
                    templateInfo: {
                        oldTemplate: currentTemplate,
                        newTemplate: stack,
                        changeSet,
                        isImport: !!resourcesToImport,
                        nestedStacks,
                        mappings,
                        environment,
                    },
                });
                if (options.securityOnly) {
                    const securityDiff = formatter.formatSecurityDiff({ quiet });
                    // Warn, count, and display the diff only if the reported changes are broadening permissions
                    if (securityDiff.permissionChangeType === toolkit_lib_1.PermissionChangeType.BROADENING) {
                        await this.ioHost.asIoHelper().defaults.warn('This deployment will make potentially sensitive changes according to your current security approval level.\nPlease confirm you intend to make the following modifications:\n');
                        await this.ioHost.asIoHelper().defaults.info(securityDiff.formattedDiff);
                        diffs += securityDiff.numStacksWithChanges;
                    }
                }
                else {
                    const diff = formatter.formatStackDiff({
                        strict,
                        contextLines,
                        quiet,
                    });
                    await this.ioHost.asIoHelper().defaults.info(diff.formattedDiff);
                    diffs += diff.numStacksWithChanges;
                }
            }
        }
        await this.ioHost.asIoHelper().defaults.info((0, node_util_1.format)('\n✨  Number of stacks with differences: %s\n', diffs));
        return diffs && options.fail ? 1 : 0;
    }
    /**
     * Try to create a diff changeset for the given stack.
     * Returns undefined if the stack cannot be accessed and changeSetOnly is not set.
     */
    async tryCreateDiffChangeSet(stack, options, parameterMap, resourcesToImport, quiet) {
        try {
            // we don't actually need to know if the stack exists here
            // we just use this to flush our any permissions issues and drop the result
            void await this.props.deployments.stackExists({
                stack,
                deployName: stack.stackName,
                tryLookupRole: true,
            });
        }
        catch (e) {
            if (options.method === 'change-set') {
                throw toolkit_lib_1.ToolkitError.withCause('DescribeStacksFailed', `Could not access stack '${stack.stackName}'. Please check your permissions or use '--method=auto' to allow falling back to a template diff.`, e);
            }
            await this.ioHost.asIoHelper().defaults.debug((0, util_1.formatErrorMessage)(e));
            if (!quiet) {
                await this.ioHost.asIoHelper().defaults.info(`Could not access stack '${stack.stackName}', falling back to template diff. Use '--method=change-set' to fail instead. Run with -v to see the reason.\n`);
            }
            return undefined;
        }
        return api_private_1.cfnApi.createDiffChangeSet((0, api_private_1.asIoHelper)(this.ioHost, 'diff'), {
            stack,
            uuid: (0, node_crypto_1.randomUUID)(),
            deployments: this.props.deployments,
            sdkProvider: this.props.sdkProvider,
            parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
            resourcesToImport,
            importExistingResources: options.importExistingResources,
            failOnError: options.method === 'change-set',
        });
    }
    async deploy(options) {
        const env_2 = { stack: [], error: void 0, hasError: false };
        try {
            if (options.watch) {
                return this.watch(options);
            }
            // set progress from options, this includes user and app config
            if (options.progress) {
                this.ioHost.stackProgress = options.progress;
            }
            // the ioHost uses this internally to determine if a confirmation
            // is actually needed, so it needs the same value we determine here.
            const requireApproval = options.requireApproval ?? cloud_assembly_schema_1.RequireApproval.BROADENING;
            this.ioHost.requireDeployApproval = requireApproval;
            // toolkit-lib emits the approval request (I5060) without mentioning
            // `--require-approval`. The CLI owns that flag, so it adds the framing here.
            // Both deploy paths resolve through this host, so one listener covers both.
            // Method-scoped (`using`): `deploy()` can run repeatedly (watch mode), and
            // each run must register a rewrite for its own `requireApproval` value.
            const _approvalFraming = __addDisposableResource(env_2, this.ioHost.rewrite(api_private_1.IO.CDK_TOOLKIT_I5060, (msg) => {
                const updateTypeText = msg.data.permissionChangeType !== toolkit_lib_1.PermissionChangeType.NONE
                    ? 'security-sensitive updates'
                    : 'updates';
                return `Stack includes ${updateTypeText} and "--require-approval" is set to '${requireApproval}'.\nDo you wish to deploy these changes?`;
            }), false);
            // execute-change-set is a new flow that we can just delegate to toolkit-lib
            if (options.deploymentMethod?.method === 'execute-change-set') {
                await this.toolkit.deploy(this.props.cloudExecutable, {
                    deploymentMethod: options.deploymentMethod,
                    stacks: {
                        patterns: options.selector.patterns,
                        strategy: api_1.StackSelectionStrategy.PATTERN_MUST_MATCH_SINGLE,
                        expand: cloud_assembly_1.ExpandStackSelection.NONE,
                    },
                    roleArn: options.roleArn,
                    forceDeployment: options.force,
                    rollback: options.rollback,
                    reuseAssets: options.reuseAssets,
                    concurrency: options.concurrency,
                    traceLogs: options.traceLogs,
                    notificationArns: options.notificationArns,
                    tags: options.tags,
                    outputsFile: options.outputsFile,
                    assetParallelism: options.assetParallelism,
                    assetBuildConcurrency: options.assetBuildConcurrency,
                    assetBuildTime: options.assetBuildTime,
                    parameters: undefined, // parameters are only set during change set creation, so this is explicitly unset because change set already exists
                });
                return;
            }
            const startSynthTime = new Date().getTime();
            const assembly = await this.assembly(options.cacheCloudAssembly);
            const stackCollection = await assembly.selectStacksV2(options.selector);
            await this.validateStacks(assembly, stackCollection);
            const elapsedSynthTime = new Date().getTime() - startSynthTime;
            await this.ioHost.asIoHelper().defaults.info(`\n✨  Synthesis time: ${(0, util_1.formatTime)(elapsedSynthTime)}s\n`);
            if (stackCollection.stackCount === 0) {
                await this.ioHost.asIoHelper().defaults.error('This app contains no stacks');
                return;
            }
            const migrator = new api_1.ResourceMigrator({
                deployments: this.props.deployments,
                ioHelper: (0, api_private_1.asIoHelper)(this.ioHost, 'deploy'),
            });
            await migrator.tryMigrateResources(stackCollection, {
                toolkitStackName: this.toolkitStackName,
                ...options,
            });
            if (options.deploymentMethod?.method === 'hotswap') {
                await this.ioHost.asIoHelper().defaults.warn('⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments');
                await this.ioHost.asIoHelper().defaults.warn('⚠️ They should only be used for development - never use them for your production Stacks!\n');
            }
            const stacks = stackCollection.stackArtifacts;
            const assetBuildTime = options.assetBuildTime ?? AssetBuildTime.ALL_BEFORE_DEPLOY;
            const prebuildAssets = assetBuildTime === AssetBuildTime.ALL_BEFORE_DEPLOY;
            const concurrency = options.concurrency || 1;
            if (concurrency > 1) {
                // the "bar" progress output doesn't support concurrency, fall back to "events"
                if (this.ioHost.stackProgress === deploy_1.StackActivityProgress.BAR) {
                    this.ioHost.stackProgress = deploy_1.StackActivityProgress.EVENTS;
                }
                // ...but only warn if the user explicitly requested "bar" progress
                if (options.progress === deploy_1.StackActivityProgress.BAR) {
                    await this.ioHost.asIoHelper().defaults.warn('⚠️ The --concurrency flag does not support --progress "bar". Switching to "events".');
                }
            }
            const stacksAndTheirAssetManifests = stacks.flatMap((stack) => [
                stack,
                ...stack.dependencies.filter(x => cxapi.AssetManifestArtifact.isAssetManifestArtifact(x)),
            ]);
            const workGraph = new api_1.WorkGraphBuilder((0, api_private_1.asIoHelper)(this.ioHost, 'deploy'), prebuildAssets).build(stacksAndTheirAssetManifests);
            // Unless we are running with '--force', skip already published assets
            if (!options.force) {
                await this.removePublishedAssets(workGraph, options);
            }
            const graphConcurrency = {
                'stack': concurrency,
                'asset-build': (options.assetParallelism ?? true) ? options.assetBuildConcurrency ?? 1 : 1, // This will be CPU-bound/memory bound, mostly matters for Docker builds
                'asset-publish': (options.assetParallelism ?? true) ? 8 : 1, // This will be I/O-bound, 8 in parallel seems reasonable
                'marker': 1,
            };
            const deploymentActions = new WorkGraphDeploymentActions(this.props.deployments, this.ioHost, this, {
                roleArn: options.roleArn,
                force: options.force,
                stackCount: stackCollection.stackCount,
                notificationArns: options.notificationArns,
                deploymentMethod: options.deploymentMethod,
                toolkitStackName: this.toolkitStackName,
                reuseAssets: options.reuseAssets,
                tags: options.tags,
                parameters: options.parameters,
                usePreviousParameters: options.usePreviousParameters,
                rollback: options.rollback,
                concurrency,
                requireApproval,
                assetParallelism: options.assetParallelism,
                extraUserAgent: options.extraUserAgent,
                cloudWatchLogMonitor: options.cloudWatchLogMonitor,
                sdkProvider: this.props.sdkProvider,
                express: options.express,
            });
            const startDeployTime = Date.now();
            await workGraph.doParallel(graphConcurrency, deploymentActions);
            if (options.outputsFile) {
                // If an outputs file has been specified, create the file path and write stack outputs to it once.
                // Outputs are written after all stacks have been deployed. If a stack deployment fails,
                // all of the outputs from successfully deployed stacks before the failure will still be written.
                await deploymentActions.writeOutputs(options.outputsFile);
            }
            // Add a timer on the COMMAND span for the full deployment wait time (not the same as the sum of all DEPLOY
            // spans because of parallelism).
            this.ioHost.telemetry?.commandSpan?.addTimer('totalDeployTime', Date.now() - startDeployTime);
            await this.ioHost.asIoHelper().defaults.info(`\n✨  Total time: ${(0, util_1.formatTime)(Date.now() - startSynthTime)}s\n`);
        }
        catch (e_2) {
            env_2.error = e_2;
            env_2.hasError = true;
        }
        finally {
            __disposeResources(env_2);
        }
    }
    /**
     * Detect infrastructure drift for the given stack(s)
     */
    async drift(options) {
        const driftResults = await this.toolkit.drift(this.props.cloudExecutable, {
            stacks: options.selector,
        });
        const totalDrifts = Object.values(driftResults).reduce((total, current) => total + (current.numResourcesWithDrift ?? 0), 0);
        return totalDrifts > 0 && options.fail ? 1 : 0;
    }
    /**
     * Validate synthesized templates against policy rules
     */
    async validate(options) {
        // Implicitly switch 'debug' mode to true; more stack traces = more useful.
        this.props.cloudExecutable.switchOnDebugging();
        // `watch` is a CLI-only flag; strip it before crossing into toolkit-lib so
        // it does not leak into the library's validate action.
        const { watch, ...validateOptions } = options;
        if (watch) {
            return this.validateWatch(validateOptions);
        }
        const result = await this.toolkit.validate(this.props.cloudExecutable, validateOptions);
        return result.conclusion === 'failure' ? 1 : 0;
    }
    /**
     * Continuously validate the project, re-synthesizing and re-validating on
     * every file change. Never deploys.
     *
     * The files to observe are configured with the "watch" key of `cdk.json`,
     * exactly like `cdk deploy --watch`.
     */
    async validateWatch(options) {
        const rootDir = path.dirname(path.resolve(user_configuration_1.PROJECT_CONFIG));
        const watchSettings = this.props.configuration.settings.get(['watch']);
        if (!watchSettings) {
            throw new toolkit_lib_1.ToolkitError('WatchConfigMissing', "Cannot use '--watch' without specifying at least one directory to monitor. " +
                'Make sure to add a "watch" key to your cdk.json');
        }
        const include = this.patternsArrayForWatch(watchSettings.include, {
            defaultPattern: '**',
            returnDefaultIfEmpty: true,
        });
        // Pass the user's excludes explicitly; toolkit-lib always appends the
        // outdir, dot-file, and node_modules excludes on top of these.
        const exclude = this.patternsArrayForWatch(watchSettings.exclude, {
            defaultPattern: '',
            returnDefaultIfEmpty: false,
        });
        const watcher = await this.toolkit.watchValidate(this.props.cloudExecutable.uncachedSource(), {
            ...options,
            watchDir: rootDir,
            include,
            exclude,
        });
        return watcher.waitForEnd();
    }
    /**
     * Diagnose errors
     */
    async diagnose(options) {
        // Implicitly switch 'debug' mode to true; more stack traces = more useful.
        this.props.cloudExecutable.switchOnDebugging();
        const results = await this.toolkit.diagnose(this.props.cloudExecutable, options);
        if (results.stacks.some(s => s.result.type !== 'no-problem')) {
            return 1;
        }
        return 0;
    }
    /**
     * Roll back the given stack or stacks.
     */
    async rollback(options) {
        const startSynthTime = new Date().getTime();
        const assembly = await this.assembly();
        const stackCollection = await assembly.selectStacksV2(options.selector);
        await this.validateStacks(assembly, stackCollection);
        const elapsedSynthTime = new Date().getTime() - startSynthTime;
        await this.ioHost.asIoHelper().defaults.info(`\n✨  Synthesis time: ${(0, util_1.formatTime)(elapsedSynthTime)}s\n`);
        if (stackCollection.stackCount === 0) {
            await this.ioHost.asIoHelper().defaults.error('No stacks selected');
            return;
        }
        let anyRollbackable = false;
        for (const stack of stackCollection.stackArtifacts) {
            await this.ioHost.asIoHelper().defaults.info('Rolling back %s', chalk_1.default.bold(stack.displayName));
            const startRollbackTime = new Date().getTime();
            try {
                const result = await this.props.deployments.rollbackStack({
                    stack,
                    roleArn: options.roleArn,
                    toolkitStackName: options.toolkitStackName,
                    orphanFailedResources: options.force,
                    validateBootstrapStackVersion: options.validateBootstrapStackVersion,
                    orphanLogicalIds: options.orphanLogicalIds,
                });
                if (!result.notInRollbackableState) {
                    anyRollbackable = true;
                }
                const elapsedRollbackTime = new Date().getTime() - startRollbackTime;
                await this.ioHost.asIoHelper().defaults.info(`\n✨  Rollback time: ${(0, util_1.formatTime)(elapsedRollbackTime).toString()}s\n`);
            }
            catch (e) {
                await this.ioHost.asIoHelper().defaults.error('\n ❌  %s failed: %s', chalk_1.default.bold(stack.displayName), (0, util_1.formatErrorMessage)(e));
                throw new toolkit_lib_1.ToolkitError('RollbackFailed', 'Rollback failed (use --force to orphan failing resources)');
            }
        }
        if (!anyRollbackable) {
            throw new toolkit_lib_1.ToolkitError('NoRollbackableStacks', 'No stacks were in a state that could be rolled back');
        }
    }
    async publishAssets(options) {
        await this.toolkit.publishAssets(this.props.cloudExecutable, options);
    }
    async watch(options) {
        const rootDir = path.dirname(path.resolve(user_configuration_1.PROJECT_CONFIG));
        const ioHelper = (0, api_private_1.asIoHelper)(this.ioHost, 'watch');
        await this.ioHost.asIoHelper().defaults.debug("root directory used for 'watch' is: %s", rootDir);
        const watchSettings = this.props.configuration.settings.get(['watch']);
        if (!watchSettings) {
            throw new toolkit_lib_1.ToolkitError('WatchConfigMissing', "Cannot use the 'watch' command without specifying at least one directory to monitor. " +
                'Make sure to add a "watch" key to your cdk.json');
        }
        // For the "include" subkey under the "watch" key, the behavior is:
        // 1. No "watch" setting? We error out.
        // 2. "watch" setting without an "include" key? We default to observing "./**".
        // 3. "watch" setting with an empty "include" key? We default to observing "./**".
        // 4. Non-empty "include" key? Just use the "include" key.
        // Note: We use '**' as the default pattern (not rootDir) because chokidar reports
        // file paths relative to cwd, and the ignored function uses picomatch which expects
        // glob patterns, not absolute paths.
        const watchIncludes = this.patternsArrayForWatch(watchSettings.include, {
            defaultPattern: '**',
            returnDefaultIfEmpty: true,
        });
        await this.ioHost.asIoHelper().defaults.debug("'include' patterns for 'watch': %s", watchIncludes);
        // For the "exclude" subkey under the "watch" key,
        // the behavior is to add some default excludes in addition to the ones specified by the user:
        // 1. The CDK output directory.
        // 2. Any file whose name starts with a dot.
        // 3. Any directory's content whose name starts with a dot.
        // 4. Any node_modules and its content (even if it's not a JS/TS project, you might be using a local aws-cli package)
        const outputDir = this.props.configuration.settings.get(['output']);
        const watchExcludes = this.patternsArrayForWatch(watchSettings.exclude, {
            defaultPattern: '',
            returnDefaultIfEmpty: false,
        }).concat(`${outputDir}/**`, '**/.*', '**/.*/**', '**/node_modules/**');
        await this.ioHost.asIoHelper().defaults.debug("'exclude' patterns for 'watch': %s", watchExcludes);
        // Since 'cdk deploy' is a relatively slow operation for a 'watch' process,
        // introduce a concurrency latch that tracks the state.
        // This way, if file change events arrive when a 'cdk deploy' is still executing,
        // we will batch them, and trigger another 'cdk deploy' after the current one finishes,
        // making sure 'cdk deploy's  always execute one at a time.
        // Here's a diagram showing the state transitions:
        // --------------                --------    file changed     --------------    file changed     --------------  file changed
        // |            |  ready event   |      | ------------------> |            | ------------------> |            | --------------|
        // | pre-ready  | -------------> | open |                     | deploying  |                     |   queued   |               |
        // |            |                |      | <------------------ |            | <------------------ |            | <-------------|
        // --------------                --------  'cdk deploy' done  --------------  'cdk deploy' done  --------------
        let latch = 'pre-ready';
        const cloudWatchLogMonitor = options.traceLogs ? new api_1.CloudWatchLogEventMonitor({
            ioHelper,
        }) : undefined;
        const deployAndWatch = async () => {
            latch = 'deploying';
            await cloudWatchLogMonitor?.deactivate();
            await this.invokeDeployFromWatch(options, cloudWatchLogMonitor);
            // If latch is still 'deploying' after the 'await', that's fine,
            // but if it's 'queued', that means we need to deploy again
            while (latch === 'queued') {
                // TypeScript doesn't realize latch can change between 'awaits',
                // and thinks the above 'while' condition is always 'false' without the cast
                latch = 'deploying';
                await this.ioHost.asIoHelper().defaults.info("Detected file changes during deployment. Invoking 'cdk deploy' again");
                await this.invokeDeployFromWatch(options, cloudWatchLogMonitor);
            }
            latch = 'open';
            await cloudWatchLogMonitor?.activate();
        };
        // Create ignore matcher for chokidar v4 compatibility
        // Chokidar v4 removed glob pattern support, so we use picomatch to filter files
        // We pass rootDir because chokidar v4 passes absolute paths to the ignored callback
        const shouldIgnore = (0, api_private_1.createIgnoreMatcher)({
            include: watchIncludes,
            exclude: watchExcludes,
            rootDir,
        });
        chokidar
            .watch('.', {
            ignored: shouldIgnore,
            cwd: rootDir,
        })
            .on('ready', async () => {
            latch = 'open';
            await this.ioHost.asIoHelper().defaults.debug("'watch' received the 'ready' event. From now on, all file changes will trigger a deployment");
            await this.ioHost.asIoHelper().defaults.info("Triggering initial 'cdk deploy'");
            await deployAndWatch();
        })
            .on('all', async (event, filePath) => {
            if (!isFileEvent(event)) {
                return; // Ignore non-file events like 'error', 'raw', 'ready', 'all'
            }
            if (latch === 'pre-ready') {
                await this.ioHost.asIoHelper().defaults.info(`'watch' is observing ${event === 'addDir' ? 'directory' : 'the file'} '%s' for changes`, filePath);
            }
            else if (latch === 'open') {
                await this.ioHost.asIoHelper().defaults.info("Detected change to '%s' (type: %s). Triggering 'cdk deploy'", filePath, event);
                await deployAndWatch();
            }
            else {
                // this means latch is either 'deploying' or 'queued'
                latch = 'queued';
                await this.ioHost.asIoHelper().defaults.info("Detected change to '%s' (type: %s) while 'cdk deploy' is still running. " +
                    'Will queue for another deployment after this one finishes', filePath, event);
            }
        });
    }
    async orphan(options) {
        await this.toolkit.orphan(this.props.cloudExecutable, {
            constructPaths: options.constructPath,
            roleArn: options.roleArn,
            toolkitStackName: options.toolkitStackName,
        });
    }
    async import(options) {
        const assembly = await this.assembly();
        const stacks = await assembly.selectStacksV2(options.selector);
        await this.validateStacks(assembly, stacks);
        // set progress from options, this includes user and app config
        if (options.progress) {
            this.ioHost.stackProgress = options.progress;
        }
        if (stacks.stackCount > 1) {
            throw new toolkit_lib_1.ToolkitError('AmbiguousStackSelection', `Stack selection is ambiguous, please choose a specific stack for import [${stacks.stackArtifacts.map((x) => x.id).join(', ')}]`);
        }
        if (!process.stdout.isTTY && !options.resourceMappingFile && !options.resourceMappingInline) {
            throw new toolkit_lib_1.ToolkitError('ResourceMappingRequired', '--resource-mapping or --resource-mapping-inline is required when input is not a terminal');
        }
        const stack = stacks.stackArtifacts[0];
        await this.ioHost.asIoHelper().defaults.info(chalk_1.default.bold(stack.displayName));
        const resourceImporter = new api_1.ResourceImporter(stack, {
            deployments: this.props.deployments,
            ioHelper: (0, api_private_1.asIoHelper)(this.ioHost, 'import'),
        });
        const { additions, hasNonAdditions, diffFormatter } = await resourceImporter.discoverImportableResources(options.force);
        // If there are non-addition changes (e.g. after orphan, hardcoded refs differ from Fn::GetAtt),
        // warn the user and ask for confirmation unless --force was given.
        if (hasNonAdditions && !options.force) {
            const ioHelper = this.ioHost.asIoHelper();
            await ioHelper.defaults.info(`The following resources have pending updates that will be reconciled with a ${chalk_1.default.blueBright('cdk deploy')} after import:`);
            const { formattedDiff } = diffFormatter.formatStackDiff();
            await ioHelper.defaults.info(formattedDiff);
            const confirmed = await ioHelper.requestResponse(api_private_1.IO.CDK_TOOLKIT_I7010.req('Perform import?', { motivation: 'Confirm import with pending drift' }));
            if (!confirmed) {
                throw new toolkit_lib_1.AbortError('ImportAborted', 'Import cancelled');
            }
        }
        if (additions.length === 0) {
            await this.ioHost.asIoHelper().defaults.warn('%s: no new resources compared to the currently deployed stack, skipping import.', chalk_1.default.bold(stack.displayName));
            return;
        }
        // Prepare a mapping of physical resources to CDK constructs
        let actualImport;
        if (options.resourceMappingInline) {
            actualImport = await resourceImporter.loadResourceIdentifiers(additions, options.resourceMappingInline);
        }
        else if (options.resourceMappingFile) {
            actualImport = await resourceImporter.loadResourceIdentifiersFromFile(additions, options.resourceMappingFile);
        }
        else {
            actualImport = await resourceImporter.askForResourceIdentifiers(additions);
        }
        if (actualImport.importResources.length === 0) {
            await this.ioHost.asIoHelper().defaults.warn('No resources selected for import.');
            return;
        }
        // If "--create-resource-mapping" option was passed, write the resource mapping to the given file and exit
        if (options.recordResourceMapping) {
            const outputFile = options.recordResourceMapping;
            fs.ensureFileSync(outputFile);
            await fs.writeJson(outputFile, actualImport.resourceMap, {
                spaces: 2,
                encoding: 'utf8',
            });
            await this.ioHost.asIoHelper().defaults.info('%s: mapping file written.', outputFile);
            return;
        }
        // Following are the same semantics we apply with respect to Notification ARNs (dictated by the SDK)
        //
        //  - undefined  =>  cdk ignores it, as if it wasn't supported (allows external management).
        //  - []:        =>  cdk manages it, and the user wants to wipe it out.
        //  - ['arn-1']  =>  cdk manages it, and the user wants to set it to ['arn-1'].
        const notificationArns = (!!options.notificationArns || !!stack.notificationArns)
            ? (options.notificationArns ?? []).concat(stack.notificationArns ?? [])
            : undefined;
        for (const notificationArn of notificationArns ?? []) {
            if (!(0, util_1.validateSnsTopicArn)(notificationArn)) {
                throw new toolkit_lib_1.ToolkitError('InvalidSnsTopicArn', `Notification arn ${notificationArn} is not a valid arn for an SNS topic`);
            }
        }
        // Import the resources according to the given mapping
        await this.ioHost.asIoHelper().defaults.info('%s: importing resources into stack...', chalk_1.default.bold(stack.displayName));
        const tags = (0, api_private_1.tagsForStack)(stack);
        await resourceImporter.importResourcesFromMap(actualImport, {
            roleArn: options.roleArn,
            tags,
            deploymentMethod: options.deploymentMethod,
            usePreviousParameters: true,
            rollback: options.rollback,
            notificationArns,
        });
        // Notify user of next steps
        if (actualImport.importResources.length < additions.length) {
            await this.ioHost.asIoHelper().defaults.warn(`Some resources were skipped. Run another ${chalk_1.default.blueBright('cdk import')} or a ${chalk_1.default.blueBright('cdk deploy')} to bring the stack up-to-date with your CDK app definition.`);
        }
        else if (hasNonAdditions) {
            // After orphan→import, the deployed template still has hardcoded values that differ from
            // the synth'd template's Fn::GetAtt/Ref intrinsics. A deploy updates the template to match the CDK app.
            if (options.force) {
                await this.ioHost.asIoHelper().defaults.info(`Import complete. Run ${chalk_1.default.blueBright('cdk deploy')} to update the stack to match your CDK app.`);
            }
            else {
                const deployNow = await this.ioHost.asIoHelper().requestResponse(api_private_1.IO.CDK_TOOLKIT_I7010.req(`Finish with a ${chalk_1.default.blueBright('cdk deploy')} now?`, { motivation: 'Update stack to match CDK app after import' }));
                if (deployNow) {
                    await this.deploy({
                        // The import selector is exact (no expansion); the follow-up deploy
                        // historically expands to upstream dependencies like a plain deploy.
                        selector: { ...options.selector, expand: cloud_assembly_1.ExpandStackSelection.UPSTREAM },
                        toolkitStackName: options.toolkitStackName,
                        roleArn: options.roleArn,
                        deploymentMethod: options.deploymentMethod,
                    });
                }
                else {
                    await this.ioHost.asIoHelper().defaults.info(`Import complete. Remember to run ${chalk_1.default.blueBright('cdk deploy')} to update the stack to match your CDK app.`);
                }
            }
        }
        else {
            await this.ioHost.asIoHelper().defaults.info(`Import operation complete. We recommend you run a ${chalk_1.default.blueBright('drift detection')} operation ` +
                'to confirm your CDK app resource definitions are up-to-date. Read more here: ' +
                chalk_1.default.underline.blueBright('https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/detect-drift-stack.html'));
        }
    }
    // The destroy action runs through toolkit-lib.
    // Suppress its new status messages to keep the output as it was before.
    async destroy(options) {
        const env_3 = { stack: [], error: void 0, hasError: false };
        try {
            // Keep the "deployed" wording when a destroy runs as part of a deploy.
            const action = options.fromDeploy ? 'deploy' : 'destroy';
            if ((options.concurrency || 1) > 1 && this.ioHost.stackProgress === deploy_1.StackActivityProgress.BAR) {
                this.ioHost.stackProgress = deploy_1.StackActivityProgress.EVENTS;
            }
            // The success line was `info` in the historical `cdk destroy`, not `result`.
            const _successLevel = __addDisposableResource(env_3, this.ioHost.on(api_private_1.IO.CDK_TOOLKIT_I7900, () => ({ level: 'info' })), false); // ✅ <stack>: destroyed
            // toolkit-lib logs a declined confirmation (E7010) and returns gracefully.
            // The CLI surfaces a decline as a non-zero, soft exit instead: throwing from
            // the listener both suppresses the log and aborts the command (the top-level
            // renders `AbortError` as "Deletion cancelled").
            const _declineAborts = __addDisposableResource(env_3, this.ioHost.on(api_private_1.IO.CDK_TOOLKIT_E7010, () => {
                throw new toolkit_lib_1.AbortError('DestroyAborted', 'Deletion cancelled');
            }), false);
            const _forceConfirms = __addDisposableResource(env_3, options.force ? this.ioHost.respondOnce(api_private_1.IO.CDK_TOOLKIT_I7010, true) : undefined, false);
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore - `_destroyWithAction` is private; the CLI sets the action label.
            await this.toolkit._destroyWithAction(this.props.cloudExecutable, action, {
                stacks: options.selector,
                roleArn: options.roleArn,
                concurrency: options.concurrency,
                express: options.express,
            });
        }
        catch (e_3) {
            env_3.error = e_3;
            env_3.hasError = true;
        }
        finally {
            __disposeResources(env_3);
        }
    }
    // cdk ls stdout is the stack listing only. Suppress the info status lines synthesis emits next
    // to it: the synth-time line (I1000) and the dependency-expansion note (I1002).
    async list(selectors, options = {}) {
        const env_4 = { stack: [], error: void 0, hasError: false };
        try {
            // One-shot: disposes itself when the listing (I2901) is emitted; the
            // `using` covers the case where `list` throws before that happens.
            const _formatter = __addDisposableResource(env_4, this.ioHost.rewriteOnce(api_private_1.IO.CDK_TOOLKIT_I2901, (msg) => (0, list_stacks_1.formatStackList)(msg.data.stacks, options)), false);
            await this.toolkit.list(this.props.cloudExecutable, {
                stacks: selectors.length > 0 ? (0, cloud_assembly_1.selectWithUpstream)(...selectors) : undefined,
            });
            return 0; // exit-code
        }
        catch (e_4) {
            env_4.error = e_4;
            env_4.hasError = true;
        }
        finally {
            __disposeResources(env_4);
        }
    }
    /**
     * Synthesize the given set of stacks (called when the user runs 'cdk synth')
     *
     * INPUT: Stack names can be supplied using a glob filter. If no stacks are
     * given, all stacks from the application are implicitly selected.
     *
     * OUTPUT: If more than one stack ends up being selected, an output directory
     * should be supplied, where the templates will be written.
     */
    async synth(options) {
        const stackNames = options.stackNames;
        const exclusively = options.exclusively ?? false;
        const quiet = options.quiet ?? false;
        const autoValidate = options.autoValidate ?? false;
        const json = options.json ?? false;
        const assembly = await this.assembly();
        const stacks = await this.selectTopLevelOrMatchingStacks(assembly, stackNames, exclusively);
        const autoValidateStacks = autoValidate
            ? assembly.selectStacksForValidation()
            : new cloud_assembly_1.StackCollection(assembly, []);
        await this.validateStacks(assembly, stacks.concat(autoValidateStacks));
        // if we have a single stack, print it to STDOUT
        if (stacks.stackCount === 1) {
            if (!quiet) {
                await printSerializedObject(this.ioHost.asIoHelper(), (0, util_1.obscureTemplate)(stacks.firstStack.template), json);
            }
            // In CI mode, non-error messages go to stdout. When we just printed the
            // template to stdout, skip the flags message to preserve the contract that
            // `cdk synth` output is valid YAML. When quiet (no template printed) or
            // non-CI (flags go to stderr), it's safe to show.
            if (quiet || !this.ioHost.isCI) {
                await displayFlagsMessage(this.ioHost.asIoHelper(), this.toolkit, this.props.cloudExecutable);
            }
            return undefined;
        }
        // not outputting template to stdout, let's explain things to the user a little bit...
        await this.ioHost.asIoHelper().defaults.info(chalk_1.default.green(`Successfully synthesized to ${chalk_1.default.blue(path.resolve(stacks.assembly.directory))}`));
        await this.ioHost.asIoHelper().defaults.info(`Supply a stack id (${stacks.stackArtifacts.map((s) => chalk_1.default.green(s.hierarchicalId)).join(', ')}) to display its template.`);
        await displayFlagsMessage(this.ioHost.asIoHelper(), this.toolkit, this.props.cloudExecutable);
        return undefined;
    }
    /**
     * Bootstrap the CDK Toolkit stack in the accounts used by the specified stack(s).
     *
     * @param userEnvironmentSpecs - environment names that need to have toolkit support
     *             provisioned, as a glob filter. If none is provided, all stacks are implicitly selected.
     * @param options - The name, role ARN, bootstrapping parameters, etc. to be used for the CDK Toolkit stack.
     */
    async bootstrap(userEnvironmentSpecs, options) {
        const bootstrapper = new bootstrap_1.Bootstrapper(options.source, (0, api_private_1.asIoHelper)(this.ioHost, 'bootstrap'));
        // If there is an '--app' argument and an environment looks like a glob, we
        // select the environments from the app. Otherwise, use what the user said.
        const environments = await this.defineEnvironments(userEnvironmentSpecs);
        const limit = pLimit(20);
        // eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
        await Promise.all(environments.map((environment) => limit(async () => {
            await this.ioHost.asIoHelper().defaults.info(chalk_1.default.green(' ⏳  Bootstrapping environment %s...'), chalk_1.default.blue(environment.name));
            try {
                const result = await bootstrapper.bootstrapEnvironment(environment, this.props.sdkProvider, options);
                const message = result.noOp
                    ? '✅  Environment %s bootstrapped (no changes).'
                    : '✅  Environment %s bootstrapped.';
                await this.ioHost.asIoHelper().defaults.info(chalk_1.default.green(message), chalk_1.default.blue(environment.name));
                if (options.express) {
                    const warning = (0, api_private_1.formatExpressStabilizationWarning)(result.stabilizingResources, 'bootstrap');
                    if (warning) {
                        await this.ioHost.asIoHelper().notify(api_private_1.IO.CDK_TOOLKIT_W9902.msg(warning));
                    }
                }
            }
            catch (e) {
                await this.ioHost.asIoHelper().defaults.error(' ❌  Environment %s failed bootstrapping: %s', chalk_1.default.blue(environment.name), e);
                throw e;
            }
        })));
    }
    /**
     * Garbage collects assets from a CDK app's environment
     * @param options - Options for Garbage Collection
     */
    async garbageCollect(userEnvironmentSpecs, options) {
        const environments = await this.defineEnvironments(userEnvironmentSpecs);
        for (const environment of environments) {
            await this.ioHost.asIoHelper().defaults.info(chalk_1.default.green(' ⏳  Garbage Collecting environment %s...'), chalk_1.default.blue(environment.name));
            const gc = new api_1.GarbageCollector({
                sdkProvider: this.props.sdkProvider,
                ioHelper: (0, api_private_1.asIoHelper)(this.ioHost, 'gc'),
                resolvedEnvironment: environment,
                bootstrapStackName: options.bootstrapStackName,
                rollbackBufferDays: options.rollbackBufferDays,
                createdBufferDays: options.createdBufferDays,
                action: options.action ?? 'full',
                type: options.type ?? 'all',
                confirm: options.confirm ?? true,
            });
            await gc.garbageCollect();
        }
    }
    async defineEnvironments(userEnvironmentSpecs) {
        // By default, glob for everything
        const environmentSpecs = userEnvironmentSpecs.length > 0 ? [...userEnvironmentSpecs] : ['**'];
        // Partition into globs and non-globs (this will mutate environmentSpecs).
        const globSpecs = (0, util_1.partition)(environmentSpecs, cxapp_1.looksLikeGlob);
        if (globSpecs.length > 0 && !this.props.cloudExecutable.hasApp) {
            if (userEnvironmentSpecs.length > 0) {
                // User did request this glob
                throw new toolkit_lib_1.ToolkitError('InvalidEnvironmentGlob', `'${globSpecs}' is not an environment name. Specify an environment name like 'aws://123456789012/us-east-1', or run in a directory with 'cdk.json' to use wildcards.`);
            }
            else {
                // User did not request anything
                throw new toolkit_lib_1.ToolkitError('EnvironmentRequired', "Specify an environment name like 'aws://123456789012/us-east-1', or run in a directory with 'cdk.json'.");
            }
        }
        const environments = [...(0, cxapp_1.environmentsFromDescriptors)(environmentSpecs)];
        // If there is an '--app' argument, select the environments from the app.
        if (this.props.cloudExecutable.hasApp) {
            const assembly = await this.assembly();
            const allStacks = await assembly.selectStacksV2(cloud_assembly_1.ALL_STACKS);
            environments.push(...(await (0, cxapp_1.globEnvironmentsFromStacks)(allStacks, globSpecs, this.props.sdkProvider)));
        }
        return environments;
    }
    /**
     * Migrates a CloudFormation stack/template to a CDK app
     * @param options - Options for CDK app creation
     */
    async migrate(options) {
        await this.ioHost.asIoHelper().defaults.warn('This command is an experimental feature.');
        const language = options.language?.toLowerCase() ?? 'typescript';
        const environment = (0, migrate_1.setEnvironment)(options.account, options.region);
        let generateTemplateOutput;
        let cfn;
        let templateToDelete;
        try {
            // if neither fromPath nor fromStack is provided, generate a template using cloudformation
            const scanType = (0, migrate_1.parseSourceOptions)(options.fromPath, options.fromStack, options.stackName).source;
            if (scanType == migrate_1.TemplateSourceOptions.SCAN) {
                generateTemplateOutput = await (0, migrate_1.generateTemplate)({
                    stackName: options.stackName,
                    filters: options.filter,
                    fromScan: options.fromScan,
                    sdkProvider: this.props.sdkProvider,
                    environment: environment,
                    ioHelper: this.ioHost.asIoHelper(),
                });
                templateToDelete = generateTemplateOutput.templateId;
            }
            else if (scanType == migrate_1.TemplateSourceOptions.PATH) {
                const templateBody = (0, migrate_1.readFromPath)(options.fromPath);
                const parsedTemplate = (0, util_1.deserializeStructure)(templateBody);
                const templateId = parsedTemplate.Metadata?.AWSToolsMetrics?.IaC_Generator?.toString();
                if (templateId) {
                    // if we have a template id, we can call describe generated template to get the resource identifiers
                    // resource metadata, and template source to generate the template
                    cfn = new migrate_1.CfnTemplateGeneratorProvider(await (0, migrate_1.buildCfnClient)(this.props.sdkProvider, environment), this.ioHost.asIoHelper());
                    const generatedTemplateSummary = await cfn.describeGeneratedTemplate(templateId);
                    generateTemplateOutput = (0, migrate_1.buildGeneratedTemplateOutput)(generatedTemplateSummary, templateBody, generatedTemplateSummary.GeneratedTemplateId);
                }
                else {
                    generateTemplateOutput = {
                        migrateJson: {
                            templateBody: templateBody,
                            source: 'localfile',
                        },
                    };
                }
            }
            else if (scanType == migrate_1.TemplateSourceOptions.STACK) {
                const template = await (0, migrate_1.readFromStack)(options.stackName, this.props.sdkProvider, environment);
                if (!template) {
                    throw new toolkit_lib_1.ToolkitError('StackTemplateNotFound', `No template found for stack-name: ${options.stackName}`);
                }
                generateTemplateOutput = {
                    migrateJson: {
                        templateBody: template,
                        source: options.stackName,
                    },
                };
            }
            else {
                // We shouldn't ever get here, but just in case.
                throw new toolkit_lib_1.ToolkitError('InvalidSourceOption', `Invalid source option provided: ${scanType}`);
            }
            const stack = (0, migrate_1.generateStack)(generateTemplateOutput.migrateJson.templateBody, options.stackName, language);
            await this.ioHost.asIoHelper().defaults.info(chalk_1.default.green(' ⏳  Generating CDK app for %s...'), chalk_1.default.blue(options.stackName));
            await (0, migrate_1.generateCdkApp)(this.ioHost.asIoHelper(), options.stackName, stack, language, options.outputPath, options.compress);
            if (generateTemplateOutput) {
                (0, migrate_1.writeMigrateJsonFile)(options.outputPath, options.stackName, generateTemplateOutput.migrateJson);
            }
            if ((0, migrate_1.isThereAWarning)(generateTemplateOutput)) {
                await this.ioHost.asIoHelper().defaults.warn(' ⚠️  Some resources could not be migrated completely. Please review the README.md file for more information.');
                (0, migrate_1.appendWarningsToReadme)(`${path.join(options.outputPath ?? process.cwd(), options.stackName)}/README.md`, generateTemplateOutput.resources);
            }
        }
        catch (e) {
            await this.ioHost.asIoHelper().defaults.error(' ❌  Migrate failed for `%s`: %s', options.stackName, e.message);
            throw e;
        }
        finally {
            if (templateToDelete) {
                if (!cfn) {
                    cfn = new migrate_1.CfnTemplateGeneratorProvider(await (0, migrate_1.buildCfnClient)(this.props.sdkProvider, environment), this.ioHost.asIoHelper());
                }
                if (!process.env.MIGRATE_INTEG_TEST) {
                    await cfn.deleteGeneratedTemplate(templateToDelete);
                }
            }
        }
    }
    async refactor(options) {
        if (options.revert && !options.overrideFile) {
            throw new toolkit_lib_1.ToolkitError('RevertRequiresOverrideFile', 'The --revert option can only be used with the --override-file option.');
        }
        try {
            await this.toolkit.refactor(this.props.cloudExecutable, {
                dryRun: options.dryRun,
                stacks: options.stacks ?? cloud_assembly_1.ALL_STACKS,
                force: options.force,
                additionalStackNames: options.additionalStackNames,
                overrides: readOverrides(options.overrideFile, options.revert),
                roleArn: options.roleArn,
            });
        }
        catch (e) {
            await this.ioHost.asIoHelper().defaults.error(e.message);
            throw e;
        }
        return 0;
        function readOverrides(filePath, revert = false) {
            if (filePath == null) {
                return [];
            }
            if (!fs.pathExistsSync(filePath)) {
                throw new toolkit_lib_1.ToolkitError('MappingFileNotFound', `The mapping file ${filePath} does not exist`);
            }
            const groups = (0, refactor_1.parseMappingGroups)(fs.readFileSync(filePath).toString('utf-8'));
            return revert
                ? groups.map((group) => ({
                    ...group,
                    resources: Object.fromEntries(Object.entries(group.resources ?? {}).map(([src, dst]) => [dst, src])),
                }))
                : groups;
        }
    }
    /**
     * Select the stacks that `synth` and `diff` operate on
     *
     * With patterns: match them (failing if nothing matches), expanding to
     * upstream dependencies unless `exclusively` is set. Without patterns: all
     * top-level stacks, exactly — the historic default selection never expands
     * to dependencies, regardless of `exclusively`. A stage-only app has no
     * top-level stacks, which selects nothing and is not an error — but an app
     * without any stacks at all still is. No single selection strategy covers
     * this combination: `MAIN_ASSEMBLY` rejects stage-only apps (as
     * `deploy --all` must keep doing) and `ALL_STACKS` would wrongly include
     * the stacks inside stages.
     */
    async selectTopLevelOrMatchingStacks(assembly, patterns, exclusively) {
        if (patterns.length > 0) {
            return assembly.selectStacksV2((0, cloud_assembly_1.mustMatch)(exclusively ? (0, cloud_assembly_1.selectExact)(...patterns) : (0, cloud_assembly_1.selectWithUpstream)(...patterns)));
        }
        if (assembly.cloudAssembly.stacks.length > 0) {
            return assembly.selectStacksV2((0, cloud_assembly_1.selectAllTopLevel)(cloud_assembly_1.ExpandStackSelection.NONE));
        }
        // Stage-only app: nothing to select, which is not an error. An app
        // without any stacks at all still is: this selection throws
        // 'This app contains no stacks' in that case.
        await assembly.selectStacksV2(cloud_assembly_1.ALL_STACKS);
        return new cloud_assembly_1.StackCollection(assembly, []);
    }
    /**
     * Validate the stacks for errors and warnings according to the CLI's current settings
     */
    async validateStacks(assembly, stacks) {
        const failAt = this.validateMetadataFailAt();
        await (0, api_private_1.throwIfValidationFailures)(assembly, stacks, failAt, this.ioHost.asIoHelper());
    }
    validateMetadataFailAt() {
        let failAt = 'error';
        if (this.props.ignoreErrors) {
            failAt = 'none';
        }
        if (this.props.strict) {
            failAt = 'warn';
        }
        return failAt;
    }
    /**
     * Converts the toolkit's `CloudExecutable` into `StackAssembly`.
     *
     * @param cacheCloudAssembly - to cache the assembly, defaults to `true`
     * @returns the converted `StackAssembly`
     */
    assembly(cacheCloudAssembly = true) {
        return this.props.cloudExecutable.synthesize(cacheCloudAssembly);
    }
    patternsArrayForWatch(patterns, options) {
        const patternsArray = patterns !== undefined ? (Array.isArray(patterns) ? patterns : [patterns]) : [];
        return patternsArray.length > 0 ? patternsArray : options.returnDefaultIfEmpty ? [options.defaultPattern] : [];
    }
    async invokeDeployFromWatch(options, cloudWatchLogMonitor) {
        const deployOptions = {
            ...options,
            requireApproval: cloud_assembly_schema_1.RequireApproval.NEVER,
            // if 'watch' is called by invoking 'cdk deploy --watch',
            // we need to make sure to not call 'deploy' with 'watch' again,
            // as that would lead to a cycle
            watch: false,
            cloudWatchLogMonitor,
            cacheCloudAssembly: false,
            extraUserAgent: `cdk-watch/hotswap-${options.deploymentMethod?.method === 'hotswap' ? 'on' : 'off'}`,
            concurrency: options.concurrency,
        };
        try {
            await this.deploy(deployOptions);
        }
        catch {
            // just continue - deploy will show the error
        }
    }
    /**
     * Remove the asset publishing and building from the work graph for assets that are already in place
     */
    async removePublishedAssets(graph, options) {
        await graph.removeUnnecessaryAssets(assetNode => this.props.deployments.isSingleAssetPublished(assetNode.assetManifest, assetNode.asset, {
            stack: assetNode.parentStack,
            roleArn: options.roleArn,
            stackName: assetNode.parentStack.stackName,
        }));
    }
}
exports.CdkToolkit = CdkToolkit;
__decorate([
    (0, io_host_1.suppressMessages)(api_private_1.IO.CDK_TOOLKIT_I1001, // Starting Synthesis (trace)
    api_private_1.IO.CDK_TOOLKIT_I1000)
], CdkToolkit.prototype, "metadata", null);
__decorate([
    (0, io_host_1.suppressMessages)(api_private_1.IO.CDK_TOOLKIT_I1001, // Starting Synthesis (trace)
    api_private_1.IO.CDK_TOOLKIT_I1000, // ✨ Synthesis time (info)
    api_private_1.IO.CDK_TOOLKIT_I7101, // Starting Destroy (trace)
    api_private_1.IO.CDK_TOOLKIT_I7001, // per-stack Destroy time (trace)
    api_private_1.IO.CDK_TOOLKIT_I7000)
], CdkToolkit.prototype, "destroy", null);
__decorate([
    (0, io_host_1.suppressMessages)(api_private_1.IO.CDK_TOOLKIT_I1000, api_private_1.IO.CDK_TOOLKIT_I1002)
], CdkToolkit.prototype, "list", null);
/**
 * Print a serialized object (YAML or JSON) to stdout.
 */
async function printSerializedObject(ioHelper, obj, json) {
    await ioHelper.defaults.result((0, util_1.serializeStructure)(obj, json));
}
function buildParameterMap(parameters) {
    const parameterMap = { '*': {} };
    for (const key in parameters) {
        if (parameters.hasOwnProperty(key)) {
            const [stack, parameter] = key.split(':', 2);
            if (!parameter) {
                parameterMap['*'][stack] = parameters[key];
            }
            else {
                if (!parameterMap[stack]) {
                    parameterMap[stack] = {};
                }
                parameterMap[stack][parameter] = parameters[key];
            }
        }
    }
    return parameterMap;
}
/**
 * Ask the user for a yes/no confirmation
 *
 * Automatically fail the confirmation in case we're in a situation where the confirmation
 * cannot be interactively obtained from a human at the keyboard.
 */
async function askUserConfirmation(ioHost, req, abortErrorCode, abortMessage) {
    await ioHost.withCorkedLogging(async () => {
        // The IoHost returns the answer rather than aborting; abort here on decline.
        const confirmed = await ioHost.asIoHelper().requestResponse(req);
        if (!confirmed) {
            throw new toolkit_lib_1.AbortError(abortErrorCode, abortMessage);
        }
    });
}
/**
 * Display a warning if there are flags that are different from the recommended value
 *
 * This happens if both of the following are true:
 *
 * - The user didn't configure the value
 * - The default value for the flag (unconfiguredBehavesLike) is different from the recommended value
 */
async function displayFlagsMessage(ioHost, toolkit, cloudExecutable) {
    const flags = await toolkit.flags(cloudExecutable);
    // The "unconfiguredBehavesLike" information got added later. If none of the flags have this information,
    // we don't have enough information to reliably display this information without scaring users, so don't do anything.
    if (flags.every(flag => flag.unconfiguredBehavesLike === undefined)) {
        return;
    }
    const unconfiguredFlags = operations_1.FlagOperations.filterNeedsAttention(flags);
    const numUnconfigured = unconfiguredFlags.length;
    if (numUnconfigured > 0) {
        await ioHost.defaults.warn(`${numUnconfigured} feature flags are not configured. Run 'cdk flags --unstable=flags' to learn more.`);
    }
}
/**
 * This class implements the callbacks for the parallel work graph executions.
 *
 * All this code used to be inlined into CdkToolkit#deploy(), but it was getting
 * too much to live in there.
 */
class WorkGraphDeploymentActions {
    deployments;
    ioHost;
    stackOperations;
    options;
    stackOutputs = {};
    assetSpans = {};
    stackCounter = 1;
    constructor(deployments, ioHost, stackOperations, options) {
        this.deployments = deployments;
        this.ioHost = ioHost;
        this.stackOperations = stackOperations;
        this.options = options;
    }
    async marker(markerNode) {
        // For assets, emit IoHost messages that have been defined to start and end asset spans, which will lead to events in telemetry.
        switch (markerNode.marker.type) {
            case 'start-asset': {
                const assetSpan = await this.obtainSpan(markerNode.marker.asset);
                // Count the asset type, both on the asset-specific span and on the global COMMAND span.
                if (markerNode.marker.asset.type === 'file') {
                    this.ioHost.telemetry?.commandSpan?.incCounter('fileAsset');
                    assetSpan.incCounter('fileAsset');
                }
                else if (markerNode.marker.asset.type === 'docker') {
                    this.ioHost.telemetry?.commandSpan?.incCounter('dockerAsset');
                    assetSpan.incCounter('dockerAsset');
                }
                break;
            }
            case 'end-asset': {
                const assetSpan = await this.obtainSpan(markerNode.marker.asset);
                await assetSpan.end({});
                break;
            }
        }
    }
    async obtainSpan(assetEntry) {
        const span = this.assetSpans[assetEntry.id.assetId];
        if (span) {
            return span;
        }
        const assetSpan = await this.ioHost.asIoHelper().span(messages_1.CLI_PRIVATE_SPAN.ASSET).begin({});
        this.assetSpans[assetEntry.id.assetId] = assetSpan;
        return assetSpan;
    }
    async buildAsset(assetNode) {
        const env_5 = { stack: [], error: void 0, hasError: false };
        try {
            // Measure asset build time. Both on the global COMMAND span as well as on the asset-specific span.
            // (parallelism may cause SUM(buildAssetST) >= totalDeployTime) on the COMMAND span, indicate with [S]ub[T]ask suffix).
            const _invokeTimer = __addDisposableResource(env_5, this.ioHost.telemetry?.commandSpan?.startTimer('buildAssetST'), false);
            const _assetTimer = __addDisposableResource(env_5, (await this.obtainSpan(assetNode.asset)).startTimer('buildAsset'), false);
            await this.deployments.buildSingleAsset(assetNode.assetManifestArtifact, assetNode.assetManifest, assetNode.asset, {
                stack: assetNode.parentStack,
                roleArn: this.options.roleArn,
                stackName: assetNode.parentStack.stackName,
            });
        }
        catch (e_5) {
            env_5.error = e_5;
            env_5.hasError = true;
        }
        finally {
            __disposeResources(env_5);
        }
    }
    async publishAsset(assetNode) {
        const env_6 = { stack: [], error: void 0, hasError: false };
        try {
            // Measure asset publish time. Both on the global COMMAND span as well as on the asset-specific span.
            // (parallelism may cause SUM(publishAssetST) >= totalDeployTime) on the COMMAND span, indicate with [S]ub[T]ask suffix).
            const _invokeTimer = __addDisposableResource(env_6, this.ioHost.telemetry?.commandSpan?.startTimer('publishAssetST'), false);
            const _assetTimer = __addDisposableResource(env_6, (await this.obtainSpan(assetNode.asset)).startTimer('publishAsset'), false);
            await this.deployments.publishSingleAsset(assetNode.assetManifest, assetNode.asset, {
                stack: assetNode.parentStack,
                roleArn: this.options.roleArn,
                stackName: assetNode.parentStack.stackName,
                forcePublish: this.options.force,
            });
        }
        catch (e_6) {
            env_6.error = e_6;
            env_6.hasError = true;
        }
        finally {
            __disposeResources(env_6);
        }
    }
    async deployStack(stackNode) {
        // Counter for totalDeployedStacks, to match 'totalDeployTime' timer on the COMMAND span.
        this.ioHost.telemetry?.commandSpan?.incCounter('totalDeployedStacks');
        const stack = stackNode.stack;
        if (this.options.stackCount !== 1) {
            await this.ioHost.asIoHelper().defaults.info(chalk_1.default.bold(stack.displayName));
        }
        if (!stack.environment) {
            // eslint-disable-next-line @stylistic/max-len
            throw new toolkit_lib_1.ToolkitError('MissingEnvironment', `Stack ${stack.displayName} does not define an environment, and AWS credentials could not be obtained from standard locations or no region was configured.`);
        }
        const resourceCount = Object.keys(stack.template.Resources || {}).length;
        if (resourceCount === 0) {
            // The generated stack has no resources
            if (!(await this.deployments.stackExists({ stack }))) {
                await this.ioHost.asIoHelper().defaults.warn('%s: stack has no resources, skipping deployment.', chalk_1.default.bold(stack.displayName));
            }
            else {
                await this.ioHost.asIoHelper().defaults.warn('%s: stack has no resources, deleting existing stack.', chalk_1.default.bold(stack.displayName));
                await this.stackOperations.destroy({
                    selector: (0, cloud_assembly_1.selectExact)(stack.hierarchicalId),
                    force: true,
                    roleArn: this.options.roleArn,
                    fromDeploy: true,
                });
            }
            return;
        }
        // Following are the same semantics we apply with respect to Notification ARNs (dictated by the SDK)
        //
        //  - undefined  =>  cdk ignores it, as if it wasn't supported (allows external management).
        //  - []:        =>  cdk manages it, and the user wants to wipe it out.
        //  - ['arn-1']  =>  cdk manages it, and the user wants to set it to ['arn-1'].
        const notificationArns = (!!this.options.notificationArns || !!stack.notificationArns)
            ? (this.options.notificationArns ?? []).concat(stack.notificationArns ?? [])
            : undefined;
        for (const notificationArn of notificationArns ?? []) {
            if (!(0, util_1.validateSnsTopicArn)(notificationArn)) {
                throw new toolkit_lib_1.ToolkitError('InvalidSnsTopicArn', `Notification arn ${notificationArn} is not a valid arn for an SNS topic`);
            }
        }
        const parameterMap = buildParameterMap(this.options.parameters);
        // Deploy options that are shared between change set creation and execution
        const sharedDeployOptions = {
            stack,
            deployName: stack.stackName,
            roleArn: this.options.roleArn,
            toolkitStackName: this.options.toolkitStackName,
            reuseAssets: this.options.reuseAssets,
            tags: (this.options.tags?.length ? this.options.tags : (0, api_private_1.tagsForStack)(stack)),
            forceDeployment: this.options.force,
            parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
            usePreviousParameters: this.options.usePreviousParameters,
            rollback: this.options.rollback,
            notificationArns,
            extraUserAgent: this.options.extraUserAgent,
            assetParallelism: this.options.assetParallelism,
            express: this.options.express,
        };
        // When using change-set method, always create the change set upfront.
        // This gives us an accurate diff for approval and avoids creating it twice.
        // For non-executing deployments (prepare-change-set), this is the final result.
        const prepareResult = (0, deploy_private_1.isChangeSetDeployment)(this.options.deploymentMethod)
            ? await this.deployments.prepareStack({
                ...sharedDeployOptions,
                deploymentMethod: this.options.deploymentMethod,
                willExecuteChangeSet: (0, deploy_private_1.isExecutingChangeSetDeployment)(this.options.deploymentMethod),
            })
            : undefined;
        // Also skip the approval flow when the prepared change set is a no-op —
        // there is nothing for the user to approve. Outputs, stack ARN, and
        // timings are still emitted via the normal no-op deploy path below.
        if (this.options.requireApproval !== cloud_assembly_schema_1.RequireApproval.NEVER && !prepareResult?.noOp) {
            const currentTemplate = await this.deployments.readCurrentTemplate(stack);
            const formatter = new api_1.DiffFormatter({
                templateInfo: {
                    oldTemplate: currentTemplate,
                    newTemplate: stack,
                    changeSet: prepareResult?.changeSet,
                },
            });
            const securityDiff = formatter.formatSecurityDiff();
            if (requiresApproval(this.options.requireApproval, securityDiff.permissionChangeType)) {
                const hasSecurityChanges = securityDiff.permissionChangeType !== toolkit_lib_1.PermissionChangeType.NONE;
                // Bare-fact motivation. The I5060 listener registered in `deploy()` adds
                // the `--require-approval` framing for terminal users.
                const motivation = hasSecurityChanges
                    ? 'Stack includes security-sensitive updates'
                    : 'Stack includes updates';
                const diffOutput = hasSecurityChanges ? securityDiff.formattedDiff : formatter.formatStackDiff().formattedDiff;
                await this.ioHost.asIoHelper().defaults.info(diffOutput);
                try {
                    await askUserConfirmation(this.ioHost, api_private_1.IO.CDK_TOOLKIT_I5060.req(`${motivation}. Do you wish to deploy these changes?`, {
                        motivation,
                        concurrency: this.options.concurrency,
                        permissionChangeType: securityDiff.permissionChangeType,
                        templateDiffs: formatter.diffs,
                    }), 'DeployAborted', 'Deployment cancelled');
                }
                catch (e) {
                    if (prepareResult?.changeSet?.ChangeSetName) {
                        await this.deployments.cleanupChangeSet(stack, prepareResult.changeSet.ChangeSetName);
                    }
                    throw e;
                }
            }
        }
        const stackIndex = this.stackCounter++;
        await this.ioHost.asIoHelper().defaults.info(`${chalk_1.default.bold(stack.displayName)}: deploying... [${stackIndex}/${this.options.stackCount}]`);
        const startDeployTime = new Date().getTime();
        // There is already a startDeployTime constant, but that does not work with telemetry.
        // We should integrate the two in the future
        const deploySpan = await this.ioHost.asIoHelper().span(messages_1.CLI_PRIVATE_SPAN.DEPLOY).begin({});
        deploySpan.incCounter('resources', resourceCount);
        this.ioHost.telemetry?.commandSpan?.incCounter('totalDeployedResources', resourceCount);
        let error;
        let elapsedDeployTime = 0;
        try {
            // The prepare result is final if the change set was empty (noOp) or
            // the deployment method is non-executing (prepare-change-set).
            const prepareIsFinal = prepareResult && (prepareResult.noOp || (0, deploy_private_1.isNonExecutingChangeSetDeployment)(this.options.deploymentMethod));
            let deployResult = prepareIsFinal ? prepareResult : undefined;
            // Start with user config for rollback,
            // but it might change if we encounter a failed state.
            let rollback = this.options.rollback;
            // We limit the loop to 2 iterations max as defensive programming.
            // Should not be possible to happen.
            let iteration = 0;
            while (!deployResult) {
                if (++iteration > 2) {
                    throw new toolkit_lib_1.ToolkitError('DeployLoopUnstable', 'This loop should have stabilized in 2 iterations, but didn\'t. If you are seeing this error, please report it at https://github.com/aws/aws-cdk/issues/new/choose');
                }
                const r = await this.deployments.deployStack({
                    ...sharedDeployOptions,
                    // On the first iteration, execute the prepared change set.
                    // On retries (after rollback), create a new change set since the old one is gone.
                    deploymentMethod: iteration === 1 && (0, deploy_private_1.isExecutingChangeSetDeployment)(this.options.deploymentMethod)
                        ? (0, deploy_private_1.toExecuteChangeSetDeployment)(this.options.deploymentMethod)
                        : this.options.deploymentMethod,
                    rollback,
                });
                switch (r.type) {
                    case 'did-deploy-stack':
                        deployResult = r;
                        break;
                    case 'failpaused-need-rollback-first': {
                        const motivation = r.reason === 'replacement'
                            ? `Stack is in a paused fail state (${r.status}) and change includes a replacement which cannot be deployed with "--no-rollback"`
                            : `Stack is in a paused fail state (${r.status}) and command line arguments do not include "--no-rollback"`;
                        if (this.options.force) {
                            await this.ioHost.asIoHelper().defaults.warn(`${motivation}. Rolling back first (--force).`);
                        }
                        else {
                            await askUserConfirmation(this.ioHost, api_private_1.IO.CDK_TOOLKIT_I5050.req(`${motivation}. Roll back first and then proceed with deployment`, {
                                motivation,
                                concurrency: this.options.concurrency,
                            }), 'RollbackAborted', 'Rollback cancelled');
                        }
                        // Perform a rollback
                        await this.stackOperations.rollback({
                            selector: (0, cloud_assembly_1.selectExact)(stack.hierarchicalId),
                            toolkitStackName: this.options.toolkitStackName,
                            force: this.options.force,
                        });
                        // Go around through the 'while' loop again but switch rollback to true.
                        rollback = true;
                        break;
                    }
                    case 'replacement-requires-rollback': {
                        const motivation = 'Change includes a replacement which cannot be deployed with "--no-rollback"';
                        if (this.options.force) {
                            await this.ioHost.asIoHelper().defaults.warn(`${motivation}. Proceeding with deployment with rollback enabled (--force).`);
                        }
                        else {
                            await askUserConfirmation(this.ioHost, api_private_1.IO.CDK_TOOLKIT_I5050.req(`${motivation}. Perform a deployment with rollback enabled`, {
                                concurrency: this.options.concurrency,
                                motivation,
                            }), 'ReplacementRollbackAborted', 'Rollback cancelled');
                        }
                        // Go around through the 'while' loop again but switch rollback to true.
                        rollback = true;
                        break;
                    }
                    default:
                        throw new toolkit_lib_1.ToolkitError('UnexpectedDeployResult', `Unexpected result type from deployStack: ${JSON.stringify(r)}. If you are seeing this error, please report it at https://github.com/aws/aws-cdk/issues/new/choose`);
                }
            }
            const message = deployResult.noOp
                ? '✅  %s (no changes)'
                : '✅  %s';
            await this.ioHost.asIoHelper().defaults.info(chalk_1.default.green('\n' + message), stack.displayName);
            elapsedDeployTime = new Date().getTime() - startDeployTime;
            await this.ioHost.asIoHelper().defaults.info(`\n✨  Deployment time: ${(0, util_1.formatTime)(elapsedDeployTime)}s\n`);
            if (this.options.express) {
                const warning = (0, api_private_1.formatExpressStabilizationWarning)(deployResult.stabilizingResources, 'deploy');
                if (warning) {
                    await this.ioHost.asIoHelper().notify(api_private_1.IO.CDK_TOOLKIT_W5902.msg(warning));
                }
            }
            if (Object.keys(deployResult.outputs).length > 0) {
                await this.ioHost.asIoHelper().defaults.info('Outputs:');
                this.stackOutputs[stack.stackName] = deployResult.outputs;
            }
            for (const name of Object.keys(deployResult.outputs).sort()) {
                const value = deployResult.outputs[name];
                await this.ioHost.asIoHelper().defaults.info(`${chalk_1.default.cyan(stack.id)}.${chalk_1.default.cyan(name)} = ${chalk_1.default.underline(chalk_1.default.cyan(value))}`);
            }
            await this.ioHost.asIoHelper().defaults.info('Stack ARN:');
            await this.ioHost.asIoHelper().defaults.result(deployResult.stackArn);
        }
        catch (e) {
            // It has to be exactly this string because an integration test tests for
            // "bold(stackname) failed: ResourceNotReady: <error>"
            const code = toolkit_lib_1.ToolkitError.isToolkitError(e) ? e.name : 'DeployStackFailed'; // Formerly 'DeployFailed'
            const newMessage = [`❌  ${chalk_1.default.bold(stack.stackName)} failed:`, ...(e.name ? [`${e.name}:`] : []), e.message].join(' ');
            const wrappedError = new toolkit_lib_1.ToolkitError(code, newMessage);
            error = {
                name: (0, error_1.cdkCliErrorName)(wrappedError),
            };
            throw wrappedError;
        }
        finally {
            await deploySpan.end({ error });
            if (this.options.cloudWatchLogMonitor) {
                const foundLogGroupsResult = await (0, api_1.findCloudWatchLogGroups)(this.options.sdkProvider, (0, api_private_1.asIoHelper)(this.ioHost, 'deploy'), stack);
                this.options.cloudWatchLogMonitor.addLogGroups(foundLogGroupsResult.env, foundLogGroupsResult.sdk, foundLogGroupsResult.logGroupNames);
            }
        }
    }
    async writeOutputs(outputsFile) {
        fs.ensureFileSync(outputsFile);
        await fs.writeJson(outputsFile, this.stackOutputs, {
            spaces: 2,
            encoding: 'utf8',
        });
    }
}
/**
 * Determine if manual approval is required or not. Requires approval for
 * - RequireApproval.ANYCHANGE
 * - RequireApproval.BROADENING and the changes are indeed broadening permissions
 */
function requiresApproval(requireApproval, permissionChangeType) {
    return requireApproval === cloud_assembly_schema_1.RequireApproval.ANYCHANGE ||
        requireApproval === cloud_assembly_schema_1.RequireApproval.BROADENING && permissionChangeType === toolkit_lib_1.PermissionChangeType.BROADENING;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2RrLXRvb2xraXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjZGstdG9vbGtpdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBbXBFQSxrREFlQztBQWxxRUQsNkNBQXlDO0FBQ3pDLGdEQUFrQztBQUNsQyx5Q0FBbUM7QUFFbkMsbUVBQXFEO0FBQ3JELDBFQUFpRTtBQUVqRSxzREFBK0Y7QUFDL0Ysa0RBQTBCO0FBQzFCLG1EQUFxQztBQUNyQyxvREFBNkQ7QUFDN0QsNkNBQStCO0FBQy9CLHVDQUF3RDtBQUV4RCw2REFBc0Q7QUFFdEQsdURBQWdLO0FBRWhLLGdDQVdnQjtBQUdoQixnREFBZ0Q7QUFFaEQsMERBQXlKO0FBQ3pKLDBEQUErSjtBQUUvSiw4Q0FBNEU7QUFFNUUsK0NBQTJEO0FBQzNELHlEQUEwRDtBQUUxRCxpREFlNkI7QUFFN0Isb0NBQWtHO0FBQ2xHLGtDQVFpQjtBQUNqQixxRUFBb0U7QUFDcEUsNkNBQW9EO0FBRXBELG1EQUF3RDtBQUV4RCw2REFBOEQ7QUFFOUQsNkVBQTZFO0FBQzdFLDRHQUE0RztBQUM1RyxNQUFNLE1BQU0sR0FBNkIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBRTVEOzs7O0dBSUc7QUFDSCxNQUFNLFdBQVcsR0FBRyxDQUFDLG1CQUFNLENBQUMsR0FBRyxFQUFFLG1CQUFNLENBQUMsT0FBTyxFQUFFLG1CQUFNLENBQUMsTUFBTSxFQUFFLG1CQUFNLENBQUMsTUFBTSxFQUFFLG1CQUFNLENBQUMsVUFBVSxDQUFVLENBQUM7QUFHM0c7O0dBRUc7QUFDSCxTQUFTLFdBQVcsQ0FBQyxLQUFnQjtJQUNuQyxPQUFRLFdBQWlDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQzVELENBQUM7QUF5REQ7O0dBRUc7QUFD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RUFDeEIsb0JBQW9CLENBQUMsR0FBRyxFQUN4QixvQkFBb0IsQ0FBQyxhQUFhLENBQ25DLENBQUM7WUFDSixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFTSxLQUFLLENBQUMsWUFBWSxDQUFDLFdBQW1CO1FBQzNDLEVBQUUsQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDL0IsTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsWUFBWSxFQUFFO1lBQ2pELE1BQU0sRUFBRSxDQUFDO1lBQ1QsUUFBUSxFQUFFLE1BQU07U0FDakIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsZUFBZ0MsRUFBRSxvQkFBMEM7SUFDcEcsT0FBTyxlQUFlLEtBQUssdUNBQWUsQ0FBQyxTQUFTO1FBQ2xELGVBQWUsS0FBSyx1Q0FBZSxDQUFDLFVBQVUsSUFBSSxvQkFBb0IsS0FBSyxrQ0FBb0IsQ0FBQyxVQUFVLENBQUM7QUFDL0csQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tICdub2RlOmNyeXB0byc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBmb3JtYXQgfSBmcm9tICdub2RlOnV0aWwnO1xuaW1wb3J0IHR5cGUgeyBJTWFuaWZlc3RFbnRyeSB9IGZyb20gJ0Bhd3MtY2RrL2Nkay1hc3NldHMtbGliJztcbmltcG9ydCAqIGFzIGN4YXBpIGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LWFwaSc7XG5pbXBvcnQgeyBSZXF1aXJlQXBwcm92YWwgfSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0IHR5cGUgeyBDb25maXJtYXRpb25SZXF1ZXN0LCBEZXBsb3ltZW50TWV0aG9kLCBEaWFnbm9zZU9wdGlvbnMsIFB1Ymxpc2hBc3NldHNPcHRpb25zLCBTdGFja1NlbGVjdG9yLCBUb29sa2l0QWN0aW9uLCBUb29sa2l0T3B0aW9ucywgVW5zdGFibGVGZWF0dXJlLCBWYWxpZGF0ZU9wdGlvbnMgfSBmcm9tICdAYXdzLWNkay90b29sa2l0LWxpYic7XG5pbXBvcnQgeyBQZXJtaXNzaW9uQ2hhbmdlVHlwZSwgVG9vbGtpdCwgVG9vbGtpdEVycm9yLCBBYm9ydEVycm9yIH0gZnJvbSAnQGF3cy1jZGsvdG9vbGtpdC1saWInO1xuaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCAqIGFzIGNob2tpZGFyIGZyb20gJ2Nob2tpZGFyJztcbmltcG9ydCB7IHR5cGUgRXZlbnROYW1lLCBFVkVOVFMgfSBmcm9tICdjaG9raWRhci9oYW5kbGVyLmpzJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCB7IENsaUlvSG9zdCwgc3VwcHJlc3NNZXNzYWdlcyB9IGZyb20gJy4vaW8taG9zdCc7XG5pbXBvcnQgdHlwZSB7IENvbmZpZ3VyYXRpb24gfSBmcm9tICcuL3VzZXItY29uZmlndXJhdGlvbic7XG5pbXBvcnQgeyBQUk9KRUNUX0NPTkZJRyB9IGZyb20gJy4vdXNlci1jb25maWd1cmF0aW9uJztcbmltcG9ydCB0eXBlIHsgQWN0aW9uTGVzc1JlcXVlc3QsIElNZXNzYWdlU3BhbiwgSW9IZWxwZXIgfSBmcm9tICcuLi8uLi9saWIvYXBpLXByaXZhdGUnO1xuaW1wb3J0IHsgYXNJb0hlbHBlciwgY2ZuQXBpLCBjcmVhdGVJZ25vcmVNYXRjaGVyLCBmb3JtYXRFeHByZXNzU3RhYmlsaXphdGlvbldhcm5pbmcsIElPLCB0YWdzRm9yU3RhY2ssIHRocm93SWZWYWxpZGF0aW9uRmFpbHVyZXMgfSBmcm9tICcuLi8uLi9saWIvYXBpLXByaXZhdGUnO1xuaW1wb3J0IHR5cGUgeyBBc3NldEJ1aWxkTm9kZSwgQXNzZXRQdWJsaXNoTm9kZSwgQ29uY3VycmVuY3ksIE1hcmtlck5vZGUsIFN0YWNrTm9kZSwgV29ya0dyYXBoLCBXb3JrR3JhcGhBY3Rpb25zIH0gZnJvbSAnLi4vYXBpJztcbmltcG9ydCB7XG4gIENsb3VkV2F0Y2hMb2dFdmVudE1vbml0b3IsXG4gIERFRkFVTFRfVE9PTEtJVF9TVEFDS19OQU1FLFxuICBEaWZmRm9ybWF0dGVyLFxuICBmaW5kQ2xvdWRXYXRjaExvZ0dyb3VwcyxcbiAgR2FyYmFnZUNvbGxlY3RvcixcbiAgcmVtb3ZlTm9uSW1wb3J0UmVzb3VyY2VzLFxuICBSZXNvdXJjZUltcG9ydGVyLFxuICBSZXNvdXJjZU1pZ3JhdG9yLFxuICBTdGFja1NlbGVjdGlvblN0cmF0ZWd5LFxuICBXb3JrR3JhcGhCdWlsZGVyLFxufSBmcm9tICcuLi9hcGknO1xuaW1wb3J0IHR5cGUgeyBTZGtQcm92aWRlciB9IGZyb20gJy4uL2FwaS9hd3MtYXV0aCc7XG5pbXBvcnQgdHlwZSB7IEJvb3RzdHJhcEVudmlyb25tZW50T3B0aW9ucyB9IGZyb20gJy4uL2FwaS9ib290c3RyYXAnO1xuaW1wb3J0IHsgQm9vdHN0cmFwcGVyIH0gZnJvbSAnLi4vYXBpL2Jvb3RzdHJhcCc7XG5pbXBvcnQgdHlwZSB7IFN0YWNrQXNzZW1ibHkgfSBmcm9tICcuLi9hcGkvY2xvdWQtYXNzZW1ibHknO1xuaW1wb3J0IHsgQUxMX1NUQUNLUywgRXhwYW5kU3RhY2tTZWxlY3Rpb24sIG11c3RNYXRjaCwgc2VsZWN0QWxsVG9wTGV2ZWwsIHNlbGVjdEV4YWN0LCBzZWxlY3RXaXRoVXBzdHJlYW0sIFN0YWNrQ29sbGVjdGlvbiB9IGZyb20gJy4uL2FwaS9jbG91ZC1hc3NlbWJseSc7XG5pbXBvcnQgeyBpc0NoYW5nZVNldERlcGxveW1lbnQsIGlzRXhlY3V0aW5nQ2hhbmdlU2V0RGVwbG95bWVudCwgaXNOb25FeGVjdXRpbmdDaGFuZ2VTZXREZXBsb3ltZW50LCB0b0V4ZWN1dGVDaGFuZ2VTZXREZXBsb3ltZW50IH0gZnJvbSAnLi4vYXBpL2RlcGxveS1wcml2YXRlJztcbmltcG9ydCB0eXBlIHsgRGVwbG95bWVudHMsIFN1Y2Nlc3NmdWxEZXBsb3lTdGFja1Jlc3VsdCB9IGZyb20gJy4uL2FwaS9kZXBsb3ltZW50cyc7XG5pbXBvcnQgeyBtYXBwaW5nc0J5RW52aXJvbm1lbnQsIHBhcnNlTWFwcGluZ0dyb3VwcyB9IGZyb20gJy4uL2FwaS9yZWZhY3Rvcic7XG5pbXBvcnQgeyB0eXBlIFRhZyB9IGZyb20gJy4uL2FwaS90YWdzJztcbmltcG9ydCB7IFN0YWNrQWN0aXZpdHlQcm9ncmVzcyB9IGZyb20gJy4uL2NvbW1hbmRzL2RlcGxveSc7XG5pbXBvcnQgeyBmb3JtYXRTdGFja0xpc3QgfSBmcm9tICcuLi9jb21tYW5kcy9saXN0LXN0YWNrcyc7XG5pbXBvcnQgdHlwZSB7IEZyb21TY2FuLCBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IH0gZnJvbSAnLi4vY29tbWFuZHMvbWlncmF0ZSc7XG5pbXBvcnQge1xuICBhcHBlbmRXYXJuaW5nc1RvUmVhZG1lLFxuICBidWlsZENmbkNsaWVudCxcbiAgYnVpbGRHZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dCxcbiAgQ2ZuVGVtcGxhdGVHZW5lcmF0b3JQcm92aWRlcixcbiAgZ2VuZXJhdGVDZGtBcHAsXG4gIGdlbmVyYXRlU3RhY2ssXG4gIGdlbmVyYXRlVGVtcGxhdGUsXG4gIGlzVGhlcmVBV2FybmluZyxcbiAgcGFyc2VTb3VyY2VPcHRpb25zLFxuICByZWFkRnJvbVBhdGgsXG4gIHJlYWRGcm9tU3RhY2ssXG4gIHNldEVudmlyb25tZW50LFxuICBUZW1wbGF0ZVNvdXJjZU9wdGlvbnMsXG4gIHdyaXRlTWlncmF0ZUpzb25GaWxlLFxufSBmcm9tICcuLi9jb21tYW5kcy9taWdyYXRlJztcbmltcG9ydCB0eXBlIHsgQ2xvdWRFeGVjdXRhYmxlIH0gZnJvbSAnLi4vY3hhcHAnO1xuaW1wb3J0IHsgZW52aXJvbm1lbnRzRnJvbURlc2NyaXB0b3JzLCBnbG9iRW52aXJvbm1lbnRzRnJvbVN0YWNrcywgbG9va3NMaWtlR2xvYiB9IGZyb20gJy4uL2N4YXBwJztcbmltcG9ydCB7XG4gIGRlc2VyaWFsaXplU3RydWN0dXJlLFxuICBmb3JtYXRFcnJvck1lc3NhZ2UsXG4gIGZvcm1hdFRpbWUsXG4gIG9ic2N1cmVUZW1wbGF0ZSxcbiAgcGFydGl0aW9uLFxuICBzZXJpYWxpemVTdHJ1Y3R1cmUsXG4gIHZhbGlkYXRlU25zVG9waWNBcm4sXG59IGZyb20gJy4uL3V0aWwnO1xuaW1wb3J0IHsgY2FuQ29sbGVjdFRlbGVtZXRyeSB9IGZyb20gJy4vdGVsZW1ldHJ5L2NvbGxlY3QtdGVsZW1ldHJ5JztcbmltcG9ydCB7IGNka0NsaUVycm9yTmFtZSB9IGZyb20gJy4vdGVsZW1ldHJ5L2Vycm9yJztcbmltcG9ydCB0eXBlIHsgRXZlbnRSZXN1bHQgfSBmcm9tICcuL3RlbGVtZXRyeS9tZXNzYWdlcyc7XG5pbXBvcnQgeyBDTElfUFJJVkFURV9TUEFOIH0gZnJvbSAnLi90ZWxlbWV0cnkvbWVzc2FnZXMnO1xuaW1wb3J0IHR5cGUgeyBFcnJvckRldGFpbHMgfSBmcm9tICcuL3RlbGVtZXRyeS9zY2hlbWEnO1xuaW1wb3J0IHsgRmxhZ09wZXJhdGlvbnMgfSBmcm9tICcuLi9jb21tYW5kcy9mbGFncy9vcGVyYXRpb25zJztcblxuLy8gTXVzdCB1c2UgYSByZXF1aXJlKCkgb3RoZXJ3aXNlIGVzYnVpbGQgY29tcGxhaW5zIGFib3V0IGNhbGxpbmcgYSBuYW1lc3BhY2Vcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzLEB0eXBlc2NyaXB0LWVzbGludC9jb25zaXN0ZW50LXR5cGUtaW1wb3J0c1xuY29uc3QgcExpbWl0OiB0eXBlb2YgaW1wb3J0KCdwLWxpbWl0JykgPSByZXF1aXJlKCdwLWxpbWl0Jyk7XG5cbi8qKlxuICogRmlsZSBldmVudHMgdGhhdCB3ZSBjYXJlIGFib3V0IGZyb20gY2hva2lkYXIuXG4gKiBJbiBjaG9raWRhciB2NCwgRXZlbnROYW1lIGluY2x1ZGVzIGFkZGl0aW9uYWwgZXZlbnRzIGxpa2UgJ2Vycm9yJywgJ3JhdycsICdyZWFkeScsICdhbGwnXG4gKiB0aGF0IHdlIG5lZWQgdG8gZmlsdGVyIG91dCBpbiB0aGUgJ2FsbCcgaGFuZGxlci5cbiAqL1xuY29uc3QgRklMRV9FVkVOVFMgPSBbRVZFTlRTLkFERCwgRVZFTlRTLkFERF9ESVIsIEVWRU5UUy5DSEFOR0UsIEVWRU5UUy5VTkxJTkssIEVWRU5UUy5VTkxJTktfRElSXSBhcyBjb25zdDtcbnR5cGUgRmlsZUV2ZW50ID0gdHlwZW9mIEZJTEVfRVZFTlRTW251bWJlcl07XG5cbi8qKlxuICogVHlwZSBndWFyZCB0byBjaGVjayBpZiBhbiBldmVudCBpcyBhIGZpbGUgZXZlbnQgd2Ugc2hvdWxkIHByb2Nlc3MuXG4gKi9cbmZ1bmN0aW9uIGlzRmlsZUV2ZW50KGV2ZW50OiBFdmVudE5hbWUpOiBldmVudCBpcyBGaWxlRXZlbnQge1xuICByZXR1cm4gKEZJTEVfRVZFTlRTIGFzIHJlYWRvbmx5IHN0cmluZ1tdKS5pbmNsdWRlcyhldmVudCk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2RrVG9vbGtpdFByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBDbG91ZCBFeGVjdXRhYmxlXG4gICAqL1xuICBjbG91ZEV4ZWN1dGFibGU6IENsb3VkRXhlY3V0YWJsZTtcblxuICAvKipcbiAgICogVGhlIHByb3Zpc2lvbmluZyBlbmdpbmUgdXNlZCB0byBhcHBseSBjaGFuZ2VzIHRvIHRoZSBjbG91ZFxuICAgKi9cbiAgZGVwbG95bWVudHM6IERlcGxveW1lbnRzO1xuXG4gIC8qKlxuICAgKiBUaGUgQ2xpSW9Ib3N0IHRoYXQncyB1c2VkIGZvciBJL08gb3BlcmF0aW9uc1xuICAgKi9cbiAgaW9Ib3N0PzogQ2xpSW9Ib3N0O1xuXG4gIC8qKlxuICAgKiBOYW1lIG9mIHRoZSB0b29sa2l0IHN0YWNrIHRvIHVzZS9kZXBsb3lcbiAgICpcbiAgICogQGRlZmF1bHQgQ0RLVG9vbGtpdFxuICAgKi9cbiAgdG9vbGtpdFN0YWNrTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0byBiZSB2ZXJib3NlXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICB2ZXJib3NlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRG9uJ3Qgc3RvcCBvbiBlcnJvciBtZXRhZGF0YVxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgaWdub3JlRXJyb3JzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogVHJlYXQgd2FybmluZ3MgaW4gbWV0YWRhdGEgYXMgZXJyb3JzXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICBzdHJpY3Q/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uIChzZXR0aW5ncyBhbmQgY29udGV4dClcbiAgICovXG4gIGNvbmZpZ3VyYXRpb246IENvbmZpZ3VyYXRpb247XG5cbiAgLyoqXG4gICAqIEFXUyBvYmplY3QgKHVzZWQgYnkgc3ludGhlc2l6ZXIgYW5kIGNvbnRleHRwcm92aWRlcilcbiAgICovXG4gIHNka1Byb3ZpZGVyOiBTZGtQcm92aWRlcjtcbn1cblxuLyoqXG4gKiBXaGVuIHRvIGJ1aWxkIGFzc2V0c1xuICovXG5leHBvcnQgZW51bSBBc3NldEJ1aWxkVGltZSB7XG4gIC8qKlxuICAgKiBCdWlsZCBhbGwgYXNzZXRzIGJlZm9yZSBkZXBsb3lpbmcgdGhlIGZpcnN0IHN0YWNrXG4gICAqXG4gICAqIFRoaXMgaXMgaW50ZW5kZWQgZm9yIGV4cGVuc2l2ZSBEb2NrZXIgaW1hZ2UgYnVpbGRzOyBzbyB0aGF0IGlmIHRoZSBEb2NrZXIgaW1hZ2UgYnVpbGRcbiAgICogZmFpbHMsIG5vIHN0YWNrcyBhcmUgdW5uZWNlc3NhcmlseSBkZXBsb3llZCAod2l0aCB0aGUgYXR0ZW5kYW50IHdhaXQgdGltZSkuXG4gICAqL1xuICBBTExfQkVGT1JFX0RFUExPWSA9ICdhbGwtYmVmb3JlLWRlcGxveScsXG5cbiAgLyoqXG4gICAqIEJ1aWxkIGFzc2V0cyBqdXN0LWluLXRpbWUsIGJlZm9yZSBwdWJsaXNoaW5nXG4gICAqL1xuICBKVVNUX0lOX1RJTUUgPSAnanVzdC1pbi10aW1lJyxcbn1cblxuLyoqXG4gKiBDdXN0b20gaW1wbGVtZW50YXRpb24gb2YgdGhlIHB1YmxpYyBUb29sa2l0IHRvIGludGVncmF0ZSB3aXRoIHRoZSBsZWdhY3kgQ2RrVG9vbGtpdFxuICpcbiAqIFRoaXMgb3ZlcndyaXRlcyBob3cgYW4gc2RrUHJvdmlkZXIgaXMgYWNxdWlyZWRcbiAqIGluIGZhdm9yIG9mIHRoZSBvbmUgcHJvdmlkZWQgZGlyZWN0bHkgdG8gQ2RrVG9vbGtpdC5cbiAqL1xuY2xhc3MgSW50ZXJuYWxUb29sa2l0IGV4dGVuZHMgVG9vbGtpdCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Nka1Byb3ZpZGVyOiBTZGtQcm92aWRlcjtcbiAgcHVibGljIGNvbnN0cnVjdG9yKHNka1Byb3ZpZGVyOiBTZGtQcm92aWRlciwgb3B0aW9uczogT21pdDxUb29sa2l0T3B0aW9ucywgJ3Nka0NvbmZpZyc+KSB7XG4gICAgc3VwZXIob3B0aW9ucyk7XG4gICAgdGhpcy5fc2RrUHJvdmlkZXIgPSBzZGtQcm92aWRlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBBY2Nlc3MgdG8gdGhlIEFXUyBTREtcbiAgICogQGludGVybmFsXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgc2RrUHJvdmlkZXIoX2FjdGlvbjogVG9vbGtpdEFjdGlvbik6IFByb21pc2U8U2RrUHJvdmlkZXI+IHtcbiAgICByZXR1cm4gdGhpcy5fc2RrUHJvdmlkZXI7XG4gIH1cbn1cblxuLyoqXG4gKiBUb29sa2l0IGxvZ2ljXG4gKlxuICogVGhlIHRvb2xraXQgcnVucyB0aGUgYGNsb3VkRXhlY3V0YWJsZWAgdG8gb2J0YWluIGEgY2xvdWQgYXNzZW1ibHkgYW5kXG4gKiBkZXBsb3lzIGFwcGxpZXMgdGhlbSB0byBgY2xvdWRGb3JtYXRpb25gLlxuICovXG5leHBvcnQgY2xhc3MgQ2RrVG9vbGtpdCB7XG4gIHByaXZhdGUgaW9Ib3N0OiBDbGlJb0hvc3Q7XG4gIHByaXZhdGUgdG9vbGtpdFN0YWNrTmFtZTogc3RyaW5nO1xuICBwcml2YXRlIHRvb2xraXQ6IEludGVybmFsVG9vbGtpdDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHByb3BzOiBDZGtUb29sa2l0UHJvcHMpIHtcbiAgICB0aGlzLmlvSG9zdCA9IHByb3BzLmlvSG9zdCA/PyBDbGlJb0hvc3QuaW5zdGFuY2UoKTtcbiAgICB0aGlzLnRvb2xraXRTdGFja05hbWUgPSBwcm9wcy50b29sa2l0U3RhY2tOYW1lID8/IERFRkFVTFRfVE9PTEtJVF9TVEFDS19OQU1FO1xuXG4gICAgLy8gV2UgZG9uJ3QgaGF2ZSB0aGUgdG9vbGtpdCBjaGVjayB1bnN0YWJsZSBmZWF0dXJlcy4gSW5zdGVhZCwgdGhlIGVycm9yXG4gICAgLy8gbWVzc2FnZXMgdGhlIENMSSBnaXZlIGFyZSBzbGlnaHRseSBkaWZmZXJlbnQsIGFuZCBzbyB0aGV5IG5lZWQgdG8gYmUgY2hlY2tlZFxuICAgIC8vIHNlcGFyYXRlbHkuIEluc3RlYWQsIHRoZSBUb29sa2l0IHdlIHVzZSBoYXMgYWxsIHVuc3RhYmxlIGZlYXR1cmVzIGF1dG9tYXRpY2FsbHlcbiAgICAvLyBlbmFibGVkLlxuICAgIGNvbnN0IGlQcm9taXNlVW5zdGFibGVuZXNzSXNDaGVja2VkQnlUaGVDbGk6IFJlY29yZDxVbnN0YWJsZUZlYXR1cmUsIHRydWU+ID0ge1xuICAgICAgJ3B1Ymxpc2gtYXNzZXRzJzogdHJ1ZSxcbiAgICAgICdkaWFnbm9zZSc6IHRydWUsXG4gICAgICAnZmxhZ3MnOiB0cnVlLFxuICAgICAgJ29ycGhhbic6IHRydWUsXG4gICAgICAncmVmYWN0b3InOiB0cnVlLFxuICAgICAgJ3ZhbGlkYXRlJzogdHJ1ZSxcbiAgICB9O1xuXG4gICAgdGhpcy50b29sa2l0ID0gbmV3IEludGVybmFsVG9vbGtpdChwcm9wcy5zZGtQcm92aWRlciwge1xuICAgICAgYXNzZW1ibHlGYWlsdXJlQXQ6IHRoaXMudmFsaWRhdGVNZXRhZGF0YUZhaWxBdCgpLFxuICAgICAgY29sb3I6IHRydWUsXG4gICAgICBlbW9qaXM6IHRydWUsXG4gICAgICBpb0hvc3Q6IHRoaXMuaW9Ib3N0LFxuICAgICAgdG9vbGtpdFN0YWNrTmFtZTogdGhpcy50b29sa2l0U3RhY2tOYW1lLFxuICAgICAgdW5zdGFibGVGZWF0dXJlczogT2JqZWN0LmtleXMoaVByb21pc2VVbnN0YWJsZW5lc3NJc0NoZWNrZWRCeVRoZUNsaSkgYXMgVW5zdGFibGVGZWF0dXJlW10sXG4gICAgfSk7XG4gIH1cblxuICBAc3VwcHJlc3NNZXNzYWdlcyhcbiAgICBJTy5DREtfVE9PTEtJVF9JMTAwMSwgLy8gU3RhcnRpbmcgU3ludGhlc2lzICh0cmFjZSlcbiAgICBJTy5DREtfVE9PTEtJVF9JMTAwMCwgLy8g4pyoIFN5bnRoZXNpcyB0aW1lIChpbmZvKVxuICApXG4gIHB1YmxpYyBhc3luYyBtZXRhZGF0YShzdGFja05hbWU6IHN0cmluZywganNvbjogYm9vbGVhbikge1xuICAgIHVzaW5nIF9mb3JtYXR0ZXIgPSB0aGlzLmlvSG9zdC5vbmNlKFxuICAgICAgSU8uQ0RLX1RPT0xLSVRfSTI5MDEsXG4gICAgICAobXNnKSA9PiAoe1xuICAgICAgICBhY3Rpb246ICdtZXRhZGF0YScsXG4gICAgICAgIG1lc3NhZ2U6IHNlcmlhbGl6ZVN0cnVjdHVyZShtc2cuZGF0YS5zdGFja3NbMF0/Lm1ldGFkYXRhID8/IHt9LCBqc29uKSxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBhd2FpdCB0aGlzLnRvb2xraXQubGlzdCh0aGlzLnByb3BzLmNsb3VkRXhlY3V0YWJsZSwge1xuICAgICAgc3RhY2tzOiB7XG4gICAgICAgIHBhdHRlcm5zOiBbc3RhY2tOYW1lXSxcbiAgICAgICAgc3RyYXRlZ3k6IFN0YWNrU2VsZWN0aW9uU3RyYXRlZ3kuUEFUVEVSTl9NVVNUX01BVENIX1NJTkdMRSxcbiAgICAgICAgZXhwYW5kOiBFeHBhbmRTdGFja1NlbGVjdGlvbi5OT05FLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBhY2tub3dsZWRnZShub3RpY2VJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgaXNzdWVOdW1iZXIgPSBOdW1iZXIobm90aWNlSWQpO1xuICAgIGlmICghTnVtYmVyLmlzSW50ZWdlcihpc3N1ZU51bWJlcikpIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXG4gICAgICAgICdJbnZhbGlkQWNrbm93bGVkZ2VtZW50SWQnLFxuICAgICAgICBgSW52YWxpZCBub3RpY2UgSUQgJyR7bm90aWNlSWR9JzogJ2NkayBhY2tub3dsZWRnZScgb25seSBhY2NlcHRzIG51bWVyaWMgbm90aWNlIElEcyAoZS5nLiAnY2RrIGFja25vd2xlZGdlIDEyMzQ1JykuIGAgK1xuICAgICAgICAnU2NvcGVkIGNvbnN0cnVjdCB3YXJuaW5ncyBzdWNoIGFzIFxcJ0Bhd3MtY2RrL2F3cy1lY3M6bWluSGVhbHRoeVBlcmNlbnRcXCcgYXJlIGFja25vd2xlZGdlZCBpbiBjb2RlIHdpdGggJyArXG4gICAgICAgICdBbm5vdGF0aW9ucy5vZihzY29wZSkuYWNrbm93bGVkZ2VXYXJuaW5nKFxcJzxpZD5cXCcpLicsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGFja3MgPSBuZXcgU2V0KHRoaXMucHJvcHMuY29uZmlndXJhdGlvbi5jb250ZXh0LmdldCgnYWNrbm93bGVkZ2VkLWlzc3VlLW51bWJlcnMnKSA/PyBbXSk7XG4gICAgYWNrcy5hZGQoaXNzdWVOdW1iZXIpO1xuICAgIHRoaXMucHJvcHMuY29uZmlndXJhdGlvbi5jb250ZXh0LnNldCgnYWNrbm93bGVkZ2VkLWlzc3VlLW51bWJlcnMnLCBBcnJheS5mcm9tKGFja3MpKTtcbiAgICBhd2FpdCB0aGlzLnByb3BzLmNvbmZpZ3VyYXRpb24uc2F2ZUNvbnRleHQoKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjbGlUZWxlbWV0cnlTdGF0dXMoYXJnczogYW55KSB7XG4gICAgY29uc3QgY2FuQ29sbGVjdCA9IGNhbkNvbGxlY3RUZWxlbWV0cnkoYXJncywgdGhpcy5wcm9wcy5jb25maWd1cmF0aW9uLmNvbnRleHQpO1xuICAgIGlmIChjYW5Db2xsZWN0KSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbygnQ0xJIFRlbGVtZXRyeSBpcyBlbmFibGVkLiBTZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2Nkay92Mi9ndWlkZS9jbGktdGVsZW1ldHJ5Lmh0bWwgZm9yIHdheXMgdG8gZGlzYWJsZS4nKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oJ0NMSSBUZWxlbWV0cnkgaXMgZGlzYWJsZWQuIFNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vY2RrL3YyL2d1aWRlL2NsaS10ZWxlbWV0cnkuaHRtbCBmb3Igd2F5cyB0byBlbmFibGUuJyk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGFzeW5jIGNsaVRlbGVtZXRyeShlbmFibGU6IGJvb2xlYW4pIHtcbiAgICB0aGlzLnByb3BzLmNvbmZpZ3VyYXRpb24uY29udGV4dC5zZXQoJ2NsaS10ZWxlbWV0cnknLCBlbmFibGUpO1xuICAgIGF3YWl0IHRoaXMucHJvcHMuY29uZmlndXJhdGlvbi5zYXZlQ29udGV4dCgpO1xuICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKGBUZWxlbWV0cnkgJHtlbmFibGUgPyAnZW5hYmxlZCcgOiAnZGlzYWJsZWQnfWApO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGRpZmYob3B0aW9uczogRGlmZk9wdGlvbnMpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGFzc2VtYmx5ID0gYXdhaXQgdGhpcy5hc3NlbWJseSgpO1xuICAgIGNvbnN0IHN0YWNrcyA9IGF3YWl0IHRoaXMuc2VsZWN0VG9wTGV2ZWxPck1hdGNoaW5nU3RhY2tzKGFzc2VtYmx5LCBvcHRpb25zLnN0YWNrTmFtZXMsIG9wdGlvbnMuZXhjbHVzaXZlbHkpO1xuICAgIGF3YWl0IHRoaXMudmFsaWRhdGVTdGFja3MoYXNzZW1ibHksIHN0YWNrcyk7XG5cbiAgICBjb25zdCBzdHJpY3QgPSAhIW9wdGlvbnMuc3RyaWN0O1xuICAgIGNvbnN0IGNvbnRleHRMaW5lcyA9IG9wdGlvbnMuY29udGV4dExpbmVzIHx8IDM7XG4gICAgY29uc3QgcXVpZXQgPSBvcHRpb25zLnF1aWV0IHx8IGZhbHNlO1xuXG4gICAgbGV0IGRpZmZzID0gMDtcbiAgICBjb25zdCBwYXJhbWV0ZXJNYXAgPSBidWlsZFBhcmFtZXRlck1hcChvcHRpb25zLnBhcmFtZXRlcnMpO1xuXG4gICAgaWYgKG9wdGlvbnMudGVtcGxhdGVQYXRoICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIC8vIENvbXBhcmUgc2luZ2xlIHN0YWNrIGFnYWluc3QgZml4ZWQgdGVtcGxhdGVcbiAgICAgIGlmIChzdGFja3Muc3RhY2tDb3VudCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKFxuICAgICAgICAgICdTaW5nbGVTdGFja1JlcXVpcmVkJyxcbiAgICAgICAgICAnQ2FuIG9ubHkgc2VsZWN0IG9uZSBzdGFjayB3aGVuIGNvbXBhcmluZyB0byBmaXhlZCB0ZW1wbGF0ZS4gVXNlIC0tZXhjbHVzaXZlbHkgdG8gYXZvaWQgc2VsZWN0aW5nIG11bHRpcGxlIHN0YWNrcy4nLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBpZiAoIShhd2FpdCBmcy5wYXRoRXhpc3RzKG9wdGlvbnMudGVtcGxhdGVQYXRoKSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignVGVtcGxhdGVOb3RGb3VuZCcsIGBUaGVyZSBpcyBubyBmaWxlIGF0ICR7b3B0aW9ucy50ZW1wbGF0ZVBhdGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChvcHRpb25zLmltcG9ydEV4aXN0aW5nUmVzb3VyY2VzKSB7XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXG4gICAgICAgICAgJ0ltcG9ydFdpdGhUZW1wbGF0ZVBhdGgnLFxuICAgICAgICAgICdDYW4gb25seSB1c2UgLS1pbXBvcnQtZXhpc3RpbmctcmVzb3VyY2VzIGZsYWcgd2hlbiBjb21wYXJpbmcgYWdhaW5zdCBkZXBsb3llZCBzdGFja3MuJyxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdGVtcGxhdGUgPSBkZXNlcmlhbGl6ZVN0cnVjdHVyZShhd2FpdCBmcy5yZWFkRmlsZShvcHRpb25zLnRlbXBsYXRlUGF0aCwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KSk7XG4gICAgICBjb25zdCBmb3JtYXR0ZXIgPSBuZXcgRGlmZkZvcm1hdHRlcih7XG4gICAgICAgIHRlbXBsYXRlSW5mbzoge1xuICAgICAgICAgIG9sZFRlbXBsYXRlOiB0ZW1wbGF0ZSxcbiAgICAgICAgICBuZXdUZW1wbGF0ZTogc3RhY2tzLmZpcnN0U3RhY2ssXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgaWYgKG9wdGlvbnMuc2VjdXJpdHlPbmx5KSB7XG4gICAgICAgIGNvbnN0IHNlY3VyaXR5RGlmZiA9IGZvcm1hdHRlci5mb3JtYXRTZWN1cml0eURpZmYoeyBxdWlldCB9KTtcbiAgICAgICAgLy8gV2FybiwgY291bnQsIGFuZCBkaXNwbGF5IHRoZSBkaWZmIG9ubHkgaWYgdGhlIHJlcG9ydGVkIGNoYW5nZXMgYXJlIGJyb2FkZW5pbmcgcGVybWlzc2lvbnNcbiAgICAgICAgaWYgKHNlY3VyaXR5RGlmZi5wZXJtaXNzaW9uQ2hhbmdlVHlwZSA9PT0gUGVybWlzc2lvbkNoYW5nZVR5cGUuQlJPQURFTklORykge1xuICAgICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy53YXJuKCdUaGlzIGRlcGxveW1lbnQgd2lsbCBtYWtlIHBvdGVudGlhbGx5IHNlbnNpdGl2ZSBjaGFuZ2VzIGFjY29yZGluZyB0byB5b3VyIGN1cnJlbnQgc2VjdXJpdHkgYXBwcm92YWwgbGV2ZWwuXFxuUGxlYXNlIGNvbmZpcm0geW91IGludGVuZCB0byBtYWtlIHRoZSBmb2xsb3dpbmcgbW9kaWZpY2F0aW9uczpcXG4nKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhzZWN1cml0eURpZmYuZm9ybWF0dGVkRGlmZik7XG4gICAgICAgICAgZGlmZnMgKz0gc2VjdXJpdHlEaWZmLm51bVN0YWNrc1dpdGhDaGFuZ2VzO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBkaWZmID0gZm9ybWF0dGVyLmZvcm1hdFN0YWNrRGlmZih7XG4gICAgICAgICAgc3RyaWN0LFxuICAgICAgICAgIGNvbnRleHRMaW5lcyxcbiAgICAgICAgICBxdWlldCxcbiAgICAgICAgfSk7XG4gICAgICAgIGRpZmZzID0gZGlmZi5udW1TdGFja3NXaXRoQ2hhbmdlcztcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oZGlmZi5mb3JtYXR0ZWREaWZmKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgYWxsTWFwcGluZ3MgPSBvcHRpb25zLmluY2x1ZGVNb3Zlc1xuICAgICAgICA/IGF3YWl0IG1hcHBpbmdzQnlFbnZpcm9ubWVudChzdGFja3Muc3RhY2tBcnRpZmFjdHMsIHRoaXMucHJvcHMuc2RrUHJvdmlkZXIsIHRydWUpXG4gICAgICAgIDogW107XG5cbiAgICAgIC8vIENvbXBhcmUgTiBzdGFja3MgYWdhaW5zdCBkZXBsb3llZCB0ZW1wbGF0ZXNcbiAgICAgIGZvciAoY29uc3Qgc3RhY2sgb2Ygc3RhY2tzLnN0YWNrQXJ0aWZhY3RzKSB7XG4gICAgICAgIGNvbnN0IHRlbXBsYXRlV2l0aE5lc3RlZFN0YWNrcyA9IGF3YWl0IHRoaXMucHJvcHMuZGVwbG95bWVudHMucmVhZEN1cnJlbnRUZW1wbGF0ZVdpdGhOZXN0ZWRTdGFja3MoXG4gICAgICAgICAgc3RhY2ssXG4gICAgICAgICAgb3B0aW9ucy5jb21wYXJlQWdhaW5zdFByb2Nlc3NlZFRlbXBsYXRlLFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBjdXJyZW50VGVtcGxhdGUgPSB0ZW1wbGF0ZVdpdGhOZXN0ZWRTdGFja3MuZGVwbG95ZWRSb290VGVtcGxhdGU7XG4gICAgICAgIGNvbnN0IG5lc3RlZFN0YWNrcyA9IHRlbXBsYXRlV2l0aE5lc3RlZFN0YWNrcy5uZXN0ZWRTdGFja3M7XG5cbiAgICAgICAgY29uc3QgZW52aXJvbm1lbnQgPSBhd2FpdCB0aGlzLnByb3BzLmRlcGxveW1lbnRzLnJlc29sdmVFbnZpcm9ubWVudChzdGFjayk7XG5cbiAgICAgICAgY29uc3QgbWlncmF0b3IgPSBuZXcgUmVzb3VyY2VNaWdyYXRvcih7XG4gICAgICAgICAgZGVwbG95bWVudHM6IHRoaXMucHJvcHMuZGVwbG95bWVudHMsXG4gICAgICAgICAgaW9IZWxwZXI6IGFzSW9IZWxwZXIodGhpcy5pb0hvc3QsICdkaWZmJyksXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCByZXNvdXJjZXNUb0ltcG9ydCA9IGF3YWl0IG1pZ3JhdG9yLnRyeUdldFJlc291cmNlcyhlbnZpcm9ubWVudCk7XG4gICAgICAgIGlmIChyZXNvdXJjZXNUb0ltcG9ydCkge1xuICAgICAgICAgIHJlbW92ZU5vbkltcG9ydFJlc291cmNlcyhzdGFjayk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjaGFuZ2VTZXQgPSAob3B0aW9ucy5tZXRob2QgIT09ICd0ZW1wbGF0ZScpXG4gICAgICAgICAgPyAoYXdhaXQgdGhpcy50cnlDcmVhdGVEaWZmQ2hhbmdlU2V0KHN0YWNrLCBvcHRpb25zLCBwYXJhbWV0ZXJNYXAsIHJlc291cmNlc1RvSW1wb3J0LCBxdWlldCkpPy5jaGFuZ2VTZXRcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcblxuICAgICAgICBjb25zdCBtYXBwaW5ncyA9IGFsbE1hcHBpbmdzLmZpbmQobSA9PlxuICAgICAgICAgIG0uZW52aXJvbm1lbnQucmVnaW9uID09PSBzdGFjay5lbnZpcm9ubWVudC5yZWdpb24gJiYgbS5lbnZpcm9ubWVudC5hY2NvdW50ID09PSBzdGFjay5lbnZpcm9ubWVudC5hY2NvdW50LFxuICAgICAgICApPy5tYXBwaW5ncyA/PyB7fTtcblxuICAgICAgICBjb25zdCBmb3JtYXR0ZXIgPSBuZXcgRGlmZkZvcm1hdHRlcih7XG4gICAgICAgICAgdGVtcGxhdGVJbmZvOiB7XG4gICAgICAgICAgICBvbGRUZW1wbGF0ZTogY3VycmVudFRlbXBsYXRlLFxuICAgICAgICAgICAgbmV3VGVtcGxhdGU6IHN0YWNrLFxuICAgICAgICAgICAgY2hhbmdlU2V0LFxuICAgICAgICAgICAgaXNJbXBvcnQ6ICEhcmVzb3VyY2VzVG9JbXBvcnQsXG4gICAgICAgICAgICBuZXN0ZWRTdGFja3MsXG4gICAgICAgICAgICBtYXBwaW5ncyxcbiAgICAgICAgICAgIGVudmlyb25tZW50LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChvcHRpb25zLnNlY3VyaXR5T25seSkge1xuICAgICAgICAgIGNvbnN0IHNlY3VyaXR5RGlmZiA9IGZvcm1hdHRlci5mb3JtYXRTZWN1cml0eURpZmYoeyBxdWlldCB9KTtcbiAgICAgICAgICAvLyBXYXJuLCBjb3VudCwgYW5kIGRpc3BsYXkgdGhlIGRpZmYgb25seSBpZiB0aGUgcmVwb3J0ZWQgY2hhbmdlcyBhcmUgYnJvYWRlbmluZyBwZXJtaXNzaW9uc1xuICAgICAgICAgIGlmIChzZWN1cml0eURpZmYucGVybWlzc2lvbkNoYW5nZVR5cGUgPT09IFBlcm1pc3Npb25DaGFuZ2VUeXBlLkJST0FERU5JTkcpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy53YXJuKCdUaGlzIGRlcGxveW1lbnQgd2lsbCBtYWtlIHBvdGVudGlhbGx5IHNlbnNpdGl2ZSBjaGFuZ2VzIGFjY29yZGluZyB0byB5b3VyIGN1cnJlbnQgc2VjdXJpdHkgYXBwcm92YWwgbGV2ZWwuXFxuUGxlYXNlIGNvbmZpcm0geW91IGludGVuZCB0byBtYWtlIHRoZSBmb2xsb3dpbmcgbW9kaWZpY2F0aW9uczpcXG4nKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKHNlY3VyaXR5RGlmZi5mb3JtYXR0ZWREaWZmKTtcbiAgICAgICAgICAgIGRpZmZzICs9IHNlY3VyaXR5RGlmZi5udW1TdGFja3NXaXRoQ2hhbmdlcztcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgZGlmZiA9IGZvcm1hdHRlci5mb3JtYXRTdGFja0RpZmYoe1xuICAgICAgICAgICAgc3RyaWN0LFxuICAgICAgICAgICAgY29udGV4dExpbmVzLFxuICAgICAgICAgICAgcXVpZXQsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oZGlmZi5mb3JtYXR0ZWREaWZmKTtcbiAgICAgICAgICBkaWZmcyArPSBkaWZmLm51bVN0YWNrc1dpdGhDaGFuZ2VzO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oZm9ybWF0KCdcXG7inKggIE51bWJlciBvZiBzdGFja3Mgd2l0aCBkaWZmZXJlbmNlczogJXNcXG4nLCBkaWZmcykpO1xuXG4gICAgcmV0dXJuIGRpZmZzICYmIG9wdGlvbnMuZmFpbCA/IDEgOiAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyeSB0byBjcmVhdGUgYSBkaWZmIGNoYW5nZXNldCBmb3IgdGhlIGdpdmVuIHN0YWNrLlxuICAgKiBSZXR1cm5zIHVuZGVmaW5lZCBpZiB0aGUgc3RhY2sgY2Fubm90IGJlIGFjY2Vzc2VkIGFuZCBjaGFuZ2VTZXRPbmx5IGlzIG5vdCBzZXQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHRyeUNyZWF0ZURpZmZDaGFuZ2VTZXQoXG4gICAgc3RhY2s6IGN4YXBpLkNsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCxcbiAgICBvcHRpb25zOiBEaWZmT3B0aW9ucyxcbiAgICBwYXJhbWV0ZXJNYXA6IHsgW25hbWU6IHN0cmluZ106IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9IH0sXG4gICAgcmVzb3VyY2VzVG9JbXBvcnQ6IEF3YWl0ZWQ8UmV0dXJuVHlwZTxSZXNvdXJjZU1pZ3JhdG9yWyd0cnlHZXRSZXNvdXJjZXMnXT4+LFxuICAgIHF1aWV0OiBib29sZWFuLFxuICApIHtcbiAgICB0cnkge1xuICAgICAgLy8gd2UgZG9uJ3QgYWN0dWFsbHkgbmVlZCB0byBrbm93IGlmIHRoZSBzdGFjayBleGlzdHMgaGVyZVxuICAgICAgLy8gd2UganVzdCB1c2UgdGhpcyB0byBmbHVzaCBvdXIgYW55IHBlcm1pc3Npb25zIGlzc3VlcyBhbmQgZHJvcCB0aGUgcmVzdWx0XG4gICAgICB2b2lkIGF3YWl0IHRoaXMucHJvcHMuZGVwbG95bWVudHMuc3RhY2tFeGlzdHMoe1xuICAgICAgICBzdGFjayxcbiAgICAgICAgZGVwbG95TmFtZTogc3RhY2suc3RhY2tOYW1lLFxuICAgICAgICB0cnlMb29rdXBSb2xlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBpZiAob3B0aW9ucy5tZXRob2QgPT09ICdjaGFuZ2Utc2V0Jykge1xuICAgICAgICB0aHJvdyBUb29sa2l0RXJyb3Iud2l0aENhdXNlKCdEZXNjcmliZVN0YWNrc0ZhaWxlZCcsIGBDb3VsZCBub3QgYWNjZXNzIHN0YWNrICcke3N0YWNrLnN0YWNrTmFtZX0nLiBQbGVhc2UgY2hlY2sgeW91ciBwZXJtaXNzaW9ucyBvciB1c2UgJy0tbWV0aG9kPWF1dG8nIHRvIGFsbG93IGZhbGxpbmcgYmFjayB0byBhIHRlbXBsYXRlIGRpZmYuYCwgZSk7XG4gICAgICB9XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuZGVidWcoZm9ybWF0RXJyb3JNZXNzYWdlKGUpKTtcbiAgICAgIGlmICghcXVpZXQpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oXG4gICAgICAgICAgYENvdWxkIG5vdCBhY2Nlc3Mgc3RhY2sgJyR7c3RhY2suc3RhY2tOYW1lfScsIGZhbGxpbmcgYmFjayB0byB0ZW1wbGF0ZSBkaWZmLiBVc2UgJy0tbWV0aG9kPWNoYW5nZS1zZXQnIHRvIGZhaWwgaW5zdGVhZC4gUnVuIHdpdGggLXYgdG8gc2VlIHRoZSByZWFzb24uXFxuYCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNmbkFwaS5jcmVhdGVEaWZmQ2hhbmdlU2V0KGFzSW9IZWxwZXIodGhpcy5pb0hvc3QsICdkaWZmJyksIHtcbiAgICAgIHN0YWNrLFxuICAgICAgdXVpZDogcmFuZG9tVVVJRCgpLFxuICAgICAgZGVwbG95bWVudHM6IHRoaXMucHJvcHMuZGVwbG95bWVudHMsXG4gICAgICBzZGtQcm92aWRlcjogdGhpcy5wcm9wcy5zZGtQcm92aWRlcixcbiAgICAgIHBhcmFtZXRlcnM6IE9iamVjdC5hc3NpZ24oe30sIHBhcmFtZXRlck1hcFsnKiddLCBwYXJhbWV0ZXJNYXBbc3RhY2suc3RhY2tOYW1lXSksXG4gICAgICByZXNvdXJjZXNUb0ltcG9ydCxcbiAgICAgIGltcG9ydEV4aXN0aW5nUmVzb3VyY2VzOiBvcHRpb25zLmltcG9ydEV4aXN0aW5nUmVzb3VyY2VzLFxuICAgICAgZmFpbE9uRXJyb3I6IG9wdGlvbnMubWV0aG9kID09PSAnY2hhbmdlLXNldCcsXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZGVwbG95KG9wdGlvbnM6IERlcGxveU9wdGlvbnMpIHtcbiAgICBpZiAob3B0aW9ucy53YXRjaCkge1xuICAgICAgcmV0dXJuIHRoaXMud2F0Y2gob3B0aW9ucyk7XG4gICAgfVxuXG4gICAgLy8gc2V0IHByb2dyZXNzIGZyb20gb3B0aW9ucywgdGhpcyBpbmNsdWRlcyB1c2VyIGFuZCBhcHAgY29uZmlnXG4gICAgaWYgKG9wdGlvbnMucHJvZ3Jlc3MpIHtcbiAgICAgIHRoaXMuaW9Ib3N0LnN0YWNrUHJvZ3Jlc3MgPSBvcHRpb25zLnByb2dyZXNzO1xuICAgIH1cblxuICAgIC8vIHRoZSBpb0hvc3QgdXNlcyB0aGlzIGludGVybmFsbHkgdG8gZGV0ZXJtaW5lIGlmIGEgY29uZmlybWF0aW9uXG4gICAgLy8gaXMgYWN0dWFsbHkgbmVlZGVkLCBzbyBpdCBuZWVkcyB0aGUgc2FtZSB2YWx1ZSB3ZSBkZXRlcm1pbmUgaGVyZS5cbiAgICBjb25zdCByZXF1aXJlQXBwcm92YWwgPSBvcHRpb25zLnJlcXVpcmVBcHByb3ZhbCA/PyBSZXF1aXJlQXBwcm92YWwuQlJPQURFTklORztcbiAgICB0aGlzLmlvSG9zdC5yZXF1aXJlRGVwbG95QXBwcm92YWwgPSByZXF1aXJlQXBwcm92YWw7XG5cbiAgICAvLyB0b29sa2l0LWxpYiBlbWl0cyB0aGUgYXBwcm92YWwgcmVxdWVzdCAoSTUwNjApIHdpdGhvdXQgbWVudGlvbmluZ1xuICAgIC8vIGAtLXJlcXVpcmUtYXBwcm92YWxgLiBUaGUgQ0xJIG93bnMgdGhhdCBmbGFnLCBzbyBpdCBhZGRzIHRoZSBmcmFtaW5nIGhlcmUuXG4gICAgLy8gQm90aCBkZXBsb3kgcGF0aHMgcmVzb2x2ZSB0aHJvdWdoIHRoaXMgaG9zdCwgc28gb25lIGxpc3RlbmVyIGNvdmVycyBib3RoLlxuICAgIC8vIE1ldGhvZC1zY29wZWQgKGB1c2luZ2ApOiBgZGVwbG95KClgIGNhbiBydW4gcmVwZWF0ZWRseSAod2F0Y2ggbW9kZSksIGFuZFxuICAgIC8vIGVhY2ggcnVuIG11c3QgcmVnaXN0ZXIgYSByZXdyaXRlIGZvciBpdHMgb3duIGByZXF1aXJlQXBwcm92YWxgIHZhbHVlLlxuICAgIHVzaW5nIF9hcHByb3ZhbEZyYW1pbmcgPSB0aGlzLmlvSG9zdC5yZXdyaXRlKElPLkNES19UT09MS0lUX0k1MDYwLCAobXNnKSA9PiB7XG4gICAgICBjb25zdCB1cGRhdGVUeXBlVGV4dCA9IG1zZy5kYXRhLnBlcm1pc3Npb25DaGFuZ2VUeXBlICE9PSBQZXJtaXNzaW9uQ2hhbmdlVHlwZS5OT05FXG4gICAgICAgID8gJ3NlY3VyaXR5LXNlbnNpdGl2ZSB1cGRhdGVzJ1xuICAgICAgICA6ICd1cGRhdGVzJztcbiAgICAgIHJldHVybiBgU3RhY2sgaW5jbHVkZXMgJHt1cGRhdGVUeXBlVGV4dH0gYW5kIFwiLS1yZXF1aXJlLWFwcHJvdmFsXCIgaXMgc2V0IHRvICcke3JlcXVpcmVBcHByb3ZhbH0nLlxcbkRvIHlvdSB3aXNoIHRvIGRlcGxveSB0aGVzZSBjaGFuZ2VzP2A7XG4gICAgfSk7XG5cbiAgICAvLyBleGVjdXRlLWNoYW5nZS1zZXQgaXMgYSBuZXcgZmxvdyB0aGF0IHdlIGNhbiBqdXN0IGRlbGVnYXRlIHRvIHRvb2xraXQtbGliXG4gICAgaWYgKG9wdGlvbnMuZGVwbG95bWVudE1ldGhvZD8ubWV0aG9kID09PSAnZXhlY3V0ZS1jaGFuZ2Utc2V0Jykge1xuICAgICAgYXdhaXQgdGhpcy50b29sa2l0LmRlcGxveSh0aGlzLnByb3BzLmNsb3VkRXhlY3V0YWJsZSwge1xuICAgICAgICBkZXBsb3ltZW50TWV0aG9kOiBvcHRpb25zLmRlcGxveW1lbnRNZXRob2QsXG4gICAgICAgIHN0YWNrczoge1xuICAgICAgICAgIHBhdHRlcm5zOiBvcHRpb25zLnNlbGVjdG9yLnBhdHRlcm5zLFxuICAgICAgICAgIHN0cmF0ZWd5OiBTdGFja1NlbGVjdGlvblN0cmF0ZWd5LlBBVFRFUk5fTVVTVF9NQVRDSF9TSU5HTEUsXG4gICAgICAgICAgZXhwYW5kOiBFeHBhbmRTdGFja1NlbGVjdGlvbi5OT05FLFxuICAgICAgICB9LFxuICAgICAgICByb2xlQXJuOiBvcHRpb25zLnJvbGVBcm4sXG4gICAgICAgIGZvcmNlRGVwbG95bWVudDogb3B0aW9ucy5mb3JjZSxcbiAgICAgICAgcm9sbGJhY2s6IG9wdGlvbnMucm9sbGJhY2ssXG4gICAgICAgIHJldXNlQXNzZXRzOiBvcHRpb25zLnJldXNlQXNzZXRzLFxuICAgICAgICBjb25jdXJyZW5jeTogb3B0aW9ucy5jb25jdXJyZW5jeSxcbiAgICAgICAgdHJhY2VMb2dzOiBvcHRpb25zLnRyYWNlTG9ncyxcbiAgICAgICAgbm90aWZpY2F0aW9uQXJuczogb3B0aW9ucy5ub3RpZmljYXRpb25Bcm5zLFxuICAgICAgICB0YWdzOiBvcHRpb25zLnRhZ3MsXG4gICAgICAgIG91dHB1dHNGaWxlOiBvcHRpb25zLm91dHB1dHNGaWxlLFxuICAgICAgICBhc3NldFBhcmFsbGVsaXNtOiBvcHRpb25zLmFzc2V0UGFyYWxsZWxpc20sXG4gICAgICAgIGFzc2V0QnVpbGRDb25jdXJyZW5jeTogb3B0aW9ucy5hc3NldEJ1aWxkQ29uY3VycmVuY3ksXG4gICAgICAgIGFzc2V0QnVpbGRUaW1lOiBvcHRpb25zLmFzc2V0QnVpbGRUaW1lLFxuICAgICAgICBwYXJhbWV0ZXJzOiB1bmRlZmluZWQsIC8vIHBhcmFtZXRlcnMgYXJlIG9ubHkgc2V0IGR1cmluZyBjaGFuZ2Ugc2V0IGNyZWF0aW9uLCBzbyB0aGlzIGlzIGV4cGxpY2l0bHkgdW5zZXQgYmVjYXVzZSBjaGFuZ2Ugc2V0IGFscmVhZHkgZXhpc3RzXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzdGFydFN5bnRoVGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIGNvbnN0IGFzc2VtYmx5ID0gYXdhaXQgdGhpcy5hc3NlbWJseShvcHRpb25zLmNhY2hlQ2xvdWRBc3NlbWJseSk7XG4gICAgY29uc3Qgc3RhY2tDb2xsZWN0aW9uID0gYXdhaXQgYXNzZW1ibHkuc2VsZWN0U3RhY2tzVjIob3B0aW9ucy5zZWxlY3Rvcik7XG4gICAgYXdhaXQgdGhpcy52YWxpZGF0ZVN0YWNrcyhhc3NlbWJseSwgc3RhY2tDb2xsZWN0aW9uKTtcbiAgICBjb25zdCBlbGFwc2VkU3ludGhUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydFN5bnRoVGltZTtcbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhgXFxu4pyoICBTeW50aGVzaXMgdGltZTogJHtmb3JtYXRUaW1lKGVsYXBzZWRTeW50aFRpbWUpfXNcXG5gKTtcblxuICAgIGlmIChzdGFja0NvbGxlY3Rpb24uc3RhY2tDb3VudCA9PT0gMCkge1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmVycm9yKCdUaGlzIGFwcCBjb250YWlucyBubyBzdGFja3MnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBtaWdyYXRvciA9IG5ldyBSZXNvdXJjZU1pZ3JhdG9yKHtcbiAgICAgIGRlcGxveW1lbnRzOiB0aGlzLnByb3BzLmRlcGxveW1lbnRzLFxuICAgICAgaW9IZWxwZXI6IGFzSW9IZWxwZXIodGhpcy5pb0hvc3QsICdkZXBsb3knKSxcbiAgICB9KTtcbiAgICBhd2FpdCBtaWdyYXRvci50cnlNaWdyYXRlUmVzb3VyY2VzKHN0YWNrQ29sbGVjdGlvbiwge1xuICAgICAgdG9vbGtpdFN0YWNrTmFtZTogdGhpcy50b29sa2l0U3RhY2tOYW1lLFxuICAgICAgLi4ub3B0aW9ucyxcbiAgICB9KTtcblxuICAgIGlmIChvcHRpb25zLmRlcGxveW1lbnRNZXRob2Q/Lm1ldGhvZCA9PT0gJ2hvdHN3YXAnKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMud2FybihcbiAgICAgICAgJ+KaoO+4jyBUaGUgLS1ob3Rzd2FwIGFuZCAtLWhvdHN3YXAtZmFsbGJhY2sgZmxhZ3MgZGVsaWJlcmF0ZWx5IGludHJvZHVjZSBDbG91ZEZvcm1hdGlvbiBkcmlmdCB0byBzcGVlZCB1cCBkZXBsb3ltZW50cycsXG4gICAgICApO1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLndhcm4oJ+KaoO+4jyBUaGV5IHNob3VsZCBvbmx5IGJlIHVzZWQgZm9yIGRldmVsb3BtZW50IC0gbmV2ZXIgdXNlIHRoZW0gZm9yIHlvdXIgcHJvZHVjdGlvbiBTdGFja3MhXFxuJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhY2tzID0gc3RhY2tDb2xsZWN0aW9uLnN0YWNrQXJ0aWZhY3RzO1xuXG4gICAgY29uc3QgYXNzZXRCdWlsZFRpbWUgPSBvcHRpb25zLmFzc2V0QnVpbGRUaW1lID8/IEFzc2V0QnVpbGRUaW1lLkFMTF9CRUZPUkVfREVQTE9ZO1xuICAgIGNvbnN0IHByZWJ1aWxkQXNzZXRzID0gYXNzZXRCdWlsZFRpbWUgPT09IEFzc2V0QnVpbGRUaW1lLkFMTF9CRUZPUkVfREVQTE9ZO1xuICAgIGNvbnN0IGNvbmN1cnJlbmN5ID0gb3B0aW9ucy5jb25jdXJyZW5jeSB8fCAxO1xuICAgIGlmIChjb25jdXJyZW5jeSA+IDEpIHtcbiAgICAgIC8vIHRoZSBcImJhclwiIHByb2dyZXNzIG91dHB1dCBkb2Vzbid0IHN1cHBvcnQgY29uY3VycmVuY3ksIGZhbGwgYmFjayB0byBcImV2ZW50c1wiXG4gICAgICBpZiAodGhpcy5pb0hvc3Quc3RhY2tQcm9ncmVzcyA9PT0gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkJBUikge1xuICAgICAgICB0aGlzLmlvSG9zdC5zdGFja1Byb2dyZXNzID0gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkVWRU5UUztcbiAgICAgIH1cblxuICAgICAgLy8gLi4uYnV0IG9ubHkgd2FybiBpZiB0aGUgdXNlciBleHBsaWNpdGx5IHJlcXVlc3RlZCBcImJhclwiIHByb2dyZXNzXG4gICAgICBpZiAob3B0aW9ucy5wcm9ncmVzcyA9PT0gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkJBUikge1xuICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMud2Fybign4pqg77iPIFRoZSAtLWNvbmN1cnJlbmN5IGZsYWcgZG9lcyBub3Qgc3VwcG9ydCAtLXByb2dyZXNzIFwiYmFyXCIuIFN3aXRjaGluZyB0byBcImV2ZW50c1wiLicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHN0YWNrc0FuZFRoZWlyQXNzZXRNYW5pZmVzdHMgPSBzdGFja3MuZmxhdE1hcCgoc3RhY2spID0+IFtcbiAgICAgIHN0YWNrLFxuICAgICAgLi4uc3RhY2suZGVwZW5kZW5jaWVzLmZpbHRlcih4ID0+IGN4YXBpLkFzc2V0TWFuaWZlc3RBcnRpZmFjdC5pc0Fzc2V0TWFuaWZlc3RBcnRpZmFjdCh4KSksXG4gICAgXSk7XG4gICAgY29uc3Qgd29ya0dyYXBoID0gbmV3IFdvcmtHcmFwaEJ1aWxkZXIoXG4gICAgICBhc0lvSGVscGVyKHRoaXMuaW9Ib3N0LCAnZGVwbG95JyksXG4gICAgICBwcmVidWlsZEFzc2V0cyxcbiAgICApLmJ1aWxkKHN0YWNrc0FuZFRoZWlyQXNzZXRNYW5pZmVzdHMpO1xuXG4gICAgLy8gVW5sZXNzIHdlIGFyZSBydW5uaW5nIHdpdGggJy0tZm9yY2UnLCBza2lwIGFscmVhZHkgcHVibGlzaGVkIGFzc2V0c1xuICAgIGlmICghb3B0aW9ucy5mb3JjZSkge1xuICAgICAgYXdhaXQgdGhpcy5yZW1vdmVQdWJsaXNoZWRBc3NldHMod29ya0dyYXBoLCBvcHRpb25zKTtcbiAgICB9XG5cbiAgICBjb25zdCBncmFwaENvbmN1cnJlbmN5OiBDb25jdXJyZW5jeSA9IHtcbiAgICAgICdzdGFjayc6IGNvbmN1cnJlbmN5LFxuICAgICAgJ2Fzc2V0LWJ1aWxkJzogKG9wdGlvbnMuYXNzZXRQYXJhbGxlbGlzbSA/PyB0cnVlKSA/IG9wdGlvbnMuYXNzZXRCdWlsZENvbmN1cnJlbmN5ID8/IDEgOiAxLCAvLyBUaGlzIHdpbGwgYmUgQ1BVLWJvdW5kL21lbW9yeSBib3VuZCwgbW9zdGx5IG1hdHRlcnMgZm9yIERvY2tlciBidWlsZHNcbiAgICAgICdhc3NldC1wdWJsaXNoJzogKG9wdGlvbnMuYXNzZXRQYXJhbGxlbGlzbSA/PyB0cnVlKSA/IDggOiAxLCAvLyBUaGlzIHdpbGwgYmUgSS9PLWJvdW5kLCA4IGluIHBhcmFsbGVsIHNlZW1zIHJlYXNvbmFibGVcbiAgICAgICdtYXJrZXInOiAxLFxuICAgIH07XG5cbiAgICBjb25zdCBkZXBsb3ltZW50QWN0aW9ucyA9IG5ldyBXb3JrR3JhcGhEZXBsb3ltZW50QWN0aW9ucyh0aGlzLnByb3BzLmRlcGxveW1lbnRzLCB0aGlzLmlvSG9zdCwgdGhpcywge1xuICAgICAgcm9sZUFybjogb3B0aW9ucy5yb2xlQXJuLFxuICAgICAgZm9yY2U6IG9wdGlvbnMuZm9yY2UsXG4gICAgICBzdGFja0NvdW50OiBzdGFja0NvbGxlY3Rpb24uc3RhY2tDb3VudCxcbiAgICAgIG5vdGlmaWNhdGlvbkFybnM6IG9wdGlvbnMubm90aWZpY2F0aW9uQXJucyxcbiAgICAgIGRlcGxveW1lbnRNZXRob2Q6IG9wdGlvbnMuZGVwbG95bWVudE1ldGhvZCxcbiAgICAgIHRvb2xraXRTdGFja05hbWU6IHRoaXMudG9vbGtpdFN0YWNrTmFtZSxcbiAgICAgIHJldXNlQXNzZXRzOiBvcHRpb25zLnJldXNlQXNzZXRzLFxuICAgICAgdGFnczogb3B0aW9ucy50YWdzLFxuICAgICAgcGFyYW1ldGVyczogb3B0aW9ucy5wYXJhbWV0ZXJzLFxuICAgICAgdXNlUHJldmlvdXNQYXJhbWV0ZXJzOiBvcHRpb25zLnVzZVByZXZpb3VzUGFyYW1ldGVycyxcbiAgICAgIHJvbGxiYWNrOiBvcHRpb25zLnJvbGxiYWNrLFxuICAgICAgY29uY3VycmVuY3ksXG4gICAgICByZXF1aXJlQXBwcm92YWwsXG4gICAgICBhc3NldFBhcmFsbGVsaXNtOiBvcHRpb25zLmFzc2V0UGFyYWxsZWxpc20sXG4gICAgICBleHRyYVVzZXJBZ2VudDogb3B0aW9ucy5leHRyYVVzZXJBZ2VudCxcbiAgICAgIGNsb3VkV2F0Y2hMb2dNb25pdG9yOiBvcHRpb25zLmNsb3VkV2F0Y2hMb2dNb25pdG9yLFxuICAgICAgc2RrUHJvdmlkZXI6IHRoaXMucHJvcHMuc2RrUHJvdmlkZXIsXG4gICAgICBleHByZXNzOiBvcHRpb25zLmV4cHJlc3MsXG4gICAgfSk7XG5cbiAgICBjb25zdCBzdGFydERlcGxveVRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgYXdhaXQgd29ya0dyYXBoLmRvUGFyYWxsZWwoZ3JhcGhDb25jdXJyZW5jeSwgZGVwbG95bWVudEFjdGlvbnMpO1xuXG4gICAgaWYgKG9wdGlvbnMub3V0cHV0c0ZpbGUpIHtcbiAgICAgIC8vIElmIGFuIG91dHB1dHMgZmlsZSBoYXMgYmVlbiBzcGVjaWZpZWQsIGNyZWF0ZSB0aGUgZmlsZSBwYXRoIGFuZCB3cml0ZSBzdGFjayBvdXRwdXRzIHRvIGl0IG9uY2UuXG4gICAgICAvLyBPdXRwdXRzIGFyZSB3cml0dGVuIGFmdGVyIGFsbCBzdGFja3MgaGF2ZSBiZWVuIGRlcGxveWVkLiBJZiBhIHN0YWNrIGRlcGxveW1lbnQgZmFpbHMsXG4gICAgICAvLyBhbGwgb2YgdGhlIG91dHB1dHMgZnJvbSBzdWNjZXNzZnVsbHkgZGVwbG95ZWQgc3RhY2tzIGJlZm9yZSB0aGUgZmFpbHVyZSB3aWxsIHN0aWxsIGJlIHdyaXR0ZW4uXG4gICAgICBhd2FpdCBkZXBsb3ltZW50QWN0aW9ucy53cml0ZU91dHB1dHMob3B0aW9ucy5vdXRwdXRzRmlsZSk7XG4gICAgfVxuXG4gICAgLy8gQWRkIGEgdGltZXIgb24gdGhlIENPTU1BTkQgc3BhbiBmb3IgdGhlIGZ1bGwgZGVwbG95bWVudCB3YWl0IHRpbWUgKG5vdCB0aGUgc2FtZSBhcyB0aGUgc3VtIG9mIGFsbCBERVBMT1lcbiAgICAvLyBzcGFucyBiZWNhdXNlIG9mIHBhcmFsbGVsaXNtKS5cbiAgICB0aGlzLmlvSG9zdC50ZWxlbWV0cnk/LmNvbW1hbmRTcGFuPy5hZGRUaW1lcigndG90YWxEZXBsb3lUaW1lJywgRGF0ZS5ub3coKSAtIHN0YXJ0RGVwbG95VGltZSk7XG5cbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhgXFxu4pyoICBUb3RhbCB0aW1lOiAke2Zvcm1hdFRpbWUoRGF0ZS5ub3coKSAtIHN0YXJ0U3ludGhUaW1lKX1zXFxuYCk7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZWN0IGluZnJhc3RydWN0dXJlIGRyaWZ0IGZvciB0aGUgZ2l2ZW4gc3RhY2socylcbiAgICovXG4gIHB1YmxpYyBhc3luYyBkcmlmdChvcHRpb25zOiBEcmlmdE9wdGlvbnMpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGRyaWZ0UmVzdWx0cyA9IGF3YWl0IHRoaXMudG9vbGtpdC5kcmlmdCh0aGlzLnByb3BzLmNsb3VkRXhlY3V0YWJsZSwge1xuICAgICAgc3RhY2tzOiBvcHRpb25zLnNlbGVjdG9yLFxuICAgIH0pO1xuXG4gICAgY29uc3QgdG90YWxEcmlmdHMgPSBPYmplY3QudmFsdWVzKGRyaWZ0UmVzdWx0cykucmVkdWNlKCh0b3RhbCwgY3VycmVudCkgPT4gdG90YWwgKyAoY3VycmVudC5udW1SZXNvdXJjZXNXaXRoRHJpZnQgPz8gMCksIDApO1xuICAgIHJldHVybiB0b3RhbERyaWZ0cyA+IDAgJiYgb3B0aW9ucy5mYWlsID8gMSA6IDA7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgc3ludGhlc2l6ZWQgdGVtcGxhdGVzIGFnYWluc3QgcG9saWN5IHJ1bGVzXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgdmFsaWRhdGUob3B0aW9uczogQ2xpVmFsaWRhdGVPcHRpb25zKTogUHJvbWlzZTxudW1iZXIgfCB2b2lkPiB7XG4gICAgLy8gSW1wbGljaXRseSBzd2l0Y2ggJ2RlYnVnJyBtb2RlIHRvIHRydWU7IG1vcmUgc3RhY2sgdHJhY2VzID0gbW9yZSB1c2VmdWwuXG4gICAgdGhpcy5wcm9wcy5jbG91ZEV4ZWN1dGFibGUuc3dpdGNoT25EZWJ1Z2dpbmcoKTtcblxuICAgIC8vIGB3YXRjaGAgaXMgYSBDTEktb25seSBmbGFnOyBzdHJpcCBpdCBiZWZvcmUgY3Jvc3NpbmcgaW50byB0b29sa2l0LWxpYiBzb1xuICAgIC8vIGl0IGRvZXMgbm90IGxlYWsgaW50byB0aGUgbGlicmFyeSdzIHZhbGlkYXRlIGFjdGlvbi5cbiAgICBjb25zdCB7IHdhdGNoLCAuLi52YWxpZGF0ZU9wdGlvbnMgfSA9IG9wdGlvbnM7XG5cbiAgICBpZiAod2F0Y2gpIHtcbiAgICAgIHJldHVybiB0aGlzLnZhbGlkYXRlV2F0Y2godmFsaWRhdGVPcHRpb25zKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnRvb2xraXQudmFsaWRhdGUodGhpcy5wcm9wcy5jbG91ZEV4ZWN1dGFibGUsIHZhbGlkYXRlT3B0aW9ucyk7XG4gICAgcmV0dXJuIHJlc3VsdC5jb25jbHVzaW9uID09PSAnZmFpbHVyZScgPyAxIDogMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb250aW51b3VzbHkgdmFsaWRhdGUgdGhlIHByb2plY3QsIHJlLXN5bnRoZXNpemluZyBhbmQgcmUtdmFsaWRhdGluZyBvblxuICAgKiBldmVyeSBmaWxlIGNoYW5nZS4gTmV2ZXIgZGVwbG95cy5cbiAgICpcbiAgICogVGhlIGZpbGVzIHRvIG9ic2VydmUgYXJlIGNvbmZpZ3VyZWQgd2l0aCB0aGUgXCJ3YXRjaFwiIGtleSBvZiBgY2RrLmpzb25gLFxuICAgKiBleGFjdGx5IGxpa2UgYGNkayBkZXBsb3kgLS13YXRjaGAuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZhbGlkYXRlV2F0Y2gob3B0aW9uczogVmFsaWRhdGVPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgcm9vdERpciA9IHBhdGguZGlybmFtZShwYXRoLnJlc29sdmUoUFJPSkVDVF9DT05GSUcpKTtcblxuICAgIGNvbnN0IHdhdGNoU2V0dGluZ3M6IHsgaW5jbHVkZT86IHN0cmluZyB8IHN0cmluZ1tdOyBleGNsdWRlPzogc3RyaW5nIHwgc3RyaW5nW10gfSB8IHVuZGVmaW5lZCA9XG4gICAgICB0aGlzLnByb3BzLmNvbmZpZ3VyYXRpb24uc2V0dGluZ3MuZ2V0KFsnd2F0Y2gnXSk7XG4gICAgaWYgKCF3YXRjaFNldHRpbmdzKSB7XG4gICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKFxuICAgICAgICAnV2F0Y2hDb25maWdNaXNzaW5nJyxcbiAgICAgICAgXCJDYW5ub3QgdXNlICctLXdhdGNoJyB3aXRob3V0IHNwZWNpZnlpbmcgYXQgbGVhc3Qgb25lIGRpcmVjdG9yeSB0byBtb25pdG9yLiBcIiArXG4gICAgICAgICdNYWtlIHN1cmUgdG8gYWRkIGEgXCJ3YXRjaFwiIGtleSB0byB5b3VyIGNkay5qc29uJyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgaW5jbHVkZSA9IHRoaXMucGF0dGVybnNBcnJheUZvcldhdGNoKHdhdGNoU2V0dGluZ3MuaW5jbHVkZSwge1xuICAgICAgZGVmYXVsdFBhdHRlcm46ICcqKicsXG4gICAgICByZXR1cm5EZWZhdWx0SWZFbXB0eTogdHJ1ZSxcbiAgICB9KTtcbiAgICAvLyBQYXNzIHRoZSB1c2VyJ3MgZXhjbHVkZXMgZXhwbGljaXRseTsgdG9vbGtpdC1saWIgYWx3YXlzIGFwcGVuZHMgdGhlXG4gICAgLy8gb3V0ZGlyLCBkb3QtZmlsZSwgYW5kIG5vZGVfbW9kdWxlcyBleGNsdWRlcyBvbiB0b3Agb2YgdGhlc2UuXG4gICAgY29uc3QgZXhjbHVkZSA9IHRoaXMucGF0dGVybnNBcnJheUZvcldhdGNoKHdhdGNoU2V0dGluZ3MuZXhjbHVkZSwge1xuICAgICAgZGVmYXVsdFBhdHRlcm46ICcnLFxuICAgICAgcmV0dXJuRGVmYXVsdElmRW1wdHk6IGZhbHNlLFxuICAgIH0pO1xuXG4gICAgY29uc3Qgd2F0Y2hlciA9IGF3YWl0IHRoaXMudG9vbGtpdC53YXRjaFZhbGlkYXRlKHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLnVuY2FjaGVkU291cmNlKCksIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICB3YXRjaERpcjogcm9vdERpcixcbiAgICAgIGluY2x1ZGUsXG4gICAgICBleGNsdWRlLFxuICAgIH0pO1xuICAgIHJldHVybiB3YXRjaGVyLndhaXRGb3JFbmQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEaWFnbm9zZSBlcnJvcnNcbiAgICovXG4gIHB1YmxpYyBhc3luYyBkaWFnbm9zZShvcHRpb25zOiBEaWFnbm9zZU9wdGlvbnMpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIC8vIEltcGxpY2l0bHkgc3dpdGNoICdkZWJ1ZycgbW9kZSB0byB0cnVlOyBtb3JlIHN0YWNrIHRyYWNlcyA9IG1vcmUgdXNlZnVsLlxuICAgIHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLnN3aXRjaE9uRGVidWdnaW5nKCk7XG5cbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgdGhpcy50b29sa2l0LmRpYWdub3NlKHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLCBvcHRpb25zKTtcblxuICAgIGlmIChyZXN1bHRzLnN0YWNrcy5zb21lKHMgPT4gcy5yZXN1bHQudHlwZSAhPT0gJ25vLXByb2JsZW0nKSkge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfVxuICAgIHJldHVybiAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFJvbGwgYmFjayB0aGUgZ2l2ZW4gc3RhY2sgb3Igc3RhY2tzLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIHJvbGxiYWNrKG9wdGlvbnM6IFJvbGxiYWNrT3B0aW9ucykge1xuICAgIGNvbnN0IHN0YXJ0U3ludGhUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgY29uc3QgYXNzZW1ibHkgPSBhd2FpdCB0aGlzLmFzc2VtYmx5KCk7XG4gICAgY29uc3Qgc3RhY2tDb2xsZWN0aW9uID0gYXdhaXQgYXNzZW1ibHkuc2VsZWN0U3RhY2tzVjIob3B0aW9ucy5zZWxlY3Rvcik7XG4gICAgYXdhaXQgdGhpcy52YWxpZGF0ZVN0YWNrcyhhc3NlbWJseSwgc3RhY2tDb2xsZWN0aW9uKTtcbiAgICBjb25zdCBlbGFwc2VkU3ludGhUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydFN5bnRoVGltZTtcbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhgXFxu4pyoICBTeW50aGVzaXMgdGltZTogJHtmb3JtYXRUaW1lKGVsYXBzZWRTeW50aFRpbWUpfXNcXG5gKTtcblxuICAgIGlmIChzdGFja0NvbGxlY3Rpb24uc3RhY2tDb3VudCA9PT0gMCkge1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmVycm9yKCdObyBzdGFja3Mgc2VsZWN0ZWQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsZXQgYW55Um9sbGJhY2thYmxlID0gZmFsc2U7XG5cbiAgICBmb3IgKGNvbnN0IHN0YWNrIG9mIHN0YWNrQ29sbGVjdGlvbi5zdGFja0FydGlmYWN0cykge1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oJ1JvbGxpbmcgYmFjayAlcycsIGNoYWxrLmJvbGQoc3RhY2suZGlzcGxheU5hbWUpKTtcbiAgICAgIGNvbnN0IHN0YXJ0Um9sbGJhY2tUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnByb3BzLmRlcGxveW1lbnRzLnJvbGxiYWNrU3RhY2soe1xuICAgICAgICAgIHN0YWNrLFxuICAgICAgICAgIHJvbGVBcm46IG9wdGlvbnMucm9sZUFybixcbiAgICAgICAgICB0b29sa2l0U3RhY2tOYW1lOiBvcHRpb25zLnRvb2xraXRTdGFja05hbWUsXG4gICAgICAgICAgb3JwaGFuRmFpbGVkUmVzb3VyY2VzOiBvcHRpb25zLmZvcmNlLFxuICAgICAgICAgIHZhbGlkYXRlQm9vdHN0cmFwU3RhY2tWZXJzaW9uOiBvcHRpb25zLnZhbGlkYXRlQm9vdHN0cmFwU3RhY2tWZXJzaW9uLFxuICAgICAgICAgIG9ycGhhbkxvZ2ljYWxJZHM6IG9wdGlvbnMub3JwaGFuTG9naWNhbElkcyxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICghcmVzdWx0Lm5vdEluUm9sbGJhY2thYmxlU3RhdGUpIHtcbiAgICAgICAgICBhbnlSb2xsYmFja2FibGUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVsYXBzZWRSb2xsYmFja1RpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0Um9sbGJhY2tUaW1lO1xuICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhgXFxu4pyoICBSb2xsYmFjayB0aW1lOiAke2Zvcm1hdFRpbWUoZWxhcHNlZFJvbGxiYWNrVGltZSkudG9TdHJpbmcoKX1zXFxuYCk7XG4gICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmVycm9yKCdcXG4g4p2MICAlcyBmYWlsZWQ6ICVzJywgY2hhbGsuYm9sZChzdGFjay5kaXNwbGF5TmFtZSksIGZvcm1hdEVycm9yTWVzc2FnZShlKSk7XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ1JvbGxiYWNrRmFpbGVkJywgJ1JvbGxiYWNrIGZhaWxlZCAodXNlIC0tZm9yY2UgdG8gb3JwaGFuIGZhaWxpbmcgcmVzb3VyY2VzKScpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWFueVJvbGxiYWNrYWJsZSkge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignTm9Sb2xsYmFja2FibGVTdGFja3MnLCAnTm8gc3RhY2tzIHdlcmUgaW4gYSBzdGF0ZSB0aGF0IGNvdWxkIGJlIHJvbGxlZCBiYWNrJyk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGFzeW5jIHB1Ymxpc2hBc3NldHMob3B0aW9uczogUHVibGlzaEFzc2V0c09wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLnRvb2xraXQucHVibGlzaEFzc2V0cyh0aGlzLnByb3BzLmNsb3VkRXhlY3V0YWJsZSwgb3B0aW9ucyk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgd2F0Y2gob3B0aW9uczogV2F0Y2hPcHRpb25zKSB7XG4gICAgY29uc3Qgcm9vdERpciA9IHBhdGguZGlybmFtZShwYXRoLnJlc29sdmUoUFJPSkVDVF9DT05GSUcpKTtcbiAgICBjb25zdCBpb0hlbHBlciA9IGFzSW9IZWxwZXIodGhpcy5pb0hvc3QsICd3YXRjaCcpO1xuICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5kZWJ1ZyhcInJvb3QgZGlyZWN0b3J5IHVzZWQgZm9yICd3YXRjaCcgaXM6ICVzXCIsIHJvb3REaXIpO1xuXG4gICAgY29uc3Qgd2F0Y2hTZXR0aW5nczogeyBpbmNsdWRlPzogc3RyaW5nIHwgc3RyaW5nW107IGV4Y2x1ZGU6IHN0cmluZyB8IHN0cmluZ1tdIH0gfCB1bmRlZmluZWQgPVxuICAgICAgdGhpcy5wcm9wcy5jb25maWd1cmF0aW9uLnNldHRpbmdzLmdldChbJ3dhdGNoJ10pO1xuICAgIGlmICghd2F0Y2hTZXR0aW5ncykge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihcbiAgICAgICAgJ1dhdGNoQ29uZmlnTWlzc2luZycsXG4gICAgICAgIFwiQ2Fubm90IHVzZSB0aGUgJ3dhdGNoJyBjb21tYW5kIHdpdGhvdXQgc3BlY2lmeWluZyBhdCBsZWFzdCBvbmUgZGlyZWN0b3J5IHRvIG1vbml0b3IuIFwiICtcbiAgICAgICAgJ01ha2Ugc3VyZSB0byBhZGQgYSBcIndhdGNoXCIga2V5IHRvIHlvdXIgY2RrLmpzb24nLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBGb3IgdGhlIFwiaW5jbHVkZVwiIHN1YmtleSB1bmRlciB0aGUgXCJ3YXRjaFwiIGtleSwgdGhlIGJlaGF2aW9yIGlzOlxuICAgIC8vIDEuIE5vIFwid2F0Y2hcIiBzZXR0aW5nPyBXZSBlcnJvciBvdXQuXG4gICAgLy8gMi4gXCJ3YXRjaFwiIHNldHRpbmcgd2l0aG91dCBhbiBcImluY2x1ZGVcIiBrZXk/IFdlIGRlZmF1bHQgdG8gb2JzZXJ2aW5nIFwiLi8qKlwiLlxuICAgIC8vIDMuIFwid2F0Y2hcIiBzZXR0aW5nIHdpdGggYW4gZW1wdHkgXCJpbmNsdWRlXCIga2V5PyBXZSBkZWZhdWx0IHRvIG9ic2VydmluZyBcIi4vKipcIi5cbiAgICAvLyA0LiBOb24tZW1wdHkgXCJpbmNsdWRlXCIga2V5PyBKdXN0IHVzZSB0aGUgXCJpbmNsdWRlXCIga2V5LlxuICAgIC8vIE5vdGU6IFdlIHVzZSAnKionIGFzIHRoZSBkZWZhdWx0IHBhdHRlcm4gKG5vdCByb290RGlyKSBiZWNhdXNlIGNob2tpZGFyIHJlcG9ydHNcbiAgICAvLyBmaWxlIHBhdGhzIHJlbGF0aXZlIHRvIGN3ZCwgYW5kIHRoZSBpZ25vcmVkIGZ1bmN0aW9uIHVzZXMgcGljb21hdGNoIHdoaWNoIGV4cGVjdHNcbiAgICAvLyBnbG9iIHBhdHRlcm5zLCBub3QgYWJzb2x1dGUgcGF0aHMuXG4gICAgY29uc3Qgd2F0Y2hJbmNsdWRlcyA9IHRoaXMucGF0dGVybnNBcnJheUZvcldhdGNoKHdhdGNoU2V0dGluZ3MuaW5jbHVkZSwge1xuICAgICAgZGVmYXVsdFBhdHRlcm46ICcqKicsXG4gICAgICByZXR1cm5EZWZhdWx0SWZFbXB0eTogdHJ1ZSxcbiAgICB9KTtcbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuZGVidWcoXCInaW5jbHVkZScgcGF0dGVybnMgZm9yICd3YXRjaCc6ICVzXCIsIHdhdGNoSW5jbHVkZXMpO1xuXG4gICAgLy8gRm9yIHRoZSBcImV4Y2x1ZGVcIiBzdWJrZXkgdW5kZXIgdGhlIFwid2F0Y2hcIiBrZXksXG4gICAgLy8gdGhlIGJlaGF2aW9yIGlzIHRvIGFkZCBzb21lIGRlZmF1bHQgZXhjbHVkZXMgaW4gYWRkaXRpb24gdG8gdGhlIG9uZXMgc3BlY2lmaWVkIGJ5IHRoZSB1c2VyOlxuICAgIC8vIDEuIFRoZSBDREsgb3V0cHV0IGRpcmVjdG9yeS5cbiAgICAvLyAyLiBBbnkgZmlsZSB3aG9zZSBuYW1lIHN0YXJ0cyB3aXRoIGEgZG90LlxuICAgIC8vIDMuIEFueSBkaXJlY3RvcnkncyBjb250ZW50IHdob3NlIG5hbWUgc3RhcnRzIHdpdGggYSBkb3QuXG4gICAgLy8gNC4gQW55IG5vZGVfbW9kdWxlcyBhbmQgaXRzIGNvbnRlbnQgKGV2ZW4gaWYgaXQncyBub3QgYSBKUy9UUyBwcm9qZWN0LCB5b3UgbWlnaHQgYmUgdXNpbmcgYSBsb2NhbCBhd3MtY2xpIHBhY2thZ2UpXG4gICAgY29uc3Qgb3V0cHV0RGlyID0gdGhpcy5wcm9wcy5jb25maWd1cmF0aW9uLnNldHRpbmdzLmdldChbJ291dHB1dCddKTtcbiAgICBjb25zdCB3YXRjaEV4Y2x1ZGVzID0gdGhpcy5wYXR0ZXJuc0FycmF5Rm9yV2F0Y2god2F0Y2hTZXR0aW5ncy5leGNsdWRlLCB7XG4gICAgICBkZWZhdWx0UGF0dGVybjogJycsXG4gICAgICByZXR1cm5EZWZhdWx0SWZFbXB0eTogZmFsc2UsXG4gICAgfSkuY29uY2F0KGAke291dHB1dERpcn0vKipgLCAnKiovLionLCAnKiovLiovKionLCAnKiovbm9kZV9tb2R1bGVzLyoqJyk7XG4gICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmRlYnVnKFwiJ2V4Y2x1ZGUnIHBhdHRlcm5zIGZvciAnd2F0Y2gnOiAlc1wiLCB3YXRjaEV4Y2x1ZGVzKTtcblxuICAgIC8vIFNpbmNlICdjZGsgZGVwbG95JyBpcyBhIHJlbGF0aXZlbHkgc2xvdyBvcGVyYXRpb24gZm9yIGEgJ3dhdGNoJyBwcm9jZXNzLFxuICAgIC8vIGludHJvZHVjZSBhIGNvbmN1cnJlbmN5IGxhdGNoIHRoYXQgdHJhY2tzIHRoZSBzdGF0ZS5cbiAgICAvLyBUaGlzIHdheSwgaWYgZmlsZSBjaGFuZ2UgZXZlbnRzIGFycml2ZSB3aGVuIGEgJ2NkayBkZXBsb3knIGlzIHN0aWxsIGV4ZWN1dGluZyxcbiAgICAvLyB3ZSB3aWxsIGJhdGNoIHRoZW0sIGFuZCB0cmlnZ2VyIGFub3RoZXIgJ2NkayBkZXBsb3knIGFmdGVyIHRoZSBjdXJyZW50IG9uZSBmaW5pc2hlcyxcbiAgICAvLyBtYWtpbmcgc3VyZSAnY2RrIGRlcGxveSdzICBhbHdheXMgZXhlY3V0ZSBvbmUgYXQgYSB0aW1lLlxuICAgIC8vIEhlcmUncyBhIGRpYWdyYW0gc2hvd2luZyB0aGUgc3RhdGUgdHJhbnNpdGlvbnM6XG4gICAgLy8gLS0tLS0tLS0tLS0tLS0gICAgICAgICAgICAgICAgLS0tLS0tLS0gICAgZmlsZSBjaGFuZ2VkICAgICAtLS0tLS0tLS0tLS0tLSAgICBmaWxlIGNoYW5nZWQgICAgIC0tLS0tLS0tLS0tLS0tICBmaWxlIGNoYW5nZWRcbiAgICAvLyB8ICAgICAgICAgICAgfCAgcmVhZHkgZXZlbnQgICB8ICAgICAgfCAtLS0tLS0tLS0tLS0tLS0tLS0+IHwgICAgICAgICAgICB8IC0tLS0tLS0tLS0tLS0tLS0tLT4gfCAgICAgICAgICAgIHwgLS0tLS0tLS0tLS0tLS18XG4gICAgLy8gfCBwcmUtcmVhZHkgIHwgLS0tLS0tLS0tLS0tLT4gfCBvcGVuIHwgICAgICAgICAgICAgICAgICAgICB8IGRlcGxveWluZyAgfCAgICAgICAgICAgICAgICAgICAgIHwgICBxdWV1ZWQgICB8ICAgICAgICAgICAgICAgfFxuICAgIC8vIHwgICAgICAgICAgICB8ICAgICAgICAgICAgICAgIHwgICAgICB8IDwtLS0tLS0tLS0tLS0tLS0tLS0gfCAgICAgICAgICAgIHwgPC0tLS0tLS0tLS0tLS0tLS0tLSB8ICAgICAgICAgICAgfCA8LS0tLS0tLS0tLS0tLXxcbiAgICAvLyAtLS0tLS0tLS0tLS0tLSAgICAgICAgICAgICAgICAtLS0tLS0tLSAgJ2NkayBkZXBsb3knIGRvbmUgIC0tLS0tLS0tLS0tLS0tICAnY2RrIGRlcGxveScgZG9uZSAgLS0tLS0tLS0tLS0tLS1cbiAgICBsZXQgbGF0Y2g6ICdwcmUtcmVhZHknIHwgJ29wZW4nIHwgJ2RlcGxveWluZycgfCAncXVldWVkJyA9ICdwcmUtcmVhZHknO1xuXG4gICAgY29uc3QgY2xvdWRXYXRjaExvZ01vbml0b3IgPSBvcHRpb25zLnRyYWNlTG9ncyA/IG5ldyBDbG91ZFdhdGNoTG9nRXZlbnRNb25pdG9yKHtcbiAgICAgIGlvSGVscGVyLFxuICAgIH0pIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IGRlcGxveUFuZFdhdGNoID0gYXN5bmMgKCkgPT4ge1xuICAgICAgbGF0Y2ggPSAnZGVwbG95aW5nJztcbiAgICAgIGF3YWl0IGNsb3VkV2F0Y2hMb2dNb25pdG9yPy5kZWFjdGl2YXRlKCk7XG5cbiAgICAgIGF3YWl0IHRoaXMuaW52b2tlRGVwbG95RnJvbVdhdGNoKG9wdGlvbnMsIGNsb3VkV2F0Y2hMb2dNb25pdG9yKTtcblxuICAgICAgLy8gSWYgbGF0Y2ggaXMgc3RpbGwgJ2RlcGxveWluZycgYWZ0ZXIgdGhlICdhd2FpdCcsIHRoYXQncyBmaW5lLFxuICAgICAgLy8gYnV0IGlmIGl0J3MgJ3F1ZXVlZCcsIHRoYXQgbWVhbnMgd2UgbmVlZCB0byBkZXBsb3kgYWdhaW5cbiAgICAgIHdoaWxlICgobGF0Y2ggYXMgJ2RlcGxveWluZycgfCAncXVldWVkJykgPT09ICdxdWV1ZWQnKSB7XG4gICAgICAgIC8vIFR5cGVTY3JpcHQgZG9lc24ndCByZWFsaXplIGxhdGNoIGNhbiBjaGFuZ2UgYmV0d2VlbiAnYXdhaXRzJyxcbiAgICAgICAgLy8gYW5kIHRoaW5rcyB0aGUgYWJvdmUgJ3doaWxlJyBjb25kaXRpb24gaXMgYWx3YXlzICdmYWxzZScgd2l0aG91dCB0aGUgY2FzdFxuICAgICAgICBsYXRjaCA9ICdkZXBsb3lpbmcnO1xuICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhcIkRldGVjdGVkIGZpbGUgY2hhbmdlcyBkdXJpbmcgZGVwbG95bWVudC4gSW52b2tpbmcgJ2NkayBkZXBsb3knIGFnYWluXCIpO1xuICAgICAgICBhd2FpdCB0aGlzLmludm9rZURlcGxveUZyb21XYXRjaChvcHRpb25zLCBjbG91ZFdhdGNoTG9nTW9uaXRvcik7XG4gICAgICB9XG4gICAgICBsYXRjaCA9ICdvcGVuJztcbiAgICAgIGF3YWl0IGNsb3VkV2F0Y2hMb2dNb25pdG9yPy5hY3RpdmF0ZSgpO1xuICAgIH07XG5cbiAgICAvLyBDcmVhdGUgaWdub3JlIG1hdGNoZXIgZm9yIGNob2tpZGFyIHY0IGNvbXBhdGliaWxpdHlcbiAgICAvLyBDaG9raWRhciB2NCByZW1vdmVkIGdsb2IgcGF0dGVybiBzdXBwb3J0LCBzbyB3ZSB1c2UgcGljb21hdGNoIHRvIGZpbHRlciBmaWxlc1xuICAgIC8vIFdlIHBhc3Mgcm9vdERpciBiZWNhdXNlIGNob2tpZGFyIHY0IHBhc3NlcyBhYnNvbHV0ZSBwYXRocyB0byB0aGUgaWdub3JlZCBjYWxsYmFja1xuICAgIGNvbnN0IHNob3VsZElnbm9yZSA9IGNyZWF0ZUlnbm9yZU1hdGNoZXIoe1xuICAgICAgaW5jbHVkZTogd2F0Y2hJbmNsdWRlcyxcbiAgICAgIGV4Y2x1ZGU6IHdhdGNoRXhjbHVkZXMsXG4gICAgICByb290RGlyLFxuICAgIH0pO1xuXG4gICAgY2hva2lkYXJcbiAgICAgIC53YXRjaCgnLicsIHtcbiAgICAgICAgaWdub3JlZDogc2hvdWxkSWdub3JlLFxuICAgICAgICBjd2Q6IHJvb3REaXIsXG4gICAgICB9KVxuICAgICAgLm9uKCdyZWFkeScsIGFzeW5jICgpID0+IHtcbiAgICAgICAgbGF0Y2ggPSAnb3Blbic7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5kZWJ1ZyhcIid3YXRjaCcgcmVjZWl2ZWQgdGhlICdyZWFkeScgZXZlbnQuIEZyb20gbm93IG9uLCBhbGwgZmlsZSBjaGFuZ2VzIHdpbGwgdHJpZ2dlciBhIGRlcGxveW1lbnRcIik7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKFwiVHJpZ2dlcmluZyBpbml0aWFsICdjZGsgZGVwbG95J1wiKTtcbiAgICAgICAgYXdhaXQgZGVwbG95QW5kV2F0Y2goKTtcbiAgICAgIH0pXG4gICAgICAub24oJ2FsbCcsIGFzeW5jIChldmVudDogRXZlbnROYW1lLCBmaWxlUGF0aD86IHN0cmluZykgPT4ge1xuICAgICAgICBpZiAoIWlzRmlsZUV2ZW50KGV2ZW50KSkge1xuICAgICAgICAgIHJldHVybjsgLy8gSWdub3JlIG5vbi1maWxlIGV2ZW50cyBsaWtlICdlcnJvcicsICdyYXcnLCAncmVhZHknLCAnYWxsJ1xuICAgICAgICB9XG4gICAgICAgIGlmIChsYXRjaCA9PT0gJ3ByZS1yZWFkeScpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhgJ3dhdGNoJyBpcyBvYnNlcnZpbmcgJHtldmVudCA9PT0gJ2FkZERpcicgPyAnZGlyZWN0b3J5JyA6ICd0aGUgZmlsZSd9ICclcycgZm9yIGNoYW5nZXNgLCBmaWxlUGF0aCk7XG4gICAgICAgIH0gZWxzZSBpZiAobGF0Y2ggPT09ICdvcGVuJykge1xuICAgICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKFwiRGV0ZWN0ZWQgY2hhbmdlIHRvICclcycgKHR5cGU6ICVzKS4gVHJpZ2dlcmluZyAnY2RrIGRlcGxveSdcIiwgZmlsZVBhdGgsIGV2ZW50KTtcbiAgICAgICAgICBhd2FpdCBkZXBsb3lBbmRXYXRjaCgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIHRoaXMgbWVhbnMgbGF0Y2ggaXMgZWl0aGVyICdkZXBsb3lpbmcnIG9yICdxdWV1ZWQnXG4gICAgICAgICAgbGF0Y2ggPSAncXVldWVkJztcbiAgICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhcbiAgICAgICAgICAgIFwiRGV0ZWN0ZWQgY2hhbmdlIHRvICclcycgKHR5cGU6ICVzKSB3aGlsZSAnY2RrIGRlcGxveScgaXMgc3RpbGwgcnVubmluZy4gXCIgK1xuICAgICAgICAgICAgJ1dpbGwgcXVldWUgZm9yIGFub3RoZXIgZGVwbG95bWVudCBhZnRlciB0aGlzIG9uZSBmaW5pc2hlcycsXG4gICAgICAgICAgICBmaWxlUGF0aCxcbiAgICAgICAgICAgIGV2ZW50LFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIG9ycGhhbihvcHRpb25zOiBPcnBoYW5PcHRpb25zKSB7XG4gICAgYXdhaXQgdGhpcy50b29sa2l0Lm9ycGhhbih0aGlzLnByb3BzLmNsb3VkRXhlY3V0YWJsZSwge1xuICAgICAgY29uc3RydWN0UGF0aHM6IG9wdGlvbnMuY29uc3RydWN0UGF0aCxcbiAgICAgIHJvbGVBcm46IG9wdGlvbnMucm9sZUFybixcbiAgICAgIHRvb2xraXRTdGFja05hbWU6IG9wdGlvbnMudG9vbGtpdFN0YWNrTmFtZSxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBpbXBvcnQob3B0aW9uczogSW1wb3J0T3B0aW9ucykge1xuICAgIGNvbnN0IGFzc2VtYmx5ID0gYXdhaXQgdGhpcy5hc3NlbWJseSgpO1xuICAgIGNvbnN0IHN0YWNrcyA9IGF3YWl0IGFzc2VtYmx5LnNlbGVjdFN0YWNrc1YyKG9wdGlvbnMuc2VsZWN0b3IpO1xuICAgIGF3YWl0IHRoaXMudmFsaWRhdGVTdGFja3MoYXNzZW1ibHksIHN0YWNrcyk7XG5cbiAgICAvLyBzZXQgcHJvZ3Jlc3MgZnJvbSBvcHRpb25zLCB0aGlzIGluY2x1ZGVzIHVzZXIgYW5kIGFwcCBjb25maWdcbiAgICBpZiAob3B0aW9ucy5wcm9ncmVzcykge1xuICAgICAgdGhpcy5pb0hvc3Quc3RhY2tQcm9ncmVzcyA9IG9wdGlvbnMucHJvZ3Jlc3M7XG4gICAgfVxuXG4gICAgaWYgKHN0YWNrcy5zdGFja0NvdW50ID4gMSkge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihcbiAgICAgICAgJ0FtYmlndW91c1N0YWNrU2VsZWN0aW9uJyxcbiAgICAgICAgYFN0YWNrIHNlbGVjdGlvbiBpcyBhbWJpZ3VvdXMsIHBsZWFzZSBjaG9vc2UgYSBzcGVjaWZpYyBzdGFjayBmb3IgaW1wb3J0IFske3N0YWNrcy5zdGFja0FydGlmYWN0cy5tYXAoKHgpID0+IHguaWQpLmpvaW4oJywgJyl9XWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghcHJvY2Vzcy5zdGRvdXQuaXNUVFkgJiYgIW9wdGlvbnMucmVzb3VyY2VNYXBwaW5nRmlsZSAmJiAhb3B0aW9ucy5yZXNvdXJjZU1hcHBpbmdJbmxpbmUpIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ1Jlc291cmNlTWFwcGluZ1JlcXVpcmVkJywgJy0tcmVzb3VyY2UtbWFwcGluZyBvciAtLXJlc291cmNlLW1hcHBpbmctaW5saW5lIGlzIHJlcXVpcmVkIHdoZW4gaW5wdXQgaXMgbm90IGEgdGVybWluYWwnKTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGFjayA9IHN0YWNrcy5zdGFja0FydGlmYWN0c1swXTtcblxuICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKGNoYWxrLmJvbGQoc3RhY2suZGlzcGxheU5hbWUpKTtcblxuICAgIGNvbnN0IHJlc291cmNlSW1wb3J0ZXIgPSBuZXcgUmVzb3VyY2VJbXBvcnRlcihzdGFjaywge1xuICAgICAgZGVwbG95bWVudHM6IHRoaXMucHJvcHMuZGVwbG95bWVudHMsXG4gICAgICBpb0hlbHBlcjogYXNJb0hlbHBlcih0aGlzLmlvSG9zdCwgJ2ltcG9ydCcpLFxuICAgIH0pO1xuICAgIGNvbnN0IHsgYWRkaXRpb25zLCBoYXNOb25BZGRpdGlvbnMsIGRpZmZGb3JtYXR0ZXIgfSA9IGF3YWl0IHJlc291cmNlSW1wb3J0ZXIuZGlzY292ZXJJbXBvcnRhYmxlUmVzb3VyY2VzKG9wdGlvbnMuZm9yY2UpO1xuXG4gICAgLy8gSWYgdGhlcmUgYXJlIG5vbi1hZGRpdGlvbiBjaGFuZ2VzIChlLmcuIGFmdGVyIG9ycGhhbiwgaGFyZGNvZGVkIHJlZnMgZGlmZmVyIGZyb20gRm46OkdldEF0dCksXG4gICAgLy8gd2FybiB0aGUgdXNlciBhbmQgYXNrIGZvciBjb25maXJtYXRpb24gdW5sZXNzIC0tZm9yY2Ugd2FzIGdpdmVuLlxuICAgIGlmIChoYXNOb25BZGRpdGlvbnMgJiYgIW9wdGlvbnMuZm9yY2UpIHtcbiAgICAgIGNvbnN0IGlvSGVscGVyID0gdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpO1xuICAgICAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhcbiAgICAgICAgYFRoZSBmb2xsb3dpbmcgcmVzb3VyY2VzIGhhdmUgcGVuZGluZyB1cGRhdGVzIHRoYXQgd2lsbCBiZSByZWNvbmNpbGVkIHdpdGggYSAke2NoYWxrLmJsdWVCcmlnaHQoJ2NkayBkZXBsb3knKX0gYWZ0ZXIgaW1wb3J0OmAsXG4gICAgICApO1xuICAgICAgY29uc3QgeyBmb3JtYXR0ZWREaWZmIH0gPSBkaWZmRm9ybWF0dGVyLmZvcm1hdFN0YWNrRGlmZigpO1xuICAgICAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhmb3JtYXR0ZWREaWZmKTtcbiAgICAgIGNvbnN0IGNvbmZpcm1lZCA9IGF3YWl0IGlvSGVscGVyLnJlcXVlc3RSZXNwb25zZShJTy5DREtfVE9PTEtJVF9JNzAxMC5yZXEoJ1BlcmZvcm0gaW1wb3J0PycsIHsgbW90aXZhdGlvbjogJ0NvbmZpcm0gaW1wb3J0IHdpdGggcGVuZGluZyBkcmlmdCcgfSkpO1xuICAgICAgaWYgKCFjb25maXJtZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEFib3J0RXJyb3IoJ0ltcG9ydEFib3J0ZWQnLCAnSW1wb3J0IGNhbmNlbGxlZCcpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChhZGRpdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMud2FybihcbiAgICAgICAgJyVzOiBubyBuZXcgcmVzb3VyY2VzIGNvbXBhcmVkIHRvIHRoZSBjdXJyZW50bHkgZGVwbG95ZWQgc3RhY2ssIHNraXBwaW5nIGltcG9ydC4nLFxuICAgICAgICBjaGFsay5ib2xkKHN0YWNrLmRpc3BsYXlOYW1lKSxcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUHJlcGFyZSBhIG1hcHBpbmcgb2YgcGh5c2ljYWwgcmVzb3VyY2VzIHRvIENESyBjb25zdHJ1Y3RzXG4gICAgbGV0IGFjdHVhbEltcG9ydDogQXdhaXRlZDxSZXR1cm5UeXBlPHR5cGVvZiByZXNvdXJjZUltcG9ydGVyLmFza0ZvclJlc291cmNlSWRlbnRpZmllcnM+PjtcbiAgICBpZiAob3B0aW9ucy5yZXNvdXJjZU1hcHBpbmdJbmxpbmUpIHtcbiAgICAgIGFjdHVhbEltcG9ydCA9IGF3YWl0IHJlc291cmNlSW1wb3J0ZXIubG9hZFJlc291cmNlSWRlbnRpZmllcnMoYWRkaXRpb25zLCBvcHRpb25zLnJlc291cmNlTWFwcGluZ0lubGluZSk7XG4gICAgfSBlbHNlIGlmIChvcHRpb25zLnJlc291cmNlTWFwcGluZ0ZpbGUpIHtcbiAgICAgIGFjdHVhbEltcG9ydCA9IGF3YWl0IHJlc291cmNlSW1wb3J0ZXIubG9hZFJlc291cmNlSWRlbnRpZmllcnNGcm9tRmlsZShhZGRpdGlvbnMsIG9wdGlvbnMucmVzb3VyY2VNYXBwaW5nRmlsZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGFjdHVhbEltcG9ydCA9IGF3YWl0IHJlc291cmNlSW1wb3J0ZXIuYXNrRm9yUmVzb3VyY2VJZGVudGlmaWVycyhhZGRpdGlvbnMpO1xuICAgIH1cblxuICAgIGlmIChhY3R1YWxJbXBvcnQuaW1wb3J0UmVzb3VyY2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLndhcm4oJ05vIHJlc291cmNlcyBzZWxlY3RlZCBmb3IgaW1wb3J0LicpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIElmIFwiLS1jcmVhdGUtcmVzb3VyY2UtbWFwcGluZ1wiIG9wdGlvbiB3YXMgcGFzc2VkLCB3cml0ZSB0aGUgcmVzb3VyY2UgbWFwcGluZyB0byB0aGUgZ2l2ZW4gZmlsZSBhbmQgZXhpdFxuICAgIGlmIChvcHRpb25zLnJlY29yZFJlc291cmNlTWFwcGluZykge1xuICAgICAgY29uc3Qgb3V0cHV0RmlsZSA9IG9wdGlvbnMucmVjb3JkUmVzb3VyY2VNYXBwaW5nO1xuICAgICAgZnMuZW5zdXJlRmlsZVN5bmMob3V0cHV0RmlsZSk7XG4gICAgICBhd2FpdCBmcy53cml0ZUpzb24ob3V0cHV0RmlsZSwgYWN0dWFsSW1wb3J0LnJlc291cmNlTWFwLCB7XG4gICAgICAgIHNwYWNlczogMixcbiAgICAgICAgZW5jb2Rpbmc6ICd1dGY4JyxcbiAgICAgIH0pO1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oJyVzOiBtYXBwaW5nIGZpbGUgd3JpdHRlbi4nLCBvdXRwdXRGaWxlKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBGb2xsb3dpbmcgYXJlIHRoZSBzYW1lIHNlbWFudGljcyB3ZSBhcHBseSB3aXRoIHJlc3BlY3QgdG8gTm90aWZpY2F0aW9uIEFSTnMgKGRpY3RhdGVkIGJ5IHRoZSBTREspXG4gICAgLy9cbiAgICAvLyAgLSB1bmRlZmluZWQgID0+ICBjZGsgaWdub3JlcyBpdCwgYXMgaWYgaXQgd2Fzbid0IHN1cHBvcnRlZCAoYWxsb3dzIGV4dGVybmFsIG1hbmFnZW1lbnQpLlxuICAgIC8vICAtIFtdOiAgICAgICAgPT4gIGNkayBtYW5hZ2VzIGl0LCBhbmQgdGhlIHVzZXIgd2FudHMgdG8gd2lwZSBpdCBvdXQuXG4gICAgLy8gIC0gWydhcm4tMSddICA9PiAgY2RrIG1hbmFnZXMgaXQsIGFuZCB0aGUgdXNlciB3YW50cyB0byBzZXQgaXQgdG8gWydhcm4tMSddLlxuICAgIGNvbnN0IG5vdGlmaWNhdGlvbkFybnMgPSAoISFvcHRpb25zLm5vdGlmaWNhdGlvbkFybnMgfHwgISFzdGFjay5ub3RpZmljYXRpb25Bcm5zKVxuICAgICAgPyAob3B0aW9ucy5ub3RpZmljYXRpb25Bcm5zID8/IFtdKS5jb25jYXQoc3RhY2subm90aWZpY2F0aW9uQXJucyA/PyBbXSlcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgZm9yIChjb25zdCBub3RpZmljYXRpb25Bcm4gb2Ygbm90aWZpY2F0aW9uQXJucyA/PyBbXSkge1xuICAgICAgaWYgKCF2YWxpZGF0ZVNuc1RvcGljQXJuKG5vdGlmaWNhdGlvbkFybikpIHtcbiAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignSW52YWxpZFNuc1RvcGljQXJuJywgYE5vdGlmaWNhdGlvbiBhcm4gJHtub3RpZmljYXRpb25Bcm59IGlzIG5vdCBhIHZhbGlkIGFybiBmb3IgYW4gU05TIHRvcGljYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSW1wb3J0IHRoZSByZXNvdXJjZXMgYWNjb3JkaW5nIHRvIHRoZSBnaXZlbiBtYXBwaW5nXG4gICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oJyVzOiBpbXBvcnRpbmcgcmVzb3VyY2VzIGludG8gc3RhY2suLi4nLCBjaGFsay5ib2xkKHN0YWNrLmRpc3BsYXlOYW1lKSk7XG4gICAgY29uc3QgdGFncyA9IHRhZ3NGb3JTdGFjayhzdGFjayk7XG4gICAgYXdhaXQgcmVzb3VyY2VJbXBvcnRlci5pbXBvcnRSZXNvdXJjZXNGcm9tTWFwKGFjdHVhbEltcG9ydCwge1xuICAgICAgcm9sZUFybjogb3B0aW9ucy5yb2xlQXJuLFxuICAgICAgdGFncyxcbiAgICAgIGRlcGxveW1lbnRNZXRob2Q6IG9wdGlvbnMuZGVwbG95bWVudE1ldGhvZCxcbiAgICAgIHVzZVByZXZpb3VzUGFyYW1ldGVyczogdHJ1ZSxcbiAgICAgIHJvbGxiYWNrOiBvcHRpb25zLnJvbGxiYWNrLFxuICAgICAgbm90aWZpY2F0aW9uQXJucyxcbiAgICB9KTtcblxuICAgIC8vIE5vdGlmeSB1c2VyIG9mIG5leHQgc3RlcHNcbiAgICBpZiAoYWN0dWFsSW1wb3J0LmltcG9ydFJlc291cmNlcy5sZW5ndGggPCBhZGRpdGlvbnMubGVuZ3RoKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMud2FybihcbiAgICAgICAgYFNvbWUgcmVzb3VyY2VzIHdlcmUgc2tpcHBlZC4gUnVuIGFub3RoZXIgJHtjaGFsay5ibHVlQnJpZ2h0KCdjZGsgaW1wb3J0Jyl9IG9yIGEgJHtjaGFsay5ibHVlQnJpZ2h0KCdjZGsgZGVwbG95Jyl9IHRvIGJyaW5nIHRoZSBzdGFjayB1cC10by1kYXRlIHdpdGggeW91ciBDREsgYXBwIGRlZmluaXRpb24uYCxcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmIChoYXNOb25BZGRpdGlvbnMpIHtcbiAgICAgIC8vIEFmdGVyIG9ycGhhbuKGkmltcG9ydCwgdGhlIGRlcGxveWVkIHRlbXBsYXRlIHN0aWxsIGhhcyBoYXJkY29kZWQgdmFsdWVzIHRoYXQgZGlmZmVyIGZyb21cbiAgICAgIC8vIHRoZSBzeW50aCdkIHRlbXBsYXRlJ3MgRm46OkdldEF0dC9SZWYgaW50cmluc2ljcy4gQSBkZXBsb3kgdXBkYXRlcyB0aGUgdGVtcGxhdGUgdG8gbWF0Y2ggdGhlIENESyBhcHAuXG4gICAgICBpZiAob3B0aW9ucy5mb3JjZSkge1xuICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhcbiAgICAgICAgICBgSW1wb3J0IGNvbXBsZXRlLiBSdW4gJHtjaGFsay5ibHVlQnJpZ2h0KCdjZGsgZGVwbG95Jyl9IHRvIHVwZGF0ZSB0aGUgc3RhY2sgdG8gbWF0Y2ggeW91ciBDREsgYXBwLmAsXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBkZXBsb3lOb3cgPSBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkucmVxdWVzdFJlc3BvbnNlKFxuICAgICAgICAgIElPLkNES19UT09MS0lUX0k3MDEwLnJlcShgRmluaXNoIHdpdGggYSAke2NoYWxrLmJsdWVCcmlnaHQoJ2NkayBkZXBsb3knKX0gbm93P2AsIHsgbW90aXZhdGlvbjogJ1VwZGF0ZSBzdGFjayB0byBtYXRjaCBDREsgYXBwIGFmdGVyIGltcG9ydCcgfSksXG4gICAgICAgICk7XG4gICAgICAgIGlmIChkZXBsb3lOb3cpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmRlcGxveSh7XG4gICAgICAgICAgICAvLyBUaGUgaW1wb3J0IHNlbGVjdG9yIGlzIGV4YWN0IChubyBleHBhbnNpb24pOyB0aGUgZm9sbG93LXVwIGRlcGxveVxuICAgICAgICAgICAgLy8gaGlzdG9yaWNhbGx5IGV4cGFuZHMgdG8gdXBzdHJlYW0gZGVwZW5kZW5jaWVzIGxpa2UgYSBwbGFpbiBkZXBsb3kuXG4gICAgICAgICAgICBzZWxlY3RvcjogeyAuLi5vcHRpb25zLnNlbGVjdG9yLCBleHBhbmQ6IEV4cGFuZFN0YWNrU2VsZWN0aW9uLlVQU1RSRUFNIH0sXG4gICAgICAgICAgICB0b29sa2l0U3RhY2tOYW1lOiBvcHRpb25zLnRvb2xraXRTdGFja05hbWUsXG4gICAgICAgICAgICByb2xlQXJuOiBvcHRpb25zLnJvbGVBcm4sXG4gICAgICAgICAgICBkZXBsb3ltZW50TWV0aG9kOiBvcHRpb25zLmRlcGxveW1lbnRNZXRob2QsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oXG4gICAgICAgICAgICBgSW1wb3J0IGNvbXBsZXRlLiBSZW1lbWJlciB0byBydW4gJHtjaGFsay5ibHVlQnJpZ2h0KCdjZGsgZGVwbG95Jyl9IHRvIHVwZGF0ZSB0aGUgc3RhY2sgdG8gbWF0Y2ggeW91ciBDREsgYXBwLmAsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhcbiAgICAgICAgYEltcG9ydCBvcGVyYXRpb24gY29tcGxldGUuIFdlIHJlY29tbWVuZCB5b3UgcnVuIGEgJHtjaGFsay5ibHVlQnJpZ2h0KCdkcmlmdCBkZXRlY3Rpb24nKX0gb3BlcmF0aW9uIGAgK1xuICAgICAgICAndG8gY29uZmlybSB5b3VyIENESyBhcHAgcmVzb3VyY2UgZGVmaW5pdGlvbnMgYXJlIHVwLXRvLWRhdGUuIFJlYWQgbW9yZSBoZXJlOiAnICtcbiAgICAgICAgY2hhbGsudW5kZXJsaW5lLmJsdWVCcmlnaHQoXG4gICAgICAgICAgJ2h0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2RldGVjdC1kcmlmdC1zdGFjay5odG1sJyxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gVGhlIGRlc3Ryb3kgYWN0aW9uIHJ1bnMgdGhyb3VnaCB0b29sa2l0LWxpYi5cbiAgLy8gU3VwcHJlc3MgaXRzIG5ldyBzdGF0dXMgbWVzc2FnZXMgdG8ga2VlcCB0aGUgb3V0cHV0IGFzIGl0IHdhcyBiZWZvcmUuXG4gIEBzdXBwcmVzc01lc3NhZ2VzKFxuICAgIElPLkNES19UT09MS0lUX0kxMDAxLCAvLyBTdGFydGluZyBTeW50aGVzaXMgKHRyYWNlKVxuICAgIElPLkNES19UT09MS0lUX0kxMDAwLCAvLyDinKggU3ludGhlc2lzIHRpbWUgKGluZm8pXG4gICAgSU8uQ0RLX1RPT0xLSVRfSTcxMDEsIC8vIFN0YXJ0aW5nIERlc3Ryb3kgKHRyYWNlKVxuICAgIElPLkNES19UT09MS0lUX0k3MDAxLCAvLyBwZXItc3RhY2sgRGVzdHJveSB0aW1lICh0cmFjZSlcbiAgICBJTy5DREtfVE9PTEtJVF9JNzAwMCwgLy8g4pyoIERlc3Ryb3kgdGltZSAoaW5mbylcbiAgKVxuICBwdWJsaWMgYXN5bmMgZGVzdHJveShvcHRpb25zOiBEZXN0cm95T3B0aW9ucykge1xuICAgIC8vIEtlZXAgdGhlIFwiZGVwbG95ZWRcIiB3b3JkaW5nIHdoZW4gYSBkZXN0cm95IHJ1bnMgYXMgcGFydCBvZiBhIGRlcGxveS5cbiAgICBjb25zdCBhY3Rpb24gPSBvcHRpb25zLmZyb21EZXBsb3kgPyAnZGVwbG95JyA6ICdkZXN0cm95JztcblxuICAgIGlmICgob3B0aW9ucy5jb25jdXJyZW5jeSB8fCAxKSA+IDEgJiYgdGhpcy5pb0hvc3Quc3RhY2tQcm9ncmVzcyA9PT0gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkJBUikge1xuICAgICAgdGhpcy5pb0hvc3Quc3RhY2tQcm9ncmVzcyA9IFN0YWNrQWN0aXZpdHlQcm9ncmVzcy5FVkVOVFM7XG4gICAgfVxuXG4gICAgLy8gVGhlIHN1Y2Nlc3MgbGluZSB3YXMgYGluZm9gIGluIHRoZSBoaXN0b3JpY2FsIGBjZGsgZGVzdHJveWAsIG5vdCBgcmVzdWx0YC5cbiAgICB1c2luZyBfc3VjY2Vzc0xldmVsID0gdGhpcy5pb0hvc3Qub24oSU8uQ0RLX1RPT0xLSVRfSTc5MDAsICgpID0+ICh7IGxldmVsOiAnaW5mbycgfSkpOyAvLyDinIUgPHN0YWNrPjogZGVzdHJveWVkXG5cbiAgICAvLyB0b29sa2l0LWxpYiBsb2dzIGEgZGVjbGluZWQgY29uZmlybWF0aW9uIChFNzAxMCkgYW5kIHJldHVybnMgZ3JhY2VmdWxseS5cbiAgICAvLyBUaGUgQ0xJIHN1cmZhY2VzIGEgZGVjbGluZSBhcyBhIG5vbi16ZXJvLCBzb2Z0IGV4aXQgaW5zdGVhZDogdGhyb3dpbmcgZnJvbVxuICAgIC8vIHRoZSBsaXN0ZW5lciBib3RoIHN1cHByZXNzZXMgdGhlIGxvZyBhbmQgYWJvcnRzIHRoZSBjb21tYW5kICh0aGUgdG9wLWxldmVsXG4gICAgLy8gcmVuZGVycyBgQWJvcnRFcnJvcmAgYXMgXCJEZWxldGlvbiBjYW5jZWxsZWRcIikuXG4gICAgdXNpbmcgX2RlY2xpbmVBYm9ydHMgPSB0aGlzLmlvSG9zdC5vbihJTy5DREtfVE9PTEtJVF9FNzAxMCwgKCkgPT4ge1xuICAgICAgdGhyb3cgbmV3IEFib3J0RXJyb3IoJ0Rlc3Ryb3lBYm9ydGVkJywgJ0RlbGV0aW9uIGNhbmNlbGxlZCcpO1xuICAgIH0pO1xuXG4gICAgdXNpbmcgX2ZvcmNlQ29uZmlybXMgPSBvcHRpb25zLmZvcmNlID8gdGhpcy5pb0hvc3QucmVzcG9uZE9uY2UoSU8uQ0RLX1RPT0xLSVRfSTcwMTAsIHRydWUpIDogdW5kZWZpbmVkO1xuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9iYW4tdHMtY29tbWVudFxuICAgIC8vIEB0cy1pZ25vcmUgLSBgX2Rlc3Ryb3lXaXRoQWN0aW9uYCBpcyBwcml2YXRlOyB0aGUgQ0xJIHNldHMgdGhlIGFjdGlvbiBsYWJlbC5cbiAgICBhd2FpdCB0aGlzLnRvb2xraXQuX2Rlc3Ryb3lXaXRoQWN0aW9uKHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLCBhY3Rpb24sIHtcbiAgICAgIHN0YWNrczogb3B0aW9ucy5zZWxlY3RvcixcbiAgICAgIHJvbGVBcm46IG9wdGlvbnMucm9sZUFybixcbiAgICAgIGNvbmN1cnJlbmN5OiBvcHRpb25zLmNvbmN1cnJlbmN5LFxuICAgICAgZXhwcmVzczogb3B0aW9ucy5leHByZXNzLFxuICAgIH0pO1xuICB9XG5cbiAgLy8gY2RrIGxzIHN0ZG91dCBpcyB0aGUgc3RhY2sgbGlzdGluZyBvbmx5LiBTdXBwcmVzcyB0aGUgaW5mbyBzdGF0dXMgbGluZXMgc3ludGhlc2lzIGVtaXRzIG5leHRcbiAgLy8gdG8gaXQ6IHRoZSBzeW50aC10aW1lIGxpbmUgKEkxMDAwKSBhbmQgdGhlIGRlcGVuZGVuY3ktZXhwYW5zaW9uIG5vdGUgKEkxMDAyKS5cbiAgQHN1cHByZXNzTWVzc2FnZXMoSU8uQ0RLX1RPT0xLSVRfSTEwMDAsIElPLkNES19UT09MS0lUX0kxMDAyKVxuICBwdWJsaWMgYXN5bmMgbGlzdChcbiAgICBzZWxlY3RvcnM6IHN0cmluZ1tdLFxuICAgIG9wdGlvbnM6IHsgbG9uZz86IGJvb2xlYW47IGpzb24/OiBib29sZWFuOyBzaG93RGVwcz86IGJvb2xlYW4gfSA9IHt9LFxuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIC8vIE9uZS1zaG90OiBkaXNwb3NlcyBpdHNlbGYgd2hlbiB0aGUgbGlzdGluZyAoSTI5MDEpIGlzIGVtaXR0ZWQ7IHRoZVxuICAgIC8vIGB1c2luZ2AgY292ZXJzIHRoZSBjYXNlIHdoZXJlIGBsaXN0YCB0aHJvd3MgYmVmb3JlIHRoYXQgaGFwcGVucy5cbiAgICB1c2luZyBfZm9ybWF0dGVyID0gdGhpcy5pb0hvc3QucmV3cml0ZU9uY2UoSU8uQ0RLX1RPT0xLSVRfSTI5MDEsIChtc2cpID0+IGZvcm1hdFN0YWNrTGlzdChtc2cuZGF0YS5zdGFja3MsIG9wdGlvbnMpKTtcblxuICAgIGF3YWl0IHRoaXMudG9vbGtpdC5saXN0KHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLCB7XG4gICAgICBzdGFja3M6IHNlbGVjdG9ycy5sZW5ndGggPiAwID8gc2VsZWN0V2l0aFVwc3RyZWFtKC4uLnNlbGVjdG9ycykgOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICByZXR1cm4gMDsgLy8gZXhpdC1jb2RlXG4gIH1cblxuICAvKipcbiAgICogU3ludGhlc2l6ZSB0aGUgZ2l2ZW4gc2V0IG9mIHN0YWNrcyAoY2FsbGVkIHdoZW4gdGhlIHVzZXIgcnVucyAnY2RrIHN5bnRoJylcbiAgICpcbiAgICogSU5QVVQ6IFN0YWNrIG5hbWVzIGNhbiBiZSBzdXBwbGllZCB1c2luZyBhIGdsb2IgZmlsdGVyLiBJZiBubyBzdGFja3MgYXJlXG4gICAqIGdpdmVuLCBhbGwgc3RhY2tzIGZyb20gdGhlIGFwcGxpY2F0aW9uIGFyZSBpbXBsaWNpdGx5IHNlbGVjdGVkLlxuICAgKlxuICAgKiBPVVRQVVQ6IElmIG1vcmUgdGhhbiBvbmUgc3RhY2sgZW5kcyB1cCBiZWluZyBzZWxlY3RlZCwgYW4gb3V0cHV0IGRpcmVjdG9yeVxuICAgKiBzaG91bGQgYmUgc3VwcGxpZWQsIHdoZXJlIHRoZSB0ZW1wbGF0ZXMgd2lsbCBiZSB3cml0dGVuLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIHN5bnRoKG9wdGlvbnM6IFN5bnRoT3B0aW9ucyk6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3Qgc3RhY2tOYW1lcyA9IG9wdGlvbnMuc3RhY2tOYW1lcztcbiAgICBjb25zdCBleGNsdXNpdmVseSA9IG9wdGlvbnMuZXhjbHVzaXZlbHkgPz8gZmFsc2U7XG4gICAgY29uc3QgcXVpZXQgPSBvcHRpb25zLnF1aWV0ID8/IGZhbHNlO1xuICAgIGNvbnN0IGF1dG9WYWxpZGF0ZSA9IG9wdGlvbnMuYXV0b1ZhbGlkYXRlID8/IGZhbHNlO1xuICAgIGNvbnN0IGpzb24gPSBvcHRpb25zLmpzb24gPz8gZmFsc2U7XG5cbiAgICBjb25zdCBhc3NlbWJseSA9IGF3YWl0IHRoaXMuYXNzZW1ibHkoKTtcbiAgICBjb25zdCBzdGFja3MgPSBhd2FpdCB0aGlzLnNlbGVjdFRvcExldmVsT3JNYXRjaGluZ1N0YWNrcyhhc3NlbWJseSwgc3RhY2tOYW1lcywgZXhjbHVzaXZlbHkpO1xuXG4gICAgY29uc3QgYXV0b1ZhbGlkYXRlU3RhY2tzID0gYXV0b1ZhbGlkYXRlXG4gICAgICA/IGFzc2VtYmx5LnNlbGVjdFN0YWNrc0ZvclZhbGlkYXRpb24oKVxuICAgICAgOiBuZXcgU3RhY2tDb2xsZWN0aW9uKGFzc2VtYmx5LCBbXSk7XG5cbiAgICBhd2FpdCB0aGlzLnZhbGlkYXRlU3RhY2tzKGFzc2VtYmx5LCBzdGFja3MuY29uY2F0KGF1dG9WYWxpZGF0ZVN0YWNrcykpO1xuXG4gICAgLy8gaWYgd2UgaGF2ZSBhIHNpbmdsZSBzdGFjaywgcHJpbnQgaXQgdG8gU1RET1VUXG4gICAgaWYgKHN0YWNrcy5zdGFja0NvdW50ID09PSAxKSB7XG4gICAgICBpZiAoIXF1aWV0KSB7XG4gICAgICAgIGF3YWl0IHByaW50U2VyaWFsaXplZE9iamVjdCh0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCksIG9ic2N1cmVUZW1wbGF0ZShzdGFja3MuZmlyc3RTdGFjay50ZW1wbGF0ZSksIGpzb24pO1xuICAgICAgfVxuXG4gICAgICAvLyBJbiBDSSBtb2RlLCBub24tZXJyb3IgbWVzc2FnZXMgZ28gdG8gc3Rkb3V0LiBXaGVuIHdlIGp1c3QgcHJpbnRlZCB0aGVcbiAgICAgIC8vIHRlbXBsYXRlIHRvIHN0ZG91dCwgc2tpcCB0aGUgZmxhZ3MgbWVzc2FnZSB0byBwcmVzZXJ2ZSB0aGUgY29udHJhY3QgdGhhdFxuICAgICAgLy8gYGNkayBzeW50aGAgb3V0cHV0IGlzIHZhbGlkIFlBTUwuIFdoZW4gcXVpZXQgKG5vIHRlbXBsYXRlIHByaW50ZWQpIG9yXG4gICAgICAvLyBub24tQ0kgKGZsYWdzIGdvIHRvIHN0ZGVyciksIGl0J3Mgc2FmZSB0byBzaG93LlxuICAgICAgaWYgKHF1aWV0IHx8ICF0aGlzLmlvSG9zdC5pc0NJKSB7XG4gICAgICAgIGF3YWl0IGRpc3BsYXlGbGFnc01lc3NhZ2UodGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLCB0aGlzLnRvb2xraXQsIHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gbm90IG91dHB1dHRpbmcgdGVtcGxhdGUgdG8gc3Rkb3V0LCBsZXQncyBleHBsYWluIHRoaW5ncyB0byB0aGUgdXNlciBhIGxpdHRsZSBiaXQuLi5cbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhjaGFsay5ncmVlbihgU3VjY2Vzc2Z1bGx5IHN5bnRoZXNpemVkIHRvICR7Y2hhbGsuYmx1ZShwYXRoLnJlc29sdmUoc3RhY2tzLmFzc2VtYmx5LmRpcmVjdG9yeSkpfWApKTtcbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhcbiAgICAgIGBTdXBwbHkgYSBzdGFjayBpZCAoJHtzdGFja3Muc3RhY2tBcnRpZmFjdHMubWFwKChzKSA9PiBjaGFsay5ncmVlbihzLmhpZXJhcmNoaWNhbElkKSkuam9pbignLCAnKX0pIHRvIGRpc3BsYXkgaXRzIHRlbXBsYXRlLmAsXG4gICAgKTtcblxuICAgIGF3YWl0IGRpc3BsYXlGbGFnc01lc3NhZ2UodGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLCB0aGlzLnRvb2xraXQsIHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlKTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEJvb3RzdHJhcCB0aGUgQ0RLIFRvb2xraXQgc3RhY2sgaW4gdGhlIGFjY291bnRzIHVzZWQgYnkgdGhlIHNwZWNpZmllZCBzdGFjayhzKS5cbiAgICpcbiAgICogQHBhcmFtIHVzZXJFbnZpcm9ubWVudFNwZWNzIC0gZW52aXJvbm1lbnQgbmFtZXMgdGhhdCBuZWVkIHRvIGhhdmUgdG9vbGtpdCBzdXBwb3J0XG4gICAqICAgICAgICAgICAgIHByb3Zpc2lvbmVkLCBhcyBhIGdsb2IgZmlsdGVyLiBJZiBub25lIGlzIHByb3ZpZGVkLCBhbGwgc3RhY2tzIGFyZSBpbXBsaWNpdGx5IHNlbGVjdGVkLlxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFRoZSBuYW1lLCByb2xlIEFSTiwgYm9vdHN0cmFwcGluZyBwYXJhbWV0ZXJzLCBldGMuIHRvIGJlIHVzZWQgZm9yIHRoZSBDREsgVG9vbGtpdCBzdGFjay5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBib290c3RyYXAoXG4gICAgdXNlckVudmlyb25tZW50U3BlY3M6IHN0cmluZ1tdLFxuICAgIG9wdGlvbnM6IEJvb3RzdHJhcEVudmlyb25tZW50T3B0aW9ucyxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgYm9vdHN0cmFwcGVyID0gbmV3IEJvb3RzdHJhcHBlcihvcHRpb25zLnNvdXJjZSwgYXNJb0hlbHBlcih0aGlzLmlvSG9zdCwgJ2Jvb3RzdHJhcCcpKTtcbiAgICAvLyBJZiB0aGVyZSBpcyBhbiAnLS1hcHAnIGFyZ3VtZW50IGFuZCBhbiBlbnZpcm9ubWVudCBsb29rcyBsaWtlIGEgZ2xvYiwgd2VcbiAgICAvLyBzZWxlY3QgdGhlIGVudmlyb25tZW50cyBmcm9tIHRoZSBhcHAuIE90aGVyd2lzZSwgdXNlIHdoYXQgdGhlIHVzZXIgc2FpZC5cblxuICAgIGNvbnN0IGVudmlyb25tZW50cyA9IGF3YWl0IHRoaXMuZGVmaW5lRW52aXJvbm1lbnRzKHVzZXJFbnZpcm9ubWVudFNwZWNzKTtcblxuICAgIGNvbnN0IGxpbWl0ID0gcExpbWl0KDIwKTtcblxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAY2RrbGFicy9wcm9taXNlYWxsLW5vLXVuYm91bmRlZC1wYXJhbGxlbGlzbVxuICAgIGF3YWl0IFByb21pc2UuYWxsKGVudmlyb25tZW50cy5tYXAoKGVudmlyb25tZW50KSA9PiBsaW1pdChhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhjaGFsay5ncmVlbignIOKPsyAgQm9vdHN0cmFwcGluZyBlbnZpcm9ubWVudCAlcy4uLicpLCBjaGFsay5ibHVlKGVudmlyb25tZW50Lm5hbWUpKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnZpcm9ubWVudCwgdGhpcy5wcm9wcy5zZGtQcm92aWRlciwgb3B0aW9ucyk7XG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPSByZXN1bHQubm9PcFxuICAgICAgICAgID8gJ+KchSAgRW52aXJvbm1lbnQgJXMgYm9vdHN0cmFwcGVkIChubyBjaGFuZ2VzKS4nXG4gICAgICAgICAgOiAn4pyFICBFbnZpcm9ubWVudCAlcyBib290c3RyYXBwZWQuJztcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oY2hhbGsuZ3JlZW4obWVzc2FnZSksIGNoYWxrLmJsdWUoZW52aXJvbm1lbnQubmFtZSkpO1xuXG4gICAgICAgIGlmIChvcHRpb25zLmV4cHJlc3MpIHtcbiAgICAgICAgICBjb25zdCB3YXJuaW5nID0gZm9ybWF0RXhwcmVzc1N0YWJpbGl6YXRpb25XYXJuaW5nKHJlc3VsdC5zdGFiaWxpemluZ1Jlc291cmNlcywgJ2Jvb3RzdHJhcCcpO1xuICAgICAgICAgIGlmICh3YXJuaW5nKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkubm90aWZ5KElPLkNES19UT09MS0lUX1c5OTAyLm1zZyh3YXJuaW5nKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5lcnJvcignIOKdjCAgRW52aXJvbm1lbnQgJXMgZmFpbGVkIGJvb3RzdHJhcHBpbmc6ICVzJywgY2hhbGsuYmx1ZShlbnZpcm9ubWVudC5uYW1lKSwgZSk7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgfSkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHYXJiYWdlIGNvbGxlY3RzIGFzc2V0cyBmcm9tIGEgQ0RLIGFwcCdzIGVudmlyb25tZW50XG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9ucyBmb3IgR2FyYmFnZSBDb2xsZWN0aW9uXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2FyYmFnZUNvbGxlY3QodXNlckVudmlyb25tZW50U3BlY3M6IHN0cmluZ1tdLCBvcHRpb25zOiBHYXJiYWdlQ29sbGVjdGlvbk9wdGlvbnMpIHtcbiAgICBjb25zdCBlbnZpcm9ubWVudHMgPSBhd2FpdCB0aGlzLmRlZmluZUVudmlyb25tZW50cyh1c2VyRW52aXJvbm1lbnRTcGVjcyk7XG5cbiAgICBmb3IgKGNvbnN0IGVudmlyb25tZW50IG9mIGVudmlyb25tZW50cykge1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oY2hhbGsuZ3JlZW4oJyDij7MgIEdhcmJhZ2UgQ29sbGVjdGluZyBlbnZpcm9ubWVudCAlcy4uLicpLCBjaGFsay5ibHVlKGVudmlyb25tZW50Lm5hbWUpKTtcbiAgICAgIGNvbnN0IGdjID0gbmV3IEdhcmJhZ2VDb2xsZWN0b3Ioe1xuICAgICAgICBzZGtQcm92aWRlcjogdGhpcy5wcm9wcy5zZGtQcm92aWRlcixcbiAgICAgICAgaW9IZWxwZXI6IGFzSW9IZWxwZXIodGhpcy5pb0hvc3QsICdnYycpLFxuICAgICAgICByZXNvbHZlZEVudmlyb25tZW50OiBlbnZpcm9ubWVudCxcbiAgICAgICAgYm9vdHN0cmFwU3RhY2tOYW1lOiBvcHRpb25zLmJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICAgICAgcm9sbGJhY2tCdWZmZXJEYXlzOiBvcHRpb25zLnJvbGxiYWNrQnVmZmVyRGF5cyxcbiAgICAgICAgY3JlYXRlZEJ1ZmZlckRheXM6IG9wdGlvbnMuY3JlYXRlZEJ1ZmZlckRheXMsXG4gICAgICAgIGFjdGlvbjogb3B0aW9ucy5hY3Rpb24gPz8gJ2Z1bGwnLFxuICAgICAgICB0eXBlOiBvcHRpb25zLnR5cGUgPz8gJ2FsbCcsXG4gICAgICAgIGNvbmZpcm06IG9wdGlvbnMuY29uZmlybSA/PyB0cnVlLFxuICAgICAgfSk7XG4gICAgICBhd2FpdCBnYy5nYXJiYWdlQ29sbGVjdCgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZGVmaW5lRW52aXJvbm1lbnRzKHVzZXJFbnZpcm9ubWVudFNwZWNzOiBzdHJpbmdbXSk6IFByb21pc2U8Y3hhcGkuRW52aXJvbm1lbnRbXT4ge1xuICAgIC8vIEJ5IGRlZmF1bHQsIGdsb2IgZm9yIGV2ZXJ5dGhpbmdcbiAgICBjb25zdCBlbnZpcm9ubWVudFNwZWNzID0gdXNlckVudmlyb25tZW50U3BlY3MubGVuZ3RoID4gMCA/IFsuLi51c2VyRW52aXJvbm1lbnRTcGVjc10gOiBbJyoqJ107XG5cbiAgICAvLyBQYXJ0aXRpb24gaW50byBnbG9icyBhbmQgbm9uLWdsb2JzICh0aGlzIHdpbGwgbXV0YXRlIGVudmlyb25tZW50U3BlY3MpLlxuICAgIGNvbnN0IGdsb2JTcGVjcyA9IHBhcnRpdGlvbihlbnZpcm9ubWVudFNwZWNzLCBsb29rc0xpa2VHbG9iKTtcbiAgICBpZiAoZ2xvYlNwZWNzLmxlbmd0aCA+IDAgJiYgIXRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLmhhc0FwcCkge1xuICAgICAgaWYgKHVzZXJFbnZpcm9ubWVudFNwZWNzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgLy8gVXNlciBkaWQgcmVxdWVzdCB0aGlzIGdsb2JcbiAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihcbiAgICAgICAgICAnSW52YWxpZEVudmlyb25tZW50R2xvYicsXG4gICAgICAgICAgYCcke2dsb2JTcGVjc30nIGlzIG5vdCBhbiBlbnZpcm9ubWVudCBuYW1lLiBTcGVjaWZ5IGFuIGVudmlyb25tZW50IG5hbWUgbGlrZSAnYXdzOi8vMTIzNDU2Nzg5MDEyL3VzLWVhc3QtMScsIG9yIHJ1biBpbiBhIGRpcmVjdG9yeSB3aXRoICdjZGsuanNvbicgdG8gdXNlIHdpbGRjYXJkcy5gLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gVXNlciBkaWQgbm90IHJlcXVlc3QgYW55dGhpbmdcbiAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihcbiAgICAgICAgICAnRW52aXJvbm1lbnRSZXF1aXJlZCcsXG4gICAgICAgICAgXCJTcGVjaWZ5IGFuIGVudmlyb25tZW50IG5hbWUgbGlrZSAnYXdzOi8vMTIzNDU2Nzg5MDEyL3VzLWVhc3QtMScsIG9yIHJ1biBpbiBhIGRpcmVjdG9yeSB3aXRoICdjZGsuanNvbicuXCIsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgZW52aXJvbm1lbnRzOiBjeGFwaS5FbnZpcm9ubWVudFtdID0gWy4uLmVudmlyb25tZW50c0Zyb21EZXNjcmlwdG9ycyhlbnZpcm9ubWVudFNwZWNzKV07XG5cbiAgICAvLyBJZiB0aGVyZSBpcyBhbiAnLS1hcHAnIGFyZ3VtZW50LCBzZWxlY3QgdGhlIGVudmlyb25tZW50cyBmcm9tIHRoZSBhcHAuXG4gICAgaWYgKHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLmhhc0FwcCkge1xuICAgICAgY29uc3QgYXNzZW1ibHkgPSBhd2FpdCB0aGlzLmFzc2VtYmx5KCk7XG4gICAgICBjb25zdCBhbGxTdGFja3MgPSBhd2FpdCBhc3NlbWJseS5zZWxlY3RTdGFja3NWMihBTExfU1RBQ0tTKTtcbiAgICAgIGVudmlyb25tZW50cy5wdXNoKFxuICAgICAgICAuLi4oYXdhaXQgZ2xvYkVudmlyb25tZW50c0Zyb21TdGFja3MoYWxsU3RhY2tzLCBnbG9iU3BlY3MsIHRoaXMucHJvcHMuc2RrUHJvdmlkZXIpKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGVudmlyb25tZW50cztcbiAgfVxuXG4gIC8qKlxuICAgKiBNaWdyYXRlcyBhIENsb3VkRm9ybWF0aW9uIHN0YWNrL3RlbXBsYXRlIHRvIGEgQ0RLIGFwcFxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbnMgZm9yIENESyBhcHAgY3JlYXRpb25cbiAgICovXG4gIHB1YmxpYyBhc3luYyBtaWdyYXRlKG9wdGlvbnM6IE1pZ3JhdGVPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLndhcm4oJ1RoaXMgY29tbWFuZCBpcyBhbiBleHBlcmltZW50YWwgZmVhdHVyZS4nKTtcbiAgICBjb25zdCBsYW5ndWFnZSA9IG9wdGlvbnMubGFuZ3VhZ2U/LnRvTG93ZXJDYXNlKCkgPz8gJ3R5cGVzY3JpcHQnO1xuICAgIGNvbnN0IGVudmlyb25tZW50ID0gc2V0RW52aXJvbm1lbnQob3B0aW9ucy5hY2NvdW50LCBvcHRpb25zLnJlZ2lvbik7XG4gICAgbGV0IGdlbmVyYXRlVGVtcGxhdGVPdXRwdXQ6IEdlbmVyYXRlVGVtcGxhdGVPdXRwdXQgfCB1bmRlZmluZWQ7XG4gICAgbGV0IGNmbjogQ2ZuVGVtcGxhdGVHZW5lcmF0b3JQcm92aWRlciB8IHVuZGVmaW5lZDtcbiAgICBsZXQgdGVtcGxhdGVUb0RlbGV0ZTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIGlmIG5laXRoZXIgZnJvbVBhdGggbm9yIGZyb21TdGFjayBpcyBwcm92aWRlZCwgZ2VuZXJhdGUgYSB0ZW1wbGF0ZSB1c2luZyBjbG91ZGZvcm1hdGlvblxuICAgICAgY29uc3Qgc2NhblR5cGUgPSBwYXJzZVNvdXJjZU9wdGlvbnMob3B0aW9ucy5mcm9tUGF0aCwgb3B0aW9ucy5mcm9tU3RhY2ssIG9wdGlvbnMuc3RhY2tOYW1lKS5zb3VyY2U7XG4gICAgICBpZiAoc2NhblR5cGUgPT0gVGVtcGxhdGVTb3VyY2VPcHRpb25zLlNDQU4pIHtcbiAgICAgICAgZ2VuZXJhdGVUZW1wbGF0ZU91dHB1dCA9IGF3YWl0IGdlbmVyYXRlVGVtcGxhdGUoe1xuICAgICAgICAgIHN0YWNrTmFtZTogb3B0aW9ucy5zdGFja05hbWUsXG4gICAgICAgICAgZmlsdGVyczogb3B0aW9ucy5maWx0ZXIsXG4gICAgICAgICAgZnJvbVNjYW46IG9wdGlvbnMuZnJvbVNjYW4sXG4gICAgICAgICAgc2RrUHJvdmlkZXI6IHRoaXMucHJvcHMuc2RrUHJvdmlkZXIsXG4gICAgICAgICAgZW52aXJvbm1lbnQ6IGVudmlyb25tZW50LFxuICAgICAgICAgIGlvSGVscGVyOiB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCksXG4gICAgICAgIH0pO1xuICAgICAgICB0ZW1wbGF0ZVRvRGVsZXRlID0gZ2VuZXJhdGVUZW1wbGF0ZU91dHB1dC50ZW1wbGF0ZUlkO1xuICAgICAgfSBlbHNlIGlmIChzY2FuVHlwZSA9PSBUZW1wbGF0ZVNvdXJjZU9wdGlvbnMuUEFUSCkge1xuICAgICAgICBjb25zdCB0ZW1wbGF0ZUJvZHkgPSByZWFkRnJvbVBhdGgob3B0aW9ucy5mcm9tUGF0aCEpO1xuXG4gICAgICAgIGNvbnN0IHBhcnNlZFRlbXBsYXRlID0gZGVzZXJpYWxpemVTdHJ1Y3R1cmUodGVtcGxhdGVCb2R5KTtcbiAgICAgICAgY29uc3QgdGVtcGxhdGVJZCA9IHBhcnNlZFRlbXBsYXRlLk1ldGFkYXRhPy5BV1NUb29sc01ldHJpY3M/LklhQ19HZW5lcmF0b3I/LnRvU3RyaW5nKCk7XG4gICAgICAgIGlmICh0ZW1wbGF0ZUlkKSB7XG4gICAgICAgICAgLy8gaWYgd2UgaGF2ZSBhIHRlbXBsYXRlIGlkLCB3ZSBjYW4gY2FsbCBkZXNjcmliZSBnZW5lcmF0ZWQgdGVtcGxhdGUgdG8gZ2V0IHRoZSByZXNvdXJjZSBpZGVudGlmaWVyc1xuICAgICAgICAgIC8vIHJlc291cmNlIG1ldGFkYXRhLCBhbmQgdGVtcGxhdGUgc291cmNlIHRvIGdlbmVyYXRlIHRoZSB0ZW1wbGF0ZVxuICAgICAgICAgIGNmbiA9IG5ldyBDZm5UZW1wbGF0ZUdlbmVyYXRvclByb3ZpZGVyKGF3YWl0IGJ1aWxkQ2ZuQ2xpZW50KHRoaXMucHJvcHMuc2RrUHJvdmlkZXIsIGVudmlyb25tZW50KSwgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpKTtcbiAgICAgICAgICBjb25zdCBnZW5lcmF0ZWRUZW1wbGF0ZVN1bW1hcnkgPSBhd2FpdCBjZm4uZGVzY3JpYmVHZW5lcmF0ZWRUZW1wbGF0ZSh0ZW1wbGF0ZUlkKTtcbiAgICAgICAgICBnZW5lcmF0ZVRlbXBsYXRlT3V0cHV0ID0gYnVpbGRHZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dChcbiAgICAgICAgICAgIGdlbmVyYXRlZFRlbXBsYXRlU3VtbWFyeSxcbiAgICAgICAgICAgIHRlbXBsYXRlQm9keSxcbiAgICAgICAgICAgIGdlbmVyYXRlZFRlbXBsYXRlU3VtbWFyeS5HZW5lcmF0ZWRUZW1wbGF0ZUlkISxcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGdlbmVyYXRlVGVtcGxhdGVPdXRwdXQgPSB7XG4gICAgICAgICAgICBtaWdyYXRlSnNvbjoge1xuICAgICAgICAgICAgICB0ZW1wbGF0ZUJvZHk6IHRlbXBsYXRlQm9keSxcbiAgICAgICAgICAgICAgc291cmNlOiAnbG9jYWxmaWxlJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzY2FuVHlwZSA9PSBUZW1wbGF0ZVNvdXJjZU9wdGlvbnMuU1RBQ0spIHtcbiAgICAgICAgY29uc3QgdGVtcGxhdGUgPSBhd2FpdCByZWFkRnJvbVN0YWNrKG9wdGlvbnMuc3RhY2tOYW1lLCB0aGlzLnByb3BzLnNka1Byb3ZpZGVyLCBlbnZpcm9ubWVudCk7XG4gICAgICAgIGlmICghdGVtcGxhdGUpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKCdTdGFja1RlbXBsYXRlTm90Rm91bmQnLCBgTm8gdGVtcGxhdGUgZm91bmQgZm9yIHN0YWNrLW5hbWU6ICR7b3B0aW9ucy5zdGFja05hbWV9YCk7XG4gICAgICAgIH1cbiAgICAgICAgZ2VuZXJhdGVUZW1wbGF0ZU91dHB1dCA9IHtcbiAgICAgICAgICBtaWdyYXRlSnNvbjoge1xuICAgICAgICAgICAgdGVtcGxhdGVCb2R5OiB0ZW1wbGF0ZSxcbiAgICAgICAgICAgIHNvdXJjZTogb3B0aW9ucy5zdGFja05hbWUsXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFdlIHNob3VsZG4ndCBldmVyIGdldCBoZXJlLCBidXQganVzdCBpbiBjYXNlLlxuICAgICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKCdJbnZhbGlkU291cmNlT3B0aW9uJywgYEludmFsaWQgc291cmNlIG9wdGlvbiBwcm92aWRlZDogJHtzY2FuVHlwZX1gKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHN0YWNrID0gZ2VuZXJhdGVTdGFjayhnZW5lcmF0ZVRlbXBsYXRlT3V0cHV0Lm1pZ3JhdGVKc29uLnRlbXBsYXRlQm9keSwgb3B0aW9ucy5zdGFja05hbWUsIGxhbmd1YWdlKTtcbiAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKGNoYWxrLmdyZWVuKCcg4o+zICBHZW5lcmF0aW5nIENESyBhcHAgZm9yICVzLi4uJyksIGNoYWxrLmJsdWUob3B0aW9ucy5zdGFja05hbWUpKTtcbiAgICAgIGF3YWl0IGdlbmVyYXRlQ2RrQXBwKHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKSwgb3B0aW9ucy5zdGFja05hbWUsIHN0YWNrISwgbGFuZ3VhZ2UsIG9wdGlvbnMub3V0cHV0UGF0aCwgb3B0aW9ucy5jb21wcmVzcyk7XG4gICAgICBpZiAoZ2VuZXJhdGVUZW1wbGF0ZU91dHB1dCkge1xuICAgICAgICB3cml0ZU1pZ3JhdGVKc29uRmlsZShvcHRpb25zLm91dHB1dFBhdGgsIG9wdGlvbnMuc3RhY2tOYW1lLCBnZW5lcmF0ZVRlbXBsYXRlT3V0cHV0Lm1pZ3JhdGVKc29uKTtcbiAgICAgIH1cbiAgICAgIGlmIChpc1RoZXJlQVdhcm5pbmcoZ2VuZXJhdGVUZW1wbGF0ZU91dHB1dCkpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLndhcm4oXG4gICAgICAgICAgJyDimqDvuI8gIFNvbWUgcmVzb3VyY2VzIGNvdWxkIG5vdCBiZSBtaWdyYXRlZCBjb21wbGV0ZWx5LiBQbGVhc2UgcmV2aWV3IHRoZSBSRUFETUUubWQgZmlsZSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4nLFxuICAgICAgICApO1xuICAgICAgICBhcHBlbmRXYXJuaW5nc1RvUmVhZG1lKFxuICAgICAgICAgIGAke3BhdGguam9pbihvcHRpb25zLm91dHB1dFBhdGggPz8gcHJvY2Vzcy5jd2QoKSwgb3B0aW9ucy5zdGFja05hbWUpfS9SRUFETUUubWRgLFxuICAgICAgICAgIGdlbmVyYXRlVGVtcGxhdGVPdXRwdXQucmVzb3VyY2VzISxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuZXJyb3IoJyDinYwgIE1pZ3JhdGUgZmFpbGVkIGZvciBgJXNgOiAlcycsIG9wdGlvbnMuc3RhY2tOYW1lLCAoZSBhcyBFcnJvcikubWVzc2FnZSk7XG4gICAgICB0aHJvdyBlO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBpZiAodGVtcGxhdGVUb0RlbGV0ZSkge1xuICAgICAgICBpZiAoIWNmbikge1xuICAgICAgICAgIGNmbiA9IG5ldyBDZm5UZW1wbGF0ZUdlbmVyYXRvclByb3ZpZGVyKGF3YWl0IGJ1aWxkQ2ZuQ2xpZW50KHRoaXMucHJvcHMuc2RrUHJvdmlkZXIsIGVudmlyb25tZW50KSwgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXByb2Nlc3MuZW52Lk1JR1JBVEVfSU5URUdfVEVTVCkge1xuICAgICAgICAgIGF3YWl0IGNmbi5kZWxldGVHZW5lcmF0ZWRUZW1wbGF0ZSh0ZW1wbGF0ZVRvRGVsZXRlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBhc3luYyByZWZhY3RvcihvcHRpb25zOiBSZWZhY3Rvck9wdGlvbnMpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGlmIChvcHRpb25zLnJldmVydCAmJiAhb3B0aW9ucy5vdmVycmlkZUZpbGUpIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ1JldmVydFJlcXVpcmVzT3ZlcnJpZGVGaWxlJywgJ1RoZSAtLXJldmVydCBvcHRpb24gY2FuIG9ubHkgYmUgdXNlZCB3aXRoIHRoZSAtLW92ZXJyaWRlLWZpbGUgb3B0aW9uLicpO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnRvb2xraXQucmVmYWN0b3IodGhpcy5wcm9wcy5jbG91ZEV4ZWN1dGFibGUsIHtcbiAgICAgICAgZHJ5UnVuOiBvcHRpb25zLmRyeVJ1bixcbiAgICAgICAgc3RhY2tzOiBvcHRpb25zLnN0YWNrcyA/PyBBTExfU1RBQ0tTLFxuICAgICAgICBmb3JjZTogb3B0aW9ucy5mb3JjZSxcbiAgICAgICAgYWRkaXRpb25hbFN0YWNrTmFtZXM6IG9wdGlvbnMuYWRkaXRpb25hbFN0YWNrTmFtZXMsXG4gICAgICAgIG92ZXJyaWRlczogcmVhZE92ZXJyaWRlcyhvcHRpb25zLm92ZXJyaWRlRmlsZSwgb3B0aW9ucy5yZXZlcnQpLFxuICAgICAgICByb2xlQXJuOiBvcHRpb25zLnJvbGVBcm4sXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuZXJyb3IoKGUgYXMgRXJyb3IpLm1lc3NhZ2UpO1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG5cbiAgICByZXR1cm4gMDtcblxuICAgIGZ1bmN0aW9uIHJlYWRPdmVycmlkZXMoZmlsZVBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZCwgcmV2ZXJ0OiBib29sZWFuID0gZmFsc2UpIHtcbiAgICAgIGlmIChmaWxlUGF0aCA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICAgIGlmICghZnMucGF0aEV4aXN0c1N5bmMoZmlsZVBhdGgpKSB7XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ01hcHBpbmdGaWxlTm90Rm91bmQnLCBgVGhlIG1hcHBpbmcgZmlsZSAke2ZpbGVQYXRofSBkb2VzIG5vdCBleGlzdGApO1xuICAgICAgfVxuICAgICAgY29uc3QgZ3JvdXBzID0gcGFyc2VNYXBwaW5nR3JvdXBzKGZzLnJlYWRGaWxlU3luYyhmaWxlUGF0aCkudG9TdHJpbmcoJ3V0Zi04JykpO1xuXG4gICAgICByZXR1cm4gcmV2ZXJ0XG4gICAgICAgID8gZ3JvdXBzLm1hcCgoZ3JvdXApID0+ICh7XG4gICAgICAgICAgLi4uZ3JvdXAsXG4gICAgICAgICAgcmVzb3VyY2VzOiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMoZ3JvdXAucmVzb3VyY2VzID8/IHt9KS5tYXAoKFtzcmMsIGRzdF0pID0+IFtkc3QsIHNyY10pKSxcbiAgICAgICAgfSkpXG4gICAgICAgIDogZ3JvdXBzO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZWxlY3QgdGhlIHN0YWNrcyB0aGF0IGBzeW50aGAgYW5kIGBkaWZmYCBvcGVyYXRlIG9uXG4gICAqXG4gICAqIFdpdGggcGF0dGVybnM6IG1hdGNoIHRoZW0gKGZhaWxpbmcgaWYgbm90aGluZyBtYXRjaGVzKSwgZXhwYW5kaW5nIHRvXG4gICAqIHVwc3RyZWFtIGRlcGVuZGVuY2llcyB1bmxlc3MgYGV4Y2x1c2l2ZWx5YCBpcyBzZXQuIFdpdGhvdXQgcGF0dGVybnM6IGFsbFxuICAgKiB0b3AtbGV2ZWwgc3RhY2tzLCBleGFjdGx5IOKAlCB0aGUgaGlzdG9yaWMgZGVmYXVsdCBzZWxlY3Rpb24gbmV2ZXIgZXhwYW5kc1xuICAgKiB0byBkZXBlbmRlbmNpZXMsIHJlZ2FyZGxlc3Mgb2YgYGV4Y2x1c2l2ZWx5YC4gQSBzdGFnZS1vbmx5IGFwcCBoYXMgbm9cbiAgICogdG9wLWxldmVsIHN0YWNrcywgd2hpY2ggc2VsZWN0cyBub3RoaW5nIGFuZCBpcyBub3QgYW4gZXJyb3Ig4oCUIGJ1dCBhbiBhcHBcbiAgICogd2l0aG91dCBhbnkgc3RhY2tzIGF0IGFsbCBzdGlsbCBpcy4gTm8gc2luZ2xlIHNlbGVjdGlvbiBzdHJhdGVneSBjb3ZlcnNcbiAgICogdGhpcyBjb21iaW5hdGlvbjogYE1BSU5fQVNTRU1CTFlgIHJlamVjdHMgc3RhZ2Utb25seSBhcHBzIChhc1xuICAgKiBgZGVwbG95IC0tYWxsYCBtdXN0IGtlZXAgZG9pbmcpIGFuZCBgQUxMX1NUQUNLU2Agd291bGQgd3JvbmdseSBpbmNsdWRlXG4gICAqIHRoZSBzdGFja3MgaW5zaWRlIHN0YWdlcy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2VsZWN0VG9wTGV2ZWxPck1hdGNoaW5nU3RhY2tzKFxuICAgIGFzc2VtYmx5OiBTdGFja0Fzc2VtYmx5LFxuICAgIHBhdHRlcm5zOiBzdHJpbmdbXSxcbiAgICBleGNsdXNpdmVseT86IGJvb2xlYW4sXG4gICk6IFByb21pc2U8U3RhY2tDb2xsZWN0aW9uPiB7XG4gICAgaWYgKHBhdHRlcm5zLmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiBhc3NlbWJseS5zZWxlY3RTdGFja3NWMihcbiAgICAgICAgbXVzdE1hdGNoKGV4Y2x1c2l2ZWx5ID8gc2VsZWN0RXhhY3QoLi4ucGF0dGVybnMpIDogc2VsZWN0V2l0aFVwc3RyZWFtKC4uLnBhdHRlcm5zKSksXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChhc3NlbWJseS5jbG91ZEFzc2VtYmx5LnN0YWNrcy5sZW5ndGggPiAwKSB7XG4gICAgICByZXR1cm4gYXNzZW1ibHkuc2VsZWN0U3RhY2tzVjIoc2VsZWN0QWxsVG9wTGV2ZWwoRXhwYW5kU3RhY2tTZWxlY3Rpb24uTk9ORSkpO1xuICAgIH1cblxuICAgIC8vIFN0YWdlLW9ubHkgYXBwOiBub3RoaW5nIHRvIHNlbGVjdCwgd2hpY2ggaXMgbm90IGFuIGVycm9yLiBBbiBhcHBcbiAgICAvLyB3aXRob3V0IGFueSBzdGFja3MgYXQgYWxsIHN0aWxsIGlzOiB0aGlzIHNlbGVjdGlvbiB0aHJvd3NcbiAgICAvLyAnVGhpcyBhcHAgY29udGFpbnMgbm8gc3RhY2tzJyBpbiB0aGF0IGNhc2UuXG4gICAgYXdhaXQgYXNzZW1ibHkuc2VsZWN0U3RhY2tzVjIoQUxMX1NUQUNLUyk7XG4gICAgcmV0dXJuIG5ldyBTdGFja0NvbGxlY3Rpb24oYXNzZW1ibHksIFtdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgc3RhY2tzIGZvciBlcnJvcnMgYW5kIHdhcm5pbmdzIGFjY29yZGluZyB0byB0aGUgQ0xJJ3MgY3VycmVudCBzZXR0aW5nc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2YWxpZGF0ZVN0YWNrcyhhc3NlbWJseTogU3RhY2tBc3NlbWJseSwgc3RhY2tzOiBTdGFja0NvbGxlY3Rpb24pIHtcbiAgICBjb25zdCBmYWlsQXQgPSB0aGlzLnZhbGlkYXRlTWV0YWRhdGFGYWlsQXQoKTtcbiAgICBhd2FpdCB0aHJvd0lmVmFsaWRhdGlvbkZhaWx1cmVzKGFzc2VtYmx5LCBzdGFja3MsIGZhaWxBdCwgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpKTtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVNZXRhZGF0YUZhaWxBdCgpOiAnd2FybicgfCAnZXJyb3InIHwgJ25vbmUnIHtcbiAgICBsZXQgZmFpbEF0OiAnd2FybicgfCAnZXJyb3InIHwgJ25vbmUnID0gJ2Vycm9yJztcbiAgICBpZiAodGhpcy5wcm9wcy5pZ25vcmVFcnJvcnMpIHtcbiAgICAgIGZhaWxBdCA9ICdub25lJztcbiAgICB9XG4gICAgaWYgKHRoaXMucHJvcHMuc3RyaWN0KSB7XG4gICAgICBmYWlsQXQgPSAnd2Fybic7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhaWxBdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0cyB0aGUgdG9vbGtpdCdzIGBDbG91ZEV4ZWN1dGFibGVgIGludG8gYFN0YWNrQXNzZW1ibHlgLlxuICAgKlxuICAgKiBAcGFyYW0gY2FjaGVDbG91ZEFzc2VtYmx5IC0gdG8gY2FjaGUgdGhlIGFzc2VtYmx5LCBkZWZhdWx0cyB0byBgdHJ1ZWBcbiAgICogQHJldHVybnMgdGhlIGNvbnZlcnRlZCBgU3RhY2tBc3NlbWJseWBcbiAgICovXG4gIHB1YmxpYyBhc3NlbWJseShjYWNoZUNsb3VkQXNzZW1ibHk6IGJvb2xlYW4gPSB0cnVlKTogUHJvbWlzZTxTdGFja0Fzc2VtYmx5PiB7XG4gICAgcmV0dXJuIHRoaXMucHJvcHMuY2xvdWRFeGVjdXRhYmxlLnN5bnRoZXNpemUoY2FjaGVDbG91ZEFzc2VtYmx5KTtcbiAgfVxuXG4gIHByaXZhdGUgcGF0dGVybnNBcnJheUZvcldhdGNoKFxuICAgIHBhdHRlcm5zOiBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZCxcbiAgICBvcHRpb25zOiB7IGRlZmF1bHRQYXR0ZXJuOiBzdHJpbmc7IHJldHVybkRlZmF1bHRJZkVtcHR5OiBib29sZWFuIH0sXG4gICk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBwYXR0ZXJuc0FycmF5OiBzdHJpbmdbXSA9IHBhdHRlcm5zICE9PSB1bmRlZmluZWQgPyAoQXJyYXkuaXNBcnJheShwYXR0ZXJucykgPyBwYXR0ZXJucyA6IFtwYXR0ZXJuc10pIDogW107XG4gICAgcmV0dXJuIHBhdHRlcm5zQXJyYXkubGVuZ3RoID4gMCA/IHBhdHRlcm5zQXJyYXkgOiBvcHRpb25zLnJldHVybkRlZmF1bHRJZkVtcHR5ID8gW29wdGlvbnMuZGVmYXVsdFBhdHRlcm5dIDogW107XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGludm9rZURlcGxveUZyb21XYXRjaChcbiAgICBvcHRpb25zOiBXYXRjaE9wdGlvbnMsXG4gICAgY2xvdWRXYXRjaExvZ01vbml0b3I/OiBDbG91ZFdhdGNoTG9nRXZlbnRNb25pdG9yLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBkZXBsb3lPcHRpb25zOiBEZXBsb3lPcHRpb25zID0ge1xuICAgICAgLi4ub3B0aW9ucyxcbiAgICAgIHJlcXVpcmVBcHByb3ZhbDogUmVxdWlyZUFwcHJvdmFsLk5FVkVSLFxuICAgICAgLy8gaWYgJ3dhdGNoJyBpcyBjYWxsZWQgYnkgaW52b2tpbmcgJ2NkayBkZXBsb3kgLS13YXRjaCcsXG4gICAgICAvLyB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSB0byBub3QgY2FsbCAnZGVwbG95JyB3aXRoICd3YXRjaCcgYWdhaW4sXG4gICAgICAvLyBhcyB0aGF0IHdvdWxkIGxlYWQgdG8gYSBjeWNsZVxuICAgICAgd2F0Y2g6IGZhbHNlLFxuICAgICAgY2xvdWRXYXRjaExvZ01vbml0b3IsXG4gICAgICBjYWNoZUNsb3VkQXNzZW1ibHk6IGZhbHNlLFxuICAgICAgZXh0cmFVc2VyQWdlbnQ6IGBjZGstd2F0Y2gvaG90c3dhcC0ke29wdGlvbnMuZGVwbG95bWVudE1ldGhvZD8ubWV0aG9kID09PSAnaG90c3dhcCcgPyAnb24nIDogJ29mZid9YCxcbiAgICAgIGNvbmN1cnJlbmN5OiBvcHRpb25zLmNvbmN1cnJlbmN5LFxuICAgIH07XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5kZXBsb3koZGVwbG95T3B0aW9ucyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBqdXN0IGNvbnRpbnVlIC0gZGVwbG95IHdpbGwgc2hvdyB0aGUgZXJyb3JcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSBhc3NldCBwdWJsaXNoaW5nIGFuZCBidWlsZGluZyBmcm9tIHRoZSB3b3JrIGdyYXBoIGZvciBhc3NldHMgdGhhdCBhcmUgYWxyZWFkeSBpbiBwbGFjZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZW1vdmVQdWJsaXNoZWRBc3NldHMoZ3JhcGg6IFdvcmtHcmFwaCwgb3B0aW9uczogRGVwbG95T3B0aW9ucykge1xuICAgIGF3YWl0IGdyYXBoLnJlbW92ZVVubmVjZXNzYXJ5QXNzZXRzKGFzc2V0Tm9kZSA9PiB0aGlzLnByb3BzLmRlcGxveW1lbnRzLmlzU2luZ2xlQXNzZXRQdWJsaXNoZWQoYXNzZXROb2RlLmFzc2V0TWFuaWZlc3QsIGFzc2V0Tm9kZS5hc3NldCwge1xuICAgICAgc3RhY2s6IGFzc2V0Tm9kZS5wYXJlbnRTdGFjayxcbiAgICAgIHJvbGVBcm46IG9wdGlvbnMucm9sZUFybixcbiAgICAgIHN0YWNrTmFtZTogYXNzZXROb2RlLnBhcmVudFN0YWNrLnN0YWNrTmFtZSxcbiAgICB9KSk7XG4gIH1cbn1cblxuLyoqXG4gKiBQcmludCBhIHNlcmlhbGl6ZWQgb2JqZWN0IChZQU1MIG9yIEpTT04pIHRvIHN0ZG91dC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcHJpbnRTZXJpYWxpemVkT2JqZWN0KGlvSGVscGVyOiBJb0hlbHBlciwgb2JqOiBhbnksIGpzb246IGJvb2xlYW4pIHtcbiAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMucmVzdWx0KHNlcmlhbGl6ZVN0cnVjdHVyZShvYmosIGpzb24pKTtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciB0aGUgc3ludGggY29tbWFuZFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN5bnRoT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBTdGFjayBuYW1lcyB0byBzeW50aGVzaXplXG4gICAqL1xuICByZWFkb25seSBzdGFja05hbWVzOiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogT25seSBzZWxlY3QgdGhlIGdpdmVuIHN0YWNrcywgd2l0aG91dCBleHBhbmRpbmcgdG8gdGhlaXIgdXBzdHJlYW0gZGVwZW5kZW5jaWVzXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBleGNsdXNpdmVseT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIERvIG5vdCBwcmludCB0aGUgdGVtcGxhdGUgdG8gc3Rkb3V0XG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBxdWlldD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWxseSB2YWxpZGF0ZSBzdGFja3MgdGhhdCBoYXZlIHRoZSBgdmFsaWRhdGVPblN5bnRoYCBmbGFnIHNldFxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgYXV0b1ZhbGlkYXRlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUHJpbnQgdGhlIHRlbXBsYXRlIGFzIEpTT04gaW5zdGVhZCBvZiBZQU1MXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBqc29uPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciB0aGUgZGlmZiBjb21tYW5kXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGlmZk9wdGlvbnMge1xuICAvKipcbiAgICogU3RhY2sgbmFtZXMgdG8gZGlmZlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhY2tOYW1lczogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIHRvb2xraXQgc3RhY2ssIGlmIG5vdCB0aGUgZGVmYXVsdCBuYW1lXG4gICAqXG4gICAqIEBkZWZhdWx0ICdDREtUb29sa2l0J1xuICAgKi9cbiAgcmVhZG9ubHkgdG9vbGtpdFN0YWNrTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogT25seSBzZWxlY3QgdGhlIGdpdmVuIHN0YWNrXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBleGNsdXNpdmVseT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFVzZWQgYSB0ZW1wbGF0ZSBmcm9tIGRpc2sgaW5zdGVhZCBvZiBmcm9tIHRoZSBzZXJ2ZXJcbiAgICpcbiAgICogQGRlZmF1bHQgVXNlIGZyb20gdGhlIHNlcnZlclxuICAgKi9cbiAgcmVhZG9ubHkgdGVtcGxhdGVQYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBTdHJpY3QgZGlmZiBtb2RlXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBzdHJpY3Q/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBIb3cgbWFueSBsaW5lcyBvZiBjb250ZXh0IHRvIHNob3cgaW4gdGhlIGRpZmZcbiAgICpcbiAgICogQGRlZmF1bHQgM1xuICAgKi9cbiAgcmVhZG9ubHkgY29udGV4dExpbmVzPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGZhaWwgd2l0aCBleGl0IGNvZGUgMSBpbiBjYXNlIG9mIGRpZmZcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGZhaWw/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPbmx5IHJ1biBkaWZmIG9uIGJyb2FkZW5lZCBzZWN1cml0eSBjaGFuZ2VzXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBzZWN1cml0eU9ubHk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHJ1biB0aGUgZGlmZiBhZ2FpbnN0IHRoZSB0ZW1wbGF0ZSBhZnRlciB0aGUgQ2xvdWRGb3JtYXRpb24gVHJhbnNmb3JtcyBpbnNpZGUgaXQgaGF2ZSBiZWVuIGV4ZWN1dGVkXG4gICAqIChhcyBvcHBvc2VkIHRvIHRoZSBvcmlnaW5hbCB0ZW1wbGF0ZSwgdGhlIGRlZmF1bHQsIHdoaWNoIGNvbnRhaW5zIHRoZSB1bnByb2Nlc3NlZCBUcmFuc2Zvcm1zKS5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGNvbXBhcmVBZ2FpbnN0UHJvY2Vzc2VkVGVtcGxhdGU/OiBib29sZWFuO1xuXG4gIC8qXG4gICAqIFJ1biBkaWZmIGluIHF1aWV0IG1vZGUgd2l0aG91dCBwcmludGluZyB0aGUgZGlmZiBzdGF0dXNlc1xuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgcXVpZXQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBZGRpdGlvbmFsIHBhcmFtZXRlcnMgZm9yIENsb3VkRm9ybWF0aW9uIGF0IGRpZmYgdGltZSwgdXNlZCB0byBjcmVhdGUgYSBjaGFuZ2Ugc2V0XG4gICAqIEBkZWZhdWx0IHt9XG4gICAqL1xuICByZWFkb25seSBwYXJhbWV0ZXJzPzogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH07XG5cbiAgLyoqXG4gICAqIEhvdyB0byBjb21wdXRlIHRoZSBkaWZmLlxuICAgKiAtICdjaGFuZ2Utc2V0JzogYWx3YXlzIHVzZSBhIGNoYW5nZXNldCwgZmFpbCBpZiBpdCBjYW5ub3QgYmUgY3JlYXRlZFxuICAgKiAtICd0ZW1wbGF0ZSc6IHNraXAgY2hhbmdlc2V0LCBjb21wYXJlIHRlbXBsYXRlcyBkaXJlY3RseVxuICAgKiAtICdhdXRvJzogdHJ5IGNoYW5nZXNldCwgZmFsbCBiYWNrIHRvIHRlbXBsYXRlIG9uIGZhaWx1cmVcbiAgICpcbiAgICogQGRlZmF1bHQgJ2F1dG8nXG4gICAqL1xuICByZWFkb25seSBtZXRob2Q/OiAnYXV0bycgfCAnY2hhbmdlLXNldCcgfCAndGVtcGxhdGUnO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCB0aGUgY2hhbmdlIHNldCBpbXBvcnRzIHJlc291cmNlcyB0aGF0IGFscmVhZHkgZXhpc3QuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBpbXBvcnRFeGlzdGluZ1Jlc291cmNlcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gaW5jbHVkZSByZXNvdXJjZSBtb3ZlcyBpbiB0aGUgZGlmZlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgaW5jbHVkZU1vdmVzPzogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIENmbkRlcGxveU9wdGlvbnMge1xuICAvKipcbiAgICogQ3JpdGVyaWEgZm9yIHNlbGVjdGluZyBzdGFja3MgdG8gZGVwbG95XG4gICAqL1xuICBzZWxlY3RvcjogU3RhY2tTZWxlY3RvcjtcblxuICAvKipcbiAgICogTmFtZSBvZiB0aGUgdG9vbGtpdCBzdGFjayB0byB1c2UvZGVwbG95XG4gICAqXG4gICAqIEBkZWZhdWx0IENES1Rvb2xraXRcbiAgICovXG4gIHRvb2xraXRTdGFja05hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJvbGUgdG8gcGFzcyB0byBDbG91ZEZvcm1hdGlvbiBmb3IgZGVwbG95bWVudFxuICAgKi9cbiAgcm9sZUFybj86IHN0cmluZztcblxuICAvKipcbiAgICogRGVwbG95bWVudCBtZXRob2RcbiAgICovXG4gIHJlYWRvbmx5IGRlcGxveW1lbnRNZXRob2Q/OiBEZXBsb3ltZW50TWV0aG9kO1xuXG4gIC8qKlxuICAgKiBEaXNwbGF5IG1vZGUgZm9yIHN0YWNrIGRlcGxveW1lbnQgcHJvZ3Jlc3MuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkJhciAtIHN0YWNrIGV2ZW50cyB3aWxsIGJlIGRpc3BsYXllZCBmb3JcbiAgICogICB0aGUgcmVzb3VyY2UgY3VycmVudGx5IGJlaW5nIGRlcGxveWVkLlxuICAgKi9cbiAgcHJvZ3Jlc3M/OiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3M7XG5cbiAgLyoqXG4gICAqIFJvbGxiYWNrIGZhaWxlZCBkZXBsb3ltZW50c1xuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSByb2xsYmFjaz86IGJvb2xlYW47XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgdGhlIHZhbGlkYXRlIGNvbW1hbmRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbGlWYWxpZGF0ZU9wdGlvbnMgZXh0ZW5kcyBWYWxpZGF0ZU9wdGlvbnMge1xuICAvKipcbiAgICogQ29udGludW91c2x5IG9ic2VydmUgdGhlIHByb2plY3QgZmlsZXMsIGFuZCByZS12YWxpZGF0ZSBhdXRvbWF0aWNhbGx5IHdoZW4gY2hhbmdlcyBhcmUgZGV0ZWN0ZWRcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHdhdGNoPzogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIFdhdGNoT3B0aW9ucyBleHRlbmRzIE9taXQ8Q2ZuRGVwbG95T3B0aW9ucywgJ2V4ZWN1dGUnPiB7XG4gIC8qKlxuICAgKiBSZXVzZSB0aGUgYXNzZXRzIHdpdGggdGhlIGdpdmVuIGFzc2V0IElEc1xuICAgKi9cbiAgcmV1c2VBc3NldHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQWx3YXlzIGRlcGxveSwgZXZlbiBpZiB0ZW1wbGF0ZXMgYXJlIGlkZW50aWNhbC5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIGZvcmNlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIGV4dHJhIHN0cmluZyB0byBhcHBlbmQgdG8gdGhlIFVzZXItQWdlbnQgaGVhZGVyIHdoZW4gcGVyZm9ybWluZyBBV1MgU0RLIGNhbGxzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vdGhpbmcgZXh0cmEgaXMgYXBwZW5kZWQgdG8gdGhlIFVzZXItQWdlbnQgaGVhZGVyXG4gICAqL1xuICByZWFkb25seSBleHRyYVVzZXJBZ2VudD86IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0byBzaG93IENsb3VkV2F0Y2ggbG9ncyBmb3IgaG90c3dhcHBlZCByZXNvdXJjZXNcbiAgICogbG9jYWxseSBpbiB0aGUgdXNlcnMgdGVybWluYWxcbiAgICpcbiAgICogQGRlZmF1bHQgLSBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgdHJhY2VMb2dzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogTWF4aW11bSBudW1iZXIgb2Ygc2ltdWx0YW5lb3VzIGRlcGxveW1lbnRzIChkZXBlbmRlbmN5IHBlcm1pdHRpbmcpIHRvIGV4ZWN1dGUuXG4gICAqIFRoZSBkZWZhdWx0IGlzICcxJywgd2hpY2ggZXhlY3V0ZXMgYWxsIGRlcGxveW1lbnRzIHNlcmlhbGx5LlxuICAgKlxuICAgKiBAZGVmYXVsdCAxXG4gICAqL1xuICByZWFkb25seSBjb25jdXJyZW5jeT86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEZXBsb3lPcHRpb25zIGV4dGVuZHMgQ2ZuRGVwbG95T3B0aW9ucywgV2F0Y2hPcHRpb25zIHtcbiAgLyoqXG4gICAqIEFSTnMgb2YgU05TIHRvcGljcyB0aGF0IENsb3VkRm9ybWF0aW9uIHdpbGwgbm90aWZ5IHdpdGggc3RhY2sgcmVsYXRlZCBldmVudHNcbiAgICovXG4gIG5vdGlmaWNhdGlvbkFybnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogV2hhdCBraW5kIG9mIHNlY3VyaXR5IGNoYW5nZXMgcmVxdWlyZSBhcHByb3ZhbFxuICAgKlxuICAgKiBAZGVmYXVsdCBSZXF1aXJlQXBwcm92YWwuQnJvYWRlbmluZ1xuICAgKi9cbiAgcmVxdWlyZUFwcHJvdmFsPzogUmVxdWlyZUFwcHJvdmFsO1xuXG4gIC8qKlxuICAgKiBUYWdzIHRvIHBhc3MgdG8gQ2xvdWRGb3JtYXRpb24gZm9yIGRlcGxveW1lbnRcbiAgICovXG4gIHRhZ3M/OiBUYWdbXTtcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBwYXJhbWV0ZXJzIGZvciBDbG91ZEZvcm1hdGlvbiBhdCBkZXBsb3kgdGltZVxuICAgKiBAZGVmYXVsdCB7fVxuICAgKi9cbiAgcGFyYW1ldGVycz86IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9O1xuXG4gIC8qKlxuICAgKiBVc2UgcHJldmlvdXMgdmFsdWVzIGZvciB1bnNwZWNpZmllZCBwYXJhbWV0ZXJzXG4gICAqXG4gICAqIElmIG5vdCBzZXQsIGFsbCBwYXJhbWV0ZXJzIG11c3QgYmUgc3BlY2lmaWVkIGZvciBldmVyeSBkZXBsb3ltZW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICB1c2VQcmV2aW91c1BhcmFtZXRlcnM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBQYXRoIHRvIGZpbGUgd2hlcmUgc3RhY2sgb3V0cHV0cyB3aWxsIGJlIHdyaXR0ZW4gYWZ0ZXIgYSBzdWNjZXNzZnVsIGRlcGxveSBhcyBKU09OXG4gICAqIEBkZWZhdWx0IC0gT3V0cHV0cyBhcmUgbm90IHdyaXR0ZW4gdG8gYW55IGZpbGVcbiAgICovXG4gIG91dHB1dHNGaWxlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHdlIGFyZSBvbiBhIENJIHN5c3RlbVxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgY2k/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgJ2RlcGxveScgY29tbWFuZCBzaG91bGQgYWN0dWFsbHkgZGVsZWdhdGUgdG8gdGhlICd3YXRjaCcgY29tbWFuZC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHdhdGNoPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB3ZSBzaG91bGQgY2FjaGUgdGhlIENsb3VkIEFzc2VtYmx5IGFmdGVyIHRoZSBmaXJzdCB0aW1lIGl0IGhhcyBiZWVuIHN5bnRoZXNpemVkLlxuICAgKiBUaGUgZGVmYXVsdCBpcyAndHJ1ZScsIHdlIG9ubHkgZG9uJ3Qgd2FudCB0byBkbyBpdCBpbiBjYXNlIHRoZSBkZXBsb3ltZW50IGlzIHRyaWdnZXJlZCBieVxuICAgKiAnY2RrIHdhdGNoJy5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgY2FjaGVDbG91ZEFzc2VtYmx5PzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQWxsb3dzIGFkZGluZyBDbG91ZFdhdGNoIGxvZyBncm91cHMgdG8gdGhlIGxvZyBtb25pdG9yIHZpYVxuICAgKiBjbG91ZFdhdGNoTG9nTW9uaXRvci5zZXRMb2dHcm91cHMoKTtcbiAgICpcbiAgICogQGRlZmF1bHQgLSBub3QgbW9uaXRvcmluZyBDbG91ZFdhdGNoIGxvZ3NcbiAgICovXG4gIHJlYWRvbmx5IGNsb3VkV2F0Y2hMb2dNb25pdG9yPzogQ2xvdWRXYXRjaExvZ0V2ZW50TW9uaXRvcjtcblxuICAvKipcbiAgICogTWF4aW11bSBudW1iZXIgb2Ygc2ltdWx0YW5lb3VzIGRlcGxveW1lbnRzIChkZXBlbmRlbmN5IHBlcm1pdHRpbmcpIHRvIGV4ZWN1dGUuXG4gICAqIFRoZSBkZWZhdWx0IGlzICcxJywgd2hpY2ggZXhlY3V0ZXMgYWxsIGRlcGxveW1lbnRzIHNlcmlhbGx5LlxuICAgKlxuICAgKiBAZGVmYXVsdCAxXG4gICAqL1xuICByZWFkb25seSBjb25jdXJyZW5jeT86IG51bWJlcjtcblxuICAvKipcbiAgICogQnVpbGQvcHVibGlzaCBhc3NldHMgZm9yIGEgc2luZ2xlIHN0YWNrIGluIHBhcmFsbGVsXG4gICAqXG4gICAqIEluZGVwZW5kZW50IG9mIHdoZXRoZXIgc3RhY2tzIGFyZSBiZWluZyBkb25lIGluIHBhcmFsbGVsIG9yIG5vLlxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBhc3NldFBhcmFsbGVsaXNtPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogTWF4aW11bSBudW1iZXIgb2YgYXNzZXQgYnVpbGRzIHRvIHJ1biBpbiBwYXJhbGxlbFxuICAgKlxuICAgKiBUaGlzIHNldHRpbmcgb25seSBoYXMgYW4gZWZmZWN0IGlmIGBhc3NldFBhcmFsbGVsaXNtYCBpcyBzZXQgdG8gYHRydWVgLlxuICAgKlxuICAgKiBAZGVmYXVsdCAxXG4gICAqL1xuICByZWFkb25seSBhc3NldEJ1aWxkQ29uY3VycmVuY3k/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFdoZW4gdG8gYnVpbGQgYXNzZXRzXG4gICAqXG4gICAqIFRoZSBkZWZhdWx0IGlzIHRoZSBEb2NrZXItZnJpZW5kbHkgZGVmYXVsdC5cbiAgICpcbiAgICogQGRlZmF1bHQgQXNzZXRCdWlsZFRpbWUuQUxMX0JFRk9SRV9ERVBMT1lcbiAgICovXG4gIHJlYWRvbmx5IGFzc2V0QnVpbGRUaW1lPzogQXNzZXRCdWlsZFRpbWU7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gdXNlIENsb3VkRm9ybWF0aW9uIGV4cHJlc3MgbW9kZSBmb3IgdGhlIGN1cnJlbnQgZGVwbG95bWVudFxuICAgKi9cbiAgcmVhZG9ubHkgZXhwcmVzcz86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUm9sbGJhY2tPcHRpb25zIHtcbiAgLyoqXG4gICAqIENyaXRlcmlhIGZvciBzZWxlY3Rpbmcgc3RhY2tzIHRvIGRlcGxveVxuICAgKi9cbiAgcmVhZG9ubHkgc2VsZWN0b3I6IFN0YWNrU2VsZWN0b3I7XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIHRvb2xraXQgc3RhY2sgdG8gdXNlL2RlcGxveVxuICAgKlxuICAgKiBAZGVmYXVsdCBDREtUb29sa2l0XG4gICAqL1xuICByZWFkb25seSB0b29sa2l0U3RhY2tOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSb2xlIHRvIHBhc3MgdG8gQ2xvdWRGb3JtYXRpb24gZm9yIGRlcGxveW1lbnRcbiAgICpcbiAgICogQGRlZmF1bHQgLSBEZWZhdWx0IHN0YWNrIHJvbGVcbiAgICovXG4gIHJlYWRvbmx5IHJvbGVBcm4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZm9yY2UgdGhlIHJvbGxiYWNrIG9yIG5vdFxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgZm9yY2U/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBMb2dpY2FsIElEcyBvZiByZXNvdXJjZXMgdG8gb3JwaGFuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gb3JwaGFuaW5nXG4gICAqL1xuICByZWFkb25seSBvcnBoYW5Mb2dpY2FsSWRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gdmFsaWRhdGUgdGhlIHZlcnNpb24gb2YgdGhlIGJvb3RzdHJhcCBzdGFjayBwZXJtaXNzaW9uc1xuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSB2YWxpZGF0ZUJvb3RzdHJhcFN0YWNrVmVyc2lvbj86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3JwaGFuT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGNvbnN0cnVjdFBhdGg6IHN0cmluZ1tdO1xuICByZWFkb25seSByb2xlQXJuPzogc3RyaW5nO1xuICByZWFkb25seSB0b29sa2l0U3RhY2tOYW1lPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEltcG9ydE9wdGlvbnMgZXh0ZW5kcyBDZm5EZXBsb3lPcHRpb25zIHtcbiAgLyoqXG4gICAqIEFSTnMgb2YgU05TIHRvcGljcyB0aGF0IENsb3VkRm9ybWF0aW9uIHdpbGwgbm90aWZ5IHdpdGggc3RhY2sgcmVsYXRlZCBldmVudHMuXG4gICAqXG4gICAqIFRoZSBmb2xsb3dpbmcgc2VtYW50aWNzIGFwcGx5IChkaWN0YXRlZCBieSB0aGUgU0RLKTpcbiAgICpcbiAgICogIC0gdW5kZWZpbmVkICA9PiAgY2RrIGlnbm9yZXMgaXQsIGFzIGlmIGl0IHdhc24ndCBzdXBwb3J0ZWQgKGFsbG93cyBleHRlcm5hbCBtYW5hZ2VtZW50KS5cbiAgICogIC0gW106ICAgICAgICA9PiAgY2RrIG1hbmFnZXMgaXQsIGFuZCB0aGUgdXNlciB3YW50cyB0byB3aXBlIGl0IG91dC5cbiAgICogIC0gWydhcm4tMSddICA9PiAgY2RrIG1hbmFnZXMgaXQsIGFuZCB0aGUgdXNlciB3YW50cyB0byBzZXQgaXQgdG8gWydhcm4tMSddLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIG5vdGlmaWNhdGlvbnNcbiAgICovXG4gIHJlYWRvbmx5IG5vdGlmaWNhdGlvbkFybnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQnVpbGQgYSBwaHlzaWNhbCByZXNvdXJjZSBtYXBwaW5nIGFuZCB3cml0ZSBpdCB0byB0aGUgZ2l2ZW4gZmlsZSwgd2l0aG91dCBwZXJmb3JtaW5nIHRoZSBhY3R1YWwgaW1wb3J0IG9wZXJhdGlvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGZpbGVcbiAgICovXG5cbiAgcmVhZG9ubHkgcmVjb3JkUmVzb3VyY2VNYXBwaW5nPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBQYXRoIHRvIGEgZmlsZSB3aXRoIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBtYXBwaW5nIHRvIENESyBjb25zdHJ1Y3RzIGluIEpTT04gZm9ybWF0XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gbWFwcGluZyBmaWxlXG4gICAqL1xuICByZWFkb25seSByZXNvdXJjZU1hcHBpbmdGaWxlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJbmxpbmUgSlNPTiBzdHJpbmcgd2l0aCB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgbWFwcGluZ1xuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGlubGluZSBtYXBwaW5nXG4gICAqL1xuICByZWFkb25seSByZXNvdXJjZU1hcHBpbmdJbmxpbmU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFsbG93IG5vbi1hZGRpdGlvbiBjaGFuZ2VzIHRvIHRoZSB0ZW1wbGF0ZVxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgZm9yY2U/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERlc3Ryb3lPcHRpb25zIHtcbiAgLyoqXG4gICAqIENyaXRlcmlhIGZvciBzZWxlY3Rpbmcgc3RhY2tzIHRvIGRlcGxveVxuICAgKi9cbiAgc2VsZWN0b3I6IFN0YWNrU2VsZWN0b3I7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gc2tpcCBwcm9tcHRpbmcgZm9yIGNvbmZpcm1hdGlvblxuICAgKi9cbiAgZm9yY2U6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBhcm4gb2YgdGhlIElBTSByb2xlIHRvIHVzZVxuICAgKi9cbiAgcm9sZUFybj86IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgZGVzdHJveSByZXF1ZXN0IGNhbWUgZnJvbSBhIGRlcGxveS5cbiAgICovXG4gIGZyb21EZXBsb3k/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBNYXhpbXVtIG51bWJlciBvZiBzaW11bHRhbmVvdXMgZGVzdHJveXMgKGRlcGVuZGVuY3kgcGVybWl0dGluZykgdG8gZXhlY3V0ZS5cbiAgICovXG4gIGNvbmN1cnJlbmN5PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHVzZSBDbG91ZEZvcm1hdGlvbiBleHByZXNzIG1vZGUgdG8gZGVsZXRlIHRoZSBzdGFjayhzKVxuICAgKi9cbiAgZXhwcmVzcz86IGJvb2xlYW47XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgdGhlIGdhcmJhZ2UgY29sbGVjdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdhcmJhZ2VDb2xsZWN0aW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgYWN0aW9uIHRvIHBlcmZvcm0uXG4gICAqXG4gICAqIEBkZWZhdWx0ICdmdWxsJ1xuICAgKi9cbiAgcmVhZG9ubHkgYWN0aW9uOiAncHJpbnQnIHwgJ3RhZycgfCAnZGVsZXRlLXRhZ2dlZCcgfCAnZnVsbCc7XG5cbiAgLyoqXG4gICAqIFRoZSB0eXBlIG9mIHRoZSBhc3NldHMgdG8gYmUgZ2FyYmFnZSBjb2xsZWN0ZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0ICdhbGwnXG4gICAqL1xuICByZWFkb25seSB0eXBlOiAnczMnIHwgJ2VjcicgfCAnYWxsJztcblxuICAvKipcbiAgICogRWxhcHNlZCB0aW1lIGJldHdlZW4gYW4gYXNzZXQgYmVpbmcgbWFya2VkIGFzIGlzb2xhdGVkIGFuZCBhY3R1YWxseSBkZWxldGVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAwXG4gICAqL1xuICByZWFkb25seSByb2xsYmFja0J1ZmZlckRheXM6IG51bWJlcjtcblxuICAvKipcbiAgICogUmVmdXNlIGRlbGV0aW9uIG9mIGFueSBhc3NldHMgeW91bmdlciB0aGFuIHRoaXMgbnVtYmVyIG9mIGRheXMuXG4gICAqL1xuICByZWFkb25seSBjcmVhdGVkQnVmZmVyRGF5czogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgc3RhY2sgbmFtZSBvZiB0aGUgYm9vdHN0cmFwIHN0YWNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCBERUZBVUxUX1RPT0xLSVRfU1RBQ0tfTkFNRVxuICAgKi9cbiAgcmVhZG9ubHkgYm9vdHN0cmFwU3RhY2tOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBTa2lwcyB0aGUgcHJvbXB0IGJlZm9yZSBhY3R1YWwgZGVsZXRpb24gYmVnaW5zXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBjb25maXJtPzogYm9vbGVhbjtcbn1cbmV4cG9ydCBpbnRlcmZhY2UgTWlncmF0ZU9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIG5hbWUgYXNzaWduZWQgdG8gdGhlIGdlbmVyYXRlZCBzdGFjay4gVGhpcyBpcyBhbHNvIHVzZWQgdG8gZ2V0XG4gICAqIHRoZSBzdGFjayBmcm9tIHRoZSB1c2VyJ3MgYWNjb3VudCBpZiBgLS1mcm9tLXN0YWNrYCBpcyB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhY2tOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSB0YXJnZXQgbGFuZ3VhZ2UgZm9yIHRoZSBnZW5lcmF0ZWQgdGhlIENESyBhcHAuXG4gICAqXG4gICAqIEBkZWZhdWx0IHR5cGVzY3JpcHRcbiAgICovXG4gIHJlYWRvbmx5IGxhbmd1YWdlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbG9jYWwgcGF0aCBvZiB0aGUgdGVtcGxhdGUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgQ0RLIGFwcC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBMb2NhbCBwYXRoIGlzIG5vdCB1c2VkIGZvciB0aGUgdGVtcGxhdGUgc291cmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgZnJvbVBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZ2V0IHRoZSB0ZW1wbGF0ZSBmcm9tIGFuIGV4aXN0aW5nIENsb3VkRm9ybWF0aW9uIHN0YWNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgZnJvbVN0YWNrPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIG91dHB1dCBwYXRoIGF0IHdoaWNoIHRvIGNyZWF0ZSB0aGUgQ0RLIGFwcC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBUaGUgY3VycmVudCBkaXJlY3RvcnlcbiAgICovXG4gIHJlYWRvbmx5IG91dHB1dFBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBhY2NvdW50IGZyb20gd2hpY2ggdG8gcmV0cmlldmUgdGhlIHRlbXBsYXRlIG9mIHRoZSBDbG91ZEZvcm1hdGlvbiBzdGFjay5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBVc2VzIHRoZSBhY2NvdW50IGZvciB0aGUgY3JlZGVudGlhbHMgaW4gdXNlIGJ5IHRoZSB1c2VyLlxuICAgKi9cbiAgcmVhZG9ubHkgYWNjb3VudD86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHJlZ2lvbiBmcm9tIHdoaWNoIHRvIHJldHJpZXZlIHRoZSB0ZW1wbGF0ZSBvZiB0aGUgQ2xvdWRGb3JtYXRpb24gc3RhY2suXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVXNlcyB0aGUgZGVmYXVsdCByZWdpb24gZm9yIHRoZSBjcmVkZW50aWFscyBpbiB1c2UgYnkgdGhlIHVzZXIuXG4gICAqL1xuICByZWFkb25seSByZWdpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEZpbHRlcmluZyBjcml0ZXJpYSB1c2VkIHRvIHNlbGVjdCB0aGUgcmVzb3VyY2VzIHRvIGJlIGluY2x1ZGVkIGluIHRoZSBnZW5lcmF0ZWQgQ0RLIGFwcC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBJbmNsdWRlIGFsbCByZXNvdXJjZXNcbiAgICovXG4gIHJlYWRvbmx5IGZpbHRlcj86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGluaXRpYXRlIGEgbmV3IGFjY291bnQgc2NhbiBmb3IgZ2VuZXJhdGluZyB0aGUgQ0RLIGFwcC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGZyb21TY2FuPzogRnJvbVNjYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gemlwIHRoZSBnZW5lcmF0ZWQgY2RrIGFwcCBmb2xkZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBjb21wcmVzcz86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVmYWN0b3JPcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gb25seSBzaG93IHRoZSBwcm9wb3NlZCByZWZhY3Rvciwgd2l0aG91dCBhcHBseWluZyBpdFxuICAgKi9cbiAgcmVhZG9ubHkgZHJ5UnVuOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaGUgYWJzb2x1dGUgcGF0aCB0byBhIGZpbGUgdGhhdCBjb250YWlucyBvdmVycmlkZXMgdG8gdGhlIG1hcHBpbmdzXG4gICAqIGNvbXB1dGVkIGJ5IHRoZSBDTEkuIFRoaXMgZmlsZSBzaG91bGQgY29udGFpbiBhIEpTT04gb2JqZWN0IHdpdGhcbiAgICogdGhlIGZvbGxvd2luZyBmb3JtYXQ6XG4gICAqXG4gICAqICAgICB7XG4gICAqICAgICAgIFwiZW52aXJvbm1lbnRzXCI6IFtcbiAgICogICAgICAgICB7XG4gICAqICAgICAgICAgICBcImFjY291bnRcIjogXCIxMjM0NTY3ODkwMTJcIixcbiAgICogICAgICAgICAgIFwicmVnaW9uXCI6IFwidXMtZWFzdC0xXCIsXG4gICAqICAgICAgICAgICBcInJlc291cmNlc1wiOiB7XG4gICAqICAgICAgICAgICAgIFwiRm9vLk9sZE5hbWVcIjogXCJCYXIuTmV3TmFtZVwiLFxuICAgKiAgICAgICAgICAgfVxuICAgKiAgICAgICAgIH0sXG4gICAqICAgICAgIF1cbiAgICogICAgIH1cbiAgICpcbiAgICogd2hlcmUgbWFwcGluZ3MgYXJlIGdyb3VwZWQgYnkgZW52aXJvbm1lbnQuIFRoZSBgcmVzb3VyY2VzYCBvYmplY3QgY29udGFpbnNcbiAgICogYSBtYXBwaW5nIHdoZXJlIGVhY2gga2V5IGlzIHRoZSBzb3VyY2UgbG9jYXRpb24gYW5kIHRoZSB2YWx1ZSBpcyB0aGVcbiAgICogZGVzdGluYXRpb24gbG9jYXRpb24uIExvY2F0aW9ucyBtdXN0IGJlIGluIHRoZSBmb3JtYXQgYFN0YWNrTmFtZS5Mb2dpY2FsSWRgLlxuICAgKiBUaGUgc291cmNlIG11c3QgcmVmZXIgdG8gYSBsb2NhdGlvbiB3aGVyZSB0aGVyZSBpcyBhIHJlc291cmNlIGN1cnJlbnRseVxuICAgKiBkZXBsb3llZCwgd2hpbGUgdGhlIGRlc3RpbmF0aW9uIG11c3QgcmVmZXIgdG8gYSBsb2NhdGlvbiB0aGF0IGlzIG5vdCBhbHJlYWR5XG4gICAqIG9jY3VwaWVkIGJ5IGFueSByZXNvdXJjZS5cbiAgICovXG4gIG92ZXJyaWRlRmlsZT86IHN0cmluZztcblxuICAvKipcbiAgICogTW9kaWZpZXMgdGhlIGJlaGF2aW9yIG9mIHRoZSBgb3ZlcnJpZGVGaWxlYCBvcHRpb24gYnkgc3dhcHBpbmcgc291cmNlIGFuZFxuICAgKiBkZXN0aW5hdGlvbiBsb2NhdGlvbnMuIFRoaXMgaXMgdXNlZnVsIHdoZW4geW91IHdhbnQgdG8gdW5kbyBhIHJlZmFjdG9yXG4gICAqIHRoYXQgd2FzIHByZXZpb3VzbHkgYXBwbGllZC5cbiAgICovXG4gIHJldmVydD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZG8gdGhlIHJlZmFjdG9yIHdpdGhvdXQgcHJvbXB0aW5nIHRoZSB1c2VyIGZvciBjb25maXJtYXRpb24uXG4gICAqL1xuICBmb3JjZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENyaXRlcmlhIGZvciBzZWxlY3Rpbmcgc3RhY2tzIHRvIGNvbXBhcmUgd2l0aCB0aGUgZGVwbG95ZWQgc3RhY2tzIGluIHRoZVxuICAgKiB0YXJnZXQgZW52aXJvbm1lbnQuXG4gICAqL1xuICBzdGFja3M/OiBTdGFja1NlbGVjdG9yO1xuXG4gIC8qKlxuICAgKiBBIGxpc3Qgb2YgbmFtZXMgb2YgYWRkaXRpb25hbCBkZXBsb3llZCBzdGFja3MgdG8gYmUgaW5jbHVkZWQgaW4gdGhlIGNvbXBhcmlzb24uXG4gICAqL1xuICBhZGRpdGlvbmFsU3RhY2tOYW1lcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBSb2xlIHRvIGFzc3VtZSBpbiB0aGUgdGFyZ2V0IGVudmlyb25tZW50IGJlZm9yZSBwZXJmb3JtaW5nIHRoZSByZWZhY3Rvci5cbiAgICovXG4gIHJvbGVBcm4/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgdGhlIGRyaWZ0IGNvbW1hbmRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEcmlmdE9wdGlvbnMge1xuICAvKipcbiAgICogQ3JpdGVyaWEgZm9yIHNlbGVjdGluZyBzdGFja3MgdG8gZGV0ZWN0IGRyaWZ0IG9uXG4gICAqL1xuICByZWFkb25seSBzZWxlY3RvcjogU3RhY2tTZWxlY3RvcjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBmYWlsIHdpdGggZXhpdCBjb2RlIDEgaWYgZHJpZnQgaXMgZGV0ZWN0ZWRcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGZhaWw/OiBib29sZWFuO1xufVxuXG5mdW5jdGlvbiBidWlsZFBhcmFtZXRlck1hcChcbiAgcGFyYW1ldGVyczpcbiAgICB8IHtcbiAgICAgIFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHwgdW5kZWZpbmVkLFxuKTogeyBbbmFtZTogc3RyaW5nXTogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH0gfSB7XG4gIGNvbnN0IHBhcmFtZXRlck1hcDoge1xuICAgIFtuYW1lOiBzdHJpbmddOiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWQgfTtcbiAgfSA9IHsgJyonOiB7fSB9O1xuICBmb3IgKGNvbnN0IGtleSBpbiBwYXJhbWV0ZXJzKSB7XG4gICAgaWYgKHBhcmFtZXRlcnMuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgY29uc3QgW3N0YWNrLCBwYXJhbWV0ZXJdID0ga2V5LnNwbGl0KCc6JywgMik7XG4gICAgICBpZiAoIXBhcmFtZXRlcikge1xuICAgICAgICBwYXJhbWV0ZXJNYXBbJyonXVtzdGFja10gPSBwYXJhbWV0ZXJzW2tleV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoIXBhcmFtZXRlck1hcFtzdGFja10pIHtcbiAgICAgICAgICBwYXJhbWV0ZXJNYXBbc3RhY2tdID0ge307XG4gICAgICAgIH1cbiAgICAgICAgcGFyYW1ldGVyTWFwW3N0YWNrXVtwYXJhbWV0ZXJdID0gcGFyYW1ldGVyc1trZXldO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBwYXJhbWV0ZXJNYXA7XG59XG5cbi8qKlxuICogQXNrIHRoZSB1c2VyIGZvciBhIHllcy9ubyBjb25maXJtYXRpb25cbiAqXG4gKiBBdXRvbWF0aWNhbGx5IGZhaWwgdGhlIGNvbmZpcm1hdGlvbiBpbiBjYXNlIHdlJ3JlIGluIGEgc2l0dWF0aW9uIHdoZXJlIHRoZSBjb25maXJtYXRpb25cbiAqIGNhbm5vdCBiZSBpbnRlcmFjdGl2ZWx5IG9idGFpbmVkIGZyb20gYSBodW1hbiBhdCB0aGUga2V5Ym9hcmQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGFza1VzZXJDb25maXJtYXRpb24oXG4gIGlvSG9zdDogQ2xpSW9Ib3N0LFxuICByZXE6IEFjdGlvbkxlc3NSZXF1ZXN0PENvbmZpcm1hdGlvblJlcXVlc3QsIGJvb2xlYW4+LFxuICBhYm9ydEVycm9yQ29kZTogc3RyaW5nLFxuICBhYm9ydE1lc3NhZ2U6IHN0cmluZyxcbikge1xuICBhd2FpdCBpb0hvc3Qud2l0aENvcmtlZExvZ2dpbmcoYXN5bmMgKCkgPT4ge1xuICAgIC8vIFRoZSBJb0hvc3QgcmV0dXJucyB0aGUgYW5zd2VyIHJhdGhlciB0aGFuIGFib3J0aW5nOyBhYm9ydCBoZXJlIG9uIGRlY2xpbmUuXG4gICAgY29uc3QgY29uZmlybWVkID0gYXdhaXQgaW9Ib3N0LmFzSW9IZWxwZXIoKS5yZXF1ZXN0UmVzcG9uc2UocmVxKTtcbiAgICBpZiAoIWNvbmZpcm1lZCkge1xuICAgICAgdGhyb3cgbmV3IEFib3J0RXJyb3IoYWJvcnRFcnJvckNvZGUsIGFib3J0TWVzc2FnZSk7XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBEaXNwbGF5IGEgd2FybmluZyBpZiB0aGVyZSBhcmUgZmxhZ3MgdGhhdCBhcmUgZGlmZmVyZW50IGZyb20gdGhlIHJlY29tbWVuZGVkIHZhbHVlXG4gKlxuICogVGhpcyBoYXBwZW5zIGlmIGJvdGggb2YgdGhlIGZvbGxvd2luZyBhcmUgdHJ1ZTpcbiAqXG4gKiAtIFRoZSB1c2VyIGRpZG4ndCBjb25maWd1cmUgdGhlIHZhbHVlXG4gKiAtIFRoZSBkZWZhdWx0IHZhbHVlIGZvciB0aGUgZmxhZyAodW5jb25maWd1cmVkQmVoYXZlc0xpa2UpIGlzIGRpZmZlcmVudCBmcm9tIHRoZSByZWNvbW1lbmRlZCB2YWx1ZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGlzcGxheUZsYWdzTWVzc2FnZShpb0hvc3Q6IElvSGVscGVyLCB0b29sa2l0OiBJbnRlcm5hbFRvb2xraXQsIGNsb3VkRXhlY3V0YWJsZTogQ2xvdWRFeGVjdXRhYmxlKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGZsYWdzID0gYXdhaXQgdG9vbGtpdC5mbGFncyhjbG91ZEV4ZWN1dGFibGUpO1xuXG4gIC8vIFRoZSBcInVuY29uZmlndXJlZEJlaGF2ZXNMaWtlXCIgaW5mb3JtYXRpb24gZ290IGFkZGVkIGxhdGVyLiBJZiBub25lIG9mIHRoZSBmbGFncyBoYXZlIHRoaXMgaW5mb3JtYXRpb24sXG4gIC8vIHdlIGRvbid0IGhhdmUgZW5vdWdoIGluZm9ybWF0aW9uIHRvIHJlbGlhYmx5IGRpc3BsYXkgdGhpcyBpbmZvcm1hdGlvbiB3aXRob3V0IHNjYXJpbmcgdXNlcnMsIHNvIGRvbid0IGRvIGFueXRoaW5nLlxuICBpZiAoZmxhZ3MuZXZlcnkoZmxhZyA9PiBmbGFnLnVuY29uZmlndXJlZEJlaGF2ZXNMaWtlID09PSB1bmRlZmluZWQpKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgdW5jb25maWd1cmVkRmxhZ3MgPSBGbGFnT3BlcmF0aW9ucy5maWx0ZXJOZWVkc0F0dGVudGlvbihmbGFncyk7XG4gIGNvbnN0IG51bVVuY29uZmlndXJlZCA9IHVuY29uZmlndXJlZEZsYWdzLmxlbmd0aDtcblxuICBpZiAobnVtVW5jb25maWd1cmVkID4gMCkge1xuICAgIGF3YWl0IGlvSG9zdC5kZWZhdWx0cy53YXJuKGAke251bVVuY29uZmlndXJlZH0gZmVhdHVyZSBmbGFncyBhcmUgbm90IGNvbmZpZ3VyZWQuIFJ1biAnY2RrIGZsYWdzIC0tdW5zdGFibGU9ZmxhZ3MnIHRvIGxlYXJuIG1vcmUuYCk7XG4gIH1cbn1cblxuaW50ZXJmYWNlIFdvcmtHcmFwaERlcGxveW1lbnRBY3Rpb25zT3B0aW9ucyB7XG4gIHJlYWRvbmx5IHJvbGVBcm4/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGZvcmNlPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc3RhY2tDb3VudD86IG51bWJlcjtcbiAgcmVhZG9ubHkgbm90aWZpY2F0aW9uQXJucz86IHN0cmluZ1tdO1xuICByZWFkb25seSBkZXBsb3ltZW50TWV0aG9kPzogRGVwbG95bWVudE1ldGhvZDtcbiAgcmVhZG9ubHkgdG9vbGtpdFN0YWNrTmFtZT86IHN0cmluZztcbiAgcmVhZG9ubHkgcmV1c2VBc3NldHM/OiBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgdGFncz86IFRhZ1tdO1xuICByZWFkb25seSBwYXJhbWV0ZXJzPzogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH07XG4gIHJlYWRvbmx5IHVzZVByZXZpb3VzUGFyYW1ldGVycz86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHJvbGxiYWNrPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZXh0cmFVc2VyQWdlbnQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGFzc2V0UGFyYWxsZWxpc20/OiBib29sZWFuO1xuICByZWFkb25seSByZXF1aXJlQXBwcm92YWw6IFJlcXVpcmVBcHByb3ZhbDtcbiAgcmVhZG9ubHkgY29uY3VycmVuY3k6IG51bWJlcjtcbiAgcmVhZG9ubHkgY2xvdWRXYXRjaExvZ01vbml0b3I/OiBDbG91ZFdhdGNoTG9nRXZlbnRNb25pdG9yO1xuICByZWFkb25seSBzZGtQcm92aWRlcjogU2RrUHJvdmlkZXI7XG4gIHJlYWRvbmx5IGV4cHJlc3M/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIFRoaXMgY2xhc3MgaW1wbGVtZW50cyB0aGUgY2FsbGJhY2tzIGZvciB0aGUgcGFyYWxsZWwgd29yayBncmFwaCBleGVjdXRpb25zLlxuICpcbiAqIEFsbCB0aGlzIGNvZGUgdXNlZCB0byBiZSBpbmxpbmVkIGludG8gQ2RrVG9vbGtpdCNkZXBsb3koKSwgYnV0IGl0IHdhcyBnZXR0aW5nXG4gKiB0b28gbXVjaCB0byBsaXZlIGluIHRoZXJlLlxuICovXG5jbGFzcyBXb3JrR3JhcGhEZXBsb3ltZW50QWN0aW9ucyBpbXBsZW1lbnRzIFdvcmtHcmFwaEFjdGlvbnMge1xuICBwcml2YXRlIHJlYWRvbmx5IHN0YWNrT3V0cHV0czogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHt9O1xuICBwcml2YXRlIHJlYWRvbmx5IGFzc2V0U3BhbnM6IFJlY29yZDxzdHJpbmcsIElNZXNzYWdlU3BhbjxFdmVudFJlc3VsdD4+ID0ge307XG4gIHByaXZhdGUgc3RhY2tDb3VudGVyID0gMTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGRlcGxveW1lbnRzOiBEZXBsb3ltZW50cyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGlvSG9zdDogQ2xpSW9Ib3N0LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RhY2tPcGVyYXRpb25zOiBQaWNrPENka1Rvb2xraXQsICdkZXN0cm95JyB8ICdyb2xsYmFjayc+LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogV29ya0dyYXBoRGVwbG95bWVudEFjdGlvbnNPcHRpb25zLFxuICApIHtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBtYXJrZXIobWFya2VyTm9kZTogTWFya2VyTm9kZSkge1xuICAgIC8vIEZvciBhc3NldHMsIGVtaXQgSW9Ib3N0IG1lc3NhZ2VzIHRoYXQgaGF2ZSBiZWVuIGRlZmluZWQgdG8gc3RhcnQgYW5kIGVuZCBhc3NldCBzcGFucywgd2hpY2ggd2lsbCBsZWFkIHRvIGV2ZW50cyBpbiB0ZWxlbWV0cnkuXG4gICAgc3dpdGNoIChtYXJrZXJOb2RlLm1hcmtlci50eXBlKSB7XG4gICAgICBjYXNlICdzdGFydC1hc3NldCc6IHtcbiAgICAgICAgY29uc3QgYXNzZXRTcGFuID0gYXdhaXQgdGhpcy5vYnRhaW5TcGFuKG1hcmtlck5vZGUubWFya2VyLmFzc2V0KTtcblxuICAgICAgICAvLyBDb3VudCB0aGUgYXNzZXQgdHlwZSwgYm90aCBvbiB0aGUgYXNzZXQtc3BlY2lmaWMgc3BhbiBhbmQgb24gdGhlIGdsb2JhbCBDT01NQU5EIHNwYW4uXG4gICAgICAgIGlmIChtYXJrZXJOb2RlLm1hcmtlci5hc3NldC50eXBlID09PSAnZmlsZScpIHtcbiAgICAgICAgICB0aGlzLmlvSG9zdC50ZWxlbWV0cnk/LmNvbW1hbmRTcGFuPy5pbmNDb3VudGVyKCdmaWxlQXNzZXQnKTtcbiAgICAgICAgICBhc3NldFNwYW4uaW5jQ291bnRlcignZmlsZUFzc2V0Jyk7XG4gICAgICAgIH0gZWxzZSBpZiAobWFya2VyTm9kZS5tYXJrZXIuYXNzZXQudHlwZSA9PT0gJ2RvY2tlcicpIHtcbiAgICAgICAgICB0aGlzLmlvSG9zdC50ZWxlbWV0cnk/LmNvbW1hbmRTcGFuPy5pbmNDb3VudGVyKCdkb2NrZXJBc3NldCcpO1xuICAgICAgICAgIGFzc2V0U3Bhbi5pbmNDb3VudGVyKCdkb2NrZXJBc3NldCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICdlbmQtYXNzZXQnOiB7XG4gICAgICAgIGNvbnN0IGFzc2V0U3BhbiA9IGF3YWl0IHRoaXMub2J0YWluU3BhbihtYXJrZXJOb2RlLm1hcmtlci5hc3NldCk7XG4gICAgICAgIGF3YWl0IGFzc2V0U3Bhbi5lbmQoe30pO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIG9idGFpblNwYW4oYXNzZXRFbnRyeTogSU1hbmlmZXN0RW50cnkpOiBQcm9taXNlPElNZXNzYWdlU3BhbjxFdmVudFJlc3VsdD4+IHtcbiAgICBjb25zdCBzcGFuID0gdGhpcy5hc3NldFNwYW5zW2Fzc2V0RW50cnkuaWQuYXNzZXRJZF07XG4gICAgaWYgKHNwYW4pIHtcbiAgICAgIHJldHVybiBzcGFuO1xuICAgIH1cbiAgICBjb25zdCBhc3NldFNwYW4gPSBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuc3BhbihDTElfUFJJVkFURV9TUEFOLkFTU0VUKS5iZWdpbih7fSk7XG4gICAgdGhpcy5hc3NldFNwYW5zW2Fzc2V0RW50cnkuaWQuYXNzZXRJZF0gPSBhc3NldFNwYW47XG4gICAgcmV0dXJuIGFzc2V0U3BhbjtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBidWlsZEFzc2V0KGFzc2V0Tm9kZTogQXNzZXRCdWlsZE5vZGUpIHtcbiAgICAvLyBNZWFzdXJlIGFzc2V0IGJ1aWxkIHRpbWUuIEJvdGggb24gdGhlIGdsb2JhbCBDT01NQU5EIHNwYW4gYXMgd2VsbCBhcyBvbiB0aGUgYXNzZXQtc3BlY2lmaWMgc3Bhbi5cbiAgICAvLyAocGFyYWxsZWxpc20gbWF5IGNhdXNlIFNVTShidWlsZEFzc2V0U1QpID49IHRvdGFsRGVwbG95VGltZSkgb24gdGhlIENPTU1BTkQgc3BhbiwgaW5kaWNhdGUgd2l0aCBbU111YltUXWFzayBzdWZmaXgpLlxuICAgIHVzaW5nIF9pbnZva2VUaW1lciA9IHRoaXMuaW9Ib3N0LnRlbGVtZXRyeT8uY29tbWFuZFNwYW4/LnN0YXJ0VGltZXIoJ2J1aWxkQXNzZXRTVCcpO1xuICAgIHVzaW5nIF9hc3NldFRpbWVyID0gKGF3YWl0IHRoaXMub2J0YWluU3Bhbihhc3NldE5vZGUuYXNzZXQpKS5zdGFydFRpbWVyKCdidWlsZEFzc2V0Jyk7XG5cbiAgICBhd2FpdCB0aGlzLmRlcGxveW1lbnRzLmJ1aWxkU2luZ2xlQXNzZXQoXG4gICAgICBhc3NldE5vZGUuYXNzZXRNYW5pZmVzdEFydGlmYWN0LFxuICAgICAgYXNzZXROb2RlLmFzc2V0TWFuaWZlc3QsXG4gICAgICBhc3NldE5vZGUuYXNzZXQsXG4gICAgICB7XG4gICAgICAgIHN0YWNrOiBhc3NldE5vZGUucGFyZW50U3RhY2ssXG4gICAgICAgIHJvbGVBcm46IHRoaXMub3B0aW9ucy5yb2xlQXJuLFxuICAgICAgICBzdGFja05hbWU6IGFzc2V0Tm9kZS5wYXJlbnRTdGFjay5zdGFja05hbWUsXG4gICAgICB9LFxuICAgICk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgcHVibGlzaEFzc2V0KGFzc2V0Tm9kZTogQXNzZXRQdWJsaXNoTm9kZSkge1xuICAgIC8vIE1lYXN1cmUgYXNzZXQgcHVibGlzaCB0aW1lLiBCb3RoIG9uIHRoZSBnbG9iYWwgQ09NTUFORCBzcGFuIGFzIHdlbGwgYXMgb24gdGhlIGFzc2V0LXNwZWNpZmljIHNwYW4uXG4gICAgLy8gKHBhcmFsbGVsaXNtIG1heSBjYXVzZSBTVU0ocHVibGlzaEFzc2V0U1QpID49IHRvdGFsRGVwbG95VGltZSkgb24gdGhlIENPTU1BTkQgc3BhbiwgaW5kaWNhdGUgd2l0aCBbU111YltUXWFzayBzdWZmaXgpLlxuICAgIHVzaW5nIF9pbnZva2VUaW1lciA9IHRoaXMuaW9Ib3N0LnRlbGVtZXRyeT8uY29tbWFuZFNwYW4/LnN0YXJ0VGltZXIoJ3B1Ymxpc2hBc3NldFNUJyk7XG4gICAgdXNpbmcgX2Fzc2V0VGltZXIgPSAoYXdhaXQgdGhpcy5vYnRhaW5TcGFuKGFzc2V0Tm9kZS5hc3NldCkpLnN0YXJ0VGltZXIoJ3B1Ymxpc2hBc3NldCcpO1xuXG4gICAgYXdhaXQgdGhpcy5kZXBsb3ltZW50cy5wdWJsaXNoU2luZ2xlQXNzZXQoYXNzZXROb2RlLmFzc2V0TWFuaWZlc3QsIGFzc2V0Tm9kZS5hc3NldCwge1xuICAgICAgc3RhY2s6IGFzc2V0Tm9kZS5wYXJlbnRTdGFjayxcbiAgICAgIHJvbGVBcm46IHRoaXMub3B0aW9ucy5yb2xlQXJuLFxuICAgICAgc3RhY2tOYW1lOiBhc3NldE5vZGUucGFyZW50U3RhY2suc3RhY2tOYW1lLFxuICAgICAgZm9yY2VQdWJsaXNoOiB0aGlzLm9wdGlvbnMuZm9yY2UsXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZGVwbG95U3RhY2soc3RhY2tOb2RlOiBTdGFja05vZGUpIHtcbiAgICAvLyBDb3VudGVyIGZvciB0b3RhbERlcGxveWVkU3RhY2tzLCB0byBtYXRjaCAndG90YWxEZXBsb3lUaW1lJyB0aW1lciBvbiB0aGUgQ09NTUFORCBzcGFuLlxuICAgIHRoaXMuaW9Ib3N0LnRlbGVtZXRyeT8uY29tbWFuZFNwYW4/LmluY0NvdW50ZXIoJ3RvdGFsRGVwbG95ZWRTdGFja3MnKTtcblxuICAgIGNvbnN0IHN0YWNrID0gc3RhY2tOb2RlLnN0YWNrO1xuICAgIGlmICh0aGlzLm9wdGlvbnMuc3RhY2tDb3VudCAhPT0gMSkge1xuICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oY2hhbGsuYm9sZChzdGFjay5kaXNwbGF5TmFtZSkpO1xuICAgIH1cblxuICAgIGlmICghc3RhY2suZW52aXJvbm1lbnQpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAc3R5bGlzdGljL21heC1sZW5cbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXG4gICAgICAgICdNaXNzaW5nRW52aXJvbm1lbnQnLFxuICAgICAgICBgU3RhY2sgJHtzdGFjay5kaXNwbGF5TmFtZX0gZG9lcyBub3QgZGVmaW5lIGFuIGVudmlyb25tZW50LCBhbmQgQVdTIGNyZWRlbnRpYWxzIGNvdWxkIG5vdCBiZSBvYnRhaW5lZCBmcm9tIHN0YW5kYXJkIGxvY2F0aW9ucyBvciBubyByZWdpb24gd2FzIGNvbmZpZ3VyZWQuYCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzb3VyY2VDb3VudCA9IE9iamVjdC5rZXlzKHN0YWNrLnRlbXBsYXRlLlJlc291cmNlcyB8fCB7fSkubGVuZ3RoO1xuICAgIGlmIChyZXNvdXJjZUNvdW50ID09PSAwKSB7XG4gICAgICAvLyBUaGUgZ2VuZXJhdGVkIHN0YWNrIGhhcyBubyByZXNvdXJjZXNcbiAgICAgIGlmICghKGF3YWl0IHRoaXMuZGVwbG95bWVudHMuc3RhY2tFeGlzdHMoeyBzdGFjayB9KSkpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLndhcm4oJyVzOiBzdGFjayBoYXMgbm8gcmVzb3VyY2VzLCBza2lwcGluZyBkZXBsb3ltZW50LicsIGNoYWxrLmJvbGQoc3RhY2suZGlzcGxheU5hbWUpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy53YXJuKCclczogc3RhY2sgaGFzIG5vIHJlc291cmNlcywgZGVsZXRpbmcgZXhpc3Rpbmcgc3RhY2suJywgY2hhbGsuYm9sZChzdGFjay5kaXNwbGF5TmFtZSkpO1xuICAgICAgICBhd2FpdCB0aGlzLnN0YWNrT3BlcmF0aW9ucy5kZXN0cm95KHtcbiAgICAgICAgICBzZWxlY3Rvcjogc2VsZWN0RXhhY3Qoc3RhY2suaGllcmFyY2hpY2FsSWQpLFxuICAgICAgICAgIGZvcmNlOiB0cnVlLFxuICAgICAgICAgIHJvbGVBcm46IHRoaXMub3B0aW9ucy5yb2xlQXJuLFxuICAgICAgICAgIGZyb21EZXBsb3k6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEZvbGxvd2luZyBhcmUgdGhlIHNhbWUgc2VtYW50aWNzIHdlIGFwcGx5IHdpdGggcmVzcGVjdCB0byBOb3RpZmljYXRpb24gQVJOcyAoZGljdGF0ZWQgYnkgdGhlIFNESylcbiAgICAvL1xuICAgIC8vICAtIHVuZGVmaW5lZCAgPT4gIGNkayBpZ25vcmVzIGl0LCBhcyBpZiBpdCB3YXNuJ3Qgc3VwcG9ydGVkIChhbGxvd3MgZXh0ZXJuYWwgbWFuYWdlbWVudCkuXG4gICAgLy8gIC0gW106ICAgICAgICA9PiAgY2RrIG1hbmFnZXMgaXQsIGFuZCB0aGUgdXNlciB3YW50cyB0byB3aXBlIGl0IG91dC5cbiAgICAvLyAgLSBbJ2Fybi0xJ10gID0+ICBjZGsgbWFuYWdlcyBpdCwgYW5kIHRoZSB1c2VyIHdhbnRzIHRvIHNldCBpdCB0byBbJ2Fybi0xJ10uXG4gICAgY29uc3Qgbm90aWZpY2F0aW9uQXJucyA9ICghIXRoaXMub3B0aW9ucy5ub3RpZmljYXRpb25Bcm5zIHx8ICEhc3RhY2subm90aWZpY2F0aW9uQXJucylcbiAgICAgID8gKHRoaXMub3B0aW9ucy5ub3RpZmljYXRpb25Bcm5zID8/IFtdKS5jb25jYXQoc3RhY2subm90aWZpY2F0aW9uQXJucyA/PyBbXSlcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgZm9yIChjb25zdCBub3RpZmljYXRpb25Bcm4gb2Ygbm90aWZpY2F0aW9uQXJucyA/PyBbXSkge1xuICAgICAgaWYgKCF2YWxpZGF0ZVNuc1RvcGljQXJuKG5vdGlmaWNhdGlvbkFybikpIHtcbiAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignSW52YWxpZFNuc1RvcGljQXJuJywgYE5vdGlmaWNhdGlvbiBhcm4gJHtub3RpZmljYXRpb25Bcm59IGlzIG5vdCBhIHZhbGlkIGFybiBmb3IgYW4gU05TIHRvcGljYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgcGFyYW1ldGVyTWFwID0gYnVpbGRQYXJhbWV0ZXJNYXAodGhpcy5vcHRpb25zLnBhcmFtZXRlcnMpO1xuXG4gICAgLy8gRGVwbG95IG9wdGlvbnMgdGhhdCBhcmUgc2hhcmVkIGJldHdlZW4gY2hhbmdlIHNldCBjcmVhdGlvbiBhbmQgZXhlY3V0aW9uXG4gICAgY29uc3Qgc2hhcmVkRGVwbG95T3B0aW9ucyA9IHtcbiAgICAgIHN0YWNrLFxuICAgICAgZGVwbG95TmFtZTogc3RhY2suc3RhY2tOYW1lLFxuICAgICAgcm9sZUFybjogdGhpcy5vcHRpb25zLnJvbGVBcm4sXG4gICAgICB0b29sa2l0U3RhY2tOYW1lOiB0aGlzLm9wdGlvbnMudG9vbGtpdFN0YWNrTmFtZSxcbiAgICAgIHJldXNlQXNzZXRzOiB0aGlzLm9wdGlvbnMucmV1c2VBc3NldHMsXG4gICAgICB0YWdzOiAodGhpcy5vcHRpb25zLnRhZ3M/Lmxlbmd0aCA/IHRoaXMub3B0aW9ucy50YWdzIDogdGFnc0ZvclN0YWNrKHN0YWNrKSksXG4gICAgICBmb3JjZURlcGxveW1lbnQ6IHRoaXMub3B0aW9ucy5mb3JjZSxcbiAgICAgIHBhcmFtZXRlcnM6IE9iamVjdC5hc3NpZ24oe30sIHBhcmFtZXRlck1hcFsnKiddLCBwYXJhbWV0ZXJNYXBbc3RhY2suc3RhY2tOYW1lXSksXG4gICAgICB1c2VQcmV2aW91c1BhcmFtZXRlcnM6IHRoaXMub3B0aW9ucy51c2VQcmV2aW91c1BhcmFtZXRlcnMsXG4gICAgICByb2xsYmFjazogdGhpcy5vcHRpb25zLnJvbGxiYWNrLFxuICAgICAgbm90aWZpY2F0aW9uQXJucyxcbiAgICAgIGV4dHJhVXNlckFnZW50OiB0aGlzLm9wdGlvbnMuZXh0cmFVc2VyQWdlbnQsXG4gICAgICBhc3NldFBhcmFsbGVsaXNtOiB0aGlzLm9wdGlvbnMuYXNzZXRQYXJhbGxlbGlzbSxcbiAgICAgIGV4cHJlc3M6IHRoaXMub3B0aW9ucy5leHByZXNzLFxuICAgIH07XG5cbiAgICAvLyBXaGVuIHVzaW5nIGNoYW5nZS1zZXQgbWV0aG9kLCBhbHdheXMgY3JlYXRlIHRoZSBjaGFuZ2Ugc2V0IHVwZnJvbnQuXG4gICAgLy8gVGhpcyBnaXZlcyB1cyBhbiBhY2N1cmF0ZSBkaWZmIGZvciBhcHByb3ZhbCBhbmQgYXZvaWRzIGNyZWF0aW5nIGl0IHR3aWNlLlxuICAgIC8vIEZvciBub24tZXhlY3V0aW5nIGRlcGxveW1lbnRzIChwcmVwYXJlLWNoYW5nZS1zZXQpLCB0aGlzIGlzIHRoZSBmaW5hbCByZXN1bHQuXG4gICAgY29uc3QgcHJlcGFyZVJlc3VsdCA9IGlzQ2hhbmdlU2V0RGVwbG95bWVudCh0aGlzLm9wdGlvbnMuZGVwbG95bWVudE1ldGhvZClcbiAgICAgID8gYXdhaXQgdGhpcy5kZXBsb3ltZW50cy5wcmVwYXJlU3RhY2soe1xuICAgICAgICAuLi5zaGFyZWREZXBsb3lPcHRpb25zLFxuICAgICAgICBkZXBsb3ltZW50TWV0aG9kOiB0aGlzLm9wdGlvbnMuZGVwbG95bWVudE1ldGhvZCxcbiAgICAgICAgd2lsbEV4ZWN1dGVDaGFuZ2VTZXQ6IGlzRXhlY3V0aW5nQ2hhbmdlU2V0RGVwbG95bWVudCh0aGlzLm9wdGlvbnMuZGVwbG95bWVudE1ldGhvZCksXG4gICAgICB9KVxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICAvLyBBbHNvIHNraXAgdGhlIGFwcHJvdmFsIGZsb3cgd2hlbiB0aGUgcHJlcGFyZWQgY2hhbmdlIHNldCBpcyBhIG5vLW9wIOKAlFxuICAgIC8vIHRoZXJlIGlzIG5vdGhpbmcgZm9yIHRoZSB1c2VyIHRvIGFwcHJvdmUuIE91dHB1dHMsIHN0YWNrIEFSTiwgYW5kXG4gICAgLy8gdGltaW5ncyBhcmUgc3RpbGwgZW1pdHRlZCB2aWEgdGhlIG5vcm1hbCBuby1vcCBkZXBsb3kgcGF0aCBiZWxvdy5cbiAgICBpZiAodGhpcy5vcHRpb25zLnJlcXVpcmVBcHByb3ZhbCAhPT0gUmVxdWlyZUFwcHJvdmFsLk5FVkVSICYmICFwcmVwYXJlUmVzdWx0Py5ub09wKSB7XG4gICAgICBjb25zdCBjdXJyZW50VGVtcGxhdGUgPSBhd2FpdCB0aGlzLmRlcGxveW1lbnRzLnJlYWRDdXJyZW50VGVtcGxhdGUoc3RhY2spO1xuICAgICAgY29uc3QgZm9ybWF0dGVyID0gbmV3IERpZmZGb3JtYXR0ZXIoe1xuICAgICAgICB0ZW1wbGF0ZUluZm86IHtcbiAgICAgICAgICBvbGRUZW1wbGF0ZTogY3VycmVudFRlbXBsYXRlLFxuICAgICAgICAgIG5ld1RlbXBsYXRlOiBzdGFjayxcbiAgICAgICAgICBjaGFuZ2VTZXQ6IHByZXBhcmVSZXN1bHQ/LmNoYW5nZVNldCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3Qgc2VjdXJpdHlEaWZmID0gZm9ybWF0dGVyLmZvcm1hdFNlY3VyaXR5RGlmZigpO1xuICAgICAgaWYgKHJlcXVpcmVzQXBwcm92YWwodGhpcy5vcHRpb25zLnJlcXVpcmVBcHByb3ZhbCwgc2VjdXJpdHlEaWZmLnBlcm1pc3Npb25DaGFuZ2VUeXBlKSkge1xuICAgICAgICBjb25zdCBoYXNTZWN1cml0eUNoYW5nZXMgPSBzZWN1cml0eURpZmYucGVybWlzc2lvbkNoYW5nZVR5cGUgIT09IFBlcm1pc3Npb25DaGFuZ2VUeXBlLk5PTkU7XG4gICAgICAgIC8vIEJhcmUtZmFjdCBtb3RpdmF0aW9uLiBUaGUgSTUwNjAgbGlzdGVuZXIgcmVnaXN0ZXJlZCBpbiBgZGVwbG95KClgIGFkZHNcbiAgICAgICAgLy8gdGhlIGAtLXJlcXVpcmUtYXBwcm92YWxgIGZyYW1pbmcgZm9yIHRlcm1pbmFsIHVzZXJzLlxuICAgICAgICBjb25zdCBtb3RpdmF0aW9uID0gaGFzU2VjdXJpdHlDaGFuZ2VzXG4gICAgICAgICAgPyAnU3RhY2sgaW5jbHVkZXMgc2VjdXJpdHktc2Vuc2l0aXZlIHVwZGF0ZXMnXG4gICAgICAgICAgOiAnU3RhY2sgaW5jbHVkZXMgdXBkYXRlcyc7XG4gICAgICAgIGNvbnN0IGRpZmZPdXRwdXQgPSBoYXNTZWN1cml0eUNoYW5nZXMgPyBzZWN1cml0eURpZmYuZm9ybWF0dGVkRGlmZiA6IGZvcm1hdHRlci5mb3JtYXRTdGFja0RpZmYoKS5mb3JtYXR0ZWREaWZmO1xuICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhkaWZmT3V0cHV0KTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGFza1VzZXJDb25maXJtYXRpb24oXG4gICAgICAgICAgICB0aGlzLmlvSG9zdCxcbiAgICAgICAgICAgIElPLkNES19UT09MS0lUX0k1MDYwLnJlcShgJHttb3RpdmF0aW9ufS4gRG8geW91IHdpc2ggdG8gZGVwbG95IHRoZXNlIGNoYW5nZXM/YCwge1xuICAgICAgICAgICAgICBtb3RpdmF0aW9uLFxuICAgICAgICAgICAgICBjb25jdXJyZW5jeTogdGhpcy5vcHRpb25zLmNvbmN1cnJlbmN5LFxuICAgICAgICAgICAgICBwZXJtaXNzaW9uQ2hhbmdlVHlwZTogc2VjdXJpdHlEaWZmLnBlcm1pc3Npb25DaGFuZ2VUeXBlLFxuICAgICAgICAgICAgICB0ZW1wbGF0ZURpZmZzOiBmb3JtYXR0ZXIuZGlmZnMsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICdEZXBsb3lBYm9ydGVkJyxcbiAgICAgICAgICAgICdEZXBsb3ltZW50IGNhbmNlbGxlZCcsXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIGlmIChwcmVwYXJlUmVzdWx0Py5jaGFuZ2VTZXQ/LkNoYW5nZVNldE5hbWUpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZGVwbG95bWVudHMuY2xlYW51cENoYW5nZVNldChzdGFjaywgcHJlcGFyZVJlc3VsdC5jaGFuZ2VTZXQuQ2hhbmdlU2V0TmFtZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBzdGFja0luZGV4ID0gdGhpcy5zdGFja0NvdW50ZXIrKztcbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhgJHtjaGFsay5ib2xkKHN0YWNrLmRpc3BsYXlOYW1lKX06IGRlcGxveWluZy4uLiBbJHtzdGFja0luZGV4fS8ke3RoaXMub3B0aW9ucy5zdGFja0NvdW50fV1gKTtcbiAgICBjb25zdCBzdGFydERlcGxveVRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgIC8vIFRoZXJlIGlzIGFscmVhZHkgYSBzdGFydERlcGxveVRpbWUgY29uc3RhbnQsIGJ1dCB0aGF0IGRvZXMgbm90IHdvcmsgd2l0aCB0ZWxlbWV0cnkuXG4gICAgLy8gV2Ugc2hvdWxkIGludGVncmF0ZSB0aGUgdHdvIGluIHRoZSBmdXR1cmVcbiAgICBjb25zdCBkZXBsb3lTcGFuID0gYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLnNwYW4oQ0xJX1BSSVZBVEVfU1BBTi5ERVBMT1kpLmJlZ2luKHt9KTtcbiAgICBkZXBsb3lTcGFuLmluY0NvdW50ZXIoJ3Jlc291cmNlcycsIHJlc291cmNlQ291bnQpO1xuICAgIHRoaXMuaW9Ib3N0LnRlbGVtZXRyeT8uY29tbWFuZFNwYW4/LmluY0NvdW50ZXIoJ3RvdGFsRGVwbG95ZWRSZXNvdXJjZXMnLCByZXNvdXJjZUNvdW50KTtcbiAgICBsZXQgZXJyb3I6IEVycm9yRGV0YWlscyB8IHVuZGVmaW5lZDtcbiAgICBsZXQgZWxhcHNlZERlcGxveVRpbWUgPSAwO1xuICAgIHRyeSB7XG4gICAgICAvLyBUaGUgcHJlcGFyZSByZXN1bHQgaXMgZmluYWwgaWYgdGhlIGNoYW5nZSBzZXQgd2FzIGVtcHR5IChub09wKSBvclxuICAgICAgLy8gdGhlIGRlcGxveW1lbnQgbWV0aG9kIGlzIG5vbi1leGVjdXRpbmcgKHByZXBhcmUtY2hhbmdlLXNldCkuXG4gICAgICBjb25zdCBwcmVwYXJlSXNGaW5hbCA9IHByZXBhcmVSZXN1bHQgJiYgKHByZXBhcmVSZXN1bHQubm9PcCB8fCBpc05vbkV4ZWN1dGluZ0NoYW5nZVNldERlcGxveW1lbnQodGhpcy5vcHRpb25zLmRlcGxveW1lbnRNZXRob2QpKTtcbiAgICAgIGxldCBkZXBsb3lSZXN1bHQ6IFN1Y2Nlc3NmdWxEZXBsb3lTdGFja1Jlc3VsdCB8IHVuZGVmaW5lZCA9IHByZXBhcmVJc0ZpbmFsID8gcHJlcGFyZVJlc3VsdCA6IHVuZGVmaW5lZDtcblxuICAgICAgLy8gU3RhcnQgd2l0aCB1c2VyIGNvbmZpZyBmb3Igcm9sbGJhY2ssXG4gICAgICAvLyBidXQgaXQgbWlnaHQgY2hhbmdlIGlmIHdlIGVuY291bnRlciBhIGZhaWxlZCBzdGF0ZS5cbiAgICAgIGxldCByb2xsYmFjayA9IHRoaXMub3B0aW9ucy5yb2xsYmFjaztcblxuICAgICAgLy8gV2UgbGltaXQgdGhlIGxvb3AgdG8gMiBpdGVyYXRpb25zIG1heCBhcyBkZWZlbnNpdmUgcHJvZ3JhbW1pbmcuXG4gICAgICAvLyBTaG91bGQgbm90IGJlIHBvc3NpYmxlIHRvIGhhcHBlbi5cbiAgICAgIGxldCBpdGVyYXRpb24gPSAwO1xuICAgICAgd2hpbGUgKCFkZXBsb3lSZXN1bHQpIHtcbiAgICAgICAgaWYgKCsraXRlcmF0aW9uID4gMikge1xuICAgICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ0RlcGxveUxvb3BVbnN0YWJsZScsICdUaGlzIGxvb3Agc2hvdWxkIGhhdmUgc3RhYmlsaXplZCBpbiAyIGl0ZXJhdGlvbnMsIGJ1dCBkaWRuXFwndC4gSWYgeW91IGFyZSBzZWVpbmcgdGhpcyBlcnJvciwgcGxlYXNlIHJlcG9ydCBpdCBhdCBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzL25ldy9jaG9vc2UnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHIgPSBhd2FpdCB0aGlzLmRlcGxveW1lbnRzLmRlcGxveVN0YWNrKHtcbiAgICAgICAgICAuLi5zaGFyZWREZXBsb3lPcHRpb25zLFxuICAgICAgICAgIC8vIE9uIHRoZSBmaXJzdCBpdGVyYXRpb24sIGV4ZWN1dGUgdGhlIHByZXBhcmVkIGNoYW5nZSBzZXQuXG4gICAgICAgICAgLy8gT24gcmV0cmllcyAoYWZ0ZXIgcm9sbGJhY2spLCBjcmVhdGUgYSBuZXcgY2hhbmdlIHNldCBzaW5jZSB0aGUgb2xkIG9uZSBpcyBnb25lLlxuICAgICAgICAgIGRlcGxveW1lbnRNZXRob2Q6IGl0ZXJhdGlvbiA9PT0gMSAmJiBpc0V4ZWN1dGluZ0NoYW5nZVNldERlcGxveW1lbnQodGhpcy5vcHRpb25zLmRlcGxveW1lbnRNZXRob2QpXG4gICAgICAgICAgICA/IHRvRXhlY3V0ZUNoYW5nZVNldERlcGxveW1lbnQodGhpcy5vcHRpb25zLmRlcGxveW1lbnRNZXRob2QpXG4gICAgICAgICAgICA6IHRoaXMub3B0aW9ucy5kZXBsb3ltZW50TWV0aG9kLFxuICAgICAgICAgIHJvbGxiYWNrLFxuICAgICAgICB9KTtcblxuICAgICAgICBzd2l0Y2ggKHIudHlwZSkge1xuICAgICAgICAgIGNhc2UgJ2RpZC1kZXBsb3ktc3RhY2snOlxuICAgICAgICAgICAgZGVwbG95UmVzdWx0ID0gcjtcbiAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgY2FzZSAnZmFpbHBhdXNlZC1uZWVkLXJvbGxiYWNrLWZpcnN0Jzoge1xuICAgICAgICAgICAgY29uc3QgbW90aXZhdGlvbiA9IHIucmVhc29uID09PSAncmVwbGFjZW1lbnQnXG4gICAgICAgICAgICAgID8gYFN0YWNrIGlzIGluIGEgcGF1c2VkIGZhaWwgc3RhdGUgKCR7ci5zdGF0dXN9KSBhbmQgY2hhbmdlIGluY2x1ZGVzIGEgcmVwbGFjZW1lbnQgd2hpY2ggY2Fubm90IGJlIGRlcGxveWVkIHdpdGggXCItLW5vLXJvbGxiYWNrXCJgXG4gICAgICAgICAgICAgIDogYFN0YWNrIGlzIGluIGEgcGF1c2VkIGZhaWwgc3RhdGUgKCR7ci5zdGF0dXN9KSBhbmQgY29tbWFuZCBsaW5lIGFyZ3VtZW50cyBkbyBub3QgaW5jbHVkZSBcIi0tbm8tcm9sbGJhY2tcImA7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZm9yY2UpIHtcbiAgICAgICAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLndhcm4oYCR7bW90aXZhdGlvbn0uIFJvbGxpbmcgYmFjayBmaXJzdCAoLS1mb3JjZSkuYCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBhd2FpdCBhc2tVc2VyQ29uZmlybWF0aW9uKFxuICAgICAgICAgICAgICAgIHRoaXMuaW9Ib3N0LFxuICAgICAgICAgICAgICAgIElPLkNES19UT09MS0lUX0k1MDUwLnJlcShgJHttb3RpdmF0aW9ufS4gUm9sbCBiYWNrIGZpcnN0IGFuZCB0aGVuIHByb2NlZWQgd2l0aCBkZXBsb3ltZW50YCwge1xuICAgICAgICAgICAgICAgICAgbW90aXZhdGlvbixcbiAgICAgICAgICAgICAgICAgIGNvbmN1cnJlbmN5OiB0aGlzLm9wdGlvbnMuY29uY3VycmVuY3ksXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgJ1JvbGxiYWNrQWJvcnRlZCcsXG4gICAgICAgICAgICAgICAgJ1JvbGxiYWNrIGNhbmNlbGxlZCcsXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFBlcmZvcm0gYSByb2xsYmFja1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5zdGFja09wZXJhdGlvbnMucm9sbGJhY2soe1xuICAgICAgICAgICAgICBzZWxlY3Rvcjogc2VsZWN0RXhhY3Qoc3RhY2suaGllcmFyY2hpY2FsSWQpLFxuICAgICAgICAgICAgICB0b29sa2l0U3RhY2tOYW1lOiB0aGlzLm9wdGlvbnMudG9vbGtpdFN0YWNrTmFtZSxcbiAgICAgICAgICAgICAgZm9yY2U6IHRoaXMub3B0aW9ucy5mb3JjZSxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBHbyBhcm91bmQgdGhyb3VnaCB0aGUgJ3doaWxlJyBsb29wIGFnYWluIGJ1dCBzd2l0Y2ggcm9sbGJhY2sgdG8gdHJ1ZS5cbiAgICAgICAgICAgIHJvbGxiYWNrID0gdHJ1ZTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNhc2UgJ3JlcGxhY2VtZW50LXJlcXVpcmVzLXJvbGxiYWNrJzoge1xuICAgICAgICAgICAgY29uc3QgbW90aXZhdGlvbiA9ICdDaGFuZ2UgaW5jbHVkZXMgYSByZXBsYWNlbWVudCB3aGljaCBjYW5ub3QgYmUgZGVwbG95ZWQgd2l0aCBcIi0tbm8tcm9sbGJhY2tcIic7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZm9yY2UpIHtcbiAgICAgICAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLndhcm4oYCR7bW90aXZhdGlvbn0uIFByb2NlZWRpbmcgd2l0aCBkZXBsb3ltZW50IHdpdGggcm9sbGJhY2sgZW5hYmxlZCAoLS1mb3JjZSkuYCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBhd2FpdCBhc2tVc2VyQ29uZmlybWF0aW9uKFxuICAgICAgICAgICAgICAgIHRoaXMuaW9Ib3N0LFxuICAgICAgICAgICAgICAgIElPLkNES19UT09MS0lUX0k1MDUwLnJlcShgJHttb3RpdmF0aW9ufS4gUGVyZm9ybSBhIGRlcGxveW1lbnQgd2l0aCByb2xsYmFjayBlbmFibGVkYCwge1xuICAgICAgICAgICAgICAgICAgY29uY3VycmVuY3k6IHRoaXMub3B0aW9ucy5jb25jdXJyZW5jeSxcbiAgICAgICAgICAgICAgICAgIG1vdGl2YXRpb24sXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgJ1JlcGxhY2VtZW50Um9sbGJhY2tBYm9ydGVkJyxcbiAgICAgICAgICAgICAgICAnUm9sbGJhY2sgY2FuY2VsbGVkJyxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gR28gYXJvdW5kIHRocm91Z2ggdGhlICd3aGlsZScgbG9vcCBhZ2FpbiBidXQgc3dpdGNoIHJvbGxiYWNrIHRvIHRydWUuXG4gICAgICAgICAgICByb2xsYmFjayA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignVW5leHBlY3RlZERlcGxveVJlc3VsdCcsIGBVbmV4cGVjdGVkIHJlc3VsdCB0eXBlIGZyb20gZGVwbG95U3RhY2s6ICR7SlNPTi5zdHJpbmdpZnkocil9LiBJZiB5b3UgYXJlIHNlZWluZyB0aGlzIGVycm9yLCBwbGVhc2UgcmVwb3J0IGl0IGF0IGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvbmV3L2Nob29zZWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSBkZXBsb3lSZXN1bHQubm9PcFxuICAgICAgICA/ICfinIUgICVzIChubyBjaGFuZ2VzKSdcbiAgICAgICAgOiAn4pyFICAlcyc7XG5cbiAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKGNoYWxrLmdyZWVuKCdcXG4nICsgbWVzc2FnZSksIHN0YWNrLmRpc3BsYXlOYW1lKTtcbiAgICAgIGVsYXBzZWREZXBsb3lUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERlcGxveVRpbWU7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkuZGVmYXVsdHMuaW5mbyhgXFxu4pyoICBEZXBsb3ltZW50IHRpbWU6ICR7Zm9ybWF0VGltZShlbGFwc2VkRGVwbG95VGltZSl9c1xcbmApO1xuXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmV4cHJlc3MpIHtcbiAgICAgICAgY29uc3Qgd2FybmluZyA9IGZvcm1hdEV4cHJlc3NTdGFiaWxpemF0aW9uV2FybmluZyhkZXBsb3lSZXN1bHQuc3RhYmlsaXppbmdSZXNvdXJjZXMsICdkZXBsb3knKTtcbiAgICAgICAgaWYgKHdhcm5pbmcpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkubm90aWZ5KElPLkNES19UT09MS0lUX1c1OTAyLm1zZyh3YXJuaW5nKSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKE9iamVjdC5rZXlzKGRlcGxveVJlc3VsdC5vdXRwdXRzKS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKCdPdXRwdXRzOicpO1xuXG4gICAgICAgIHRoaXMuc3RhY2tPdXRwdXRzW3N0YWNrLnN0YWNrTmFtZV0gPSBkZXBsb3lSZXN1bHQub3V0cHV0cztcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBuYW1lIG9mIE9iamVjdC5rZXlzKGRlcGxveVJlc3VsdC5vdXRwdXRzKS5zb3J0KCkpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBkZXBsb3lSZXN1bHQub3V0cHV0c1tuYW1lXTtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLmRlZmF1bHRzLmluZm8oYCR7Y2hhbGsuY3lhbihzdGFjay5pZCl9LiR7Y2hhbGsuY3lhbihuYW1lKX0gPSAke2NoYWxrLnVuZGVybGluZShjaGFsay5jeWFuKHZhbHVlKSl9YCk7XG4gICAgICB9XG5cbiAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5pbmZvKCdTdGFjayBBUk46Jyk7XG5cbiAgICAgIGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5kZWZhdWx0cy5yZXN1bHQoZGVwbG95UmVzdWx0LnN0YWNrQXJuKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIC8vIEl0IGhhcyB0byBiZSBleGFjdGx5IHRoaXMgc3RyaW5nIGJlY2F1c2UgYW4gaW50ZWdyYXRpb24gdGVzdCB0ZXN0cyBmb3JcbiAgICAgIC8vIFwiYm9sZChzdGFja25hbWUpIGZhaWxlZDogUmVzb3VyY2VOb3RSZWFkeTogPGVycm9yPlwiXG4gICAgICBjb25zdCBjb2RlID0gVG9vbGtpdEVycm9yLmlzVG9vbGtpdEVycm9yKGUpID8gZS5uYW1lIDogJ0RlcGxveVN0YWNrRmFpbGVkJzsgLy8gRm9ybWVybHkgJ0RlcGxveUZhaWxlZCdcbiAgICAgIGNvbnN0IG5ld01lc3NhZ2UgPSBbYOKdjCAgJHtjaGFsay5ib2xkKHN0YWNrLnN0YWNrTmFtZSl9IGZhaWxlZDpgLCAuLi4oZS5uYW1lID8gW2Ake2UubmFtZX06YF0gOiBbXSksIGUubWVzc2FnZV0uam9pbignICcpO1xuICAgICAgY29uc3Qgd3JhcHBlZEVycm9yID0gbmV3IFRvb2xraXRFcnJvcihjb2RlLCBuZXdNZXNzYWdlKTtcblxuICAgICAgZXJyb3IgPSB7XG4gICAgICAgIG5hbWU6IGNka0NsaUVycm9yTmFtZSh3cmFwcGVkRXJyb3IpLFxuICAgICAgfTtcblxuICAgICAgdGhyb3cgd3JhcHBlZEVycm9yO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCBkZXBsb3lTcGFuLmVuZCh7IGVycm9yIH0pO1xuXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmNsb3VkV2F0Y2hMb2dNb25pdG9yKSB7XG4gICAgICAgIGNvbnN0IGZvdW5kTG9nR3JvdXBzUmVzdWx0ID0gYXdhaXQgZmluZENsb3VkV2F0Y2hMb2dHcm91cHModGhpcy5vcHRpb25zLnNka1Byb3ZpZGVyLCBhc0lvSGVscGVyKHRoaXMuaW9Ib3N0LCAnZGVwbG95JyksIHN0YWNrKTtcbiAgICAgICAgdGhpcy5vcHRpb25zLmNsb3VkV2F0Y2hMb2dNb25pdG9yLmFkZExvZ0dyb3VwcyhcbiAgICAgICAgICBmb3VuZExvZ0dyb3Vwc1Jlc3VsdC5lbnYsXG4gICAgICAgICAgZm91bmRMb2dHcm91cHNSZXN1bHQuc2RrLFxuICAgICAgICAgIGZvdW5kTG9nR3JvdXBzUmVzdWx0LmxvZ0dyb3VwTmFtZXMsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGFzeW5jIHdyaXRlT3V0cHV0cyhvdXRwdXRzRmlsZTogc3RyaW5nKSB7XG4gICAgZnMuZW5zdXJlRmlsZVN5bmMob3V0cHV0c0ZpbGUpO1xuICAgIGF3YWl0IGZzLndyaXRlSnNvbihvdXRwdXRzRmlsZSwgdGhpcy5zdGFja091dHB1dHMsIHtcbiAgICAgIHNwYWNlczogMixcbiAgICAgIGVuY29kaW5nOiAndXRmOCcsXG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBEZXRlcm1pbmUgaWYgbWFudWFsIGFwcHJvdmFsIGlzIHJlcXVpcmVkIG9yIG5vdC4gUmVxdWlyZXMgYXBwcm92YWwgZm9yXG4gKiAtIFJlcXVpcmVBcHByb3ZhbC5BTllDSEFOR0VcbiAqIC0gUmVxdWlyZUFwcHJvdmFsLkJST0FERU5JTkcgYW5kIHRoZSBjaGFuZ2VzIGFyZSBpbmRlZWQgYnJvYWRlbmluZyBwZXJtaXNzaW9uc1xuICovXG5mdW5jdGlvbiByZXF1aXJlc0FwcHJvdmFsKHJlcXVpcmVBcHByb3ZhbDogUmVxdWlyZUFwcHJvdmFsLCBwZXJtaXNzaW9uQ2hhbmdlVHlwZTogUGVybWlzc2lvbkNoYW5nZVR5cGUpIHtcbiAgcmV0dXJuIHJlcXVpcmVBcHByb3ZhbCA9PT0gUmVxdWlyZUFwcHJvdmFsLkFOWUNIQU5HRSB8fFxuICAgIHJlcXVpcmVBcHByb3ZhbCA9PT0gUmVxdWlyZUFwcHJvdmFsLkJST0FERU5JTkcgJiYgcGVybWlzc2lvbkNoYW5nZVR5cGUgPT09IFBlcm1pc3Npb25DaGFuZ2VUeXBlLkJST0FERU5JTkc7XG59XG5cbiJdfQ==