UNPKG

@aws/pdk

Version:

All documentation is located at: https://aws.github.io/aws-pdk

374 lines 41.3 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.Filters = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ const constructs_1 = require("constructs"); const memoize = require("lodash.memoize"); // eslint-disable-line @typescript-eslint/no-require-imports const types_1 = require("./types"); const utils_1 = require("./utils"); const core_1 = require("../core"); class Filters { /** * Verify that store is filterable, meaning it allows destructive mutations. * @throws Error if store is not filterable */ static verifyFilterable(store) { if (!store.allowDestructiveMutations) { throw new Error("Store must allow destructive mutations to perform filtering; clone the store before applying filters using `store.clone(true)` operation and passing the cloned store to filtering operation."); } } /** * Prune **extraneous** nodes and edges * @throws Error if store is not filterable * @destructive */ static pruneExtraneous() { return { filter: (store) => { Filters.verifyFilterable(store); const extraneousNodes = store.root.findAll({ order: constructs_1.ConstructOrder.POSTORDER, predicate: { filter: (node) => node.isExtraneous }, }); // collapse all extraneous nodes to nearest non-extraneous parent, or prune the node for (const extraneousNode of extraneousNodes) { const nonExtraneousAncestor = extraneousNode.findAncestor({ filter: (node) => !node.isExtraneous, }); if (nonExtraneousAncestor && !nonExtraneousAncestor.isGraphContainer) { extraneousNode.mutateCollapseTo(nonExtraneousAncestor); } else { extraneousNode.mutateDestroy(); } } store.edges.forEach((edge) => { if (edge.isExtraneous) { edge.mutateDestroy(); } }); }, }; } /** * Collapses all Cdk Owned containers, which more closely mirrors the application code * by removing resources that are automatically created by cdk. */ static collapseCdkOwnedResources() { return { filter: (store) => { store.root .findAll({ order: constructs_1.ConstructOrder.POSTORDER, predicate: { filter: (node) => core_1.Graph.ResourceNode.isResourceNode(node) && node.isCdkOwned, }, }) .forEach((node) => { if (node.isDestroyed) return; node.mutateCollapse(); }); }, }; } /** * Collapses all Cdk Resource wrappers that wrap directly wrap a CfnResource. * Example, s3.Bucket wraps s3.CfnBucket. */ static collapseCdkWrappers() { return { filter: (store) => { const cdkResources = store.root.findAll({ order: constructs_1.ConstructOrder.POSTORDER, predicate: { filter: (node) => core_1.Graph.ResourceNode.isResourceNode(node) && !node.isLeaf, }, }); // collapse all cfnResource wrapped by cdk resource for (const cdkResource of cdkResources) { if (cdkResource.isWrapper) { cdkResource.mutateCollapse(); } } }, }; } /** * Collapses Custom Resource nodes to a single node. */ static collapseCustomResources() { return { filter: (store) => { store.root .findAll({ predicate: { filter: (node) => { return node.hasFlag(core_1.FlagEnum.CUSTOM_RESOURCE); }, }, }) .forEach((customResource) => { if (customResource.isDestroyed) return; customResource.mutateCollapse(); // const REF_FQN = /^aws-cdk-lib\.aws-(iam|lambda)/ if (!customResource.hasFlag(core_1.FlagEnum.AWS_CUSTOM_RESOURCE) && !customResource.parent?.hasFlag(core_1.FlagEnum.AWS_CUSTOM_RESOURCE)) { let crId = customResource.id; if (crId !== "Provider" && crId.endsWith("Provider")) { crId = crId.replace(/Provider$/, ""); } // Try to find resources that are utilized only for the custom resource (0, utils_1.findReferencesOfSubGraph)(customResource, 3, { filter: (node) => { return node.id.includes(crId); // return false && /^aws-cdk-lib\.(aws_)?(iam|lambda)/.test(node.constructInfoFqn || "") }, }).forEach((_ref) => _ref.mutateMove(customResource)); customResource.mutateCollapse(); } }); }, }; } /** * Prune Custom Resource nodes. */ static pruneCustomResources() { return { filter: (store) => { store.root .findAll({ predicate: { filter: (node) => { return node.hasFlag(core_1.FlagEnum.CUSTOM_RESOURCE); }, }, }) .forEach((customResource) => { if (customResource.isDestroyed) return; customResource.mutateDestroy(); }); }, }; } /** * Prune empty containers, which are non-resource default nodes without any children. * * Generally L3 constructs in which all children have already been pruned, which * would be useful as containers, but without children are considered extraneous. */ static pruneEmptyContainers() { return { filter: (store) => { store.root .findAll({ predicate: { filter: (node) => { if (node.nodeType !== core_1.NodeTypeEnum.DEFAULT) return false; if (!node.isLeaf) return false; if (node.cfnType) return false; if (node.constructInfoFqn?.startsWith("aws-cdk-lib.")) return false; return true; }, }, }) .forEach((node) => { if (node.isDestroyed) return; node.mutateDestroy(); }); }, }; } /** * Collapses extraneous nodes to parent and cdk created nodes on themselves, * and prunes extraneous edges. * * This most closely represents the developers code for the current application * and reduces the noise one expects. * * Invokes: * 1. * 1. pruneExtraneous()(store); * 1. collapseCdkOwnedResources()(store); * 1. collapseCdkWrappers()(store); * 1. collapseCustomResources()(store); * 1. ~pruneCustomResources()(store);~ * 1. pruneEmptyContainers()(store); * * @throws Error if store is not filterable * @destructive */ static compact() { return { filter: (store) => { Filters.verifyFilterable(store); Filters.pruneExtraneous().filter(store); Filters.collapseCdkOwnedResources().filter(store); Filters.collapseCdkWrappers().filter(store); Filters.collapseCustomResources().filter(store); // TODO: decide if we should prune custom resources in "compact" // pruneCustomResources()(store); Filters.pruneEmptyContainers().filter(store); }, }; } /** * @internal */ static _filterNodeType(values, exclude) { const isMatch = memoize((input) => { if (input == null) { return false; } return (values.find((_value) => { if (_value.value) { return input === _value.value; } else if (_value.regex) { return new RegExp(_value.regex).test(input); } else { return undefined; } }) != null); }); return { filter: (store) => { for (const node of store.root.findAll({ order: constructs_1.ConstructOrder.POSTORDER, })) { if (isMatch(node.nodeType) === exclude) { if (node.isLeaf) { node.mutateCollapseToParent(); } else { node.mutateUncluster(); } } } }, }; } /** * Prune all {@link Graph.Node}s *except those matching* specified list. * * This filter targets all nodes (except root) - {@link IGraphFilter.allNodes} * @throws Error if store is not filterable * @destructive */ static includeNodeType(nodeTypes) { return Filters._filterNodeType(nodeTypes, false); } /** * Prune all {@link Graph.Node}s *matching* specified list. * * This filter targets all nodes (except root) - {@link IGraphFilter.allNodes} * @throws Error if store is not filterable * @destructive */ static excludeNodeType(nodeTypes) { return Filters._filterNodeType(nodeTypes, true); } /** * @internal */ static _filterCfnType(values, exclude) { const isMatch = memoize((input) => { if (input == null) { return false; } return (values.find((_value) => { if (_value.value) { return input === _value.value; } else if (_value.regex) { return new RegExp(_value.regex).test(input); } else { return undefined; } }) != null); }); return { strategy: types_1.FilterStrategy.PRUNE, node: { filter: (node) => { // Preserve container structure (stages, stacks, etc.) if (node.isCluster || node.isGraphContainer) return true; if (core_1.Graph.isResourceLike(node)) { const match = !!node.cfnType && isMatch(node.cfnType); return (match && !exclude) || (!match && exclude); } // Preserve non *Resource nodes return true; }, }, }; } /** * Prune all {@link Graph.ResourceNode} and {@link Graph.CfnResourceNode} nodes * *except those matching* specified list of CloudFormation types. * @throws Error if store is not filterable * @destructive */ static includeCfnType(cfnTypes) { return Filters._filterCfnType(cfnTypes, false); } /** * Prune all {@link Graph.ResourceNode} and {@link Graph.CfnResourceNode} nodes * *matching* specified list of CloudFormation types. * @throws Error if store is not filterable * @destructive */ static excludeCfnType(cfnTypes) { return Filters._filterCfnType(cfnTypes, true); } /** * Remove clusters by hoisting their children to the parent of the cluster * and collapsing the cluster itself to its parent. * @param clusterTypes * @throws Error if store is not filterable * @see {@link Graph.Node.mutateUncluster} * @destructive */ static uncluster(clusterTypes) { // Use set for constant lookup const clusterTypesSet = new Set(clusterTypes); return { filter: (store) => { Filters.verifyFilterable(store); const clusters = store.root.findAll({ predicate: { filter: (node) => { if (node.isGraphContainer) return false; if (clusterTypesSet.size === 0) return node.isCluster; return clusterTypesSet.has(node.nodeType); }, }, }); for (const cluster of clusters) { cluster.mutateUncluster(); } }, }; } } exports.Filters = Filters; _a = JSII_RTTI_SYMBOL_1; Filters[_a] = { fqn: "@aws/pdk.cdk_graph.Filters", version: "0.26.14" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImZpbHRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtzQ0FDc0M7QUFDdEMsMkNBQTRDO0FBQzVDLDBDQUEyQyxDQUFDLDREQUE0RDtBQUN4RyxtQ0FBMEU7QUFDMUUsbUNBQW1EO0FBQ25ELGtDQUF3RDtBQWlCeEQsTUFBYSxPQUFPO0lBQ2xCOzs7T0FHRztJQUNJLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFrQjtRQUMvQyxJQUFJLENBQUMsS0FBSyxDQUFDLHlCQUF5QixFQUFFLENBQUM7WUFDckMsTUFBTSxJQUFJLEtBQUssQ0FDYiwrTEFBK0wsQ0FDaE0sQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxlQUFlO1FBQzNCLE9BQU87WUFDTCxNQUFNLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtnQkFDaEIsT0FBTyxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUVoQyxNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztvQkFDekMsS0FBSyxFQUFFLDJCQUFjLENBQUMsU0FBUztvQkFDL0IsU0FBUyxFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFO2lCQUNuRCxDQUFDLENBQUM7Z0JBQ0gsb0ZBQW9GO2dCQUNwRixLQUFLLE1BQU0sY0FBYyxJQUFJLGVBQWUsRUFBRSxDQUFDO29CQUM3QyxNQUFNLHFCQUFxQixHQUFHLGNBQWMsQ0FBQyxZQUFZLENBQUM7d0JBQ3hELE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWTtxQkFDckMsQ0FBQyxDQUFDO29CQUNILElBQ0UscUJBQXFCO3dCQUNyQixDQUFDLHFCQUFxQixDQUFDLGdCQUFnQixFQUN2QyxDQUFD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UUFDbkQsOEJBQThCO1FBQzlCLE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxDQUFlLFlBQVksQ0FBQyxDQUFDO1FBRTVELE9BQU87WUFDTCxNQUFNLEVBQUUsQ0FBQyxLQUFLLEVBQVEsRUFBRTtnQkFDdEIsT0FBTyxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUVoQyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztvQkFDbEMsU0FBUyxFQUFFO3dCQUNULE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFOzRCQUNmLElBQUksSUFBSSxDQUFDLGdCQUFnQjtnQ0FBRSxPQUFPLEtBQUssQ0FBQzs0QkFDeEMsSUFBSSxlQUFlLENBQUMsSUFBSSxLQUFLLENBQUM7Z0NBQUUsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDOzRCQUN0RCxPQUFPLGVBQWUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO3dCQUM1QyxDQUFDO3FCQUNGO2lCQUNGLENBQUMsQ0FBQztnQkFFSCxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO29CQUMvQixPQUFPLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQzVCLENBQUM7WUFDSCxDQUFDO1NBQ0YsQ0FBQztJQUNKLENBQUM7O0FBcFlILDBCQXFZQyIsInNvdXJjZXNDb250ZW50IjpbIi8qISBDb3B5cmlnaHQgW0FtYXpvbi5jb21dKGh0dHA6Ly9hbWF6b24uY29tLyksIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMCAqL1xuaW1wb3J0IHsgQ29uc3RydWN0T3JkZXIgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IG1lbW9pemUgPSByZXF1aXJlKFwibG9kYXNoLm1lbW9pemVcIik7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuaW1wb3J0IHsgRmlsdGVyU3RyYXRlZ3ksIElHcmFwaEZpbHRlciwgSUdyYXBoU3RvcmVGaWx0ZXIgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgZmluZFJlZmVyZW5jZXNPZlN1YkdyYXBoIH0gZnJvbSBcIi4vdXRpbHNcIjtcbmltcG9ydCB7IEZsYWdFbnVtLCBHcmFwaCwgTm9kZVR5cGVFbnVtIH0gZnJvbSBcIi4uL2NvcmVcIjtcblxuLyoqXG4gKiBGaWx0ZXIgdmFsdWUgdG8gdXNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZpbHRlclZhbHVlIHtcbiAgLyoqXG4gICAqIFN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBhIHJlZ2V4XG4gICAqL1xuICByZWFkb25seSByZWdleD86IHN0cmluZztcblxuICAvKipcbiAgICogUmF3IHZhbHVlXG4gICAqL1xuICByZWFkb25seSB2YWx1ZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIEZpbHRlcnMge1xuICAvKipcbiAgICogVmVyaWZ5IHRoYXQgc3RvcmUgaXMgZmlsdGVyYWJsZSwgbWVhbmluZyBpdCBhbGxvd3MgZGVzdHJ1Y3RpdmUgbXV0YXRpb25zLlxuICAgKiBAdGhyb3dzIEVycm9yIGlmIHN0b3JlIGlzIG5vdCBmaWx0ZXJhYmxlXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHZlcmlmeUZpbHRlcmFibGUoc3RvcmU6IEdyYXBoLlN0b3JlKTogdm9pZCB7XG4gICAgaWYgKCFzdG9yZS5hbGxvd0Rlc3RydWN0aXZlTXV0YXRpb25zKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIFwiU3RvcmUgbXVzdCBhbGxvdyBkZXN0cnVjdGl2ZSBtdXRhdGlvbnMgdG8gcGVyZm9ybSBmaWx0ZXJpbmc7IGNsb25lIHRoZSBzdG9yZSBiZWZvcmUgYXBwbHlpbmcgZmlsdGVycyB1c2luZyBgc3RvcmUuY2xvbmUodHJ1ZSlgIG9wZXJhdGlvbiBhbmQgcGFzc2luZyB0aGUgY2xvbmVkIHN0b3JlIHRvIGZpbHRlcmluZyBvcGVyYXRpb24uXCJcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFBydW5lICoqZXh0cmFuZW91cyoqIG5vZGVzIGFuZCBlZGdlc1xuICAgKiBAdGhyb3dzIEVycm9yIGlmIHN0b3JlIGlzIG5vdCBmaWx0ZXJhYmxlXG4gICAqIEBkZXN0cnVjdGl2ZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBwcnVuZUV4dHJhbmVvdXMoKTogSUdyYXBoU3RvcmVGaWx0ZXIge1xuICAgIHJldHVybiB7XG4gICAgICBmaWx0ZXI6IChzdG9yZSkgPT4ge1xuICAgICAgICBGaWx0ZXJzLnZlcmlmeUZpbHRlcmFibGUoc3RvcmUpO1xuXG4gICAgICAgIGNvbnN0IGV4dHJhbmVvdXNOb2RlcyA9IHN0b3JlLnJvb3QuZmluZEFsbCh7XG4gICAgICAgICAgb3JkZXI6IENvbnN0cnVjdE9yZGVyLlBPU1RPUkRFUixcbiAgICAgICAgICBwcmVkaWNhdGU6IHsgZmlsdGVyOiAobm9kZSkgPT4gbm9kZS5pc0V4dHJhbmVvdXMgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIGNvbGxhcHNlIGFsbCBleHRyYW5lb3VzIG5vZGVzIHRvIG5lYXJlc3Qgbm9uLWV4dHJhbmVvdXMgcGFyZW50LCBvciBwcnVuZSB0aGUgbm9kZVxuICAgICAgICBmb3IgKGNvbnN0IGV4dHJhbmVvdXNOb2RlIG9mIGV4dHJhbmVvdXNOb2Rlcykge1xuICAgICAgICAgIGNvbnN0IG5vbkV4dHJhbmVvdXNBbmNlc3RvciA9IGV4dHJhbmVvdXNOb2RlLmZpbmRBbmNlc3Rvcih7XG4gICAgICAgICAgICBmaWx0ZXI6IChub2RlKSA9PiAhbm9kZS5pc0V4dHJhbmVvdXMsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgbm9uRXh0cmFuZW91c0FuY2VzdG9yICYmXG4gICAgICAgICAgICAhbm9uRXh0cmFuZW91c0FuY2VzdG9yLmlzR3JhcGhDb250YWluZXJcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIGV4dHJhbmVvdXNOb2RlLm11dGF0ZUNvbGxhcHNlVG8obm9uRXh0cmFuZW91c0FuY2VzdG9yKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZXh0cmFuZW91c05vZGUubXV0YXRlRGVzdHJveSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHN0b3JlLmVkZ2VzLmZvckVhY2goKGVkZ2UpID0+IHtcbiAgICAgICAgICBpZiAoZWRnZS5pc0V4dHJhbmVvdXMpIHtcbiAgICAgICAgICAgIGVkZ2UubXV0YXRlRGVzdHJveSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ29sbGFwc2VzIGFsbCBDZGsgT3duZWQgY29udGFpbmVycywgd2hpY2ggbW9yZSBjbG9zZWx5IG1pcnJvcnMgdGhlIGFwcGxpY2F0aW9uIGNvZGVcbiAgICogYnkgcmVtb3ZpbmcgcmVzb3VyY2VzIHRoYXQgYXJlIGF1dG9tYXRpY2FsbHkgY3JlYXRlZCBieSBjZGsuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNvbGxhcHNlQ2RrT3duZWRSZXNvdXJjZXMoKTogSUdyYXBoU3RvcmVGaWx0ZXIge1xuICAgIHJldHVybiB7XG4gICAgICBmaWx0ZXI6IChzdG9yZSkgPT4ge1xuICAgICAgICBzdG9yZS5yb290XG4gICAgICAgICAgLmZpbmRBbGwoe1xuICAgICAgICAgICAgb3JkZXI6IENvbnN0cnVjdE9yZGVyLlBPU1RPUkRFUixcbiAgICAgICAgICAgIHByZWRpY2F0ZToge1xuICAgICAgICAgICAgICBmaWx0ZXI6IChub2RlKSA9PlxuICAgICAgICAgICAgICAgIEdyYXBoLlJlc291cmNlTm9kZS5pc1Jlc291cmNlTm9kZShub2RlKSAmJiBub2RlLmlzQ2RrT3duZWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLmZvckVhY2goKG5vZGUpID0+IHtcbiAgICAgICAgICAgIGlmIChub2RlLmlzRGVzdHJveWVkKSByZXR1cm47XG4gICAgICAgICAgICBub2RlLm11dGF0ZUNvbGxhcHNlKCk7XG4gICAgICAgICAgfSk7XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ29sbGFwc2VzIGFsbCBDZGsgUmVzb3VyY2Ugd3JhcHBlcnMgdGhhdCB3cmFwIGRpcmVjdGx5IHdyYXAgYSBDZm5SZXNvdXJjZS5cbiAgICogRXhhbXBsZSwgczMuQnVja2V0IHdyYXBzIHMzLkNmbkJ1Y2tldC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY29sbGFwc2VDZGtXcmFwcGVycygpOiBJR3JhcGhTdG9yZUZpbHRlciB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZpbHRlcjogKHN0b3JlKSA9PiB7XG4gICAgICAgIGNvbnN0IGNka1Jlc291cmNlcyA9IHN0b3JlLnJvb3QuZmluZEFsbCh7XG4gICAgICAgICAgb3JkZXI6IENvbnN0cnVjdE9yZGVyLlBPU1RPUkRFUixcbiAgICAgICAgICBwcmVkaWNhdGU6IHtcbiAgICAgICAgICAgIGZpbHRlcjogKG5vZGUpID0+XG4gICAgICAgICAgICAgIEdyYXBoLlJlc291cmNlTm9kZS5pc1Jlc291cmNlTm9kZShub2RlKSAmJiAhbm9kZS5pc0xlYWYsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSkgYXMgR3JhcGguUmVzb3VyY2VOb2RlW107XG4gICAgICAgIC8vIGNvbGxhcHNlIGFsbCBjZm5SZXNvdXJjZSB3cmFwcGVkIGJ5IGNkayByZXNvdXJjZVxuICAgICAgICBmb3IgKGNvbnN0IGNka1Jlc291cmNlIG9mIGNka1Jlc291cmNlcykge1xuICAgICAgICAgIGlmIChjZGtSZXNvdXJjZS5pc1dyYXBwZXIpIHtcbiAgICAgICAgICAgIGNka1Jlc291cmNlLm11dGF0ZUNvbGxhcHNlKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ29sbGFwc2VzIEN1c3RvbSBSZXNvdXJjZSBub2RlcyB0byBhIHNpbmdsZSBub2RlLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb2xsYXBzZUN1c3RvbVJlc291cmNlcygpOiBJR3JhcGhTdG9yZUZpbHRlciB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZpbHRlcjogKHN0b3JlKSA9PiB7XG4gICAgICAgIHN0b3JlLnJvb3RcbiAgICAgICAgICAuZmluZEFsbCh7XG4gICAgICAgICAgICBwcmVkaWNhdGU6IHtcbiAgICAgICAgICAgICAgZmlsdGVyOiAobm9kZSkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBub2RlLmhhc0ZsYWcoRmxhZ0VudW0uQ1VTVE9NX1JFU09VUkNFKTtcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuZm9yRWFjaCgoY3VzdG9tUmVzb3VyY2UpID0+IHtcbiAgICAgICAgICAgIGlmIChjdXN0b21SZXNvdXJjZS5pc0Rlc3Ryb3llZCkgcmV0dXJuO1xuXG4gICAgICAgICAgICBjdXN0b21SZXNvdXJjZS5tdXRhdGVDb2xsYXBzZSgpO1xuXG4gICAgICAgICAgICAvLyBjb25zdCBSRUZfRlFOID0gL15hd3MtY2RrLWxpYlxcLmF3cy0oaWFtfGxhbWJkYSkvXG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgIWN1c3RvbVJlc291cmNlLmhhc0ZsYWcoRmxhZ0VudW0uQVdTX0NVU1RPTV9SRVNPVVJDRSkgJiZcbiAgICAgICAgICAgICAgIWN1c3RvbVJlc291cmNlLnBhcmVudD8uaGFzRmxhZyhGbGFnRW51bS5BV1NfQ1VTVE9NX1JFU09VUkNFKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIGxldCBjcklkID0gY3VzdG9tUmVzb3VyY2UuaWQ7XG4gICAgICAgICAgICAgIGlmIChjcklkICE9PSBcIlByb3ZpZGVyXCIgJiYgY3JJZC5lbmRzV2l0aChcIlByb3ZpZGVyXCIpKSB7XG4gICAgICAgICAgICAgICAgY3JJZCA9IGNySWQucmVwbGFjZSgvUHJvdmlkZXIkLywgXCJcIik7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgLy8gVHJ5IHRvIGZpbmQgcmVzb3VyY2VzIHRoYXQgYXJlIHV0aWxpemVkIG9ubHkgZm9yIHRoZSBjdXN0b20gcmVzb3VyY2VcbiAgICAgICAgICAgICAgZmluZFJlZmVyZW5jZXNPZlN1YkdyYXBoKGN1c3RvbVJlc291cmNlLCAzLCB7XG4gICAgICAgICAgICAgICAgZmlsdGVyOiAobm9kZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vZGUuaWQuaW5jbHVkZXMoY3JJZCk7XG4gICAgICAgICAgICAgICAgICAvLyByZXR1cm4gZmFsc2UgJiYgL15hd3MtY2RrLWxpYlxcLihhd3NfKT8oaWFtfGxhbWJkYSkvLnRlc3Qobm9kZS5jb25zdHJ1Y3RJbmZvRnFuIHx8IFwiXCIpXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSkuZm9yRWFjaCgoX3JlZikgPT4gX3JlZi5tdXRhdGVNb3ZlKGN1c3RvbVJlc291cmNlKSk7XG5cbiAgICAgICAgICAgICAgY3VzdG9tUmVzb3VyY2UubXV0YXRlQ29sbGFwc2UoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcnVuZSBDdXN0b20gUmVzb3VyY2Ugbm9kZXMuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHBydW5lQ3VzdG9tUmVzb3VyY2VzKCk6IElHcmFwaFN0b3JlRmlsdGVyIHtcbiAgICByZXR1cm4ge1xuICAgICAgZmlsdGVyOiAoc3RvcmUpID0+IHtcbiAgICAgICAgc3RvcmUucm9vdFxuICAgICAgICAgIC5maW5kQWxsKHtcbiAgICAgICAgICAgIHByZWRpY2F0ZToge1xuICAgICAgICAgICAgICBmaWx0ZXI6IChub2RlKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5vZGUuaGFzRmxhZyhGbGFnRW51bS5DVVNUT01fUkVTT1VSQ0UpO1xuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5mb3JFYWNoKChjdXN0b21SZXNvdXJjZSkgPT4ge1xuICAgICAgICAgICAgaWYgKGN1c3RvbVJlc291cmNlLmlzRGVzdHJveWVkKSByZXR1cm47XG5cbiAgICAgICAgICAgIGN1c3RvbVJlc291cmNlLm11dGF0ZURlc3Ryb3koKTtcbiAgICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcnVuZSBlbXB0eSBjb250YWluZXJzLCB3aGljaCBhcmUgbm9uLXJlc291cmNlIGRlZmF1bHQgbm9kZXMgd2l0aG91dCBhbnkgY2hpbGRyZW4uXG4gICAqXG4gICAqIEdlbmVyYWxseSBMMyBjb25zdHJ1Y3RzIGluIHdoaWNoIGFsbCBjaGlsZHJlbiBoYXZlIGFscmVhZHkgYmVlbiBwcnVuZWQsIHdoaWNoXG4gICAqIHdvdWxkIGJlIHVzZWZ1bCBhcyBjb250YWluZXJzLCBidXQgd2l0aG91dCBjaGlsZHJlbiBhcmUgY29uc2lkZXJlZCBleHRyYW5lb3VzLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBwcnVuZUVtcHR5Q29udGFpbmVycygpOiBJR3JhcGhTdG9yZUZpbHRlciB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZpbHRlcjogKHN0b3JlKSA9PiB7XG4gICAgICAgIHN0b3JlLnJvb3RcbiAgICAgICAgICAuZmluZEFsbCh7XG4gICAgICAgICAgICBwcmVkaWNhdGU6IHtcbiAgICAgICAgICAgICAgZmlsdGVyOiAobm9kZSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChub2RlLm5vZGVUeXBlICE9PSBOb2RlVHlwZUVudW0uREVGQVVMVCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIGlmICghbm9kZS5pc0xlYWYpIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICBpZiAobm9kZS5jZm5UeXBlKSByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgaWYgKG5vZGUuY29uc3RydWN0SW5mb0Zxbj8uc3RhcnRzV2l0aChcImF3cy1jZGstbGliLlwiKSlcbiAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuZm9yRWFjaCgobm9kZSkgPT4ge1xuICAgICAgICAgICAgaWYgKG5vZGUuaXNEZXN0cm95ZWQpIHJldHVybjtcblxuICAgICAgICAgICAgbm9kZS5tdXRhdGVEZXN0cm95KCk7XG4gICAgICAgICAgfSk7XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ29sbGFwc2VzIGV4dHJhbmVvdXMgbm9kZXMgdG8gcGFyZW50IGFuZCBjZGsgY3JlYXRlZCBub2RlcyBvbiB0aGVtc2VsdmVzLFxuICAgKiBhbmQgcHJ1bmVzIGV4dHJhbmVvdXMgZWRnZXMuXG4gICAqXG4gICAqIFRoaXMgbW9zdCBjbG9zZWx5IHJlcHJlc2VudHMgdGhlIGRldmVsb3BlcnMgY29kZSBmb3IgdGhlIGN1cnJlbnQgYXBwbGljYXRpb25cbiAgICogYW5kIHJlZHVjZXMgdGhlIG5vaXNlIG9uZSBleHBlY3RzLlxuICAgKlxuICAgKiBJbnZva2VzOlxuICAgKiAxLlxuICAgKiAxLiBwcnVuZUV4dHJhbmVvdXMoKShzdG9yZSk7XG4gICAqIDEuIGNvbGxhcHNlQ2RrT3duZWRSZXNvdXJjZXMoKShzdG9yZSk7XG4gICAqIDEuIGNvbGxhcHNlQ2RrV3JhcHBlcnMoKShzdG9yZSk7XG4gICAqIDEuIGNvbGxhcHNlQ3VzdG9tUmVzb3VyY2VzKCkoc3RvcmUpO1xuICAgKiAxLiB+cHJ1bmVDdXN0b21SZXNvdXJjZXMoKShzdG9yZSk7flxuICAgKiAxLiBwcnVuZUVtcHR5Q29udGFpbmVycygpKHN0b3JlKTtcbiAgICpcbiAgICogQHRocm93cyBFcnJvciBpZiBzdG9yZSBpcyBub3QgZmlsdGVyYWJsZVxuICAgKiBAZGVzdHJ1Y3RpdmVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY29tcGFjdCgpOiBJR3JhcGhTdG9yZUZpbHRlciB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZpbHRlcjogKHN0b3JlKSA9PiB7XG4gICAgICAgIEZpbHRlcnMudmVyaWZ5RmlsdGVyYWJsZShzdG9yZSk7XG5cbiAgICAgICAgRmlsdGVycy5wcnVuZUV4dHJhbmVvdXMoKS5maWx0ZXIoc3RvcmUpO1xuICAgICAgICBGaWx0ZXJzLmNvbGxhcHNlQ2RrT3duZWRSZXNvdXJjZXMoKS5maWx0ZXIoc3RvcmUpO1xuICAgICAgICBGaWx0ZXJzLmNvbGxhcHNlQ2RrV3JhcHBlcnMoKS5maWx0ZXIoc3RvcmUpO1xuICAgICAgICBGaWx0ZXJzLmNvbGxhcHNlQ3VzdG9tUmVzb3VyY2VzKCkuZmlsdGVyKHN0b3JlKTtcbiAgICAgICAgLy8gVE9ETzogZGVjaWRlIGlmIHdlIHNob3VsZCBwcnVuZSBjdXN0b20gcmVzb3VyY2VzIGluIFwiY29tcGFjdFwiXG4gICAgICAgIC8vIHBydW5lQ3VzdG9tUmVzb3VyY2VzKCkoc3RvcmUpO1xuICAgICAgICBGaWx0ZXJzLnBydW5lRW1wdHlDb250YWluZXJzKCkuZmlsdGVyKHN0b3JlKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgX2ZpbHRlck5vZGVUeXBlKFxuICAgIHZhbHVlczogRmlsdGVyVmFsdWVbXSxcbiAgICBleGNsdWRlOiBib29sZWFuXG4gICk6IElHcmFwaFN0b3JlRmlsdGVyIHtcbiAgICBjb25zdCBpc01hdGNoID0gbWVtb2l6ZSgoaW5wdXQ6IHN0cmluZykgPT4ge1xuICAgICAgaWYgKGlucHV0ID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gKFxuICAgICAgICB2YWx1ZXMuZmluZCgoX3ZhbHVlKSA9PiB7XG4gICAgICAgICAgaWYgKF92YWx1ZS52YWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0ID09PSBfdmFsdWUudmFsdWU7XG4gICAgICAgICAgfSBlbHNlIGlmIChfdmFsdWUucmVnZXgpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUmVnRXhwKF92YWx1ZS5yZWdleCkudGVzdChpbnB1dCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgfVxuICAgICAgICB9KSAhPSBudWxsXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGZpbHRlcjogKHN0b3JlKSA9PiB7XG4gICAgICAgIGZvciAoY29uc3Qgbm9kZSBvZiBzdG9yZS5yb290LmZpbmRBbGwoe1xuICAgICAgICAgIG9yZGVyOiBDb25zdHJ1Y3RPcmRlci5QT1NUT1JERVIsXG4gICAgICAgIH0pKSB7XG4gICAgICAgICAgaWYgKGlzTWF0Y2gobm9kZS5ub2RlVHlwZSkgPT09IGV4Y2x1ZGUpIHtcbiAgICAgICAgICAgIGlmIChub2RlLmlzTGVhZikge1xuICAgICAgICAgICAgICBub2RlLm11dGF0ZUNvbGxhcHNlVG9QYXJlbnQoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIG5vZGUubXV0YXRlVW5jbHVzdGVyKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUHJ1bmUgYWxsIHtAbGluayBHcmFwaC5Ob2RlfXMgKmV4Y2VwdCB0aG9zZSBtYXRjaGluZyogc3BlY2lmaWVkIGxpc3QuXG4gICAqXG4gICAqIFRoaXMgZmlsdGVyIHRhcmdldHMgYWxsIG5vZGVzIChleGNlcHQgcm9vdCkgLSB7QGxpbmsgSUdyYXBoRmlsdGVyLmFsbE5vZGVzfVxuICAgKiBAdGhyb3dzIEVycm9yIGlmIHN0b3JlIGlzIG5vdCBmaWx0ZXJhYmxlXG4gICAqIEBkZXN0cnVjdGl2ZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBpbmNsdWRlTm9kZVR5cGUobm9kZVR5cGVzOiBGaWx0ZXJWYWx1ZVtdKTogSUdyYXBoU3RvcmVGaWx0ZXIge1xuICAgIHJldHVybiBGaWx0ZXJzLl9maWx0ZXJOb2RlVHlwZShub2RlVHlwZXMsIGZhbHNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcnVuZSBhbGwge0BsaW5rIEdyYXBoLk5vZGV9cyAqbWF0Y2hpbmcqIHNwZWNpZmllZCBsaXN0LlxuICAgKlxuICAgKiBUaGlzIGZpbHRlciB0YXJnZXRzIGFsbCBub2RlcyAoZXhjZXB0IHJvb3QpIC0ge0BsaW5rIElHcmFwaEZpbHRlci5hbGxOb2Rlc31cbiAgICogQHRocm93cyBFcnJvciBpZiBzdG9yZSBpcyBub3QgZmlsdGVyYWJsZVxuICAgKiBAZGVzdHJ1Y3RpdmVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZXhjbHVkZU5vZGVUeXBlKG5vZGVUeXBlczogRmlsdGVyVmFsdWVbXSk6IElHcmFwaFN0b3JlRmlsdGVyIHtcbiAgICByZXR1cm4gRmlsdGVycy5fZmlsdGVyTm9kZVR5cGUobm9kZVR5cGVzLCB0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgX2ZpbHRlckNmblR5cGUoXG4gICAgdmFsdWVzOiBGaWx0ZXJWYWx1ZVtdLFxuICAgIGV4Y2x1ZGU6IGJvb2xlYW5cbiAgKTogSUdyYXBoRmlsdGVyIHtcbiAgICBjb25zdCBpc01hdGNoID0gbWVtb2l6ZSgoaW5wdXQ6IHN0cmluZykgPT4ge1xuICAgICAgaWYgKGlucHV0ID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gKFxuICAgICAgICB2YWx1ZXMuZmluZCgoX3ZhbHVlKSA9PiB7XG4gICAgICAgICAgaWYgKF92YWx1ZS52YWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0ID09PSBfdmFsdWUudmFsdWU7XG4gICAgICAgICAgfSBlbHNlIGlmIChfdmFsdWUucmVnZXgpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUmVnRXhwKF92YWx1ZS5yZWdleCkudGVzdChpbnB1dCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgfVxuICAgICAgICB9KSAhPSBudWxsXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN0cmF0ZWd5OiBGaWx0ZXJTdHJhdGVneS5QUlVORSxcbiAgICAgIG5vZGU6IHtcbiAgICAgICAgZmlsdGVyOiAobm9kZSkgPT4ge1xuICAgICAgICAgIC8vIFByZXNlcnZlIGNvbnRhaW5lciBzdHJ1Y3R1cmUgKHN0YWdlcywgc3RhY2tzLCBldGMuKVxuICAgICAgICAgIGlmIChub2RlLmlzQ2x1c3RlciB8fCBub2RlLmlzR3JhcGhDb250YWluZXIpIHJldHVybiB0cnVlO1xuICAgICAgICAgIGlmIChHcmFwaC5pc1Jlc291cmNlTGlrZShub2RlKSkge1xuICAgICAgICAgICAgY29uc3QgbWF0Y2ggPSAhIW5vZGUuY2ZuVHlwZSAmJiBpc01hdGNoKG5vZGUuY2ZuVHlwZSk7XG4gICAgICAgICAgICByZXR1cm4gKG1hdGNoICYmICFleGNsdWRlKSB8fCAoIW1hdGNoICYmIGV4Y2x1ZGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBQcmVzZXJ2ZSBub24gKlJlc291cmNlIG5vZGVzXG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUHJ1bmUgYWxsIHtAbGluayBHcmFwaC5SZXNvdXJjZU5vZGV9IGFuZCB7QGxpbmsgR3JhcGguQ2ZuUmVzb3VyY2VOb2RlfSBub2Rlc1xuICAgKiAqZXhjZXB0IHRob3NlIG1hdGNoaW5nKiBzcGVjaWZpZWQgbGlzdCBvZiBDbG91ZEZvcm1hdGlvbiB0eXBlcy5cbiAgICogQHRocm93cyBFcnJvciBpZiBzdG9yZSBpcyBub3QgZmlsdGVyYWJsZVxuICAgKiBAZGVzdHJ1Y3RpdmVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgaW5jbHVkZUNmblR5cGUoY2ZuVHlwZXM6IEZpbHRlclZhbHVlW10pOiBJR3JhcGhGaWx0ZXIge1xuICAgIHJldHVybiBGaWx0ZXJzLl9maWx0ZXJDZm5UeXBlKGNmblR5cGVzLCBmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogUHJ1bmUgYWxsIHtAbGluayBHcmFwaC5SZXNvdXJjZU5vZGV9IGFuZCB7QGxpbmsgR3JhcGguQ2ZuUmVzb3VyY2VOb2RlfSBub2Rlc1xuICAgKiAqbWF0Y2hpbmcqIHNwZWNpZmllZCBsaXN0IG9mIENsb3VkRm9ybWF0aW9uIHR5cGVzLlxuICAgKiBAdGhyb3dzIEVycm9yIGlmIHN0b3JlIGlzIG5vdCBmaWx0ZXJhYmxlXG4gICAqIEBkZXN0cnVjdGl2ZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBleGNsdWRlQ2ZuVHlwZShjZm5UeXBlczogRmlsdGVyVmFsdWVbXSk6IElHcmFwaEZpbHRlciB7XG4gICAgcmV0dXJuIEZpbHRlcnMuX2ZpbHRlckNmblR5cGUoY2ZuVHlwZXMsIHRydWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBjbHVzdGVycyBieSBob2lzdGluZyB0aGVpciBjaGlsZHJlbiB0byB0aGUgcGFyZW50IG9mIHRoZSBjbHVzdGVyXG4gICAqIGFuZCBjb2xsYXBzaW5nIHRoZSBjbHVzdGVyIGl0c2VsZiB0byBpdHMgcGFyZW50LlxuICAgKiBAcGFyYW0gY2x1c3RlclR5cGVzXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgc3RvcmUgaXMgbm90IGZpbHRlcmFibGVcbiAgICogQHNlZSB7QGxpbmsgR3JhcGguTm9kZS5tdXRhdGVVbmNsdXN0ZXJ9XG4gICAqIEBkZXN0cnVjdGl2ZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyB1bmNsdXN0ZXIoY2x1c3RlclR5cGVzPzogTm9kZVR5cGVFbnVtW10pOiBJR3JhcGhTdG9yZUZpbHRlciB7XG4gICAgLy8gVXNlIHNldCBmb3IgY29uc3RhbnQgbG9va3VwXG4gICAgY29uc3QgY2x1c3RlclR5cGVzU2V0ID0gbmV3IFNldDxOb2RlVHlwZUVudW0+KGNsdXN0ZXJUeXBlcyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZmlsdGVyOiAoc3RvcmUpOiB2b2lkID0+IHtcbiAgICAgICAgRmlsdGVycy52ZXJpZnlGaWx0ZXJhYmxlKHN0b3JlKTtcblxuICAgICAgICBjb25zdCBjbHVzdGVycyA9IHN0b3JlLnJvb3QuZmluZEFsbCh7XG4gICAgICAgICAgcHJlZGljYXRlOiB7XG4gICAgICAgICAgICBmaWx0ZXI6IChub2RlKSA9PiB7XG4gICAgICAgICAgICAgIGlmIChub2RlLmlzR3JhcGhDb250YWluZXIpIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgaWYgKGNsdXN0ZXJUeXBlc1NldC5zaXplID09PSAwKSByZXR1cm4gbm9kZS5pc0NsdXN0ZXI7XG4gICAgICAgICAgICAgIHJldHVybiBjbHVzdGVyVHlwZXNTZXQuaGFzKG5vZGUubm9kZVR5cGUpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBmb3IgKGNvbnN0IGNsdXN0ZXIgb2YgY2x1c3RlcnMpIHtcbiAgICAgICAgICBjbHVzdGVyLm11dGF0ZVVuY2x1c3RlcigpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH07XG4gIH1cbn1cbiJdfQ==