@aws-cdk/aws-iam
Version:
CDK routines for easily assigning correct and minimal IAM permissions
470 lines • 66.6 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Role = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const core_1 = require("@aws-cdk/core");
const constructs_1 = require("constructs");
const grant_1 = require("./grant");
const iam_generated_1 = require("./iam.generated");
const managed_policy_1 = require("./managed-policy");
const policy_1 = require("./policy");
const policy_document_1 = require("./policy-document");
const principals_1 = require("./principals");
const assume_role_policy_1 = require("./private/assume-role-policy");
const immutable_role_1 = require("./private/immutable-role");
const policydoc_adapter_1 = require("./private/policydoc-adapter");
const util_1 = require("./util");
const MAX_INLINE_SIZE = 10000;
const MAX_MANAGEDPOL_SIZE = 6000;
/**
* IAM Role
*
* Defines an IAM role. The role is created with an assume policy document associated with
* the specified AWS service principal defined in `serviceAssumeRole`.
*/
class Role extends core_1.Resource {
constructor(scope, id, props) {
super(scope, id, {
physicalName: props.roleName,
});
this.grantPrincipal = this;
this.principalAccount = this.env.account;
this.assumeRoleAction = 'sts:AssumeRole';
this.managedPolicies = [];
this.attachedPolicies = new util_1.AttachedPolicies();
this.dependables = new Map();
this._didSplit = false;
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_RoleProps(props);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, Role);
}
throw error;
}
const externalIds = props.externalIds || [];
if (props.externalId) {
externalIds.push(props.externalId);
}
this.assumeRolePolicy = createAssumeRolePolicy(props.assumedBy, externalIds);
this.managedPolicies.push(...props.managedPolicies || []);
this.inlinePolicies = props.inlinePolicies || {};
this.permissionsBoundary = props.permissionsBoundary;
const maxSessionDuration = props.maxSessionDuration && props.maxSessionDuration.toSeconds();
validateMaxSessionDuration(maxSessionDuration);
const description = (props.description && props.description?.length > 0) ? props.description : undefined;
if (description && description.length > 1000) {
throw new Error('Role description must be no longer than 1000 characters.');
}
validateRolePath(props.path);
const role = new iam_generated_1.CfnRole(this, 'Resource', {
assumeRolePolicyDocument: this.assumeRolePolicy,
managedPolicyArns: util_1.UniqueStringSet.from(() => this.managedPolicies.map(p => p.managedPolicyArn)),
policies: _flatten(this.inlinePolicies),
path: props.path,
permissionsBoundary: this.permissionsBoundary ? this.permissionsBoundary.managedPolicyArn : undefined,
roleName: this.physicalName,
maxSessionDuration,
description,
});
this.roleId = role.attrRoleId;
this.roleArn = this.getResourceArnAttribute(role.attrArn, {
region: '',
service: 'iam',
resource: 'role',
// Removes leading slash from path
resourceName: `${props.path ? props.path.substr(props.path.charAt(0) === '/' ? 1 : 0) : ''}${this.physicalName}`,
});
this.roleName = this.getResourceNameAttribute(role.ref);
this.policyFragment = new principals_1.ArnPrincipal(this.roleArn).policyFragment;
function _flatten(policies) {
if (policies == null || Object.keys(policies).length === 0) {
return undefined;
}
const result = new Array();
for (const policyName of Object.keys(policies)) {
const policyDocument = policies[policyName];
result.push({ policyName, policyDocument });
}
return result;
}
core_1.Aspects.of(this).add({
visit: (c) => {
if (c === this) {
this.splitLargePolicy();
}
},
});
}
/**
* Import an external role by ARN.
*
* If the imported Role ARN is a Token (such as a
* `CfnParameter.valueAsString` or a `Fn.importValue()`) *and* the referenced
* role has a `path` (like `arn:...:role/AdminRoles/Alice`), the
* `roleName` property will not resolve to the correct value. Instead it
* will resolve to the first path component. We unfortunately cannot express
* the correct calculation of the full path name as a CloudFormation
* expression. In this scenario the Role ARN should be supplied without the
* `path` in order to resolve the correct role resource.
*
* @param scope construct scope
* @param id construct id
* @param roleArn the ARN of the role to import
* @param options allow customizing the behavior of the returned role
*/
static fromRoleArn(scope, id, roleArn, options = {}) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_FromRoleArnOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.fromRoleArn);
}
throw error;
}
const scopeStack = core_1.Stack.of(scope);
const parsedArn = scopeStack.splitArn(roleArn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
const resourceName = parsedArn.resourceName;
const roleAccount = parsedArn.account;
// service roles have an ARN like 'arn:aws:iam::<account>:role/service-role/<roleName>'
// or 'arn:aws:iam::<account>:role/service-role/servicename.amazonaws.com/service-role/<roleName>'
// we want to support these as well, so we just use the element after the last slash as role name
const roleName = resourceName.split('/').pop();
class Import extends core_1.Resource {
constructor(_scope, _id) {
super(_scope, _id, {
account: roleAccount,
});
this.grantPrincipal = this;
this.principalAccount = roleAccount;
this.assumeRoleAction = 'sts:AssumeRole';
this.policyFragment = new principals_1.ArnPrincipal(roleArn).policyFragment;
this.roleArn = roleArn;
this.roleName = roleName;
this.attachedPolicies = new util_1.AttachedPolicies();
}
addToPolicy(statement) {
return this.addToPrincipalPolicy(statement).statementAdded;
}
addToPrincipalPolicy(statement) {
if (!this.defaultPolicy) {
this.defaultPolicy = new policy_1.Policy(this, 'Policy');
this.attachInlinePolicy(this.defaultPolicy);
}
this.defaultPolicy.addStatements(statement);
return { statementAdded: true, policyDependable: this.defaultPolicy };
}
attachInlinePolicy(policy) {
const thisAndPolicyAccountComparison = core_1.Token.compareStrings(this.env.account, policy.env.account);
const equalOrAnyUnresolved = thisAndPolicyAccountComparison === core_1.TokenComparison.SAME ||
thisAndPolicyAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
thisAndPolicyAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
if (equalOrAnyUnresolved) {
this.attachedPolicies.attach(policy);
policy.attachToRole(this);
}
}
addManagedPolicy(_policy) {
// FIXME: Add warning that we're ignoring this
}
/**
* Grant permissions to the given principal to pass this role.
*/
grantPassRole(identity) {
return this.grant(identity, 'iam:PassRole');
}
/**
* Grant permissions to the given principal to pass this role.
*/
grantAssumeRole(identity) {
return this.grant(identity, 'sts:AssumeRole');
}
/**
* Grant the actions defined in actions to the identity Principal on this resource.
*/
grant(grantee, ...actions) {
return grant_1.Grant.addToPrincipal({
grantee,
actions,
resourceArns: [this.roleArn],
scope: this,
});
}
dedupeString() {
return `ImportedRole:${roleArn}`;
}
}
if (options.addGrantsToResources !== undefined && options.mutable !== false) {
throw new Error('\'addGrantsToResources\' can only be passed if \'mutable: false\'');
}
const roleArnAndScopeStackAccountComparison = core_1.Token.compareStrings(roleAccount ?? '', scopeStack.account);
const equalOrAnyUnresolved = roleArnAndScopeStackAccountComparison === core_1.TokenComparison.SAME ||
roleArnAndScopeStackAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
roleArnAndScopeStackAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
// if we are returning an immutable role then the 'importedRole' is just a throwaway construct
// so give it a different id
const mutableRoleId = (options.mutable !== false && equalOrAnyUnresolved) ? id : `MutableRole${id}`;
const importedRole = new Import(scope, mutableRoleId);
// we only return an immutable Role if both accounts were explicitly provided, and different
return options.mutable !== false && equalOrAnyUnresolved
? importedRole
: new immutable_role_1.ImmutableRole(scope, id, importedRole, options.addGrantsToResources ?? false);
}
/**
* Import an external role by name.
*
* The imported role is assumed to exist in the same account as the account
* the scope's containing Stack is being deployed to.
*/
static fromRoleName(scope, id, roleName) {
return Role.fromRoleArn(scope, id, core_1.Stack.of(scope).formatArn({
region: '',
service: 'iam',
resource: 'role',
resourceName: roleName,
}));
}
/**
* Adds a permission to the role's default policy document.
* If there is no default policy attached to this role, it will be created.
* @param statement The permission statement to add to the policy document
*/
addToPrincipalPolicy(statement) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addToPrincipalPolicy);
}
throw error;
}
if (!this.defaultPolicy) {
this.defaultPolicy = new policy_1.Policy(this, 'DefaultPolicy');
this.attachInlinePolicy(this.defaultPolicy);
}
this.defaultPolicy.addStatements(statement);
// We might split this statement off into a different policy, so we'll need to
// late-bind the dependable.
const policyDependable = new core_1.ConcreteDependable();
this.dependables.set(statement, policyDependable);
return { statementAdded: true, policyDependable };
}
addToPolicy(statement) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addToPolicy);
}
throw error;
}
return this.addToPrincipalPolicy(statement).statementAdded;
}
/**
* Attaches a managed policy to this role.
* @param policy The the managed policy to attach.
*/
addManagedPolicy(policy) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_IManagedPolicy(policy);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addManagedPolicy);
}
throw error;
}
if (this.managedPolicies.find(mp => mp === policy)) {
return;
}
this.managedPolicies.push(policy);
}
/**
* Attaches a policy to this role.
* @param policy The policy to attach
*/
attachInlinePolicy(policy) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_Policy(policy);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.attachInlinePolicy);
}
throw error;
}
this.attachedPolicies.attach(policy);
policy.attachToRole(this);
}
/**
* Grant the actions defined in actions to the identity Principal on this resource.
*/
grant(grantee, ...actions) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(grantee);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.grant);
}
throw error;
}
return grant_1.Grant.addToPrincipal({
grantee,
actions,
resourceArns: [this.roleArn],
scope: this,
});
}
/**
* Grant permissions to the given principal to pass this role.
*/
grantPassRole(identity) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(identity);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.grantPassRole);
}
throw error;
}
return this.grant(identity, 'iam:PassRole');
}
/**
* Grant permissions to the given principal to assume this role.
*/
grantAssumeRole(identity) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(identity);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.grantAssumeRole);
}
throw error;
}
return this.grant(identity, 'sts:AssumeRole');
}
/**
* Return a copy of this Role object whose Policies will not be updated
*
* Use the object returned by this method if you want this Role to be used by
* a construct without it automatically updating the Role's Policies.
*
* If you do, you are responsible for adding the correct statements to the
* Role's policies yourself.
*/
withoutPolicyUpdates(options = {}) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_WithoutPolicyUpdatesOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.withoutPolicyUpdates);
}
throw error;
}
if (!this.immutableRole) {
this.immutableRole = new immutable_role_1.ImmutableRole(constructs_1.Node.of(this).scope, `ImmutableRole${this.node.id}`, this, options.addGrantsToResources ?? false);
}
return this.immutableRole;
}
validate() {
const errors = super.validate();
errors.push(...this.assumeRolePolicy?.validateForResourcePolicy() || []);
for (const policy of Object.values(this.inlinePolicies)) {
errors.push(...policy.validateForIdentityPolicy());
}
return errors;
}
/**
* Split large inline policies into managed policies
*
* This gets around the 10k bytes limit on role policies.
*/
splitLargePolicy() {
if (!this.defaultPolicy || this._didSplit) {
return;
}
this._didSplit = true;
const self = this;
const originalDoc = this.defaultPolicy.document;
const splitOffDocs = originalDoc._splitDocument(this, MAX_INLINE_SIZE, MAX_MANAGEDPOL_SIZE);
// Includes the "current" document
const mpCount = this.managedPolicies.length + (splitOffDocs.size - 1);
if (mpCount > 20) {
core_1.Annotations.of(this).addWarning(`Policy too large: ${mpCount} exceeds the maximum of 20 managed policies attached to a Role`);
}
else if (mpCount > 10) {
core_1.Annotations.of(this).addWarning(`Policy large: ${mpCount} exceeds 10 managed policies attached to a Role, this requires a quota increase`);
}
// Create the managed policies and fix up the dependencies
markDeclaringConstruct(originalDoc, this.defaultPolicy);
let i = 1;
for (const newDoc of splitOffDocs.keys()) {
if (newDoc === originalDoc) {
continue;
}
const mp = new managed_policy_1.ManagedPolicy(this, `OverflowPolicy${i++}`, {
description: `Part of the policies for ${this.node.path}`,
document: newDoc,
roles: [this],
});
markDeclaringConstruct(newDoc, mp);
}
/**
* Update the Dependables for the statements in the given PolicyDocument to point to the actual declaring construct
*/
function markDeclaringConstruct(doc, declaringConstruct) {
for (const original of splitOffDocs.get(doc) ?? []) {
self.dependables.get(original)?.add(declaringConstruct);
}
}
}
}
exports.Role = Role;
_a = JSII_RTTI_SYMBOL_1;
Role[_a] = { fqn: "@aws-cdk/aws-iam.Role", version: "1.204.0" };
function createAssumeRolePolicy(principal, externalIds) {
const actualDoc = new policy_document_1.PolicyDocument();
// If requested, add externalIds to every statement added to this doc
const addDoc = externalIds.length === 0
? actualDoc
: new policydoc_adapter_1.MutatingPolicyDocumentAdapter(actualDoc, (statement) => {
statement.addCondition('StringEquals', {
'sts:ExternalId': externalIds.length === 1 ? externalIds[0] : externalIds,
});
return statement;
});
assume_role_policy_1.defaultAddPrincipalToAssumeRole(principal, addDoc);
return actualDoc;
}
function validateRolePath(path) {
if (path === undefined || core_1.Token.isUnresolved(path)) {
return;
}
const validRolePath = /^(\/|\/[\u0021-\u007F]+\/)$/;
if (path.length == 0 || path.length > 512) {
throw new Error(`Role path must be between 1 and 512 characters. The provided role path is ${path.length} characters.`);
}
else if (!validRolePath.test(path)) {
throw new Error('Role path must be either a slash or valid characters (alphanumerics and symbols) surrounded by slashes. '
+ `Valid characters are unicode characters in [\\u0021-\\u007F]. However, ${path} is provided.`);
}
}
function validateMaxSessionDuration(duration) {
if (duration === undefined) {
return;
}
if (duration < 3600 || duration > 43200) {
throw new Error(`maxSessionDuration is set to ${duration}, but must be >= 3600sec (1hr) and <= 43200sec (12hrs)`);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9sZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJvbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsd0NBQW1KO0FBQ25KLDJDQUE2QztBQUM3QyxtQ0FBZ0M7QUFDaEMsbURBQTBDO0FBRTFDLHFEQUFpRTtBQUNqRSxxQ0FBa0M7QUFDbEMsdURBQW1EO0FBRW5ELDZDQUFtSTtBQUNuSSxxRUFBK0U7QUFDL0UsNkRBQXlEO0FBQ3pELG1FQUE0RTtBQUM1RSxpQ0FBMkQ7QUFFM0QsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDO0FBQzlCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0FBc0pqQzs7Ozs7R0FLRztBQUNILE1BQWEsSUFBSyxTQUFRLGVBQVE7SUF3TGhDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBZ0I7UUFDeEQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixZQUFZLEVBQUUsS0FBSyxDQUFDLFFBQVE7U0FDN0IsQ0FBQyxDQUFDO1FBakRXLG1CQUFjLEdBQWUsSUFBSSxDQUFDO1FBQ2xDLHFCQUFnQixHQUF1QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUV4RCxxQkFBZ0IsR0FBVyxnQkFBZ0IsQ0FBQztRQW9DM0Msb0JBQWUsR0FBcUIsRUFBRSxDQUFDO1FBQ3ZDLHFCQUFnQixHQUFHLElBQUksdUJBQWdCLEVBQUUsQ0FBQztRQUUxQyxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUF1QyxDQUFDO1FBRXRFLGNBQVMsR0FBRyxLQUFLLENBQUM7Ozs7OzsrQ0F0TGYsSUFBSTs7OztRQTZMYixNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztRQUM1QyxJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUU7WUFDcEIsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7U0FDcEM7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLEdB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TCxvREFBK0IsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFFbkQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQUMsSUFBYTtJQUNyQyxJQUFJLElBQUksS0FBSyxTQUFTLElBQUksWUFBSyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUNsRCxPQUFPO0tBQ1I7SUFFRCxNQUFNLGFBQWEsR0FBRyw2QkFBNkIsQ0FBQztJQUVwRCxJQUFJLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFO1FBQ3pDLE1BQU0sSUFBSSxLQUFLLENBQUMsNkVBQTZFLElBQUksQ0FBQyxNQUFNLGNBQWMsQ0FBQyxDQUFDO0tBQ3pIO1NBQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7UUFDcEMsTUFBTSxJQUFJLEtBQUssQ0FDYiwwR0FBMEc7Y0FDeEcsMEVBQTBFLElBQUksZUFBZSxDQUFDLENBQUM7S0FDcEc7QUFDSCxDQUFDO0FBRUQsU0FBUywwQkFBMEIsQ0FBQyxRQUFpQjtJQUNuRCxJQUFJLFFBQVEsS0FBSyxTQUFTLEVBQUU7UUFDMUIsT0FBTztLQUNSO0lBRUQsSUFBSSxRQUFRLEdBQUcsSUFBSSxJQUFJLFFBQVEsR0FBRyxLQUFLLEVBQUU7UUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsUUFBUSx3REFBd0QsQ0FBQyxDQUFDO0tBQ25IO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFybkZvcm1hdCwgSUNvbnN0cnVjdCwgRHVyYXRpb24sIFJlc291cmNlLCBTdGFjaywgVG9rZW4sIFRva2VuQ29tcGFyaXNvbiwgQXNwZWN0cywgQ29uY3JldGVEZXBlbmRhYmxlLCBBbm5vdGF0aW9ucyB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBOb2RlIH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBHcmFudCB9IGZyb20gJy4vZ3JhbnQnO1xuaW1wb3J0IHsgQ2ZuUm9sZSB9IGZyb20gJy4vaWFtLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBJSWRlbnRpdHkgfSBmcm9tICcuL2lkZW50aXR5LWJhc2UnO1xuaW1wb3J0IHsgSU1hbmFnZWRQb2xpY3ksIE1hbmFnZWRQb2xpY3kgfSBmcm9tICcuL21hbmFnZWQtcG9saWN5JztcbmltcG9ydCB7IFBvbGljeSB9IGZyb20gJy4vcG9saWN5JztcbmltcG9ydCB7IFBvbGljeURvY3VtZW50IH0gZnJvbSAnLi9wb2xpY3ktZG9jdW1lbnQnO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50IH0gZnJvbSAnLi9wb2xpY3ktc3RhdGVtZW50JztcbmltcG9ydCB7IEFkZFRvUHJpbmNpcGFsUG9saWN5UmVzdWx0LCBBcm5QcmluY2lwYWwsIElQcmluY2lwYWwsIFByaW5jaXBhbFBvbGljeUZyYWdtZW50LCBJQ29tcGFyYWJsZVByaW5jaXBhbCB9IGZyb20gJy4vcHJpbmNpcGFscyc7XG5pbXBvcnQgeyBkZWZhdWx0QWRkUHJpbmNpcGFsVG9Bc3N1bWVSb2xlIH0gZnJvbSAnLi9wcml2YXRlL2Fzc3VtZS1yb2xlLXBvbGljeSc7XG5pbXBvcnQgeyBJbW11dGFibGVSb2xlIH0gZnJvbSAnLi9wcml2YXRlL2ltbXV0YWJsZS1yb2xlJztcbmltcG9ydCB7IE11dGF0aW5nUG9saWN5RG9jdW1lbnRBZGFwdGVyIH0gZnJvbSAnLi9wcml2YXRlL3BvbGljeWRvYy1hZGFwdGVyJztcbmltcG9ydCB7IEF0dGFjaGVkUG9saWNpZXMsIFVuaXF1ZVN0cmluZ1NldCB9IGZyb20gJy4vdXRpbCc7XG5cbmNvbnN0IE1BWF9JTkxJTkVfU0laRSA9IDEwMDAwO1xuY29uc3QgTUFYX01BTkFHRURQT0xfU0laRSA9IDYwMDA7XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgZGVmaW5pbmcgYW4gSUFNIFJvbGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb2xlUHJvcHMge1xuICAvKipcbiAgICogVGhlIElBTSBwcmluY2lwYWwgKGkuZS4gYG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdzbnMuYW1hem9uYXdzLmNvbScpYClcbiAgICogd2hpY2ggY2FuIGFzc3VtZSB0aGlzIHJvbGUuXG4gICAqXG4gICAqIFlvdSBjYW4gbGF0ZXIgbW9kaWZ5IHRoZSBhc3N1bWUgcm9sZSBwb2xpY3kgZG9jdW1lbnQgYnkgYWNjZXNzaW5nIGl0IHZpYVxuICAgKiB0aGUgYGFzc3VtZVJvbGVQb2xpY3lgIHByb3BlcnR5LlxuICAgKi9cbiAgcmVhZG9ubHkgYXNzdW1lZEJ5OiBJUHJpbmNpcGFsO1xuXG4gIC8qKlxuICAgKiBJRCB0aGF0IHRoZSByb2xlIGFzc3VtZXIgbmVlZHMgdG8gcHJvdmlkZSB3aGVuIGFzc3VtaW5nIHRoaXMgcm9sZVxuICAgKlxuICAgKiBJZiB0aGUgY29uZmlndXJlZCBhbmQgcHJvdmlkZWQgZXh0ZXJuYWwgSURzIGRvIG5vdCBtYXRjaCwgdGhlXG4gICAqIEFzc3VtZVJvbGUgb3BlcmF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgc2VlIHtAbGluayBleHRlcm5hbElkc31cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gZXh0ZXJuYWwgSUQgcmVxdWlyZWRcbiAgICovXG4gIHJlYWRvbmx5IGV4dGVybmFsSWQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgSURzIHRoYXQgdGhlIHJvbGUgYXNzdW1lciBuZWVkcyB0byBwcm92aWRlIG9uZSBvZiB3aGVuIGFzc3VtaW5nIHRoaXMgcm9sZVxuICAgKlxuICAgKiBJZiB0aGUgY29uZmlndXJlZCBhbmQgcHJvdmlkZWQgZXh0ZXJuYWwgSURzIGRvIG5vdCBtYXRjaCwgdGhlXG4gICAqIEFzc3VtZVJvbGUgb3BlcmF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gZXh0ZXJuYWwgSUQgcmVxdWlyZWRcbiAgICovXG4gIHJlYWRvbmx5IGV4dGVybmFsSWRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBtYW5hZ2VkIHBvbGljaWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJvbGUuXG4gICAqXG4gICAqIFlvdSBjYW4gYWRkIG1hbmFnZWQgcG9saWNpZXMgbGF0ZXIgdXNpbmdcbiAgICogYGFkZE1hbmFnZWRQb2xpY3koTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUocG9saWN5TmFtZSkpYC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBtYW5hZ2VkIHBvbGljaWVzLlxuICAgKi9cbiAgcmVhZG9ubHkgbWFuYWdlZFBvbGljaWVzPzogSU1hbmFnZWRQb2xpY3lbXTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIG5hbWVkIHBvbGljaWVzIHRvIGlubGluZSBpbnRvIHRoaXMgcm9sZS4gVGhlc2UgcG9saWNpZXMgd2lsbCBiZVxuICAgKiBjcmVhdGVkIHdpdGggdGhlIHJvbGUsIHdoZXJlYXMgdGhvc2UgYWRkZWQgYnkgYGBhZGRUb1BvbGljeWBgIGFyZSBhZGRlZFxuICAgKiB1c2luZyBhIHNlcGFyYXRlIENsb3VkRm9ybWF0aW9uIHJlc291cmNlIChhbGxvd2luZyBhIHdheSBhcm91bmQgY2lyY3VsYXJcbiAgICogZGVwZW5kZW5jaWVzIHRoYXQgY291bGQgb3RoZXJ3aXNlIGJlIGludHJvZHVjZWQpLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHBvbGljeSBpcyBpbmxpbmVkIGluIHRoZSBSb2xlIHJlc291cmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgaW5saW5lUG9saWNpZXM/OiB7IFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudCB9O1xuXG4gIC8qKlxuICAgKiBUaGUgcGF0aCBhc3NvY2lhdGVkIHdpdGggdGhpcyByb2xlLiBGb3IgaW5mb3JtYXRpb24gYWJvdXQgSUFNIHBhdGhzLCBzZWVcbiAgICogRnJpZW5kbHkgTmFtZXMgYW5kIFBhdGhzIGluIElBTSBVc2VyIEd1aWRlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAvXG4gICAqL1xuICByZWFkb25seSBwYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBV1Mgc3VwcG9ydHMgcGVybWlzc2lvbnMgYm91bmRhcmllcyBmb3IgSUFNIGVudGl0aWVzICh1c2VycyBvciByb2xlcykuXG4gICAqIEEgcGVybWlzc2lvbnMgYm91bmRhcnkgaXMgYW4gYWR2YW5jZWQgZmVhdHVyZSBmb3IgdXNpbmcgYSBtYW5hZ2VkIHBvbGljeVxuICAgKiB0byBzZXQgdGhlIG1heGltdW0gcGVybWlzc2lvbnMgdGhhdCBhbiBpZGVudGl0eS1iYXNlZCBwb2xpY3kgY2FuIGdyYW50IHRvXG4gICAqIGFuIElBTSBlbnRpdHkuIEFuIGVudGl0eSdzIHBlcm1pc3Npb25zIGJvdW5kYXJ5IGFsbG93cyBpdCB0byBwZXJmb3JtIG9ubHlcbiAgICogdGhlIGFjdGlvbnMgdGhhdCBhcmUgYWxsb3dlZCBieSBib3RoIGl0cyBpZGVudGl0eS1iYXNlZCBwb2xpY2llcyBhbmQgaXRzXG4gICAqIHBlcm1pc3Npb25zIGJvdW5kYXJpZXMuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2F3cy1yZXNvdXJjZS1pYW0tcm9sZS5odG1sI2Nmbi1pYW0tcm9sZS1wZXJtaXNzaW9uc2JvdW5kYXJ5XG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9hY2Nlc3NfcG9saWNpZXNfYm91bmRhcmllcy5odG1sXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcGVybWlzc2lvbnMgYm91bmRhcnkuXG4gICAqL1xuICByZWFkb25seSBwZXJtaXNzaW9uc0JvdW5kYXJ5PzogSU1hbmFnZWRQb2xpY3k7XG5cbiAgLyoqXG4gICAqIEEgbmFtZSBmb3IgdGhlIElBTSByb2xlLiBGb3IgdmFsaWQgdmFsdWVzLCBzZWUgdGhlIFJvbGVOYW1lIHBhcmFtZXRlciBmb3JcbiAgICogdGhlIENyZWF0ZVJvbGUgYWN0aW9uIGluIHRoZSBJQU0gQVBJIFJlZmVyZW5jZS5cbiAgICpcbiAgICogSU1QT1JUQU5UOiBJZiB5b3Ugc3BlY2lmeSBhIG5hbWUsIHlvdSBjYW5ub3QgcGVyZm9ybSB1cGRhdGVzIHRoYXQgcmVxdWlyZVxuICAgKiByZXBsYWNlbWVudCBvZiB0aGlzIHJlc291cmNlLiBZb3UgY2FuIHBlcmZvcm0gdXBkYXRlcyB0aGF0IHJlcXVpcmUgbm8gb3JcbiAgICogc29tZSBpbnRlcnJ1cHRpb24uIElmIHlvdSBtdXN0IHJlcGxhY2UgdGhlIHJlc291cmNlLCBzcGVjaWZ5IGEgbmV3IG5hbWUuXG4gICAqXG4gICAqIElmIHlvdSBzcGVjaWZ5IGEgbmFtZSwgeW91IG11c3Qgc3BlY2lmeSB0aGUgQ0FQQUJJTElUWV9OQU1FRF9JQU0gdmFsdWUgdG9cbiAgICogYWNrbm93bGVkZ2UgeW91ciB0ZW1wbGF0ZSdzIGNhcGFiaWxpdGllcy4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZVxuICAgKiBBY2tub3dsZWRnaW5nIElBTSBSZXNvdXJjZXMgaW4gQVdTIENsb3VkRm9ybWF0aW9uIFRlbXBsYXRlcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBV1MgQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzIGEgdW5pcXVlIHBoeXNpY2FsIElEIGFuZCB1c2VzIHRoYXQgSURcbiAgICogZm9yIHRoZSByb2xlIG5hbWUuXG4gICAqL1xuICByZWFkb25seSByb2xlTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG1heGltdW0gc2Vzc2lvbiBkdXJhdGlvbiB0aGF0IHlvdSB3YW50IHRvIHNldCBmb3IgdGhlIHNwZWNpZmllZCByb2xlLlxuICAgKiBUaGlzIHNldHRpbmcgY2FuIGhhdmUgYSB2YWx1ZSBmcm9tIDEgaG91ciAoMzYwMHNlYykgdG8gMTIgKDQzMjAwc2VjKSBob3Vycy5cbiAgICpcbiAgICogQW55b25lIHdobyBhc3N1bWVzIHRoZSByb2xlIGZyb20gdGhlIEFXUyBDTEkgb3IgQVBJIGNhbiB1c2UgdGhlXG4gICAqIER1cmF0aW9uU2Vjb25kcyBBUEkgcGFyYW1ldGVyIG9yIHRoZSBkdXJhdGlvbi1zZWNvbmRzIENMSSBwYXJhbWV0ZXIgdG9cbiAgICogcmVxdWVzdCBhIGxvbmdlciBzZXNzaW9uLiBUaGUgTWF4U2Vzc2lvbkR1cmF0aW9uIHNldHRpbmcgZGV0ZXJtaW5lcyB0aGVcbiAgICogbWF4aW11bSBkdXJhdGlvbiB0aGF0IGNhbiBiZSByZXF1ZXN0ZWQgdXNpbmcgdGhlIER1cmF0aW9uU2Vjb25kc1xuICAgKiBwYXJhbWV0ZXIuXG4gICAqXG4gICAqIElmIHVzZXJzIGRvbid0IHNwZWNpZnkgYSB2YWx1ZSBmb3IgdGhlIER1cmF0aW9uU2Vjb25kcyBwYXJhbWV0ZXIsIHRoZWlyXG4gICAqIHNlY3VyaXR5IGNyZWRlbnRpYWxzIGFyZSB2YWxpZCBmb3Igb25lIGhvdXIgYnkgZGVmYXVsdC4gVGhpcyBhcHBsaWVzIHdoZW5cbiAgICogeW91IHVzZSB0aGUgQXNzdW1lUm9sZSogQVBJIG9wZXJhdGlvbnMgb3IgdGhlIGFzc3VtZS1yb2xlKiBDTEkgb3BlcmF0aW9uc1xuICAgKiBidXQgZG9lcyBub3QgYXBwbHkgd2hlbiB5b3UgdXNlIHRob3NlIG9wZXJhdGlvbnMgdG8gY3JlYXRlIGEgY29uc29sZSBVUkwuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9pZF9yb2xlc191c2UuaHRtbFxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5ob3VycygxKVxuICAgKi9cbiAgcmVhZG9ubHkgbWF4U2Vzc2lvbkR1cmF0aW9uPzogRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIEEgZGVzY3JpcHRpb24gb2YgdGhlIHJvbGUuIEl0IGNhbiBiZSB1cCB0byAxMDAwIGNoYXJhY3RlcnMgbG9uZy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBkZXNjcmlwdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgYWxsb3dpbmcgY3VzdG9taXppbmcgdGhlIGJlaGF2aW9yIG9mIHtAbGluayBSb2xlLmZyb21Sb2xlQXJufS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBGcm9tUm9sZUFybk9wdGlvbnMge1xuICAvKipcbiAgICogV2hldGhlciB0aGUgaW1wb3J0ZWQgcm9sZSBjYW4gYmUgbW9kaWZpZWQgYnkgYXR0YWNoaW5nIHBvbGljeSByZXNvdXJjZXMgdG8gaXQuXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IG11dGFibGU/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBGb3IgaW1tdXRhYmxlIHJvbGVzOiBhZGQgZ3JhbnRzIHRvIHJlc291cmNlcyBpbnN0ZWFkIG9mIGRyb3BwaW5nIHRoZW1cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgZmFsc2VgIG9yIG5vdCBzcGVjaWZpZWQsIGdyYW50IHBlcm1pc3Npb25zIGFkZGVkIHRvIHRoaXMgcm9sZSBhcmUgaWdub3JlZC5cbiAgICogSXQgaXMgeW91ciBvd24gcmVzcG9uc2liaWxpdHkgdG8gbWFrZSBzdXJlIHRoZSByb2xlIGhhcyB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMuXG4gICAqXG4gICAqIElmIHRoaXMgaXMgYHRydWVgLCBhbnkgZ3JhbnQgcGVybWlzc2lvbnMgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVzb3VyY2UgaW5zdGVhZC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFkZEdyYW50c1RvUmVzb3VyY2VzPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBJQU0gUm9sZVxuICpcbiAqIERlZmluZXMgYW4gSUFNIHJvbGUuIFRoZSByb2xlIGlzIGNyZWF0ZWQgd2l0aCBhbiBhc3N1bWUgcG9saWN5IGRvY3VtZW50IGFzc29jaWF0ZWQgd2l0aFxuICogdGhlIHNwZWNpZmllZCBBV1Mgc2VydmljZSBwcmluY2lwYWwgZGVmaW5lZCBpbiBgc2VydmljZUFzc3VtZVJvbGVgLlxuICovXG5leHBvcnQgY2xhc3MgUm9sZSBleHRlbmRzIFJlc291cmNlIGltcGxlbWVudHMgSVJvbGUge1xuICAvKipcbiAgICogSW1wb3J0IGFuIGV4dGVybmFsIHJvbGUgYnkgQVJOLlxuICAgKlxuICAgKiBJZiB0aGUgaW1wb3J0ZWQgUm9sZSBBUk4gaXMgYSBUb2tlbiAoc3VjaCBhcyBhXG4gICAqIGBDZm5QYXJhbWV0ZXIudmFsdWVBc1N0cmluZ2Agb3IgYSBgRm4uaW1wb3J0VmFsdWUoKWApICphbmQqIHRoZSByZWZlcmVuY2VkXG4gICAqIHJvbGUgaGFzIGEgYHBhdGhgIChsaWtlIGBhcm46Li4uOnJvbGUvQWRtaW5Sb2xlcy9BbGljZWApLCB0aGVcbiAgICogYHJvbGVOYW1lYCBwcm9wZXJ0eSB3aWxsIG5vdCByZXNvbHZlIHRvIHRoZSBjb3JyZWN0IHZhbHVlLiBJbnN0ZWFkIGl0XG4gICAqIHdpbGwgcmVzb2x2ZSB0byB0aGUgZmlyc3QgcGF0aCBjb21wb25lbnQuIFdlIHVuZm9ydHVuYXRlbHkgY2Fubm90IGV4cHJlc3NcbiAgICogdGhlIGNvcnJlY3QgY2FsY3VsYXRpb24gb2YgdGhlIGZ1bGwgcGF0aCBuYW1lIGFzIGEgQ2xvdWRGb3JtYXRpb25cbiAgICogZXhwcmVzc2lvbi4gSW4gdGhpcyBzY2VuYXJpbyB0aGUgUm9sZSBBUk4gc2hvdWxkIGJlIHN1cHBsaWVkIHdpdGhvdXQgdGhlXG4gICAqIGBwYXRoYCBpbiBvcmRlciB0byByZXNvbHZlIHRoZSBjb3JyZWN0IHJvbGUgcmVzb3VyY2UuXG4gICAqXG4gICAqIEBwYXJhbSBzY29wZSBjb25zdHJ1Y3Qgc2NvcGVcbiAgICogQHBhcmFtIGlkIGNvbnN0cnVjdCBpZFxuICAgKiBAcGFyYW0gcm9sZUFybiB0aGUgQVJOIG9mIHRoZSByb2xlIHRvIGltcG9ydFxuICAgKiBAcGFyYW0gb3B0aW9ucyBhbGxvdyBjdXN0b21pemluZyB0aGUgYmVoYXZpb3Igb2YgdGhlIHJldHVybmVkIHJvbGVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVJvbGVBcm4oc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcm9sZUFybjogc3RyaW5nLCBvcHRpb25zOiBGcm9tUm9sZUFybk9wdGlvbnMgPSB7fSk6IElSb2xlIHtcbiAgICBjb25zdCBzY29wZVN0YWNrID0gU3RhY2sub2Yoc2NvcGUpO1xuICAgIGNvbnN0IHBhcnNlZEFybiA9IHNjb3BlU3RhY2suc3BsaXRBcm4ocm9sZUFybiwgQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUpO1xuICAgIGNvbnN0IHJlc291cmNlTmFtZSA9IHBhcnNlZEFybi5yZXNvdXJjZU5hbWUhO1xuICAgIGNvbnN0IHJvbGVBY2NvdW50ID0gcGFyc2VkQXJuLmFjY291bnQ7XG4gICAgLy8gc2VydmljZSByb2xlcyBoYXZlIGFuIEFSTiBsaWtlICdhcm46YXdzOmlhbTo6PGFjY291bnQ+OnJvbGUvc2VydmljZS1yb2xlLzxyb2xlTmFtZT4nXG4gICAgLy8gb3IgJ2Fybjphd3M6aWFtOjo8YWNjb3VudD46cm9sZS9zZXJ2aWNlLXJvbGUvc2VydmljZW5hbWUuYW1hem9uYXdzLmNvbS9zZXJ2aWNlLXJvbGUvPHJvbGVOYW1lPidcbiAgICAvLyB3ZSB3YW50IHRvIHN1cHBvcnQgdGhlc2UgYXMgd2VsbCwgc28gd2UganVzdCB1c2UgdGhlIGVsZW1lbnQgYWZ0ZXIgdGhlIGxhc3Qgc2xhc2ggYXMgcm9sZSBuYW1lXG4gICAgY29uc3Qgcm9sZU5hbWUgPSByZXNvdXJjZU5hbWUuc3BsaXQoJy8nKS5wb3AoKSE7XG5cbiAgICBjbGFzcyBJbXBvcnQgZXh0ZW5kcyBSZXNvdXJjZSBpbXBsZW1lbnRzIElSb2xlLCBJQ29tcGFyYWJsZVByaW5jaXBhbCB7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgZ3JhbnRQcmluY2lwYWw6IElQcmluY2lwYWwgPSB0aGlzO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHByaW5jaXBhbEFjY291bnQgPSByb2xlQWNjb3VudDtcbiAgICAgIHB1YmxpYyByZWFkb25seSBhc3N1bWVSb2xlQWN0aW9uOiBzdHJpbmcgPSAnc3RzOkFzc3VtZVJvbGUnO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHBvbGljeUZyYWdtZW50ID0gbmV3IEFyblByaW5jaXBhbChyb2xlQXJuKS5wb2xpY3lGcmFnbWVudDtcbiAgICAgIHB1YmxpYyByZWFkb25seSByb2xlQXJuID0gcm9sZUFybjtcbiAgICAgIHB1YmxpYyByZWFkb25seSByb2xlTmFtZSA9IHJvbGVOYW1lO1xuICAgICAgcHJpdmF0ZSByZWFkb25seSBhdHRhY2hlZFBvbGljaWVzID0gbmV3IEF0dGFjaGVkUG9saWNpZXMoKTtcbiAgICAgIHByaXZhdGUgZGVmYXVsdFBvbGljeT86IFBvbGljeTtcblxuICAgICAgY29uc3RydWN0b3IoX3Njb3BlOiBDb25zdHJ1Y3QsIF9pZDogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKF9zY29wZSwgX2lkLCB7XG4gICAgICAgICAgYWNjb3VudDogcm9sZUFjY291bnQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYWRkVG9Qb2xpY3koc3RhdGVtZW50OiBQb2xpY3lTdGF0ZW1lbnQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkVG9QcmluY2lwYWxQb2xpY3koc3RhdGVtZW50KS5zdGF0ZW1lbnRBZGRlZDtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQge1xuICAgICAgICBpZiAoIXRoaXMuZGVmYXVsdFBvbGljeSkge1xuICAgICAgICAgIHRoaXMuZGVmYXVsdFBvbGljeSA9IG5ldyBQb2xpY3kodGhpcywgJ1BvbGljeScpO1xuICAgICAgICAgIHRoaXMuYXR0YWNoSW5saW5lUG9saWN5KHRoaXMuZGVmYXVsdFBvbGljeSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kZWZhdWx0UG9saWN5LmFkZFN0YXRlbWVudHMoc3RhdGVtZW50KTtcbiAgICAgICAgcmV0dXJuIHsgc3RhdGVtZW50QWRkZWQ6IHRydWUsIHBvbGljeURlcGVuZGFibGU6IHRoaXMuZGVmYXVsdFBvbGljeSB9O1xuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYXR0YWNoSW5saW5lUG9saWN5KHBvbGljeTogUG9saWN5KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9IFRva2VuLmNvbXBhcmVTdHJpbmdzKHRoaXMuZW52LmFjY291bnQsIHBvbGljeS5lbnYuYWNjb3VudCk7XG4gICAgICAgIGNvbnN0IGVxdWFsT3JBbnlVbnJlc29sdmVkID0gdGhpc0FuZFBvbGljeUFjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uU0FNRSB8fFxuICAgICAgICAgIHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLkJPVEhfVU5SRVNPTFZFRCB8fFxuICAgICAgICAgIHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLk9ORV9VTlJFU09MVkVEO1xuICAgICAgICBpZiAoZXF1YWxPckFueVVucmVzb2x2ZWQpIHtcbiAgICAgICAgICB0aGlzLmF0dGFjaGVkUG9saWNpZXMuYXR0YWNoKHBvbGljeSk7XG4gICAgICAgICAgcG9saWN5LmF0dGFjaFRvUm9sZSh0aGlzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYWRkTWFuYWdlZFBvbGljeShfcG9saWN5OiBJTWFuYWdlZFBvbGljeSk6IHZvaWQge1xuICAgICAgICAvLyBGSVhNRTogQWRkIHdhcm5pbmcgdGhhdCB3ZSdyZSBpZ25vcmluZyB0aGlzXG4gICAgICB9XG5cbiAgICAgIC8qKlxuICAgICAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICAgICAqL1xuICAgICAgcHVibGljIGdyYW50UGFzc1JvbGUoaWRlbnRpdHk6IElQcmluY2lwYWwpOiBHcmFudCB7XG4gICAgICAgIHJldHVybiB0aGlzLmdyYW50KGlkZW50aXR5LCAnaWFtOlBhc3NSb2xlJyk7XG4gICAgICB9XG5cbiAgICAgIC8qKlxuICAgICAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICAgICAqL1xuICAgICAgcHVibGljIGdyYW50QXNzdW1lUm9sZShpZGVudGl0eTogSVByaW5jaXBhbCk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ3JhbnQoaWRlbnRpdHksICdzdHM6QXNzdW1lUm9sZScpO1xuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIEdyYW50IHRoZSBhY3Rpb25zIGRlZmluZWQgaW4gYWN0aW9ucyB0byB0aGUgaWRlbnRpdHkgUHJpbmNpcGFsIG9uIHRoaXMgcmVzb3VyY2UuXG4gICAgICAgKi9cbiAgICAgIHB1YmxpYyBncmFudChncmFudGVlOiBJUHJpbmNpcGFsLCAuLi5hY3Rpb25zOiBzdHJpbmdbXSk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIEdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgICAgICBncmFudGVlLFxuICAgICAgICAgIGFjdGlvbnMsXG4gICAgICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy5yb2xlQXJuXSxcbiAgICAgICAgICBzY29wZTogdGhpcyxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyBkZWR1cGVTdHJpbmcoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIGBJbXBvcnRlZFJvbGU6JHtyb2xlQXJufWA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuYWRkR3JhbnRzVG9SZXNvdXJjZXMgIT09IHVuZGVmaW5lZCAmJiBvcHRpb25zLm11dGFibGUgIT09IGZhbHNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1xcJ2FkZEdyYW50c1RvUmVzb3VyY2VzXFwnIGNhbiBvbmx5IGJlIHBhc3NlZCBpZiBcXCdtdXRhYmxlOiBmYWxzZVxcJycpO1xuICAgIH1cblxuICAgIGNvbnN0IHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPSBUb2tlbi5jb21wYXJlU3RyaW5ncyhyb2xlQWNjb3VudCA/PyAnJywgc2NvcGVTdGFjay5hY2NvdW50KTtcbiAgICBjb25zdCBlcXVhbE9yQW55VW5yZXNvbHZlZCA9IHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5TQU1FIHx8XG4gICAgICByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uQk9USF9VTlJFU09MVkVEIHx8XG4gICAgICByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uT05FX1VOUkVTT0xWRUQ7XG5cbiAgICAvLyBpZiB3ZSBhcmUgcmV0dXJuaW5nIGFuIGltbXV0YWJsZSByb2xlIHRoZW4gdGhlICdpbXBvcnRlZFJvbGUnIGlzIGp1c3QgYSB0aHJvd2F3YXkgY29uc3RydWN0XG4gICAgLy8gc28gZ2l2ZSBpdCBhIGRpZmZlcmVudCBpZFxuICAgIGNvbnN0IG11dGFibGVSb2xlSWQgPSAob3B0aW9ucy5tdXRhYmxlICE9PSBmYWxzZSAmJiBlcXVhbE9yQW55V