UNPKG

@aws-cdk/aws-iam

Version:

CDK routines for easily assigning correct and minimal IAM permissions

470 lines 66.6 kB
"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9sZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJvbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsd0NBQW1KO0FBQ25KLDJDQUE2QztBQUM3QyxtQ0FBZ0M7QUFDaEMsbURBQTBDO0FBRTFDLHFEQUFpRTtBQUNqRSxxQ0FBa0M7QUFDbEMsdURBQW1EO0FBRW5ELDZDQUFtSTtBQUNuSSxxRUFBK0U7QUFDL0UsNkRBQXlEO0FBQ3pELG1FQUE0RTtBQUM1RSxpQ0FBMkQ7QUFFM0QsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDO0FBQzlCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0FBc0pqQzs7Ozs7R0FLRztBQUNILE1BQWEsSUFBSyxTQUFRLGVBQVE7SUF3TGhDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBZ0I7UUFDeEQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixZQUFZLEVBQUUsS0FBSyxDQUFDLFFBQVE7U0FDN0IsQ0FBQyxDQUFDO1FBakRXLG1CQUFjLEdBQWUsSUFBSSxDQUFDO1FBQ2xDLHFCQUFnQixHQUF1QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUV4RCxxQkFBZ0IsR0FBVyxnQkFBZ0IsQ0FBQztRQW9DM0Msb0JBQWUsR0FBcUIsRUFBRSxDQUFDO1FBQ3ZDLHFCQUFnQixHQUFHLElBQUksdUJBQWdCLEVBQUUsQ0FBQztRQUUxQyxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUF1QyxDQUFDO1FBRXRFLGNBQVMsR0FBRyxLQUFLLENBQUM7Ozs7OzsrQ0F0TGYsSUFBSTs7OztRQTZMYixNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztRQUM1QyxJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUU7WUFDcEIsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7U0FDcEM7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsc0JBQXNCLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUM3RSxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQyxlQUFlLElBQUksRUFBRSxDQUFDLENBQUM7UUFDMUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxLQUFLLENBQUMsY0FBYyxJQUFJLEVBQUUsQ0FBQztRQUNqRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsS0FBSyxDQUFDLG1CQUFtQixDQUFDO1FBQ3JELE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixJQUFJLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUM1RiwwQkFBMEIsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQy9DLE1BQU0sV0FBVyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsSUFBSSxLQUFLLENBQUMsV0FBVyxFQUFFLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBRXpHLElBQUksV0FBVyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsSUFBSSxFQUFFO1lBQzVDLE1BQU0sSUFBSSxLQUFLLENBQUMsMERBQTBELENBQUMsQ0FBQztTQUM3RTtRQUVELGdCQUFnQixDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUU3QixNQUFNLElBQUksR0FBRyxJQUFJLHVCQUFPLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRTtZQUN6Qyx3QkFBd0IsRUFBRSxJQUFJLENBQUMsZ0JBQXVCO1lBQ3RELGlCQUFpQixFQUFFLHNCQUFlLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFDaEcsUUFBUSxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDO1lBQ3ZDLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtZQUNoQixtQkFBbUIsRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsU0FBUztZQUNyRyxRQUFRLEVBQUUsSUFBSSxDQUFDLFlBQVk7WUFDM0Isa0JBQWtCO1lBQ2xCLFdBQVc7U0FDWixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUM7UUFDOUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsdUJBQXVCLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUN4RCxNQUFNLEVBQUUsRUFBRTtZQUNWLE9BQU8sRUFBRSxLQUFLO1lBQ2QsUUFBUSxFQUFFLE1BQU07WUFDaEIsa0NBQWtDO1lBQ2xDLFlBQVksRUFBRSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUU7U0FDakgsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hELElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSx5QkFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxjQUFjLENBQUM7UUFFcEUsU0FBUyxRQUFRLENBQUMsUUFBNkM7WUFDN0QsSUFBSSxRQUFRLElBQUksSUFBSSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtnQkFDMUQsT0FBTyxTQUFTLENBQUM7YUFDbEI7WUFDRCxNQUFNLE1BQU0sR0FBRyxJQUFJLEtBQUssRUFBMEIsQ0FBQztZQUNuRCxLQUFLLE1BQU0sVUFBVSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUU7Z0JBQzlDLE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDNUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO2FBQzdDO1lBQ0QsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUVELGNBQU8sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQ25CLEtBQUssRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFO2dCQUNYLElBQUksQ0FBQyxLQUFLLElBQUksRUFBRTtvQkFDZCxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztpQkFDekI7WUFDSCxDQUFDO1NBQ0YsQ0FBQyxDQUFDO0tBQ0o7SUF4UEQ7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSSxNQUFNLENBQUMsV0FBVyxDQUFDLEtBQWdCLEVBQUUsRUFBVSxFQUFFLE9BQWUsRUFBRSxVQUE4QixFQUFFOzs7Ozs7Ozs7O1FBQ3ZHLE1BQU0sVUFBVSxHQUFHLFlBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsZ0JBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQzlFLE1BQU0sWUFBWSxHQUFHLFNBQVMsQ0FBQyxZQUFhLENBQUM7UUFDN0MsTUFBTSxXQUFXLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQztRQUN0Qyx1RkFBdUY7UUFDdkYsa0dBQWtHO1FBQ2xHLGlHQUFpRztRQUNqRyxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRyxDQUFDO1FBRWhELE1BQU0sTUFBTyxTQUFRLGVBQVE7WUFVM0IsWUFBWSxNQUFpQixFQUFFLEdBQVc7Z0JBQ3hDLEtBQUssQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFO29CQUNqQixPQUFPLEVBQUUsV0FBVztpQkFDckIsQ0FBQyxDQUFDO2dCQVpXLG1CQUFjLEdBQWUsSUFBSSxDQUFDO2dCQUNsQyxxQkFBZ0IsR0FBRyxXQUFXLENBQUM7Z0JBQy9CLHFCQUFnQixHQUFXLGdCQUFnQixDQUFDO2dCQUM1QyxtQkFBYyxHQUFHLElBQUkseUJBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxjQUFjLENBQUM7Z0JBQzFELFlBQU8sR0FBRyxPQUFPLENBQUM7Z0JBQ2xCLGFBQVEsR0FBRyxRQUFRLENBQUM7Z0JBQ25CLHFCQUFnQixHQUFHLElBQUksdUJBQWdCLEVBQUUsQ0FBQztZQU8zRCxDQUFDO1lBRU0sV0FBVyxDQUFDLFNBQTBCO2dCQUMzQyxPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsQ0FBQyxjQUFjLENBQUM7WUFDN0QsQ0FBQztZQUVNLG9CQUFvQixDQUFDLFNBQTBCO2dCQUNwRCxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtvQkFDdkIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLGVBQU0sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7b0JBQ2hELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7aUJBQzdDO2dCQUNELElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUM1QyxPQUFPLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDeEUsQ0FBQztZQUVNLGtCQUFrQixDQUFDLE1BQWM7Z0JBQ3RDLE1BQU0sOEJBQThCLEdBQUcsWUFBSyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNsRyxNQUFNLG9CQUFvQixHQUFHLDhCQUE4QixLQUFLLHNCQUFlLENBQUMsSUFBSTtvQkFDbEYsOEJBQThCLEtBQUssc0JBQWUsQ0FBQyxlQUFlO29CQUNsRSw4QkFBOEIsS0FBSyxzQkFBZSxDQUFDLGNBQWMsQ0FBQztnQkFDcEUsSUFBSSxvQkFBb0IsRUFBRTtvQkFDeEIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDckMsTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDM0I7WUFDSCxDQUFDO1lBRU0sZ0JBQWdCLENBQUMsT0FBdUI7Z0JBQzdDLDhDQUE4QztZQUNoRCxDQUFDO1lBRUQ7O2VBRUc7WUFDSSxhQUFhLENBQUMsUUFBb0I7Z0JBQ3ZDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsY0FBYyxDQUFDLENBQUM7WUFDOUMsQ0FBQztZQUVEOztlQUVHO1lBQ0ksZUFBZSxDQUFDLFFBQW9CO2dCQUN6QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLGdCQUFnQixDQUFDLENBQUM7WUFDaEQsQ0FBQztZQUVEOztlQUVHO1lBQ0ksS0FBSyxDQUFDLE9BQW1CLEVBQUUsR0FBRyxPQUFpQjtnQkFDcEQsT0FBTyxhQUFLLENBQUMsY0FBYyxDQUFDO29CQUMxQixPQUFPO29CQUNQLE9BQU87b0JBQ1AsWUFBWSxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztvQkFDNUIsS0FBSyxFQUFFLElBQUk7aUJBQ1osQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUVNLFlBQVk7Z0JBQ2pCLE9BQU8sZ0JBQWdCLE9BQU8sRUFBRSxDQUFDO1lBQ25DLENBQUM7U0FDRjtRQUVELElBQUksT0FBTyxDQUFDLG9CQUFvQixLQUFLLFNBQVMsSUFBSSxPQUFPLENBQUMsT0FBTyxLQUFLLEtBQUssRUFBRTtZQUMzRSxNQUFNLElBQUksS0FBSyxDQUFDLG1FQUFtRSxDQUFDLENBQUM7U0FDdEY7UUFFRCxNQUFNLHFDQUFxQyxHQUFHLFlBQUssQ0FBQyxjQUFjLENBQUMsV0FBVyxJQUFJLEVBQUUsRUFBRSxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUcsTUFBTSxvQkFBb0IsR0FBRyxxQ0FBcUMsS0FBSyxzQkFBZSxDQUFDLElBQUk7WUFDekYscUNBQXFDLEtBQUssc0JBQWUsQ0FBQyxlQUFlO1lBQ3pFLHFDQUFxQyxLQUFLLHNCQUFlLENBQUMsY0FBYyxDQUFDO1FBRTNFLDhGQUE4RjtRQUM5Riw0QkFBNEI7UUFDNUIsTUFBTSxhQUFhLEdBQUcsQ0FBQyxPQUFPLENBQUMsT0FBTyxLQUFLLEtBQUssSUFBSSxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUM7UUFDcEcsTUFBTSxZQUFZLEdBQUcsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBRXRELDRGQUE0RjtRQUM1RixPQUFPLE9BQU8sQ0FBQyxPQUFPLEtBQUssS0FBSyxJQUFJLG9CQUFvQjtZQUN0RCxDQUFDLENBQUMsWUFBWTtZQUNkLENBQUMsQ0FBQyxJQUFJLDhCQUFhLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDLG9CQUFvQixJQUFJLEtBQUssQ0FBQyxDQUFDO0tBQ3ZGO0lBRUQ7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQWdCLEVBQUUsRUFBVSxFQUFFLFFBQWdCO1FBQ3ZFLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLFlBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDO1lBQzNELE1BQU0sRUFBRSxFQUFFO1lBQ1YsT0FBTyxFQUFFLEtBQUs7WUFDZCxRQUFRLEVBQUUsTUFBTTtZQUNoQixZQUFZLEVBQUUsUUFBUTtTQUN2QixDQUFDLENBQUMsQ0FBQztLQUNMO0lBbUhEOzs7O09BSUc7SUFDSSxvQkFBb0IsQ0FBQyxTQUEwQjs7Ozs7Ozs7OztRQUNwRCxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUN2QixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksZUFBTSxDQUFDLElBQUksRUFBRSxlQUFlLENBQUMsQ0FBQztZQUN2RCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1NBQzdDO1FBQ0QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFNUMsOEVBQThFO1FBQzlFLDRCQUE0QjtRQUM1QixNQUFNLGdCQUFnQixHQUFHLElBQUkseUJBQWtCLEVBQUUsQ0FBQztRQUNsRCxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUVsRCxPQUFPLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxDQUFDO0tBQ25EO0lBRU0sV0FBVyxDQUFDLFNBQTBCOzs7Ozs7Ozs7O1FBQzNDLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDLGNBQWMsQ0FBQztLQUM1RDtJQUVEOzs7T0FHRztJQUNJLGdCQUFnQixDQUFDLE1BQXNCOzs7Ozs7Ozs7O1FBQzVDLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssTUFBTSxDQUFDLEVBQUU7WUFBRSxPQUFPO1NBQUU7UUFDL0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7S0FDbkM7SUFFRDs7O09BR0c7SUFDSSxrQkFBa0IsQ0FBQyxNQUFjOzs7Ozs7Ozs7O1FBQ3RDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDckMsTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztLQUMzQjtJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLE9BQW1CLEVBQUUsR0FBRyxPQUFpQjs7Ozs7Ozs7OztRQUNwRCxPQUFPLGFBQUssQ0FBQyxjQUFjLENBQUM7WUFDMUIsT0FBTztZQUNQLE9BQU87WUFDUCxZQUFZLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO1lBQzVCLEtBQUssRUFBRSxJQUFJO1NBQ1osQ0FBQyxDQUFDO0tBQ0o7SUFFRDs7T0FFRztJQUNJLGFBQWEsQ0FBQyxRQUFvQjs7Ozs7Ozs7OztRQUN2QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0tBQzdDO0lBRUQ7O09BRUc7SUFDSSxlQUFlLENBQUMsUUFBb0I7Ozs7Ozs7Ozs7UUFDekMsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0tBQy9DO0lBR0Q7Ozs7Ozs7O09BUUc7SUFDSSxvQkFBb0IsQ0FBQyxVQUF1QyxFQUFFOzs7Ozs7Ozs7O1FBQ25FLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSw4QkFBYSxDQUFDLGlCQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQWtCLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsSUFBSSxLQUFLLENBQUMsQ0FBQztTQUN2SjtRQUVELE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQztLQUMzQjtJQUVTLFFBQVE7UUFDaEIsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUseUJBQXlCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUN6RSxLQUFLLE1BQU0sTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxFQUFFO1lBQ3ZELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxDQUFDO1NBQ3BEO1FBRUQsT0FBTyxNQUFNLENBQUM7S0FDZjtJQUVEOzs7O09BSUc7SUFDSyxnQkFBZ0I7UUFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUN6QyxPQUFPO1NBQ1I7UUFDRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztRQUV0QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUM7UUFDbEIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUM7UUFFaEQsTUFBTSxZQUFZLEdBQUcsV0FBVyxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsZUFBZSxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDNUYsa0NBQWtDO1FBRWxDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsWUFBWSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN0RSxJQUFJLE9BQU8sR0FBRyxFQUFFLEVBQUU7WUFDaEIsa0JBQVcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLHFCQUFxQixPQUFPLGdFQUFnRSxDQUFDLENBQUM7U0FDL0g7YUFBTSxJQUFJLE9BQU8sR0FBRyxFQUFFLEVBQUU7WUFDdkIsa0JBQVcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLGlCQUFpQixPQUFPLGlGQUFpRixDQUFDLENBQUM7U0FDNUk7UUFFRCwwREFBMEQ7UUFDMUQsc0JBQXNCLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUV4RCxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDVixLQUFLLE1BQU0sTUFBTSxJQUFJLFlBQVksQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUN4QyxJQUFJLE1BQU0sS0FBSyxXQUFXLEVBQUU7Z0JBQUUsU0FBUzthQUFFO1lBRXpDLE1BQU0sRUFBRSxHQUFHLElBQUksOEJBQWEsQ0FBQyxJQUFJLEVBQUUsaUJBQWlCLENBQUMsRUFBRSxFQUFFLEVBQUU7Z0JBQ3pELFdBQVcsRUFBRSw0QkFBNEIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ3pELFFBQVEsRUFBRSxNQUFNO2dCQUNoQixLQUFLLEVBQUUsQ0FBQyxJQUFJLENBQUM7YUFDZCxDQUFDLENBQUM7WUFDSCxzQkFBc0IsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7U0FDcEM7UUFFRDs7V0FFRztRQUNILFNBQVMsc0JBQXNCLENBQUMsR0FBbUIsRUFBRSxrQkFBOEI7WUFDakYsS0FBSyxNQUFNLFFBQVEsSUFBSSxZQUFZLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsRUFBRTtnQkFDbEQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUM7YUFDekQ7UUFDSCxDQUFDO0tBQ0Y7O0FBMVlILG9CQTJZQzs7O0FBb0NELFNBQVMsc0JBQXNCLENBQUMsU0FBcUIsRUFBRSxXQUFxQjtJQUMxRSxNQUFNLFNBQVMsR0FBRyxJQUFJLGdDQUFjLEVBQUUsQ0FBQztJQUV2QyxxRUFBcUU7SUFDckUsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQ3JDLENBQUMsQ0FBQyxTQUFTO1FBQ1gsQ0FBQyxDQUFDLElBQUksaURBQTZCLENBQUMsU0FBUyxFQUFFLENBQUMsU0FBUyxFQUFFLEVBQUU7WUFDM0QsU0FBUyxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUU7Z0JBQ3JDLGdCQUFnQixFQUFFLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVc7YUFDMUUsQ0FBQyxDQUFDO1lBQ0gsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQyxDQUFDLENBQUM7SUFFTCxvREFBK0IsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFFbkQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQUMsSUFBYTtJQUNyQyxJQUFJLElBQUksS0FBSyxTQUFTLElBQUksWUFBSyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUNsRCxPQUFPO0tBQ1I7SUFFRCxNQUFNLGFBQWEsR0FBRyw2QkFBNkIsQ0FBQztJQUVwRCxJQUFJLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFO1FBQ3pDLE1BQU0sSUFBSSxLQUFLLENBQUMsNkVBQTZFLElBQUksQ0FBQyxNQUFNLGNBQWMsQ0FBQyxDQUFDO0tBQ3pIO1NBQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7UUFDcEMsTUFBTSxJQUFJLEtBQUssQ0FDYiwwR0FBMEc7Y0FDeEcsMEVBQTBFLElBQUksZUFBZSxDQUFDLENBQUM7S0FDcEc7QUFDSCxDQUFDO0FBRUQsU0FBUywwQkFBMEIsQ0FBQyxRQUFpQjtJQUNuRCxJQUFJLFFBQVEsS0FBSyxTQUFTLEVBQUU7UUFDMUIsT0FBTztLQUNSO0lBRUQsSUFBSSxRQUFRLEdBQUcsSUFBSSxJQUFJLFFBQVEsR0FBRyxLQUFLLEVBQUU7UUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsUUFBUSx3REFBd0QsQ0FBQyxDQUFDO0tBQ25IO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFybkZvcm1hdCwgSUNvbnN0cnVjdCwgRHVyYXRpb24sIFJlc291cmNlLCBTdGFjaywgVG9rZW4sIFRva2VuQ29tcGFyaXNvbiwgQXNwZWN0cywgQ29uY3JldGVEZXBlbmRhYmxlLCBBbm5vdGF0aW9ucyB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBOb2RlIH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBHcmFudCB9IGZyb20gJy4vZ3JhbnQnO1xuaW1wb3J0IHsgQ2ZuUm9sZSB9IGZyb20gJy4vaWFtLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBJSWRlbnRpdHkgfSBmcm9tICcuL2lkZW50aXR5LWJhc2UnO1xuaW1wb3J0IHsgSU1hbmFnZWRQb2xpY3ksIE1hbmFnZWRQb2xpY3kgfSBmcm9tICcuL21hbmFnZWQtcG9saWN5JztcbmltcG9ydCB7IFBvbGljeSB9IGZyb20gJy4vcG9saWN5JztcbmltcG9ydCB7IFBvbGljeURvY3VtZW50IH0gZnJvbSAnLi9wb2xpY3ktZG9jdW1lbnQnO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50IH0gZnJvbSAnLi9wb2xpY3ktc3RhdGVtZW50JztcbmltcG9ydCB7IEFkZFRvUHJpbmNpcGFsUG9saWN5UmVzdWx0LCBBcm5QcmluY2lwYWwsIElQcmluY2lwYWwsIFByaW5jaXBhbFBvbGljeUZyYWdtZW50LCBJQ29tcGFyYWJsZVByaW5jaXBhbCB9IGZyb20gJy4vcHJpbmNpcGFscyc7XG5pbXBvcnQgeyBkZWZhdWx0QWRkUHJpbmNpcGFsVG9Bc3N1bWVSb2xlIH0gZnJvbSAnLi9wcml2YXRlL2Fzc3VtZS1yb2xlLXBvbGljeSc7XG5pbXBvcnQgeyBJbW11dGFibGVSb2xlIH0gZnJvbSAnLi9wcml2YXRlL2ltbXV0YWJsZS1yb2xlJztcbmltcG9ydCB7IE11dGF0aW5nUG9saWN5RG9jdW1lbnRBZGFwdGVyIH0gZnJvbSAnLi9wcml2YXRlL3BvbGljeWRvYy1hZGFwdGVyJztcbmltcG9ydCB7IEF0dGFjaGVkUG9saWNpZXMsIFVuaXF1ZVN0cmluZ1NldCB9IGZyb20gJy4vdXRpbCc7XG5cbmNvbnN0IE1BWF9JTkxJTkVfU0laRSA9IDEwMDAwO1xuY29uc3QgTUFYX01BTkFHRURQT0xfU0laRSA9IDYwMDA7XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgZGVmaW5pbmcgYW4gSUFNIFJvbGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb2xlUHJvcHMge1xuICAvKipcbiAgICogVGhlIElBTSBwcmluY2lwYWwgKGkuZS4gYG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdzbnMuYW1hem9uYXdzLmNvbScpYClcbiAgICogd2hpY2ggY2FuIGFzc3VtZSB0aGlzIHJvbGUuXG4gICAqXG4gICAqIFlvdSBjYW4gbGF0ZXIgbW9kaWZ5IHRoZSBhc3N1bWUgcm9sZSBwb2xpY3kgZG9jdW1lbnQgYnkgYWNjZXNzaW5nIGl0IHZpYVxuICAgKiB0aGUgYGFzc3VtZVJvbGVQb2xpY3lgIHByb3BlcnR5LlxuICAgKi9cbiAgcmVhZG9ubHkgYXNzdW1lZEJ5OiBJUHJpbmNpcGFsO1xuXG4gIC8qKlxuICAgKiBJRCB0aGF0IHRoZSByb2xlIGFzc3VtZXIgbmVlZHMgdG8gcHJvdmlkZSB3aGVuIGFzc3VtaW5nIHRoaXMgcm9sZVxuICAgKlxuICAgKiBJZiB0aGUgY29uZmlndXJlZCBhbmQgcHJvdmlkZWQgZXh0ZXJuYWwgSURzIGRvIG5vdCBtYXRjaCwgdGhlXG4gICAqIEFzc3VtZVJvbGUgb3BlcmF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgc2VlIHtAbGluayBleHRlcm5hbElkc31cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gZXh0ZXJuYWwgSUQgcmVxdWlyZWRcbiAgICovXG4gIHJlYWRvbmx5IGV4dGVybmFsSWQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgSURzIHRoYXQgdGhlIHJvbGUgYXNzdW1lciBuZWVkcyB0byBwcm92aWRlIG9uZSBvZiB3aGVuIGFzc3VtaW5nIHRoaXMgcm9sZVxuICAgKlxuICAgKiBJZiB0aGUgY29uZmlndXJlZCBhbmQgcHJvdmlkZWQgZXh0ZXJuYWwgSURzIGRvIG5vdCBtYXRjaCwgdGhlXG4gICAqIEFzc3VtZVJvbGUgb3BlcmF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gZXh0ZXJuYWwgSUQgcmVxdWlyZWRcbiAgICovXG4gIHJlYWRvbmx5IGV4dGVybmFsSWRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBtYW5hZ2VkIHBvbGljaWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJvbGUuXG4gICAqXG4gICAqIFlvdSBjYW4gYWRkIG1hbmFnZWQgcG9saWNpZXMgbGF0ZXIgdXNpbmdcbiAgICogYGFkZE1hbmFnZWRQb2xpY3koTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUocG9saWN5TmFtZSkpYC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBtYW5hZ2VkIHBvbGljaWVzLlxuICAgKi9cbiAgcmVhZG9ubHkgbWFuYWdlZFBvbGljaWVzPzogSU1hbmFnZWRQb2xpY3lbXTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIG5hbWVkIHBvbGljaWVzIHRvIGlubGluZSBpbnRvIHRoaXMgcm9sZS4gVGhlc2UgcG9saWNpZXMgd2lsbCBiZVxuICAgKiBjcmVhdGVkIHdpdGggdGhlIHJvbGUsIHdoZXJlYXMgdGhvc2UgYWRkZWQgYnkgYGBhZGRUb1BvbGljeWBgIGFyZSBhZGRlZFxuICAgKiB1c2luZyBhIHNlcGFyYXRlIENsb3VkRm9ybWF0aW9uIHJlc291cmNlIChhbGxvd2luZyBhIHdheSBhcm91bmQgY2lyY3VsYXJcbiAgICogZGVwZW5kZW5jaWVzIHRoYXQgY291bGQgb3RoZXJ3aXNlIGJlIGludHJvZHVjZWQpLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHBvbGljeSBpcyBpbmxpbmVkIGluIHRoZSBSb2xlIHJlc291cmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgaW5saW5lUG9saWNpZXM/OiB7IFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudCB9O1xuXG4gIC8qKlxuICAgKiBUaGUgcGF0aCBhc3NvY2lhdGVkIHdpdGggdGhpcyByb2xlLiBGb3IgaW5mb3JtYXRpb24gYWJvdXQgSUFNIHBhdGhzLCBzZWVcbiAgICogRnJpZW5kbHkgTmFtZXMgYW5kIFBhdGhzIGluIElBTSBVc2VyIEd1aWRlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAvXG4gICAqL1xuICByZWFkb25seSBwYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBV1Mgc3VwcG9ydHMgcGVybWlzc2lvbnMgYm91bmRhcmllcyBmb3IgSUFNIGVudGl0aWVzICh1c2VycyBvciByb2xlcykuXG4gICAqIEEgcGVybWlzc2lvbnMgYm91bmRhcnkgaXMgYW4gYWR2YW5jZWQgZmVhdHVyZSBmb3IgdXNpbmcgYSBtYW5hZ2VkIHBvbGljeVxuICAgKiB0byBzZXQgdGhlIG1heGltdW0gcGVybWlzc2lvbnMgdGhhdCBhbiBpZGVudGl0eS1iYXNlZCBwb2xpY3kgY2FuIGdyYW50IHRvXG4gICAqIGFuIElBTSBlbnRpdHkuIEFuIGVudGl0eSdzIHBlcm1pc3Npb25zIGJvdW5kYXJ5IGFsbG93cyBpdCB0byBwZXJmb3JtIG9ubHlcbiAgICogdGhlIGFjdGlvbnMgdGhhdCBhcmUgYWxsb3dlZCBieSBib3RoIGl0cyBpZGVudGl0eS1iYXNlZCBwb2xpY2llcyBhbmQgaXRzXG4gICAqIHBlcm1pc3Npb25zIGJvdW5kYXJpZXMuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2F3cy1yZXNvdXJjZS1pYW0tcm9sZS5odG1sI2Nmbi1pYW0tcm9sZS1wZXJtaXNzaW9uc2JvdW5kYXJ5XG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9hY2Nlc3NfcG9saWNpZXNfYm91bmRhcmllcy5odG1sXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcGVybWlzc2lvbnMgYm91bmRhcnkuXG4gICAqL1xuICByZWFkb25seSBwZXJtaXNzaW9uc0JvdW5kYXJ5PzogSU1hbmFnZWRQb2xpY3k7XG5cbiAgLyoqXG4gICAqIEEgbmFtZSBmb3IgdGhlIElBTSByb2xlLiBGb3IgdmFsaWQgdmFsdWVzLCBzZWUgdGhlIFJvbGVOYW1lIHBhcmFtZXRlciBmb3JcbiAgICogdGhlIENyZWF0ZVJvbGUgYWN0aW9uIGluIHRoZSBJQU0gQVBJIFJlZmVyZW5jZS5cbiAgICpcbiAgICogSU1QT1JUQU5UOiBJZiB5b3Ugc3BlY2lmeSBhIG5hbWUsIHlvdSBjYW5ub3QgcGVyZm9ybSB1cGRhdGVzIHRoYXQgcmVxdWlyZVxuICAgKiByZXBsYWNlbWVudCBvZiB0aGlzIHJlc291cmNlLiBZb3UgY2FuIHBlcmZvcm0gdXBkYXRlcyB0aGF0IHJlcXVpcmUgbm8gb3JcbiAgICogc29tZSBpbnRlcnJ1cHRpb24uIElmIHlvdSBtdXN0IHJlcGxhY2UgdGhlIHJlc291cmNlLCBzcGVjaWZ5IGEgbmV3IG5hbWUuXG4gICAqXG4gICAqIElmIHlvdSBzcGVjaWZ5IGEgbmFtZSwgeW91IG11c3Qgc3BlY2lmeSB0aGUgQ0FQQUJJTElUWV9OQU1FRF9JQU0gdmFsdWUgdG9cbiAgICogYWNrbm93bGVkZ2UgeW91ciB0ZW1wbGF0ZSdzIGNhcGFiaWxpdGllcy4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZVxuICAgKiBBY2tub3dsZWRnaW5nIElBTSBSZXNvdXJjZXMgaW4gQVdTIENsb3VkRm9ybWF0aW9uIFRlbXBsYXRlcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBV1MgQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzIGEgdW5pcXVlIHBoeXNpY2FsIElEIGFuZCB1c2VzIHRoYXQgSURcbiAgICogZm9yIHRoZSByb2xlIG5hbWUuXG4gICAqL1xuICByZWFkb25seSByb2xlTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG1heGltdW0gc2Vzc2lvbiBkdXJhdGlvbiB0aGF0IHlvdSB3YW50IHRvIHNldCBmb3IgdGhlIHNwZWNpZmllZCByb2xlLlxuICAgKiBUaGlzIHNldHRpbmcgY2FuIGhhdmUgYSB2YWx1ZSBmcm9tIDEgaG91ciAoMzYwMHNlYykgdG8gMTIgKDQzMjAwc2VjKSBob3Vycy5cbiAgICpcbiAgICogQW55b25lIHdobyBhc3N1bWVzIHRoZSByb2xlIGZyb20gdGhlIEFXUyBDTEkgb3IgQVBJIGNhbiB1c2UgdGhlXG4gICAqIER1cmF0aW9uU2Vjb25kcyBBUEkgcGFyYW1ldGVyIG9yIHRoZSBkdXJhdGlvbi1zZWNvbmRzIENMSSBwYXJhbWV0ZXIgdG9cbiAgICogcmVxdWVzdCBhIGxvbmdlciBzZXNzaW9uLiBUaGUgTWF4U2Vzc2lvbkR1cmF0aW9uIHNldHRpbmcgZGV0ZXJtaW5lcyB0aGVcbiAgICogbWF4aW11bSBkdXJhdGlvbiB0aGF0IGNhbiBiZSByZXF1ZXN0ZWQgdXNpbmcgdGhlIER1cmF0aW9uU2Vjb25kc1xuICAgKiBwYXJhbWV0ZXIuXG4gICAqXG4gICAqIElmIHVzZXJzIGRvbid0IHNwZWNpZnkgYSB2YWx1ZSBmb3IgdGhlIER1cmF0aW9uU2Vjb25kcyBwYXJhbWV0ZXIsIHRoZWlyXG4gICAqIHNlY3VyaXR5IGNyZWRlbnRpYWxzIGFyZSB2YWxpZCBmb3Igb25lIGhvdXIgYnkgZGVmYXVsdC4gVGhpcyBhcHBsaWVzIHdoZW5cbiAgICogeW91IHVzZSB0aGUgQXNzdW1lUm9sZSogQVBJIG9wZXJhdGlvbnMgb3IgdGhlIGFzc3VtZS1yb2xlKiBDTEkgb3BlcmF0aW9uc1xuICAgKiBidXQgZG9lcyBub3QgYXBwbHkgd2hlbiB5b3UgdXNlIHRob3NlIG9wZXJhdGlvbnMgdG8gY3JlYXRlIGEgY29uc29sZSBVUkwuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9pZF9yb2xlc191c2UuaHRtbFxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5ob3VycygxKVxuICAgKi9cbiAgcmVhZG9ubHkgbWF4U2Vzc2lvbkR1cmF0aW9uPzogRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIEEgZGVzY3JpcHRpb24gb2YgdGhlIHJvbGUuIEl0IGNhbiBiZSB1cCB0byAxMDAwIGNoYXJhY3RlcnMgbG9uZy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBkZXNjcmlwdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgYWxsb3dpbmcgY3VzdG9taXppbmcgdGhlIGJlaGF2aW9yIG9mIHtAbGluayBSb2xlLmZyb21Sb2xlQXJufS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBGcm9tUm9sZUFybk9wdGlvbnMge1xuICAvKipcbiAgICogV2hldGhlciB0aGUgaW1wb3J0ZWQgcm9sZSBjYW4gYmUgbW9kaWZpZWQgYnkgYXR0YWNoaW5nIHBvbGljeSByZXNvdXJjZXMgdG8gaXQuXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IG11dGFibGU/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBGb3IgaW1tdXRhYmxlIHJvbGVzOiBhZGQgZ3JhbnRzIHRvIHJlc291cmNlcyBpbnN0ZWFkIG9mIGRyb3BwaW5nIHRoZW1cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgZmFsc2VgIG9yIG5vdCBzcGVjaWZpZWQsIGdyYW50IHBlcm1pc3Npb25zIGFkZGVkIHRvIHRoaXMgcm9sZSBhcmUgaWdub3JlZC5cbiAgICogSXQgaXMgeW91ciBvd24gcmVzcG9uc2liaWxpdHkgdG8gbWFrZSBzdXJlIHRoZSByb2xlIGhhcyB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMuXG4gICAqXG4gICAqIElmIHRoaXMgaXMgYHRydWVgLCBhbnkgZ3JhbnQgcGVybWlzc2lvbnMgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVzb3VyY2UgaW5zdGVhZC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFkZEdyYW50c1RvUmVzb3VyY2VzPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBJQU0gUm9sZVxuICpcbiAqIERlZmluZXMgYW4gSUFNIHJvbGUuIFRoZSByb2xlIGlzIGNyZWF0ZWQgd2l0aCBhbiBhc3N1bWUgcG9saWN5IGRvY3VtZW50IGFzc29jaWF0ZWQgd2l0aFxuICogdGhlIHNwZWNpZmllZCBBV1Mgc2VydmljZSBwcmluY2lwYWwgZGVmaW5lZCBpbiBgc2VydmljZUFzc3VtZVJvbGVgLlxuICovXG5leHBvcnQgY2xhc3MgUm9sZSBleHRlbmRzIFJlc291cmNlIGltcGxlbWVudHMgSVJvbGUge1xuICAvKipcbiAgICogSW1wb3J0IGFuIGV4dGVybmFsIHJvbGUgYnkgQVJOLlxuICAgKlxuICAgKiBJZiB0aGUgaW1wb3J0ZWQgUm9sZSBBUk4gaXMgYSBUb2tlbiAoc3VjaCBhcyBhXG4gICAqIGBDZm5QYXJhbWV0ZXIudmFsdWVBc1N0cmluZ2Agb3IgYSBgRm4uaW1wb3J0VmFsdWUoKWApICphbmQqIHRoZSByZWZlcmVuY2VkXG4gICAqIHJvbGUgaGFzIGEgYHBhdGhgIChsaWtlIGBhcm46Li4uOnJvbGUvQWRtaW5Sb2xlcy9BbGljZWApLCB0aGVcbiAgICogYHJvbGVOYW1lYCBwcm9wZXJ0eSB3aWxsIG5vdCByZXNvbHZlIHRvIHRoZSBjb3JyZWN0IHZhbHVlLiBJbnN0ZWFkIGl0XG4gICAqIHdpbGwgcmVzb2x2ZSB0byB0aGUgZmlyc3QgcGF0aCBjb21wb25lbnQuIFdlIHVuZm9ydHVuYXRlbHkgY2Fubm90IGV4cHJlc3NcbiAgICogdGhlIGNvcnJlY3QgY2FsY3VsYXRpb24gb2YgdGhlIGZ1bGwgcGF0aCBuYW1lIGFzIGEgQ2xvdWRGb3JtYXRpb25cbiAgICogZXhwcmVzc2lvbi4gSW4gdGhpcyBzY2VuYXJpbyB0aGUgUm9sZSBBUk4gc2hvdWxkIGJlIHN1cHBsaWVkIHdpdGhvdXQgdGhlXG4gICAqIGBwYXRoYCBpbiBvcmRlciB0byByZXNvbHZlIHRoZSBjb3JyZWN0IHJvbGUgcmVzb3VyY2UuXG4gICAqXG4gICAqIEBwYXJhbSBzY29wZSBjb25zdHJ1Y3Qgc2NvcGVcbiAgICogQHBhcmFtIGlkIGNvbnN0cnVjdCBpZFxuICAgKiBAcGFyYW0gcm9sZUFybiB0aGUgQVJOIG9mIHRoZSByb2xlIHRvIGltcG9ydFxuICAgKiBAcGFyYW0gb3B0aW9ucyBhbGxvdyBjdXN0b21pemluZyB0aGUgYmVoYXZpb3Igb2YgdGhlIHJldHVybmVkIHJvbGVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVJvbGVBcm4oc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcm9sZUFybjogc3RyaW5nLCBvcHRpb25zOiBGcm9tUm9sZUFybk9wdGlvbnMgPSB7fSk6IElSb2xlIHtcbiAgICBjb25zdCBzY29wZVN0YWNrID0gU3RhY2sub2Yoc2NvcGUpO1xuICAgIGNvbnN0IHBhcnNlZEFybiA9IHNjb3BlU3RhY2suc3BsaXRBcm4ocm9sZUFybiwgQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUpO1xuICAgIGNvbnN0IHJlc291cmNlTmFtZSA9IHBhcnNlZEFybi5yZXNvdXJjZU5hbWUhO1xuICAgIGNvbnN0IHJvbGVBY2NvdW50ID0gcGFyc2VkQXJuLmFjY291bnQ7XG4gICAgLy8gc2VydmljZSByb2xlcyBoYXZlIGFuIEFSTiBsaWtlICdhcm46YXdzOmlhbTo6PGFjY291bnQ+OnJvbGUvc2VydmljZS1yb2xlLzxyb2xlTmFtZT4nXG4gICAgLy8gb3IgJ2Fybjphd3M6aWFtOjo8YWNjb3VudD46cm9sZS9zZXJ2aWNlLXJvbGUvc2VydmljZW5hbWUuYW1hem9uYXdzLmNvbS9zZXJ2aWNlLXJvbGUvPHJvbGVOYW1lPidcbiAgICAvLyB3ZSB3YW50IHRvIHN1cHBvcnQgdGhlc2UgYXMgd2VsbCwgc28gd2UganVzdCB1c2UgdGhlIGVsZW1lbnQgYWZ0ZXIgdGhlIGxhc3Qgc2xhc2ggYXMgcm9sZSBuYW1lXG4gICAgY29uc3Qgcm9sZU5hbWUgPSByZXNvdXJjZU5hbWUuc3BsaXQoJy8nKS5wb3AoKSE7XG5cbiAgICBjbGFzcyBJbXBvcnQgZXh0ZW5kcyBSZXNvdXJjZSBpbXBsZW1lbnRzIElSb2xlLCBJQ29tcGFyYWJsZVByaW5jaXBhbCB7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgZ3JhbnRQcmluY2lwYWw6IElQcmluY2lwYWwgPSB0aGlzO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHByaW5jaXBhbEFjY291bnQgPSByb2xlQWNjb3VudDtcbiAgICAgIHB1YmxpYyByZWFkb25seSBhc3N1bWVSb2xlQWN0aW9uOiBzdHJpbmcgPSAnc3RzOkFzc3VtZVJvbGUnO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHBvbGljeUZyYWdtZW50ID0gbmV3IEFyblByaW5jaXBhbChyb2xlQXJuKS5wb2xpY3lGcmFnbWVudDtcbiAgICAgIHB1YmxpYyByZWFkb25seSByb2xlQXJuID0gcm9sZUFybjtcbiAgICAgIHB1YmxpYyByZWFkb25seSByb2xlTmFtZSA9IHJvbGVOYW1lO1xuICAgICAgcHJpdmF0ZSByZWFkb25seSBhdHRhY2hlZFBvbGljaWVzID0gbmV3IEF0dGFjaGVkUG9saWNpZXMoKTtcbiAgICAgIHByaXZhdGUgZGVmYXVsdFBvbGljeT86IFBvbGljeTtcblxuICAgICAgY29uc3RydWN0b3IoX3Njb3BlOiBDb25zdHJ1Y3QsIF9pZDogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKF9zY29wZSwgX2lkLCB7XG4gICAgICAgICAgYWNjb3VudDogcm9sZUFjY291bnQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYWRkVG9Qb2xpY3koc3RhdGVtZW50OiBQb2xpY3lTdGF0ZW1lbnQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkVG9QcmluY2lwYWxQb2xpY3koc3RhdGVtZW50KS5zdGF0ZW1lbnRBZGRlZDtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQge1xuICAgICAgICBpZiAoIXRoaXMuZGVmYXVsdFBvbGljeSkge1xuICAgICAgICAgIHRoaXMuZGVmYXVsdFBvbGljeSA9IG5ldyBQb2xpY3kodGhpcywgJ1BvbGljeScpO1xuICAgICAgICAgIHRoaXMuYXR0YWNoSW5saW5lUG9saWN5KHRoaXMuZGVmYXVsdFBvbGljeSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kZWZhdWx0UG9saWN5LmFkZFN0YXRlbWVudHMoc3RhdGVtZW50KTtcbiAgICAgICAgcmV0dXJuIHsgc3RhdGVtZW50QWRkZWQ6IHRydWUsIHBvbGljeURlcGVuZGFibGU6IHRoaXMuZGVmYXVsdFBvbGljeSB9O1xuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYXR0YWNoSW5saW5lUG9saWN5KHBvbGljeTogUG9saWN5KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9IFRva2VuLmNvbXBhcmVTdHJpbmdzKHRoaXMuZW52LmFjY291bnQsIHBvbGljeS5lbnYuYWNjb3VudCk7XG4gICAgICAgIGNvbnN0IGVxdWFsT3JBbnlVbnJlc29sdmVkID0gdGhpc0FuZFBvbGljeUFjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uU0FNRSB8fFxuICAgICAgICAgIHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLkJPVEhfVU5SRVNPTFZFRCB8fFxuICAgICAgICAgIHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLk9ORV9VTlJFU09MVkVEO1xuICAgICAgICBpZiAoZXF1YWxPckFueVVucmVzb2x2ZWQpIHtcbiAgICAgICAgICB0aGlzLmF0dGFjaGVkUG9saWNpZXMuYXR0YWNoKHBvbGljeSk7XG4gICAgICAgICAgcG9saWN5LmF0dGFjaFRvUm9sZSh0aGlzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYWRkTWFuYWdlZFBvbGljeShfcG9saWN5OiBJTWFuYWdlZFBvbGljeSk6IHZvaWQge1xuICAgICAgICAvLyBGSVhNRTogQWRkIHdhcm5pbmcgdGhhdCB3ZSdyZSBpZ25vcmluZyB0aGlzXG4gICAgICB9XG5cbiAgICAgIC8qKlxuICAgICAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICAgICAqL1xuICAgICAgcHVibGljIGdyYW50UGFzc1JvbGUoaWRlbnRpdHk6IElQcmluY2lwYWwpOiBHcmFudCB7XG4gICAgICAgIHJldHVybiB0aGlzLmdyYW50KGlkZW50aXR5LCAnaWFtOlBhc3NSb2xlJyk7XG4gICAgICB9XG5cbiAgICAgIC8qKlxuICAgICAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICAgICAqL1xuICAgICAgcHVibGljIGdyYW50QXNzdW1lUm9sZShpZGVudGl0eTogSVByaW5jaXBhbCk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ3JhbnQoaWRlbnRpdHksICdzdHM6QXNzdW1lUm9sZScpO1xuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIEdyYW50IHRoZSBhY3Rpb25zIGRlZmluZWQgaW4gYWN0aW9ucyB0byB0aGUgaWRlbnRpdHkgUHJpbmNpcGFsIG9uIHRoaXMgcmVzb3VyY2UuXG4gICAgICAgKi9cbiAgICAgIHB1YmxpYyBncmFudChncmFudGVlOiBJUHJpbmNpcGFsLCAuLi5hY3Rpb25zOiBzdHJpbmdbXSk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIEdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgICAgICBncmFudGVlLFxuICAgICAgICAgIGFjdGlvbnMsXG4gICAgICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy5yb2xlQXJuXSxcbiAgICAgICAgICBzY29wZTogdGhpcyxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyBkZWR1cGVTdHJpbmcoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIGBJbXBvcnRlZFJvbGU6JHtyb2xlQXJufWA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuYWRkR3JhbnRzVG9SZXNvdXJjZXMgIT09IHVuZGVmaW5lZCAmJiBvcHRpb25zLm11dGFibGUgIT09IGZhbHNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1xcJ2FkZEdyYW50c1RvUmVzb3VyY2VzXFwnIGNhbiBvbmx5IGJlIHBhc3NlZCBpZiBcXCdtdXRhYmxlOiBmYWxzZVxcJycpO1xuICAgIH1cblxuICAgIGNvbnN0IHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPSBUb2tlbi5jb21wYXJlU3RyaW5ncyhyb2xlQWNjb3VudCA/PyAnJywgc2NvcGVTdGFjay5hY2NvdW50KTtcbiAgICBjb25zdCBlcXVhbE9yQW55VW5yZXNvbHZlZCA9IHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5TQU1FIHx8XG4gICAgICByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uQk9USF9VTlJFU09MVkVEIHx8XG4gICAgICByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uT05FX1VOUkVTT0xWRUQ7XG5cbiAgICAvLyBpZiB3ZSBhcmUgcmV0dXJuaW5nIGFuIGltbXV0YWJsZSByb2xlIHRoZW4gdGhlICdpbXBvcnRlZFJvbGUnIGlzIGp1c3QgYSB0aHJvd2F3YXkgY29uc3RydWN0XG4gICAgLy8gc28gZ2l2ZSBpdCBhIGRpZmZlcmVudCBpZFxuICAgIGNvbnN0IG11dGFibGVSb2xlSWQgPSAob3B0aW9ucy5tdXRhYmxlICE9PSBmYWxzZSAmJiBlcXVhbE9yQW55V