@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
333 lines • 44.2 kB
JavaScript
;
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==