UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

333 lines 44.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const cxapi = require("@aws-cdk/cx-api"); // import required to be here, otherwise causes a cycle when running the generated JavaScript // tslint:disable-next-line:ordered-imports const cfn_element_1 = require("./cfn-element"); const cfn_resource_policy_1 = require("./cfn-resource-policy"); const deps_1 = require("./deps"); const cfn_reference_1 = require("./private/cfn-reference"); const removal_policy_1 = require("./removal-policy"); const tag_manager_1 = require("./tag-manager"); const util_1 = require("./util"); /** * Represents a CloudFormation resource. */ class CfnResource extends cfn_element_1.CfnRefElement { /** * Creates a resource construct. * @param cfnResourceType The CloudFormation type of this resource (e.g. AWS::DynamoDB::Table) */ constructor(scope, id, props) { super(scope, id); // MAINTAINERS NOTE: this class serves as the base class for the generated L1 // ("CFN") resources (such as `s3.CfnBucket`). These resources will have a // property for each CloudFormation property of the resource. This means that // if at some point in the future a property is introduced with a name similar // to one of the properties here, it will be "masked" by the derived class. To // that end, we prefix all properties in this class with `cfnXxx` with the // hope to avoid those conflicts in the future. /** * Options for this resource, such as condition, update policy etc. */ this.cfnOptions = {}; /** * An object to be merged on top of the entire resource definition. */ this.rawOverrides = {}; /** * Logical IDs of dependencies. * * Is filled during prepare(). */ this.dependsOn = new Set(); if (!props.type) { throw new Error('The `type` property is required'); } this.cfnResourceType = props.type; this._cfnProperties = props.properties || {}; // if aws:cdk:enable-path-metadata is set, embed the current construct's // path in the CloudFormation template, so it will be possible to trace // back to the actual construct path. if (this.node.tryGetContext(cxapi.PATH_METADATA_ENABLE_CONTEXT)) { this.cfnOptions.metadata = { [cxapi.PATH_METADATA_KEY]: this.node.path, }; } } /** * Check whether the given construct is a CfnResource */ static isCfnResource(construct) { return construct.cfnResourceType !== undefined; } /** * Sets the deletion policy of the resource based on the removal policy specified. */ applyRemovalPolicy(policy, options = {}) { policy = policy || options.default || removal_policy_1.RemovalPolicy.RETAIN; let deletionPolicy; switch (policy) { case removal_policy_1.RemovalPolicy.DESTROY: deletionPolicy = cfn_resource_policy_1.CfnDeletionPolicy.DELETE; break; case removal_policy_1.RemovalPolicy.RETAIN: deletionPolicy = cfn_resource_policy_1.CfnDeletionPolicy.RETAIN; break; default: throw new Error(`Invalid removal policy: ${policy}`); } this.cfnOptions.deletionPolicy = deletionPolicy; if (options.applyToUpdateReplacePolicy !== false) { this.cfnOptions.updateReplacePolicy = deletionPolicy; } } /** * Returns a token for an runtime attribute of this resource. * Ideally, use generated attribute accessors (e.g. `resource.arn`), but this can be used for future compatibility * in case there is no generated attribute. * @param attributeName The name of the attribute. */ getAtt(attributeName) { return cfn_reference_1.CfnReference.for(this, attributeName); } /** * Adds an override to the synthesized CloudFormation resource. To add a * property override, either use `addPropertyOverride` or prefix `path` with * "Properties." (i.e. `Properties.TopicName`). * * If the override is nested, separate each nested level using a dot (.) in the path parameter. * If there is an array as part of the nesting, specify the index in the path. * * For example, * ```typescript * addOverride('Properties.GlobalSecondaryIndexes.0.Projection.NonKeyAttributes', ['myattribute']) * addOverride('Properties.GlobalSecondaryIndexes.1.ProjectionType', 'INCLUDE') * ``` * would add the overrides * ```json * "Properties": { * "GlobalSecondaryIndexes": [ * { * "Projection": { * "NonKeyAttributes": [ "myattribute" ] * ... * } * ... * }, * { * "ProjectionType": "INCLUDE" * ... * }, * ] * ... * } * ``` * * @param path - The path of the property, you can use dot notation to * override values in complex types. Any intermdediate keys * will be created as needed. * @param value - The value. Could be primitive or complex. */ addOverride(path, value) { const parts = path.split('.'); let curr = this.rawOverrides; while (parts.length > 1) { const key = parts.shift(); // if we can't recurse further or the previous value is not an // object overwrite it with an object. const isObject = curr[key] != null && typeof (curr[key]) === 'object' && !Array.isArray(curr[key]); if (!isObject) { curr[key] = {}; } curr = curr[key]; } const lastKey = parts.shift(); curr[lastKey] = value; } /** * Syntactic sugar for `addOverride(path, undefined)`. * @param path The path of the value to delete */ addDeletionOverride(path) { this.addOverride(path, undefined); } /** * Adds an override to a resource property. * * Syntactic sugar for `addOverride("Properties.<...>", value)`. * * @param propertyPath The path of the property * @param value The value */ addPropertyOverride(propertyPath, value) { this.addOverride(`Properties.${propertyPath}`, value); } /** * Adds an override that deletes the value of a property from the resource definition. * @param propertyPath The path to the property. */ addPropertyDeletionOverride(propertyPath) { this.addPropertyOverride(propertyPath, undefined); } /** * Indicates that this resource depends on another resource and cannot be * provisioned unless the other resource has been successfully provisioned. * * This can be used for resources across stacks (or nested stack) boundaries * and the dependency will automatically be transferred to the relevant scope. */ addDependsOn(target) { deps_1.addDependency(this, target, `"${this.node.path}" depends on "${target.node.path}"`); } /** * @returns a string representation of this resource */ toString() { return `${super.toString()} [${this.cfnResourceType}]`; } /** * Called by the `addDependency` helper function in order to realize a direct * dependency between two resources that are directly defined in the same * stacks. * * Use `resource.addDependsOn` to define the dependency between two resources, * which also takes stack boundaries into account. * * @internal */ _addResourceDependency(target) { this.dependsOn.add(target); } /** * Emits CloudFormation for this resource. * @internal */ _toCloudFormation() { try { const ret = { Resources: { // Post-Resolve operation since otherwise deepMerge is going to mix values into // the Token objects returned by ignoreEmpty. [this.logicalId]: new util_1.PostResolveToken({ Type: this.cfnResourceType, Properties: util_1.ignoreEmpty(this.cfnProperties), DependsOn: util_1.ignoreEmpty(renderDependsOn(this.dependsOn)), CreationPolicy: util_1.capitalizePropertyNames(this, renderCreationPolicy(this.cfnOptions.creationPolicy)), UpdatePolicy: util_1.capitalizePropertyNames(this, this.cfnOptions.updatePolicy), UpdateReplacePolicy: util_1.capitalizePropertyNames(this, this.cfnOptions.updateReplacePolicy), DeletionPolicy: util_1.capitalizePropertyNames(this, this.cfnOptions.deletionPolicy), Metadata: util_1.ignoreEmpty(this.cfnOptions.metadata), Condition: this.cfnOptions.condition && this.cfnOptions.condition.logicalId, }, props => { const renderedProps = this.renderProperties(props.Properties || {}); props.Properties = renderedProps && (Object.values(renderedProps).find(v => !!v) ? renderedProps : undefined); return deepMerge(props, this.rawOverrides); }), }, }; return ret; } catch (e) { // Change message e.message = `While synthesizing ${this.node.path}: ${e.message}`; // Adjust stack trace (make it look like node built it, too...) const trace = this.creationStack; if (trace) { const creationStack = ['--- resource created at ---', ...trace].join('\n at '); const problemTrace = e.stack.substr(e.stack.indexOf(e.message) + e.message.length); e.stack = `${e.message}\n ${creationStack}\n --- problem discovered at ---${problemTrace}`; } // Re-throw throw e; } // returns the set of logical ID (tokens) this resource depends on // sorted by construct paths to ensure test determinism function renderDependsOn(dependsOn) { return Array .from(dependsOn) .sort((x, y) => x.node.path.localeCompare(y.node.path)) .map(r => r.logicalId); } function renderCreationPolicy(policy) { if (!policy) { return undefined; } const result = { ...policy }; if (policy.resourceSignal && policy.resourceSignal.timeout) { result.resourceSignal = policy.resourceSignal; } return result; } } get cfnProperties() { const props = this._cfnProperties || {}; if (tag_manager_1.TagManager.isTaggable(this)) { const tagsProp = {}; tagsProp[this.tags.tagPropertyName] = this.tags.renderTags(); return deepMerge(props, tagsProp); } return props; } renderProperties(props) { return props; } /** * Return properties modified after initiation * * Resources that expose mutable properties should override this function to * collect and return the properties object for this resource. */ get updatedProperites() { return this._cfnProperties; } validateProperties(_properties) { // Nothing } } exports.CfnResource = CfnResource; var TagType; (function (TagType) { TagType["STANDARD"] = "StandardTag"; TagType["AUTOSCALING_GROUP"] = "AutoScalingGroupTag"; TagType["MAP"] = "StringToStringMap"; TagType["KEY_VALUE"] = "KeyValue"; TagType["NOT_TAGGABLE"] = "NotTaggable"; })(TagType = exports.TagType || (exports.TagType = {})); /** * Merges `source` into `target`, overriding any existing values. * `null`s will cause a value to be deleted. */ function deepMerge(target, ...sources) { for (const source of sources) { if (typeof (source) !== 'object' || typeof (target) !== 'object') { throw new Error(`Invalid usage. Both source (${JSON.stringify(source)}) and target (${JSON.stringify(target)}) must be objects`); } for (const key of Object.keys(source)) { const value = source[key]; if (typeof (value) === 'object' && value != null && !Array.isArray(value)) { // if the value at the target is not an object, override it with an // object so we can continue the recursion if (typeof (target[key]) !== 'object') { target[key] = {}; } deepMerge(target[key], value); // if the result of the merge is an empty object, it's because the // eventual value we assigned is `undefined`, and there are no // sibling concrete values alongside, so we can delete this tree. const output = target[key]; if (typeof (output) === 'object' && Object.keys(output).length === 0) { delete target[key]; } } else if (value === undefined) { delete target[key]; } else { target[key] = value; } } } return target; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2ZuLXJlc291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2ZuLXJlc291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEseUNBQXlDO0FBRXpDLDZGQUE2RjtBQUM3RiwyQ0FBMkM7QUFDM0MsK0NBQThDO0FBQzlDLCtEQUE4RjtBQUU5RixpQ0FBdUM7QUFDdkMsMkRBQXVEO0FBRXZELHFEQUF1RTtBQUN2RSwrQ0FBMkM7QUFDM0MsaUNBQWdGO0FBZ0JoRjs7R0FFRztBQUNILE1BQWEsV0FBWSxTQUFRLDJCQUFhO0lBOEM1Qzs7O09BR0c7SUFDSCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXVCO1FBQy9ELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUEzQ25CLDZFQUE2RTtRQUM3RSwwRUFBMEU7UUFDMUUsNkVBQTZFO1FBQzdFLDhFQUE4RTtRQUM5RSw4RUFBOEU7UUFDOUUsMEVBQTBFO1FBQzFFLCtDQUErQztRQUUvQzs7V0FFRztRQUNhLGVBQVUsR0FBd0IsRUFBRSxDQUFDO1FBZXJEOztXQUVHO1FBQ2MsaUJBQVksR0FBUSxFQUFFLENBQUM7UUFFeEM7Ozs7V0FJRztRQUNjLGNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBZSxDQUFDO1FBU2xELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFO1lBQ2YsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1NBQ3BEO1FBRUQsSUFBSSxDQUFDLGVBQWUsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUM7UUFFN0Msd0VBQXdFO1FBQ3hFLHVFQUF1RTtRQUN2RSxxQ0FBcUM7UUFDckMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsNEJBQTRCLENBQUMsRUFBRTtZQUMvRCxJQUFJLENBQUMsVUFBVSxD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QUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDckMsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzFCLElBQUksT0FBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLFFBQVEsSUFBSSxLQUFLLElBQUksSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtnQkFDeEUsbUVBQW1FO2dCQUNuRSwwQ0FBMEM7Z0JBQzFDLElBQUksT0FBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLFFBQVEsRUFBRTtvQkFDcEMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztpQkFDbEI7Z0JBRUQsU0FBUyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFFOUIsa0VBQWtFO2dCQUNsRSw4REFBOEQ7Z0JBQzlELGlFQUFpRTtnQkFDakUsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUMzQixJQUFJLE9BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO29CQUNuRSxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztpQkFDcEI7YUFDRjtpQkFBTSxJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUU7Z0JBQzlCLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ3BCO2lCQUFNO2dCQUNMLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7YUFDckI7U0FDRjtLQUNGO0lBRUQsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGN4YXBpIGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgeyBDZm5Db25kaXRpb24gfSBmcm9tICcuL2Nmbi1jb25kaXRpb24nO1xuLy8gaW1wb3J0IHJlcXVpcmVkIHRvIGJlIGhlcmUsIG90aGVyd2lzZSBjYXVzZXMgYSBjeWNsZSB3aGVuIHJ1bm5pbmcgdGhlIGdlbmVyYXRlZCBKYXZhU2NyaXB0XG4vLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6b3JkZXJlZC1pbXBvcnRzXG5pbXBvcnQgeyBDZm5SZWZFbGVtZW50IH0gZnJvbSAnLi9jZm4tZWxlbWVudCc7XG5pbXBvcnQgeyBDZm5DcmVhdGlvblBvbGljeSwgQ2ZuRGVsZXRpb25Qb2xpY3ksIENmblVwZGF0ZVBvbGljeSB9IGZyb20gJy4vY2ZuLXJlc291cmNlLXBvbGljeSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QsIElDb25zdHJ1Y3QgfSBmcm9tICcuL2NvbnN0cnVjdC1jb21wYXQnO1xuaW1wb3J0IHsgYWRkRGVwZW5kZW5jeSB9IGZyb20gJy4vZGVwcyc7XG5pbXBvcnQgeyBDZm5SZWZlcmVuY2UgfSBmcm9tICcuL3ByaXZhdGUvY2ZuLXJlZmVyZW5jZSc7XG5pbXBvcnQgeyBSZWZlcmVuY2UgfSBmcm9tICcuL3JlZmVyZW5jZSc7XG5pbXBvcnQgeyBSZW1vdmFsUG9saWN5LCBSZW1vdmFsUG9saWN5T3B0aW9ucyB9IGZyb20gJy4vcmVtb3ZhbC1wb2xpY3knO1xuaW1wb3J0IHsgVGFnTWFuYWdlciB9IGZyb20gJy4vdGFnLW1hbmFnZXInO1xuaW1wb3J0IHsgY2FwaXRhbGl6ZVByb3BlcnR5TmFtZXMsIGlnbm9yZUVtcHR5LCBQb3N0UmVzb2x2ZVRva2VuIH0gZnJvbSAnLi91dGlsJztcblxuZXhwb3J0IGludGVyZmFjZSBDZm5SZXNvdXJjZVByb3BzIHtcbiAgLyoqXG4gICAqIENsb3VkRm9ybWF0aW9uIHJlc291cmNlIHR5cGUgKGUuZy4gYEFXUzo6UzM6OkJ1Y2tldGApLlxuICAgKi9cbiAgcmVhZG9ubHkgdHlwZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZXNvdXJjZSBwcm9wZXJ0aWVzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHJlc291cmNlIHByb3BlcnRpZXMuXG4gICAqL1xuICByZWFkb25seSBwcm9wZXJ0aWVzPzogeyBbbmFtZTogc3RyaW5nXTogYW55IH07XG59XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIENsb3VkRm9ybWF0aW9uIHJlc291cmNlLlxuICovXG5leHBvcnQgY2xhc3MgQ2ZuUmVzb3VyY2UgZXh0ZW5kcyBDZm5SZWZFbGVtZW50IHtcbiAgLyoqXG4gICAqIENoZWNrIHdoZXRoZXIgdGhlIGdpdmVuIGNvbnN0cnVjdCBpcyBhIENmblJlc291cmNlXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGlzQ2ZuUmVzb3VyY2UoY29uc3RydWN0OiBJQ29uc3RydWN0KTogY29uc3RydWN0IGlzIENmblJlc291cmNlIHtcbiAgICByZXR1cm4gKGNvbnN0cnVjdCBhcyBhbnkpLmNmblJlc291cmNlVHlwZSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLy8gTUFJTlRBSU5FUlMgTk9URTogdGhpcyBjbGFzcyBzZXJ2ZXMgYXMgdGhlIGJhc2UgY2xhc3MgZm9yIHRoZSBnZW5lcmF0ZWQgTDFcbiAgLy8gKFwiQ0ZOXCIpIHJlc291cmNlcyAoc3VjaCBhcyBgczMuQ2ZuQnVja2V0YCkuIFRoZXNlIHJlc291cmNlcyB3aWxsIGhhdmUgYVxuICAvLyBwcm9wZXJ0eSBmb3IgZWFjaCBDbG91ZEZvcm1hdGlvbiBwcm9wZXJ0eSBvZiB0aGUgcmVzb3VyY2UuIFRoaXMgbWVhbnMgdGhhdFxuICAvLyBpZiBhdCBzb21lIHBvaW50IGluIHRoZSBmdXR1cmUgYSBwcm9wZXJ0eSBpcyBpbnRyb2R1Y2VkIHdpdGggYSBuYW1lIHNpbWlsYXJcbiAgLy8gdG8gb25lIG9mIHRoZSBwcm9wZXJ0aWVzIGhlcmUsIGl0IHdpbGwgYmUgXCJtYXNrZWRcIiBieSB0aGUgZGVyaXZlZCBjbGFzcy4gVG9cbiAgLy8gdGhhdCBlbmQsIHdlIHByZWZpeCBhbGwgcHJvcGVydGllcyBpbiB0aGlzIGNsYXNzIHdpdGggYGNmblh4eGAgd2l0aCB0aGVcbiAgLy8gaG9wZSB0byBhdm9pZCB0aG9zZSBjb25mbGljdHMgaW4gdGhlIGZ1dHVyZS5cblxuICAvKipcbiAgICogT3B0aW9ucyBmb3IgdGhpcyByZXNvdXJjZSwgc3VjaCBhcyBjb25kaXRpb24sIHVwZGF0ZSBwb2xpY3kgZXRjLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNmbk9wdGlvbnM6IElDZm5SZXNvdXJjZU9wdGlvbnMgPSB7fTtcblxuICAvKipcbiAgICogQVdTIHJlc291cmNlIHR5cGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY2ZuUmVzb3VyY2VUeXBlOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFXUyBDbG91ZEZvcm1hdGlvbiByZXNvdXJjZSBwcm9wZXJ0aWVzLlxuICAgKlxuICAgKiBUaGlzIG9iamVjdCBpcyByZXR1cm5lZCB2aWEgY2ZuUHJvcGVydGllc1xuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByb3RlY3RlZCByZWFkb25seSBfY2ZuUHJvcGVydGllczogYW55O1xuXG4gIC8qKlxuICAgKiBBbiBvYmplY3QgdG8gYmUgbWVyZ2VkIG9uIHRvcCBvZiB0aGUgZW50aXJlIHJlc291cmNlIGRlZmluaXRpb24uXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJhd092ZXJyaWRlczogYW55ID0ge307XG5cbiAgLyoqXG4gICAqIExvZ2ljYWwgSURzIG9mIGRlcGVuZGVuY2llcy5cbiAgICpcbiAgICogSXMgZmlsbGVkIGR1cmluZyBwcmVwYXJlKCkuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGRlcGVuZHNPbiA9IG5ldyBTZXQ8Q2ZuUmVzb3VyY2U+KCk7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSByZXNvdXJjZSBjb25zdHJ1Y3QuXG4gICAqIEBwYXJhbSBjZm5SZXNvdXJjZVR5cGUgVGhlIENsb3VkRm9ybWF0aW9uIHR5cGUgb2YgdGhpcyByZXNvdXJjZSAoZS5nLiBBV1M6OkR5bmFtb0RCOjpUYWJsZSlcbiAgICovXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBDZm5SZXNvdXJjZVByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGlmICghcHJvcHMudHlwZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgYHR5cGVgIHByb3BlcnR5IGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuXG4gICAgdGhpcy5jZm5SZXNvdXJjZVR5cGUgPSBwcm9wcy50eXBlO1xuICAgIHRoaXMuX2NmblByb3BlcnRpZXMgPSBwcm9wcy5wcm9wZXJ0aWVzIHx8IHt9O1xuXG4gICAgLy8gaWYgYXdzOmNkazplbmFibGUtcGF0aC1tZXRhZGF0YSBpcyBzZXQsIGVtYmVkIHRoZSBjdXJyZW50IGNvbnN0cnVjdCdzXG4gICAgLy8gcGF0aCBpbiB0aGUgQ2xvdWRGb3JtYXRpb24gdGVtcGxhdGUsIHNvIGl0IHdpbGwgYmUgcG9zc2libGUgdG8gdHJhY2VcbiAgICAvLyBiYWNrIHRvIHRoZSBhY3R1YWwgY29uc3RydWN0IHBhdGguXG4gICAgaWYgKHRoaXMubm9kZS50cnlHZXRDb250ZXh0KGN4YXBpLlBBVEhfTUVUQURBVEFfRU5BQkxFX0NPTlRFWFQpKSB7XG4gICAgICB0aGlzLmNmbk9wdGlvbnMubWV0YWRhdGEgPSB7XG4gICAgICAgIFtjeGFwaS5QQVRIX01FVEFEQVRBX0tFWV06IHRoaXMubm9kZS5wYXRoLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgZGVsZXRpb24gcG9saWN5IG9mIHRoZSByZXNvdXJjZSBiYXNlZCBvbiB0aGUgcmVtb3ZhbCBwb2xpY3kgc3BlY2lmaWVkLlxuICAgKi9cbiAgcHVibGljIGFwcGx5UmVtb3ZhbFBvbGljeShwb2xpY3k6IFJlbW92YWxQb2xpY3kgfCB1bmRlZmluZWQsIG9wdGlvbnM6IFJlbW92YWxQb2xpY3lPcHRpb25zID0ge30pIHtcbiAgICBwb2xpY3kgPSBwb2xpY3kgfHwgb3B0aW9ucy5kZWZhdWx0IHx8IFJlbW92YWxQb2xpY3kuUkVUQUlOO1xuXG4gICAgbGV0IGRlbGV0aW9uUG9saWN5O1xuXG4gICAgc3dpdGNoIChwb2xpY3kpIHtcbiAgICAgIGNhc2UgUmVtb3ZhbFBvbGljeS5ERVNUUk9ZOlxuICAgICAgICBkZWxldGlvblBvbGljeSA9IENmbkRlbGV0aW9uUG9saWN5LkRFTEVURTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgUmVtb3ZhbFBvbGljeS5SRVRBSU46XG4gICAgICAgIGRlbGV0aW9uUG9saWN5ID0gQ2ZuRGVsZXRpb25Qb2xpY3kuUkVUQUlOO1xuICAgICAgICBicmVhaztcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHJlbW92YWwgcG9saWN5OiAke3BvbGljeX1gKTtcbiAgICB9XG5cbiAgICB0aGlzLmNmbk9wdGlvbnMuZGVsZXRpb25Qb2xpY3kgPSBkZWxldGlvblBvbGljeTtcbiAgICBpZiAob3B0aW9ucy5hcHBseVRvVXBkYXRlUmVwbGFjZVBvbGljeSAhPT0gZmFsc2UpIHtcbiAgICAgIHRoaXMuY2ZuT3B0aW9ucy51cGRhdGVSZXBsYWNlUG9saWN5ID0gZGVsZXRpb25Qb2xpY3k7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB0b2tlbiBmb3IgYW4gcnVudGltZSBhdHRyaWJ1dGUgb2YgdGhpcyByZXNvdXJjZS5cbiAgICogSWRlYWxseSwgdXNlIGdlbmVyYXRlZCBhdHRyaWJ1dGUgYWNjZXNzb3JzIChlLmcuIGByZXNvdXJjZS5hcm5gKSwgYnV0IHRoaXMgY2FuIGJlIHVzZWQgZm9yIGZ1dHVyZSBjb21wYXRpYmlsaXR5XG4gICAqIGluIGNhc2UgdGhlcmUgaXMgbm8gZ2VuZXJhdGVkIGF0dHJpYnV0ZS5cbiAgICogQHBhcmFtIGF0dHJpYnV0ZU5hbWUgVGhlIG5hbWUgb2YgdGhlIGF0dHJpYnV0ZS5cbiAgICovXG4gIHB1YmxpYyBnZXRBdHQoYXR0cmlidXRlTmFtZTogc3RyaW5nKTogUmVmZXJlbmNlIHtcbiAgICByZXR1cm4gQ2ZuUmVmZXJlbmNlLmZvcih0aGlzLCBhdHRyaWJ1dGVOYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFuIG92ZXJyaWRlIHRvIHRoZSBzeW50aGVzaXplZCBDbG91ZEZvcm1hdGlvbiByZXNvdXJjZS4gVG8gYWRkIGFcbiAgICogcHJvcGVydHkgb3ZlcnJpZGUsIGVpdGhlciB1c2UgYGFkZFByb3BlcnR5T3ZlcnJpZGVgIG9yIHByZWZpeCBgcGF0aGAgd2l0aFxuICAgKiBcIlByb3BlcnRpZXMuXCIgKGkuZS4gYFByb3BlcnRpZXMuVG9waWNOYW1lYCkuXG4gICAqXG4gICAqIElmIHRoZSBvdmVycmlkZSBpcyBuZXN0ZWQsIHNlcGFyYXRlIGVhY2ggbmVzdGVkIGxldmVsIHVzaW5nIGEgZG90ICguKSBpbiB0aGUgcGF0aCBwYXJhbWV0ZXIuXG4gICAqIElmIHRoZXJlIGlzIGFuIGFycmF5IGFzIHBhcnQgb2YgdGhlIG5lc3RpbmcsIHNwZWNpZnkgdGhlIGluZGV4IGluIHRoZSBwYXRoLlxuICAgKlxuICAgKiBGb3IgZXhhbXBsZSxcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhZGRPdmVycmlkZSgnUHJvcGVydGllcy5HbG9iYWxTZWNvbmRhcnlJbmRleGVzLjAuUHJvamVjdGlvbi5Ob25LZXlBdHRyaWJ1dGVzJywgWydteWF0dHJpYnV0ZSddKVxuICAgKiBhZGRPdmVycmlkZSgnUHJvcGVydGllcy5HbG9iYWxTZWNvbmRhcnlJbmRleGVzLjEuUHJvamVjdGlvblR5cGUnLCAnSU5DTFVERScpXG4gICAqIGBgYFxuICAgKiB3b3VsZCBhZGQgdGhlIG92ZXJyaWRlc1xuICAgKiBgYGBqc29uXG4gICAqIFwiUHJvcGVydGllc1wiOiB7XG4gICAqICAgXCJHbG9iYWxTZWNvbmRhcnlJbmRleGVzXCI6IFtcbiAgICogICAgIHtcbiAgICogICAgICAgXCJQcm9qZWN0aW9uXCI6IHtcbiAgICogICAgICAgICBcIk5vbktleUF0dHJpYnV0ZXNcIjogWyBcIm15YXR0cmlidXRlXCIgXVxuICAgKiAgICAgICAgIC4uLlxuICAgKiAgICAgICB9XG4gICAqICAgICAgIC4uLlxuICAgKiAgICAgfSxcbiAgICogICAgIHtcbiAgICogICAgICAgXCJQcm9qZWN0aW9uVHlwZVwiOiBcIklOQ0xVREVcIlxuICAgKiAgICAgICAuLi5cbiAgICogICAgIH0sXG4gICAqICAgXVxuICAgKiAgIC4uLlxuICAgKiB9XG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gcGF0aCAtIFRoZSBwYXRoIG9mIHRoZSBwcm9wZXJ0eSwgeW91IGNhbiB1c2UgZG90IG5vdGF0aW9uIHRvXG4gICAqICAgICAgICBvdmVycmlkZSB2YWx1ZXMgaW4gY29tcGxleCB0eXBlcy4gQW55IGludGVybWRlZGlhdGUga2V5c1xuICAgKiAgICAgICAgd2lsbCBiZSBjcmVhdGVkIGFzIG5lZWRlZC5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlLiBDb3VsZCBiZSBwcmltaXRpdmUgb3IgY29tcGxleC5cbiAgICovXG4gIHB1YmxpYyBhZGRPdmVycmlkZShwYXRoOiBzdHJpbmcsIHZhbHVlOiBhbnkpIHtcbiAgICBjb25zdCBwYXJ0cyA9IHBhdGguc3BsaXQoJy4nKTtcbiAgICBsZXQgY3VycjogYW55ID0gdGhpcy5yYXdPdmVycmlkZXM7XG5cbiAgICB3aGlsZSAocGFydHMubGVuZ3RoID4gMSkge1xuICAgICAgY29uc3Qga2V5ID0gcGFydHMuc2hpZnQoKSE7XG5cbiAgICAgIC8vIGlmIHdlIGNhbid0IHJlY3Vyc2UgZnVydGhlciBvciB0aGUgcHJldmlvdXMgdmFsdWUgaXMgbm90IGFuXG4gICAgICAvLyBvYmplY3Qgb3ZlcndyaXRlIGl0IHdpdGggYW4gb2JqZWN0LlxuICAgICAgY29uc3QgaXNPYmplY3QgPSBjdXJyW2tleV0gIT0gbnVsbCAmJiB0eXBlb2YoY3VycltrZXldKSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoY3VycltrZXldKTtcbiAgICAgIGlmICghaXNPYmplY3QpIHtcbiAgICAgICAgY3VycltrZXldID0ge307XG4gICAgICB9XG5cbiAgICAgIGN1cnIgPSBjdXJyW2tleV07XG4gICAgfVxuXG4gICAgY29uc3QgbGFzdEtleSA9IHBhcnRzLnNoaWZ0KCkhO1xuICAgIGN1cnJbbGFzdEtleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTeW50YWN0aWMgc3VnYXIgZm9yIGBhZGRPdmVycmlkZShwYXRoLCB1bmRlZmluZWQpYC5cbiAgICogQHBhcmFtIHBhdGggVGhlIHBhdGggb2YgdGhlIHZhbHVlIHRvIGRlbGV0ZVxuICAgKi9cbiAgcHVibGljIGFkZERlbGV0aW9uT3ZlcnJpZGUocGF0aDogc3RyaW5nKSB7XG4gICAgdGhpcy5hZGRPdmVycmlkZShwYXRoLCB1bmRlZmluZWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gb3ZlcnJpZGUgdG8gYSByZXNvdXJjZSBwcm9wZXJ0eS5cbiAgICpcbiAgICogU3ludGFjdGljIHN1Z2FyIGZvciBgYWRkT3ZlcnJpZGUoXCJQcm9wZXJ0aWVzLjwuLi4+XCIsIHZhbHVlKWAuXG4gICAqXG4gICAqIEBwYXJhbSBwcm9wZXJ0eVBhdGggVGhlIHBhdGggb2YgdGhlIHByb3BlcnR5XG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWVcbiAgICovXG4gIHB1YmxpYyBhZGRQcm9wZXJ0eU92ZXJyaWRlKHByb3BlcnR5UGF0aDogc3RyaW5nLCB2YWx1ZTogYW55KSB7XG4gICAgdGhpcy5hZGRPdmVycmlkZShgUHJvcGVydGllcy4ke3Byb3BlcnR5UGF0aH1gLCB2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhbiBvdmVycmlkZSB0aGF0IGRlbGV0ZXMgdGhlIHZhbHVlIG9mIGEgcHJvcGVydHkgZnJvbSB0aGUgcmVzb3VyY2UgZGVmaW5pdGlvbi5cbiAgICogQHBhcmFtIHByb3BlcnR5UGF0aCBUaGUgcGF0aCB0byB0aGUgcHJvcGVydHkuXG4gICAqL1xuICBwdWJsaWMgYWRkUHJvcGVydHlEZWxldGlvbk92ZXJyaWRlKHByb3BlcnR5UGF0aDogc3RyaW5nKSB7XG4gICAgdGhpcy5hZGRQcm9wZXJ0eU92ZXJyaWRlKHByb3BlcnR5UGF0aCwgdW5kZWZpbmVkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgdGhhdCB0aGlzIHJlc291cmNlIGRlcGVuZHMgb24gYW5vdGhlciByZXNvdXJjZSBhbmQgY2Fubm90IGJlXG4gICAqIHByb3Zpc2lvbmVkIHVubGVzcyB0aGUgb3RoZXIgcmVzb3VyY2UgaGFzIGJlZW4gc3VjY2Vzc2Z1bGx5IHByb3Zpc2lvbmVkLlxuICAgKlxuICAgKiBUaGlzIGNhbiBiZSB1c2VkIGZvciByZXNvdXJjZXMgYWNyb3NzIHN0YWNrcyAob3IgbmVzdGVkIHN0YWNrKSBib3VuZGFyaWVzXG4gICAqIGFuZCB0aGUgZGVwZW5kZW5jeSB3aWxsIGF1dG9tYXRpY2FsbHkgYmUgdHJhbnNmZXJyZWQgdG8gdGhlIHJlbGV2YW50IHNjb3BlLlxuICAgKi9cbiAgcHVibGljIGFkZERlcGVuZHNPbih0YXJnZXQ6IENmblJlc291cmNlKSB7XG4gICAgYWRkRGVwZW5kZW5jeSh0aGlzLCB0YXJnZXQsIGBcIiR7dGhpcy5ub2RlLnBhdGh9XCIgZGVwZW5kcyBvbiBcIiR7dGFyZ2V0Lm5vZGUucGF0aH1cImApO1xuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgcmVzb3VyY2VcbiAgICovXG4gIHB1YmxpYyB0b1N0cmluZygpIHtcbiAgICByZXR1cm4gYCR7c3VwZXIudG9TdHJpbmcoKX0gWyR7dGhpcy5jZm5SZXNvdXJjZVR5cGV9XWA7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbGVkIGJ5IHRoZSBgYWRkRGVwZW5kZW5jeWAgaGVscGVyIGZ1bmN0aW9uIGluIG9yZGVyIHRvIHJlYWxpemUgYSBkaXJlY3RcbiAgICogZGVwZW5kZW5jeSBiZXR3ZWVuIHR3byByZXNvdXJjZXMgdGhhdCBhcmUgZGlyZWN0bHkgZGVmaW5lZCBpbiB0aGUgc2FtZVxuICAgKiBzdGFja3MuXG4gICAqXG4gICAqIFVzZSBgcmVzb3VyY2UuYWRkRGVwZW5kc09uYCB0byBkZWZpbmUgdGhlIGRlcGVuZGVuY3kgYmV0d2VlbiB0d28gcmVzb3VyY2VzLFxuICAgKiB3aGljaCBhbHNvIHRha2VzIHN0YWNrIGJvdW5kYXJpZXMgaW50byBhY2NvdW50LlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHB1YmxpYyBfYWRkUmVzb3VyY2VEZXBlbmRlbmN5KHRhcmdldDogQ2ZuUmVzb3VyY2UpIHtcbiAgICB0aGlzLmRlcGVuZHNPbi5hZGQodGFyZ2V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbWl0cyBDbG91ZEZvcm1hdGlvbiBmb3IgdGhpcyByZXNvdXJjZS5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBwdWJsaWMgX3RvQ2xvdWRGb3JtYXRpb24oKTogb2JqZWN0IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmV0ID0ge1xuICAgICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgICAvLyBQb3N0LVJlc29sdmUgb3BlcmF0aW9uIHNpbmNlIG90aGVyd2lzZSBkZWVwTWVyZ2UgaXMgZ29pbmcgdG8gbWl4IHZhbHVlcyBpbnRvXG4gICAgICAgICAgLy8gdGhlIFRva2VuIG9iamVjdHMgcmV0dXJuZWQgYnkgaWdub3JlRW1wdHkuXG4gICAgICAgICAgW3RoaXMubG9naWNhbElkXTogbmV3IFBvc3RSZXNvbHZlVG9rZW4oe1xuICAgICAgICAgICAgVHlwZTogdGhpcy5jZm5SZXNvdXJjZVR5cGUsXG4gICAgICAgICAgICBQcm9wZXJ0aWVzOiBpZ25vcmVFbXB0eSh0aGlzLmNmblByb3BlcnRpZXMpLFxuICAgICAgICAgICAgRGVwZW5kc09uOiBpZ25vcmVFbXB0eShyZW5kZXJEZXBlbmRzT24odGhpcy5kZXBlbmRzT24pKSxcbiAgICAgICAgICAgIENyZWF0aW9uUG9saWN5OiAgY2FwaXRhbGl6ZVByb3BlcnR5TmFtZXModGhpcywgcmVuZGVyQ3JlYXRpb25Qb2xpY3kodGhpcy5jZm5PcHRpb25zLmNyZWF0aW9uUG9saWN5KSksXG4gICAgICAgICAgICBVcGRhdGVQb2xpY3k6IGNhcGl0YWxpemVQcm9wZXJ0eU5hbWVzKHRoaXMsIHRoaXMuY2ZuT3B0aW9ucy51cGRhdGVQb2xpY3kpLFxuICAgICAgICAgICAgVXBkYXRlUmVwbGFjZVBvbGljeTogY2FwaXRhbGl6ZVByb3BlcnR5TmFtZXModGhpcywgdGhpcy5jZm5PcHRpb25zLnVwZGF0ZVJlcGxhY2VQb2xpY3kpLFxuICAgICAgICAgICAgRGVsZXRpb25Qb2xpY3k6IGNhcGl0YWxpemVQcm9wZXJ0eU5hbWVzKHRoaXMsIHRoaXMuY2ZuT3B0aW9ucy5kZWxldGlvblBvbGljeSksXG4gICAgICAgICAgICBNZXRhZGF0YTogaWdub3JlRW1wdHkodGhpcy5jZm5PcHRpb25zLm1ldGFkYXRhKSxcbiAgICAgICAgICAgIENvbmRpdGlvbjogdGhpcy5jZm5PcHRpb25zLmNvbmRpdGlvbiAmJiB0aGlzLmNmbk9wdGlvbnMuY29uZGl0aW9uLmxvZ2ljYWxJZCxcbiAgICAgICAgICB9LCBwcm9wcyA9PiB7XG4gICAgICAgICAgICBjb25zdCByZW5kZXJlZFByb3BzID0gdGhpcy5yZW5kZXJQcm9wZXJ0aWVzKHByb3BzLlByb3BlcnRpZXMgfHwge30pO1xuICAgICAgICAgICAgcHJvcHMuUHJvcGVydGllcyA9IHJlbmRlcmVkUHJvcHMgJiYgKE9iamVjdC52YWx1ZXMocmVuZGVyZWRQcm9wcykuZmluZCh2ID0+ICEhdikgPyByZW5kZXJlZFByb3BzIDogdW5kZWZpbmVkKTtcbiAgICAgICAgICAgIHJldHVybiBkZWVwTWVyZ2UocHJvcHMsIHRoaXMucmF3T3ZlcnJpZGVzKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICByZXR1cm4gcmV0O1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIC8vIENoYW5nZSBtZXNzYWdlXG4gICAgICBlLm1lc3NhZ2UgPSBgV2hpbGUgc3ludGhlc2l6aW5nICR7dGhpcy5ub2RlLnBhdGh9OiAke2UubWVzc2FnZX1gO1xuICAgICAgLy8gQWRqdXN0IHN0YWNrIHRyYWNlIChtYWtlIGl0IGxvb2sgbGlrZSBub2RlIGJ1aWx0IGl0LCB0b28uLi4pXG4gICAgICBjb25zdCB0cmFjZSA9IHRoaXMuY3JlYXRpb25TdGFjaztcbiAgICAgIGlmICh0cmFjZSkge1xuICAgICAgICBjb25zdCBjcmVhdGlvblN0YWNrID0gWyctLS0gcmVzb3VyY2UgY3JlYXRlZCBhdCAtLS0nLCAuLi50cmFjZV0uam9pbignXFxuICBhdCAnKTtcbiAgICAgICAgY29uc3QgcHJvYmxlbVRyYWNlID0gZS5zdGFjay5zdWJzdHIoZS5zdGFjay5pbmRleE9mKGUubWVzc2FnZSkgKyBlLm1lc3NhZ2UubGVuZ3RoKTtcbiAgICAgICAgZS5zdGFjayA9IGAke2UubWVzc2FnZX1cXG4gICR7Y3JlYXRpb25TdGFja31cXG4gIC0tLSBwcm9ibGVtIGRpc2NvdmVyZWQgYXQgLS0tJHtwcm9ibGVtVHJhY2V9YDtcbiAgICAgIH1cblxuICAgICAgLy8gUmUtdGhyb3dcbiAgICAgIHRocm93IGU7XG4gICAgfVxuXG4gICAgLy8gcmV0dXJucyB0aGUgc2V0IG9mIGxvZ2ljYWwgSUQgKHRva2VucykgdGhpcyByZXNvdXJjZSBkZXBlbmRzIG9uXG4gICAgLy8gc29ydGVkIGJ5IGNvbnN0cnVjdCBwYXRocyB0byBlbnN1cmUgdGVzdCBkZXRlcm1pbmlzbVxuICAgIGZ1bmN0aW9uIHJlbmRlckRlcGVuZHNPbihkZXBlbmRzT246IFNldDxDZm5SZXNvdXJjZT4pIHtcbiAgICAgIHJldHVybiBBcnJheVxuICAgICAgICAuZnJvbShkZXBlbmRzT24pXG4gICAgICAgIC5zb3J0KCh4LCB5KSA9PiB4Lm5vZGUucGF0aC5sb2NhbGVDb21wYXJlKHkubm9kZS5wYXRoKSlcbiAgICAgICAgLm1hcChyID0+IHIubG9naWNhbElkKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZW5kZXJDcmVhdGlvblBvbGljeShwb2xpY3k6IENmbkNyZWF0aW9uUG9saWN5IHwgdW5kZWZpbmVkKTogYW55IHtcbiAgICAgIGlmICghcG9saWN5KSB7IHJldHVybiB1bmRlZmluZWQ7IH1cbiAgICAgIGNvbnN0IHJlc3VsdDogYW55ID0geyAuLi5wb2xpY3kgfTtcbiAgICAgIGlmIChwb2xpY3kucmVzb3VyY2VTaWduYWwgJiYgcG9saWN5LnJlc291cmNlU2lnbmFsLnRpbWVvdXQpIHtcbiAgICAgICAgcmVzdWx0LnJlc291cmNlU2lnbmFsID0gcG9saWN5LnJlc291cmNlU2lnbmFsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IGNmblByb3BlcnRpZXMoKTogeyBba2V5OiBzdHJpbmddOiBhbnkgfSB7XG4gICAgY29uc3QgcHJvcHMgPSB0aGlzLl9jZm5Qcm9wZXJ0aWVzIHx8IHt9O1xuICAgIGlmIChUYWdNYW5hZ2VyLmlzVGFnZ2FibGUodGhpcykpIHtcbiAgICAgIGNvbnN0IHRhZ3NQcm9wOiB7IFtrZXk6IHN0cmluZ106IGFueSB9ID0ge307XG4gICAgICB0YWdzUHJvcFt0aGlzLnRhZ3MudGFnUHJvcGVydHlOYW1lXSA9IHRoaXMudGFncy5yZW5kZXJUYWdzKCk7XG4gICAgICByZXR1cm4gZGVlcE1lcmdlKHByb3BzLCB0YWdzUHJvcCk7XG4gICAgfVxuICAgIHJldHVybiBwcm9wcztcbiAgfVxuXG4gIHByb3RlY3RlZCByZW5kZXJQcm9wZXJ0aWVzKHByb3BzOiB7W2tleTogc3RyaW5nXTogYW55fSk6IHsgW2tleTogc3RyaW5nXTogYW55IH0ge1xuICAgIHJldHVybiBwcm9wcztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gcHJvcGVydGllcyBtb2RpZmllZCBhZnRlciBpbml0aWF0aW9uXG4gICAqXG4gICAqIFJlc291cmNlcyB0aGF0IGV4cG9zZSBtdXRhYmxlIHByb3BlcnRpZXMgc2hvdWxkIG92ZXJyaWRlIHRoaXMgZnVuY3Rpb24gdG9cbiAgICogY29sbGVjdCBhbmQgcmV0dXJuIHRoZSBwcm9wZXJ0aWVzIG9iamVjdCBmb3IgdGhpcyByZXNvdXJjZS5cbiAgICovXG4gIHByb3RlY3RlZCBnZXQgdXBkYXRlZFByb3Blcml0ZXMoKTogeyBba2V5OiBzdHJpbmddOiBhbnkgfSB7XG4gICAgcmV0dXJuIHRoaXMuX2NmblByb3BlcnRpZXM7XG4gIH1cblxuICBwcm90ZWN0ZWQgdmFsaWRhdGVQcm9wZXJ0aWVzKF9wcm9wZXJ0aWVzOiBhbnkpIHtcbiAgICAvLyBOb3RoaW5nXG4gIH1cbn1cblxuZXhwb3J0IGVudW0gVGFnVHlwZSB7XG4gIFNUQU5EQVJEID0gJ1N0YW5kYXJkVGFnJyxcbiAgQVVUT1NDQUxJTkdfR1JPVVAgPSAnQXV0b1NjYWxpbmdHcm91cFRhZycsXG4gIE1BUCA9ICdTdHJpbmdUb1N0cmluZ01hcCcsXG4gIEtFWV9WQUxVRSA9ICdLZXlWYWx1ZScsXG4gIE5PVF9UQUdHQUJMRSA9ICdOb3RUYWdnYWJsZScsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSUNmblJlc291cmNlT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBIGNvbmRpdGlvbiB0byBhc3NvY2lhdGUgd2l0aCB0aGlzIHJlc291cmNlLiBUaGlzIG1lYW5zIHRoYXQgb25seSBpZiB0aGUgY29uZGl0aW9uIGV2YWx1YXRlcyB0byAndHJ1ZScgd2hlbiB0aGUgc3RhY2tcbiAgICogaXMgZGVwbG95ZWQsIHRoZSByZXNvdXJjZSB3aWxsIGJlIGluY2x1ZGVkLiBUaGlzIGlzIHByb3ZpZGVkIHRvIGFsbG93IENESyBwcm9qZWN0cyB0byBwcm9kdWNlIGxlZ2FjeSB0ZW1wbGF0ZXMsIGJ1dCBub3JhbWxseVxuICAgKiB0aGVyZSBpcyBubyBuZWVkIHRvIHVzZSBpdCBpbiBDREsgcHJvamVjdHMuXG4gICAqL1xuICBjb25kaXRpb24/OiBDZm5Db25kaXRpb247XG5cbiAgLyoqXG4gICAqIEFzc29jaWF0ZSB0aGUgQ3JlYXRpb25Qb2xpY3kgYXR0cmlidXRlIHdpdGggYSByZXNvdXJjZSB0byBwcmV2ZW50IGl0cyBzdGF0dXMgZnJvbSByZWFjaGluZyBjcmVhdGUgY29tcGxldGUgdW50aWxcbiAgICogQVdTIENsb3VkRm9ybWF0aW9uIHJlY2VpdmVzIGEgc3BlY2lmaWVkIG51bWJlciBvZiBzdWNjZXNzIHNpZ25hbHMgb3IgdGhlIHRpbWVvdXQgcGVyaW9kIGlzIGV4Y2VlZGVkLiBUbyBzaWduYWwgYVxuICAgKiByZXNvdXJjZSwgeW91IGNhbiB1c2UgdGhlIGNmbi1zaWduYWwgaGVscGVyIHNjcmlwdCBvciBTaWduYWxSZXNvdXJjZSBBUEkuIEFXUyBDbG91ZEZvcm1hdGlvbiBwdWJsaXNoZXMgdmFsaWQgc2lnbmFsc1xuICAgKiB0byB0aGUgc3RhY2sgZXZlbnRzIHNvIHRoYXQgeW91IHRyYWNrIHRoZSBudW1iZXIgb2Ygc2lnbmFscyBzZW50LlxuICAgKi9cbiAgY3JlYXRpb25Qb2xpY3k/OiBDZm5DcmVhdGlvblBvbGljeTtcblxuICAvKipcbiAgICogV2l0aCB0aGUgRGVsZXRpb25Qb2xpY3kgYXR0cmlidXRlIHlvdSBjYW4gcHJlc2VydmUgb3IgKGluIHNvbWUgY2FzZXMpIGJhY2t1cCBhIHJlc291cmNlIHdoZW4gaXRzIHN0YWNrIGlzIGRlbGV0ZWQuXG4gICAqIFlvdSBzcGVjaWZ5IGEgRGVsZXRpb25Qb2xpY3kgYXR0cmlidXRlIGZvciBlYWNoIHJlc291cmNlIHRoYXQgeW91IHdhbnQgdG8gY29udHJvbC4gSWYgYSByZXNvdXJjZSBoYXMgbm8gRGVsZXRpb25Qb2xpY3lcbiAgICogYXR0cmlidXRlLCBBV1MgQ2xvdWRGb3JtYXRpb24gZGVsZXRlcyB0aGUgcmVzb3VyY2UgYnkgZGVmYXVsdC4gTm90ZSB0aGF0IHRoaXMgY2FwYWJpbGl0eSBhbHNvIGFwcGxpZXMgdG8gdXBkYXRlIG9wZXJhdGlvbnNcbiAgICogdGhhdCBsZWFkIHRvIHJlc291cmNlcyBiZWluZyByZW1vdmVkLlxuICAgKi9cbiAgZGVsZXRpb25Qb2xpY3k/OiBDZm5EZWxldGlvblBvbGljeTtcblxuICAvKipcbiAgICogVXNlIHRoZSBVcGRhdGVQb2xpY3kgYXR0cmlidXRlIHRvIHNwZWNpZnkgaG93IEFXUyBDbG91ZEZvcm1hdGlvbiBoYW5kbGVzIHVwZGF0ZXMgdG8gdGhlIEFXUzo6QXV0b1NjYWxpbmc6OkF1dG9TY2FsaW5nR3JvdXBcbiAgICogcmVzb3VyY2UuIEFXUyBDbG91ZEZvcm1hdGlvbiBpbnZva2VzIG9uZSBvZiB0aHJlZSB1cGRhdGUgcG9saWNpZXMgZGVwZW5kaW5nIG9uIHRoZSB0eXBlIG9mIGNoYW5nZSB5b3UgbWFrZSBvciB3aGV0aGVyIGFcbiAgICogc2NoZWR1bGVkIGFjdGlvbiBpcyBhc3NvY2lhdGVkIHdpdGggdGhlIEF1dG8gU2NhbGluZyBncm91cC5cbiAgICovXG4gIHVwZGF0ZVBvbGljeT86IENmblVwZGF0ZVBvbGljeTtcblxuICAvKipcbiAgICogVXNlIHRoZSBVcGRhdGVSZXBsYWNlUG9saWN5IGF0dHJpYnV0ZSB0byByZXRhaW4gb3IgKGluIHNvbWUgY2FzZXMpIGJhY2t1cCB0aGUgZXhpc3RpbmcgcGh5c2ljYWwgaW5zdGFuY2Ugb2YgYSByZXNvdXJjZVxuICAgKiB3aGVuIGl0IGlzIHJlcGxhY2VkIGR1cmluZyBhIHN0YWNrIHVwZGF0ZSBvcGVyYXRpb24uXG4gICAqL1xuICB1cGRhdGVSZXBsYWNlUG9saWN5PzogQ2ZuRGVsZXRpb25Qb2xpY3k7XG5cbiAgLyoqXG4gICAqIE1ldGFkYXRhIGFzc29jaWF0ZWQgd2l0aCB0aGUgQ2xvdWRGb3JtYXRpb24gcmVzb3VyY2UuIFRoaXMgaXMgbm90IHRoZSBzYW1lIGFzIHRoZSBjb25zdHJ1Y3QgbWV0YWRhdGEgd2hpY2ggY2FuIGJlIGFkZGVkXG4gICAqIHVzaW5nIGNvbnN0cnVjdC5hZGRNZXRhZGF0YSgpLCBidXQgd291bGQgbm90IGFwcGVhciBpbiB0aGUgQ2xvdWRGb3JtYXRpb24gdGVtcGxhdGUgYXV0b21hdGljYWxseS5cbiAgICovXG4gIG1ldGFkYXRhPzogeyBba2V5OiBzdHJpbmddOiBhbnkgfTtcbn1cblxuLyoqXG4gKiBNZXJnZXMgYHNvdXJjZWAgaW50byBgdGFyZ2V0YCwgb3ZlcnJpZGluZyBhbnkgZXhpc3RpbmcgdmFsdWVzLlxuICogYG51bGxgcyB3aWxsIGNhdXNlIGEgdmFsdWUgdG8gYmUgZGVsZXRlZC5cbiAqL1xuZnVuY3Rpb24gZGVlcE1lcmdlKHRhcmdldDogYW55LCAuLi5zb3VyY2VzOiBhbnlbXSkge1xuICBmb3IgKGNvbnN0IHNvdXJjZSBvZiBzb3VyY2VzKSB7XG4gICAgaWYgKHR5cGVvZihzb3VyY2UpICE9PSAnb2JqZWN0JyB8fCB0eXBlb2YodGFyZ2V0KSAhPT0gJ29iamVjdCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB1c2FnZS4gQm90aCBzb3VyY2UgKCR7SlNPTi5zdHJpbmdpZnkoc291cmNlKX0pIGFuZCB0YXJnZXQgKCR7SlNPTi5zdHJpbmdpZnkodGFyZ2V0KX0pIG11c3QgYmUgb2JqZWN0c2ApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHNvdXJjZSkpIHtcbiAgICAgIGNvbnN0IHZhbHVlID0gc291cmNlW2tleV07XG4gICAgICBpZiAodHlwZW9mKHZhbHVlKSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgIT0gbnVsbCAmJiAhQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgLy8gaWYgdGhlIHZhbHVlIGF0IHRoZSB0YXJnZXQgaXMgbm90IGFuIG9iamVjdCwgb3ZlcnJpZGUgaXQgd2l0aCBhblxuICAgICAgICAvLyBvYmplY3Qgc28gd2UgY2FuIGNvbnRpbnVlIHRoZSByZWN1cnNpb25cbiAgICAgICAgaWYgKHR5cGVvZih0YXJnZXRba2V5XSkgIT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgdGFyZ2V0W2tleV0gPSB7fTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlZXBNZXJnZSh0YXJnZXRba2V5XSwgdmFsdWUpO1xuXG4gICAgICAgIC8vIGlmIHRoZSByZXN1bHQgb2YgdGhlIG1lcmdlIGlzIGFuIGVtcHR5IG9iamVjdCwgaXQncyBiZWNhdXNlIHRoZVxuICAgICAgICAvLyBldmVudHVhbCB2YWx1ZSB3ZSBhc3NpZ25lZCBpcyBgdW5kZWZpbmVkYCwgYW5kIHRoZXJlIGFyZSBub1xuICAgICAgICAvLyBzaWJsaW5nIGNvbmNyZXRlIHZhbHVlcyBhbG9uZ3NpZGUsIHNvIHdlIGNhbiBkZWxldGUgdGhpcyB0cmVlLlxuICAgICAgICBjb25zdCBvdXRwdXQgPSB0YXJnZXRba2V5XTtcbiAgICAgICAgaWYgKHR5cGVvZihvdXRwdXQpID09PSAnb2JqZWN0JyAmJiBPYmplY3Qua2V5cyhvdXRwdXQpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGRlbGV0ZSB0YXJnZXRba2V5XTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGRlbGV0ZSB0YXJnZXRba2V5XTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRhcmdldFtrZXldID0gdmFsdWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRhcmdldDtcbn1cbiJdfQ==