1 | ;
|
2 | var _a;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | exports.Role = void 0;
|
5 | const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
|
6 | const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
7 | const core_1 = require("@aws-cdk/core");
|
8 | const constructs_1 = require("constructs");
|
9 | const grant_1 = require("./grant");
|
10 | const iam_generated_1 = require("./iam.generated");
|
11 | const policy_1 = require("./policy");
|
12 | const policy_document_1 = require("./policy-document");
|
13 | const principals_1 = require("./principals");
|
14 | const assume_role_policy_1 = require("./private/assume-role-policy");
|
15 | const immutable_role_1 = require("./private/immutable-role");
|
16 | const policydoc_adapter_1 = require("./private/policydoc-adapter");
|
17 | const util_1 = require("./util");
|
18 | /**
|
19 | * IAM Role
|
20 | *
|
21 | * Defines an IAM role. The role is created with an assume policy document associated with
|
22 | * the specified AWS service principal defined in `serviceAssumeRole`.
|
23 | */
|
24 | class Role extends core_1.Resource {
|
25 | constructor(scope, id, props) {
|
26 | var _b;
|
27 | super(scope, id, {
|
28 | physicalName: props.roleName,
|
29 | });
|
30 | this.grantPrincipal = this;
|
31 | this.principalAccount = this.env.account;
|
32 | this.assumeRoleAction = 'sts:AssumeRole';
|
33 | this.managedPolicies = [];
|
34 | this.attachedPolicies = new util_1.AttachedPolicies();
|
35 | try {
|
36 | jsiiDeprecationWarnings._aws_cdk_aws_iam_RoleProps(props);
|
37 | }
|
38 | catch (error) {
|
39 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
40 | Error.captureStackTrace(error, this.constructor);
|
41 | }
|
42 | throw error;
|
43 | }
|
44 | const externalIds = props.externalIds || [];
|
45 | if (props.externalId) {
|
46 | externalIds.push(props.externalId);
|
47 | }
|
48 | this.assumeRolePolicy = createAssumeRolePolicy(props.assumedBy, externalIds);
|
49 | this.managedPolicies.push(...props.managedPolicies || []);
|
50 | this.inlinePolicies = props.inlinePolicies || {};
|
51 | this.permissionsBoundary = props.permissionsBoundary;
|
52 | const maxSessionDuration = props.maxSessionDuration && props.maxSessionDuration.toSeconds();
|
53 | validateMaxSessionDuration(maxSessionDuration);
|
54 | const description = (props.description && ((_b = props.description) === null || _b === void 0 ? void 0 : _b.length) > 0) ? props.description : undefined;
|
55 | if (description && description.length > 1000) {
|
56 | throw new Error('Role description must be no longer than 1000 characters.');
|
57 | }
|
58 | const role = new iam_generated_1.CfnRole(this, 'Resource', {
|
59 | assumeRolePolicyDocument: this.assumeRolePolicy,
|
60 | managedPolicyArns: util_1.UniqueStringSet.from(() => this.managedPolicies.map(p => p.managedPolicyArn)),
|
61 | policies: _flatten(this.inlinePolicies),
|
62 | path: props.path,
|
63 | permissionsBoundary: this.permissionsBoundary ? this.permissionsBoundary.managedPolicyArn : undefined,
|
64 | roleName: this.physicalName,
|
65 | maxSessionDuration,
|
66 | description,
|
67 | });
|
68 | this.roleId = role.attrRoleId;
|
69 | this.roleArn = this.getResourceArnAttribute(role.attrArn, {
|
70 | region: '',
|
71 | service: 'iam',
|
72 | resource: 'role',
|
73 | // Removes leading slash from path
|
74 | resourceName: `${props.path ? props.path.substr(props.path.charAt(0) === '/' ? 1 : 0) : ''}${this.physicalName}`,
|
75 | });
|
76 | this.roleName = this.getResourceNameAttribute(role.ref);
|
77 | this.policyFragment = new principals_1.ArnPrincipal(this.roleArn).policyFragment;
|
78 | function _flatten(policies) {
|
79 | if (policies == null || Object.keys(policies).length === 0) {
|
80 | return undefined;
|
81 | }
|
82 | const result = new Array();
|
83 | for (const policyName of Object.keys(policies)) {
|
84 | const policyDocument = policies[policyName];
|
85 | result.push({ policyName, policyDocument });
|
86 | }
|
87 | return result;
|
88 | }
|
89 | }
|
90 | /**
|
91 | * Import an external role by ARN.
|
92 | *
|
93 | * If the imported Role ARN is a Token (such as a
|
94 | * `CfnParameter.valueAsString` or a `Fn.importValue()`) *and* the referenced
|
95 | * role has a `path` (like `arn:...:role/AdminRoles/Alice`), the
|
96 | * `roleName` property will not resolve to the correct value. Instead it
|
97 | * will resolve to the first path component. We unfortunately cannot express
|
98 | * the correct calculation of the full path name as a CloudFormation
|
99 | * expression. In this scenario the Role ARN should be supplied without the
|
100 | * `path` in order to resolve the correct role resource.
|
101 | *
|
102 | * @param scope construct scope
|
103 | * @param id construct id
|
104 | * @param roleArn the ARN of the role to import
|
105 | * @param options allow customizing the behavior of the returned role
|
106 | */
|
107 | static fromRoleArn(scope, id, roleArn, options = {}) {
|
108 | var _b;
|
109 | try {
|
110 | jsiiDeprecationWarnings._aws_cdk_aws_iam_FromRoleArnOptions(options);
|
111 | }
|
112 | catch (error) {
|
113 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
114 | Error.captureStackTrace(error, this.fromRoleArn);
|
115 | }
|
116 | throw error;
|
117 | }
|
118 | const scopeStack = core_1.Stack.of(scope);
|
119 | const parsedArn = scopeStack.splitArn(roleArn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
|
120 | const resourceName = parsedArn.resourceName;
|
121 | const roleAccount = parsedArn.account;
|
122 | // service roles have an ARN like 'arn:aws:iam::<account>:role/service-role/<roleName>'
|
123 | // or 'arn:aws:iam::<account>:role/service-role/servicename.amazonaws.com/service-role/<roleName>'
|
124 | // we want to support these as well, so we just use the element after the last slash as role name
|
125 | const roleName = resourceName.split('/').pop();
|
126 | class Import extends core_1.Resource {
|
127 | constructor(_scope, _id) {
|
128 | super(_scope, _id, {
|
129 | account: roleAccount,
|
130 | });
|
131 | this.grantPrincipal = this;
|
132 | this.principalAccount = roleAccount;
|
133 | this.assumeRoleAction = 'sts:AssumeRole';
|
134 | this.policyFragment = new principals_1.ArnPrincipal(roleArn).policyFragment;
|
135 | this.roleArn = roleArn;
|
136 | this.roleName = roleName;
|
137 | this.attachedPolicies = new util_1.AttachedPolicies();
|
138 | }
|
139 | addToPolicy(statement) {
|
140 | return this.addToPrincipalPolicy(statement).statementAdded;
|
141 | }
|
142 | addToPrincipalPolicy(statement) {
|
143 | if (!this.defaultPolicy) {
|
144 | this.defaultPolicy = new policy_1.Policy(this, 'Policy');
|
145 | this.attachInlinePolicy(this.defaultPolicy);
|
146 | }
|
147 | this.defaultPolicy.addStatements(statement);
|
148 | return { statementAdded: true, policyDependable: this.defaultPolicy };
|
149 | }
|
150 | attachInlinePolicy(policy) {
|
151 | const thisAndPolicyAccountComparison = core_1.Token.compareStrings(this.env.account, policy.env.account);
|
152 | const equalOrAnyUnresolved = thisAndPolicyAccountComparison === core_1.TokenComparison.SAME ||
|
153 | thisAndPolicyAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
|
154 | thisAndPolicyAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
|
155 | if (equalOrAnyUnresolved) {
|
156 | this.attachedPolicies.attach(policy);
|
157 | policy.attachToRole(this);
|
158 | }
|
159 | }
|
160 | addManagedPolicy(_policy) {
|
161 | // FIXME: Add warning that we're ignoring this
|
162 | }
|
163 | /**
|
164 | * Grant permissions to the given principal to pass this role.
|
165 | */
|
166 | grantPassRole(identity) {
|
167 | return this.grant(identity, 'iam:PassRole');
|
168 | }
|
169 | /**
|
170 | * Grant the actions defined in actions to the identity Principal on this resource.
|
171 | */
|
172 | grant(grantee, ...actions) {
|
173 | return grant_1.Grant.addToPrincipal({
|
174 | grantee,
|
175 | actions,
|
176 | resourceArns: [this.roleArn],
|
177 | scope: this,
|
178 | });
|
179 | }
|
180 | }
|
181 | if (options.addGrantsToResources !== undefined && options.mutable !== false) {
|
182 | throw new Error('\'addGrantsToResources\' can only be passed if \'mutable: false\'');
|
183 | }
|
184 | const importedRole = new Import(scope, id);
|
185 | const roleArnAndScopeStackAccountComparison = core_1.Token.compareStrings(importedRole.env.account, scopeStack.account);
|
186 | const equalOrAnyUnresolved = roleArnAndScopeStackAccountComparison === core_1.TokenComparison.SAME ||
|
187 | roleArnAndScopeStackAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
|
188 | roleArnAndScopeStackAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
|
189 | // we only return an immutable Role if both accounts were explicitly provided, and different
|
190 | return options.mutable !== false && equalOrAnyUnresolved
|
191 | ? importedRole
|
192 | : new immutable_role_1.ImmutableRole(scope, `ImmutableRole${id}`, importedRole, (_b = options.addGrantsToResources) !== null && _b !== void 0 ? _b : false);
|
193 | }
|
194 | /**
|
195 | * Import an external role by name.
|
196 | *
|
197 | * The imported role is assumed to exist in the same account as the account
|
198 | * the scope's containing Stack is being deployed to.
|
199 | */
|
200 | static fromRoleName(scope, id, roleName) {
|
201 | return Role.fromRoleArn(scope, id, core_1.Stack.of(scope).formatArn({
|
202 | region: '',
|
203 | service: 'iam',
|
204 | resource: 'role',
|
205 | resourceName: roleName,
|
206 | }));
|
207 | }
|
208 | /**
|
209 | * Adds a permission to the role's default policy document.
|
210 | * If there is no default policy attached to this role, it will be created.
|
211 | * @param statement The permission statement to add to the policy document
|
212 | */
|
213 | addToPrincipalPolicy(statement) {
|
214 | try {
|
215 | jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
|
216 | }
|
217 | catch (error) {
|
218 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
219 | Error.captureStackTrace(error, this.addToPrincipalPolicy);
|
220 | }
|
221 | throw error;
|
222 | }
|
223 | if (!this.defaultPolicy) {
|
224 | this.defaultPolicy = new policy_1.Policy(this, 'DefaultPolicy');
|
225 | this.attachInlinePolicy(this.defaultPolicy);
|
226 | }
|
227 | this.defaultPolicy.addStatements(statement);
|
228 | return { statementAdded: true, policyDependable: this.defaultPolicy };
|
229 | }
|
230 | addToPolicy(statement) {
|
231 | try {
|
232 | jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
|
233 | }
|
234 | catch (error) {
|
235 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
236 | Error.captureStackTrace(error, this.addToPolicy);
|
237 | }
|
238 | throw error;
|
239 | }
|
240 | return this.addToPrincipalPolicy(statement).statementAdded;
|
241 | }
|
242 | /**
|
243 | * Attaches a managed policy to this role.
|
244 | * @param policy The the managed policy to attach.
|
245 | */
|
246 | addManagedPolicy(policy) {
|
247 | try {
|
248 | jsiiDeprecationWarnings._aws_cdk_aws_iam_IManagedPolicy(policy);
|
249 | }
|
250 | catch (error) {
|
251 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
252 | Error.captureStackTrace(error, this.addManagedPolicy);
|
253 | }
|
254 | throw error;
|
255 | }
|
256 | if (this.managedPolicies.find(mp => mp === policy)) {
|
257 | return;
|
258 | }
|
259 | this.managedPolicies.push(policy);
|
260 | }
|
261 | /**
|
262 | * Attaches a policy to this role.
|
263 | * @param policy The policy to attach
|
264 | */
|
265 | attachInlinePolicy(policy) {
|
266 | try {
|
267 | jsiiDeprecationWarnings._aws_cdk_aws_iam_Policy(policy);
|
268 | }
|
269 | catch (error) {
|
270 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
271 | Error.captureStackTrace(error, this.attachInlinePolicy);
|
272 | }
|
273 | throw error;
|
274 | }
|
275 | this.attachedPolicies.attach(policy);
|
276 | policy.attachToRole(this);
|
277 | }
|
278 | /**
|
279 | * Grant the actions defined in actions to the identity Principal on this resource.
|
280 | */
|
281 | grant(grantee, ...actions) {
|
282 | try {
|
283 | jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(grantee);
|
284 | }
|
285 | catch (error) {
|
286 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
287 | Error.captureStackTrace(error, this.grant);
|
288 | }
|
289 | throw error;
|
290 | }
|
291 | return grant_1.Grant.addToPrincipal({
|
292 | grantee,
|
293 | actions,
|
294 | resourceArns: [this.roleArn],
|
295 | scope: this,
|
296 | });
|
297 | }
|
298 | /**
|
299 | * Grant permissions to the given principal to pass this role.
|
300 | */
|
301 | grantPassRole(identity) {
|
302 | try {
|
303 | jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(identity);
|
304 | }
|
305 | catch (error) {
|
306 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
307 | Error.captureStackTrace(error, this.grantPassRole);
|
308 | }
|
309 | throw error;
|
310 | }
|
311 | return this.grant(identity, 'iam:PassRole');
|
312 | }
|
313 | /**
|
314 | * Return a copy of this Role object whose Policies will not be updated
|
315 | *
|
316 | * Use the object returned by this method if you want this Role to be used by
|
317 | * a construct without it automatically updating the Role's Policies.
|
318 | *
|
319 | * If you do, you are responsible for adding the correct statements to the
|
320 | * Role's policies yourself.
|
321 | */
|
322 | withoutPolicyUpdates(options = {}) {
|
323 | var _b;
|
324 | try {
|
325 | jsiiDeprecationWarnings._aws_cdk_aws_iam_WithoutPolicyUpdatesOptions(options);
|
326 | }
|
327 | catch (error) {
|
328 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
329 | Error.captureStackTrace(error, this.withoutPolicyUpdates);
|
330 | }
|
331 | throw error;
|
332 | }
|
333 | if (!this.immutableRole) {
|
334 | this.immutableRole = new immutable_role_1.ImmutableRole(constructs_1.Node.of(this).scope, `ImmutableRole${this.node.id}`, this, (_b = options.addGrantsToResources) !== null && _b !== void 0 ? _b : false);
|
335 | }
|
336 | return this.immutableRole;
|
337 | }
|
338 | validate() {
|
339 | var _b;
|
340 | const errors = super.validate();
|
341 | errors.push(...((_b = this.assumeRolePolicy) === null || _b === void 0 ? void 0 : _b.validateForResourcePolicy()) || []);
|
342 | for (const policy of Object.values(this.inlinePolicies)) {
|
343 | errors.push(...policy.validateForIdentityPolicy());
|
344 | }
|
345 | return errors;
|
346 | }
|
347 | }
|
348 | exports.Role = Role;
|
349 | _a = JSII_RTTI_SYMBOL_1;
|
350 | Role[_a] = { fqn: "@aws-cdk/aws-iam.Role", version: "1.156.1" };
|
351 | function createAssumeRolePolicy(principal, externalIds) {
|
352 | const actualDoc = new policy_document_1.PolicyDocument();
|
353 | // If requested, add externalIds to every statement added to this doc
|
354 | const addDoc = externalIds.length === 0
|
355 | ? actualDoc
|
356 | : new policydoc_adapter_1.MutatingPolicyDocumentAdapter(actualDoc, (statement) => {
|
357 | statement.addCondition('StringEquals', {
|
358 | 'sts:ExternalId': externalIds.length === 1 ? externalIds[0] : externalIds,
|
359 | });
|
360 | return statement;
|
361 | });
|
362 | assume_role_policy_1.defaultAddPrincipalToAssumeRole(principal, addDoc);
|
363 | return actualDoc;
|
364 | }
|
365 | function validateMaxSessionDuration(duration) {
|
366 | if (duration === undefined) {
|
367 | return;
|
368 | }
|
369 | if (duration < 3600 || duration > 43200) {
|
370 | throw new Error(`maxSessionDuration is set to ${duration}, but must be >= 3600sec (1hr) and <= 43200sec (12hrs)`);
|
371 | }
|
372 | }
|
373 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9sZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJvbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsd0NBQTZGO0FBQzdGLDJDQUE2QztBQUM3QyxtQ0FBZ0M7QUFDaEMsbURBQTBDO0FBRzFDLHFDQUFrQztBQUNsQyx1REFBbUQ7QUFFbkQsNkNBQTZHO0FBQzdHLHFFQUErRTtBQUMvRSw2REFBeUQ7QUFDekQsbUVBQTRFO0FBQzVFLGlDQUEyRDtBQXNKM0Q7Ozs7O0dBS0c7QUFDSCxNQUFhLElBQUssU0FBUSxlQUFRO0lBc0toQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQWdCOztRQUN4RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLFlBQVksRUFBRSxLQUFLLENBQUMsUUFBUTtTQUM3QixDQUFDLENBQUM7UUEvQ1csbUJBQWMsR0FBZSxJQUFJLENBQUM7UUFDbEMscUJBQWdCLEdBQXVCLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO1FBRXhELHFCQUFnQixHQUFXLGdCQUFnQixDQUFDO1FBb0MzQyxvQkFBZSxHQUFxQixFQUFFLENBQUM7UUFDdkMscUJBQWdCLEdBQUcsSUFBSSx1QkFBZ0IsRUFBRSxDQUFDOzs7Ozs7Ozs7O1FBU3pELE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO1FBQzVDLElBQUksS0FBSyxDQUFDLFVBQVUsRUFBRTtZQUNwQixXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztTQUNwQztRQUVELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQzdFLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDLGVBQWUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsY0FBYyxHQUFH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QWMsQ0FBQyxFQUFFO1lBQ3ZELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxDQUFDO1NBQ3BEO1FBQ0QsT0FBTyxNQUFNLENBQUM7S0FDZjs7QUE5U0gsb0JBK1NDOzs7QUErQkQsU0FBUyxzQkFBc0IsQ0FBQyxTQUFxQixFQUFFLFdBQXFCO0lBQzFFLE1BQU0sU0FBUyxHQUFHLElBQUksZ0NBQWMsRUFBRSxDQUFDO0lBRXZDLHFFQUFxRTtJQUNyRSxNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUM7UUFDckMsQ0FBQyxDQUFDLFNBQVM7UUFDWCxDQUFDLENBQUMsSUFBSSxpREFBNkIsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxTQUFTLEVBQUUsRUFBRTtZQUMzRCxTQUFTLENBQUMsWUFBWSxDQUFDLGNBQWMsRUFBRTtnQkFDckMsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVzthQUMxRSxDQUFDLENBQUM7WUFDSCxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDLENBQUMsQ0FBQztJQUVMLG9EQUErQixDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUVuRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQsU0FBUywwQkFBMEIsQ0FBQyxRQUFpQjtJQUNuRCxJQUFJLFFBQVEsS0FBSyxTQUFTLEVBQUU7UUFDMUIsT0FBTztLQUNSO0lBRUQsSUFBSSxRQUFRLEdBQUcsSUFBSSxJQUFJLFFBQVEsR0FBRyxLQUFLLEVBQUU7UUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsUUFBUSx3REFBd0QsQ0FBQyxDQUFDO0tBQ25IO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFybkZvcm1hdCwgRHVyYXRpb24sIFJlc291cmNlLCBTdGFjaywgVG9rZW4sIFRva2VuQ29tcGFyaXNvbiB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBOb2RlIH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBHcmFudCB9IGZyb20gJy4vZ3JhbnQnO1xuaW1wb3J0IHsgQ2ZuUm9sZSB9IGZyb20gJy4vaWFtLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBJSWRlbnRpdHkgfSBmcm9tICcuL2lkZW50aXR5LWJhc2UnO1xuaW1wb3J0IHsgSU1hbmFnZWRQb2xpY3kgfSBmcm9tICcuL21hbmFnZWQtcG9saWN5JztcbmltcG9ydCB7IFBvbGljeSB9IGZyb20gJy4vcG9saWN5JztcbmltcG9ydCB7IFBvbGljeURvY3VtZW50IH0gZnJvbSAnLi9wb2xpY3ktZG9jdW1lbnQnO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50IH0gZnJvbSAnLi9wb2xpY3ktc3RhdGVtZW50JztcbmltcG9ydCB7IEFkZFRvUHJpbmNpcGFsUG9saWN5UmVzdWx0LCBBcm5QcmluY2lwYWwsIElQcmluY2lwYWwsIFByaW5jaXBhbFBvbGljeUZyYWdtZW50IH0gZnJvbSAnLi9wcmluY2lwYWxzJztcbmltcG9ydCB7IGRlZmF1bHRBZGRQcmluY2lwYWxUb0Fzc3VtZVJvbGUgfSBmcm9tICcuL3ByaXZhdGUvYXNzdW1lLXJvbGUtcG9saWN5JztcbmltcG9ydCB7IEltbXV0YWJsZVJvbGUgfSBmcm9tICcuL3ByaXZhdGUvaW1tdXRhYmxlLXJvbGUnO1xuaW1wb3J0IHsgTXV0YXRpbmdQb2xpY3lEb2N1bWVudEFkYXB0ZXIgfSBmcm9tICcuL3ByaXZhdGUvcG9saWN5ZG9jLWFkYXB0ZXInO1xuaW1wb3J0IHsgQXR0YWNoZWRQb2xpY2llcywgVW5pcXVlU3RyaW5nU2V0IH0gZnJvbSAnLi91dGlsJztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBkZWZpbmluZyBhbiBJQU0gUm9sZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJvbGVQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgSUFNIHByaW5jaXBhbCAoaS5lLiBgbmV3IFNlcnZpY2VQcmluY2lwYWwoJ3Nucy5hbWF6b25hd3MuY29tJylgKVxuICAgKiB3aGljaCBjYW4gYXNzdW1lIHRoaXMgcm9sZS5cbiAgICpcbiAgICogWW91IGNhbiBsYXRlciBtb2RpZnkgdGhlIGFzc3VtZSByb2xlIHBvbGljeSBkb2N1bWVudCBieSBhY2Nlc3NpbmcgaXQgdmlhXG4gICAqIHRoZSBgYXNzdW1lUm9sZVBvbGljeWAgcHJvcGVydHkuXG4gICAqL1xuICByZWFkb25seSBhc3N1bWVkQnk6IElQcmluY2lwYWw7XG5cbiAgLyoqXG4gICAqIElEIHRoYXQgdGhlIHJvbGUgYXNzdW1lciBuZWVkcyB0byBwcm92aWRlIHdoZW4gYXNzdW1pbmcgdGhpcyByb2xlXG4gICAqXG4gICAqIElmIHRoZSBjb25maWd1cmVkIGFuZCBwcm92aWRlZCBleHRlcm5hbCBJRHMgZG8gbm90IG1hdGNoLCB0aGVcbiAgICogQXNzdW1lUm9sZSBvcGVyYXRpb24gd2lsbCBmYWlsLlxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCBzZWUge0BsaW5rIGV4dGVybmFsSWRzfVxuICAgKlxuICAgKiBAZGVmYXVsdCBObyBleHRlcm5hbCBJRCByZXF1aXJlZFxuICAgKi9cbiAgcmVhZG9ubHkgZXh0ZXJuYWxJZD86IHN0cmluZztcblxuICAvKipcbiAgICogTGlzdCBvZiBJRHMgdGhhdCB0aGUgcm9sZSBhc3N1bWVyIG5lZWRzIHRvIHByb3ZpZGUgb25lIG9mIHdoZW4gYXNzdW1pbmcgdGhpcyByb2xlXG4gICAqXG4gICAqIElmIHRoZSBjb25maWd1cmVkIGFuZCBwcm92aWRlZCBleHRlcm5hbCBJRHMgZG8gbm90IG1hdGNoLCB0aGVcbiAgICogQXNzdW1lUm9sZSBvcGVyYXRpb24gd2lsbCBmYWlsLlxuICAgKlxuICAgKiBAZGVmYXVsdCBObyBleHRlcm5hbCBJRCByZXF1aXJlZFxuICAgKi9cbiAgcmVhZG9ubHkgZXh0ZXJuYWxJZHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIG1hbmFnZWQgcG9saWNpZXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgcm9sZS5cbiAgICpcbiAgICogWW91IGNhbiBhZGQgbWFuYWdlZCBwb2xpY2llcyBsYXRlciB1c2luZ1xuICAgKiBgYWRkTWFuYWdlZFBvbGljeShNYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZShwb2xpY3lOYW1lKSlgLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIG1hbmFnZWQgcG9saWNpZXMuXG4gICAqL1xuICByZWFkb25seSBtYW5hZ2VkUG9saWNpZXM/OiBJTWFuYWdlZFBvbGljeVtdO1xuXG4gIC8qKlxuICAgKiBBIGxpc3Qgb2YgbmFtZWQgcG9saWNpZXMgdG8gaW5saW5lIGludG8gdGhpcyByb2xlLiBUaGVzZSBwb2xpY2llcyB3aWxsIGJlXG4gICAqIGNyZWF0ZWQgd2l0aCB0aGUgcm9sZSwgd2hlcmVhcyB0aG9zZSBhZGRlZCBieSBgYGFkZFRvUG9saWN5YGAgYXJlIGFkZGVkXG4gICAqIHVzaW5nIGEgc2VwYXJhdGUgQ2xvdWRGb3JtYXRpb24gcmVzb3VyY2UgKGFsbG93aW5nIGEgd2F5IGFyb3VuZCBjaXJjdWxhclxuICAgKiBkZXBlbmRlbmNpZXMgdGhhdCBjb3VsZCBvdGhlcndpc2UgYmUgaW50cm9kdWNlZCkuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcG9saWN5IGlzIGlubGluZWQgaW4gdGhlIFJvbGUgcmVzb3VyY2UuXG4gICAqL1xuICByZWFkb25seSBpbmxpbmVQb2xpY2llcz86IHsgW25hbWU6IHN0cmluZ106IFBvbGljeURvY3VtZW50IH07XG5cbiAgLyoqXG4gICAqIFRoZSBwYXRoIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJvbGUuIEZvciBpbmZvcm1hdGlvbiBhYm91dCBJQU0gcGF0aHMsIHNlZVxuICAgKiBGcmllbmRseSBOYW1lcyBhbmQgUGF0aHMgaW4gSUFNIFVzZXIgR3VpZGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC9cbiAgICovXG4gIHJlYWRvbmx5IHBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFXUyBzdXBwb3J0cyBwZXJtaXNzaW9ucyBib3VuZGFyaWVzIGZvciBJQU0gZW50aXRpZXMgKHVzZXJzIG9yIHJvbGVzKS5cbiAgICogQSBwZXJtaXNzaW9ucyBib3VuZGFyeSBpcyBhbiBhZHZhbmNlZCBmZWF0dXJlIGZvciB1c2luZyBhIG1hbmFnZWQgcG9saWN5XG4gICAqIHRvIHNldCB0aGUgbWF4aW11bSBwZXJtaXNzaW9ucyB0aGF0IGFuIGlkZW50aXR5LWJhc2VkIHBvbGljeSBjYW4gZ3JhbnQgdG9cbiAgICogYW4gSUFNIGVudGl0eS4gQW4gZW50aXR5J3MgcGVybWlzc2lvbnMgYm91bmRhcnkgYWxsb3dzIGl0IHRvIHBlcmZvcm0gb25seVxuICAgKiB0aGUgYWN0aW9ucyB0aGF0IGFyZSBhbGxvd2VkIGJ5IGJvdGggaXRzIGlkZW50aXR5LWJhc2VkIHBvbGljaWVzIGFuZCBpdHNcbiAgICogcGVybWlzc2lvbnMgYm91bmRhcmllcy5cbiAgICpcbiAgICogQGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0Nsb3VkRm9ybWF0aW9uL2xhdGVzdC9Vc2VyR3VpZGUvYXdzLXJlc291cmNlLWlhbS1yb2xlLmh0bWwjY2ZuLWlhbS1yb2xlLXBlcm1pc3Npb25zYm91bmRhcnlcbiAgICogQGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL2FjY2Vzc19wb2xpY2llc19ib3VuZGFyaWVzLmh0bWxcbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBwZXJtaXNzaW9ucyBib3VuZGFyeS5cbiAgICovXG4gIHJlYWRvbmx5IHBlcm1pc3Npb25zQm91bmRhcnk/OiBJTWFuYWdlZFBvbGljeTtcblxuICAvKipcbiAgICogQSBuYW1lIGZvciB0aGUgSUFNIHJvbGUuIEZvciB2YWxpZCB2YWx1ZXMsIHNlZSB0aGUgUm9sZU5hbWUgcGFyYW1ldGVyIGZvclxuICAgKiB0aGUgQ3JlYXRlUm9sZSBhY3Rpb24gaW4gdGhlIElBTSBBUEkgUmVmZXJlbmNlLlxuICAgKlxuICAgKiBJTVBPUlRBTlQ6IElmIHlvdSBzcGVjaWZ5IGEgbmFtZSwgeW91IGNhbm5vdCBwZXJmb3JtIHVwZGF0ZXMgdGhhdCByZXF1aXJlXG4gICAqIHJlcGxhY2VtZW50IG9mIHRoaXMgcmVzb3VyY2UuIFlvdSBjYW4gcGVyZm9ybSB1cGRhdGVzIHRoYXQgcmVxdWlyZSBubyBvclxuICAgKiBzb21lIGludGVycnVwdGlvbi4gSWYgeW91IG11c3QgcmVwbGFjZSB0aGUgcmVzb3VyY2UsIHNwZWNpZnkgYSBuZXcgbmFtZS5cbiAgICpcbiAgICogSWYgeW91IHNwZWNpZnkgYSBuYW1lLCB5b3UgbXVzdCBzcGVjaWZ5IHRoZSBDQVBBQklMSVRZX05BTUVEX0lBTSB2YWx1ZSB0b1xuICAgKiBhY2tub3dsZWRnZSB5b3VyIHRlbXBsYXRlJ3MgY2FwYWJpbGl0aWVzLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiwgc2VlXG4gICAqIEFja25vd2xlZGdpbmcgSUFNIFJlc291cmNlcyBpbiBBV1MgQ2xvdWRGb3JtYXRpb24gVGVtcGxhdGVzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEFXUyBDbG91ZEZvcm1hdGlvbiBnZW5lcmF0ZXMgYSB1bmlxdWUgcGh5c2ljYWwgSUQgYW5kIHVzZXMgdGhhdCBJRFxuICAgKiBmb3IgdGhlIHJvbGUgbmFtZS5cbiAgICovXG4gIHJlYWRvbmx5IHJvbGVOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbWF4aW11bSBzZXNzaW9uIGR1cmF0aW9uIHRoYXQgeW91IHdhbnQgdG8gc2V0IGZvciB0aGUgc3BlY2lmaWVkIHJvbGUuXG4gICAqIFRoaXMgc2V0dGluZyBjYW4gaGF2ZSBhIHZhbHVlIGZyb20gMSBob3VyICgzNjAwc2VjKSB0byAxMiAoNDMyMDBzZWMpIGhvdXJzLlxuICAgKlxuICAgKiBBbnlvbmUgd2hvIGFzc3VtZXMgdGhlIHJvbGUgZnJvbSB0aGUgQVdTIENMSSBvciBBUEkgY2FuIHVzZSB0aGVcbiAgICogRHVyYXRpb25TZWNvbmRzIEFQSSBwYXJhbWV0ZXIgb3IgdGhlIGR1cmF0aW9uLXNlY29uZHMgQ0xJIHBhcmFtZXRlciB0b1xuICAgKiByZXF1ZXN0IGEgbG9uZ2VyIHNlc3Npb24uIFRoZSBNYXhTZXNzaW9uRHVyYXRpb24gc2V0dGluZyBkZXRlcm1pbmVzIHRoZVxuICAgKiBtYXhpbXVtIGR1cmF0aW9uIHRoYXQgY2FuIGJlIHJlcXVlc3RlZCB1c2luZyB0aGUgRHVyYXRpb25TZWNvbmRzXG4gICAqIHBhcmFtZXRlci5cbiAgICpcbiAgICogSWYgdXNlcnMgZG9uJ3Qgc3BlY2lmeSBhIHZhbHVlIGZvciB0aGUgRHVyYXRpb25TZWNvbmRzIHBhcmFtZXRlciwgdGhlaXJcbiAgICogc2VjdXJpdHkgY3JlZGVudGlhbHMgYXJlIHZhbGlkIGZvciBvbmUgaG91ciBieSBkZWZhdWx0LiBUaGlzIGFwcGxpZXMgd2hlblxuICAgKiB5b3UgdXNlIHRoZSBBc3N1bWVSb2xlKiBBUEkgb3BlcmF0aW9ucyBvciB0aGUgYXNzdW1lLXJvbGUqIENMSSBvcGVyYXRpb25zXG4gICAqIGJ1dCBkb2VzIG5vdCBhcHBseSB3aGVuIHlvdSB1c2UgdGhvc2Ugb3BlcmF0aW9ucyB0byBjcmVhdGUgYSBjb25zb2xlIFVSTC5cbiAgICpcbiAgICogQGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL2lkX3JvbGVzX3VzZS5odG1sXG4gICAqXG4gICAqIEBkZWZhdWx0IER1cmF0aW9uLmhvdXJzKDEpXG4gICAqL1xuICByZWFkb25seSBtYXhTZXNzaW9uRHVyYXRpb24/OiBEdXJhdGlvbjtcblxuICAvKipcbiAgICogQSBkZXNjcmlwdGlvbiBvZiB0aGUgcm9sZS4gSXQgY2FuIGJlIHVwIHRvIDEwMDAgY2hhcmFjdGVycyBsb25nLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGRlc2NyaXB0aW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBhbGxvd2luZyBjdXN0b21pemluZyB0aGUgYmVoYXZpb3Igb2Yge0BsaW5rIFJvbGUuZnJvbVJvbGVBcm59LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZyb21Sb2xlQXJuT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBpbXBvcnRlZCByb2xlIGNhbiBiZSBtb2RpZmllZCBieSBhdHRhY2hpbmcgcG9saWN5IHJlc291cmNlcyB0byBpdC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgbXV0YWJsZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEZvciBpbW11dGFibGUgcm9sZXM6IGFkZCBncmFudHMgdG8gcmVzb3VyY2VzIGluc3RlYWQgb2YgZHJvcHBpbmcgdGhlbVxuICAgKlxuICAgKiBJZiB0aGlzIGlzIGBmYWxzZWAgb3Igbm90IHNwZWNpZmllZCwgZ3JhbnQgcGVybWlzc2lvbnMgYWRkZWQgdG8gdGhpcyByb2xlIGFyZSBpZ25vcmVkLlxuICAgKiBJdCBpcyB5b3VyIG93biByZXNwb25zaWJpbGl0eSB0byBtYWtlIHN1cmUgdGhlIHJvbGUgaGFzIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucy5cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgdHJ1ZWAsIGFueSBncmFudCBwZXJtaXNzaW9ucyB3aWxsIGJlIGFkZGVkIHRvIHRoZSByZXNvdXJjZSBpbnN0ZWFkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgYWRkR3JhbnRzVG9SZXNvdXJjZXM/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIElBTSBSb2xlXG4gKlxuICogRGVmaW5lcyBhbiBJQU0gcm9sZS4gVGhlIHJvbGUgaXMgY3JlYXRlZCB3aXRoIGFuIGFzc3VtZSBwb2xpY3kgZG9jdW1lbnQgYXNzb2NpYXRlZCB3aXRoXG4gKiB0aGUgc3BlY2lmaWVkIEFXUyBzZXJ2aWNlIHByaW5jaXBhbCBkZWZpbmVkIGluIGBzZXJ2aWNlQXNzdW1lUm9sZWAuXG4gKi9cbmV4cG9ydCBjbGFzcyBSb2xlIGV4dGVuZHMgUmVzb3VyY2UgaW1wbGVtZW50cyBJUm9sZSB7XG4gIC8qKlxuICAgKiBJbXBvcnQgYW4gZXh0ZXJuYWwgcm9sZSBieSBBUk4uXG4gICAqXG4gICAqIElmIHRoZSBpbXBvcnRlZCBSb2xlIEFSTiBpcyBhIFRva2VuIChzdWNoIGFzIGFcbiAgICogYENmblBhcmFtZXRlci52YWx1ZUFzU3RyaW5nYCBvciBhIGBGbi5pbXBvcnRWYWx1ZSgpYCkgKmFuZCogdGhlIHJlZmVyZW5jZWRcbiAgICogcm9sZSBoYXMgYSBgcGF0aGAgKGxpa2UgYGFybjouLi46cm9sZS9BZG1pblJvbGVzL0FsaWNlYCksIHRoZVxuICAgKiBgcm9sZU5hbWVgIHByb3BlcnR5IHdpbGwgbm90IHJlc29sdmUgdG8gdGhlIGNvcnJlY3QgdmFsdWUuIEluc3RlYWQgaXRcbiAgICogd2lsbCByZXNvbHZlIHRvIHRoZSBmaXJzdCBwYXRoIGNvbXBvbmVudC4gV2UgdW5mb3J0dW5hdGVseSBjYW5ub3QgZXhwcmVzc1xuICAgKiB0aGUgY29ycmVjdCBjYWxjdWxhdGlvbiBvZiB0aGUgZnVsbCBwYXRoIG5hbWUgYXMgYSBDbG91ZEZvcm1hdGlvblxuICAgKiBleHByZXNzaW9uLiBJbiB0aGlzIHNjZW5hcmlvIHRoZSBSb2xlIEFSTiBzaG91bGQgYmUgc3VwcGxpZWQgd2l0aG91dCB0aGVcbiAgICogYHBhdGhgIGluIG9yZGVyIHRvIHJlc29sdmUgdGhlIGNvcnJlY3Qgcm9sZSByZXNvdXJjZS5cbiAgICpcbiAgICogQHBhcmFtIHNjb3BlIGNvbnN0cnVjdCBzY29wZVxuICAgKiBAcGFyYW0gaWQgY29uc3RydWN0IGlkXG4gICAqIEBwYXJhbSByb2xlQXJuIHRoZSBBUk4gb2YgdGhlIHJvbGUgdG8gaW1wb3J0XG4gICAqIEBwYXJhbSBvcHRpb25zIGFsbG93IGN1c3RvbWl6aW5nIHRoZSBiZWhhdmlvciBvZiB0aGUgcmV0dXJuZWQgcm9sZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmcm9tUm9sZUFybihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCByb2xlQXJuOiBzdHJpbmcsIG9wdGlvbnM6IEZyb21Sb2xlQXJuT3B0aW9ucyA9IHt9KTogSVJvbGUge1xuICAgIGNvbnN0IHNjb3BlU3RhY2sgPSBTdGFjay5vZihzY29wZSk7XG4gICAgY29uc3QgcGFyc2VkQXJuID0gc2NvcGVTdGFjay5zcGxpdEFybihyb2xlQXJuLCBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSk7XG4gICAgY29uc3QgcmVzb3VyY2VOYW1lID0gcGFyc2VkQXJuLnJlc291cmNlTmFtZSE7XG4gICAgY29uc3Qgcm9sZUFjY291bnQgPSBwYXJzZWRBcm4uYWNjb3VudDtcbiAgICAvLyBzZXJ2aWNlIHJvbGVzIGhhdmUgYW4gQVJOIGxpa2UgJ2Fybjphd3M6aWFtOjo8YWNjb3VudD46cm9sZS9zZXJ2aWNlLXJvbGUvPHJvbGVOYW1lPidcbiAgICAvLyBvciAnYXJuOmF3czppYW06OjxhY2NvdW50Pjpyb2xlL3NlcnZpY2Utcm9sZS9zZXJ2aWNlbmFtZS5hbWF6b25hd3MuY29tL3NlcnZpY2Utcm9sZS88cm9sZU5hbWU+J1xuICAgIC8vIHdlIHdhbnQgdG8gc3VwcG9ydCB0aGVzZSBhcyB3ZWxsLCBzbyB3ZSBqdXN0IHVzZSB0aGUgZWxlbWVudCBhZnRlciB0aGUgbGFzdCBzbGFzaCBhcyByb2xlIG5hbWVcbiAgICBjb25zdCByb2xlTmFtZSA9IHJlc291cmNlTmFtZS5zcGxpdCgnLycpLnBvcCgpITtcblxuICAgIGNsYXNzIEltcG9ydCBleHRlbmRzIFJlc291cmNlIGltcGxlbWVudHMgSVJvbGUge1xuICAgICAgcHVibGljIHJlYWRvbmx5IGdyYW50UHJpbmNpcGFsOiBJUHJpbmNpcGFsID0gdGhpcztcbiAgICAgIHB1YmxpYyByZWFkb25seSBwcmluY2lwYWxBY2NvdW50ID0gcm9sZUFjY291bnQ7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgYXNzdW1lUm9sZUFjdGlvbjogc3RyaW5nID0gJ3N0czpBc3N1bWVSb2xlJztcbiAgICAgIHB1YmxpYyByZWFkb25seSBwb2xpY3lGcmFnbWVudCA9IG5ldyBBcm5QcmluY2lwYWwocm9sZUFybikucG9saWN5RnJhZ21lbnQ7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgcm9sZUFybiA9IHJvbGVBcm47XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgcm9sZU5hbWUgPSByb2xlTmFtZTtcbiAgICAgIHByaXZhdGUgcmVhZG9ubHkgYXR0YWNoZWRQb2xpY2llcyA9IG5ldyBBdHRhY2hlZFBvbGljaWVzKCk7XG4gICAgICBwcml2YXRlIGRlZmF1bHRQb2xpY3k/OiBQb2xpY3k7XG5cbiAgICAgIGNvbnN0cnVjdG9yKF9zY29wZTogQ29uc3RydWN0LCBfaWQ6IHN0cmluZykge1xuICAgICAgICBzdXBlcihfc2NvcGUsIF9pZCwge1xuICAgICAgICAgIGFjY291bnQ6IHJvbGVBY2NvdW50LFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGFkZFRvUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudCkuc3RhdGVtZW50QWRkZWQ7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyBhZGRUb1ByaW5jaXBhbFBvbGljeShzdGF0ZW1lbnQ6IFBvbGljeVN0YXRlbWVudCk6IEFkZFRvUHJpbmNpcGFsUG9saWN5UmVzdWx0IHtcbiAgICAgICAgaWYgKCF0aGlzLmRlZmF1bHRQb2xpY3kpIHtcbiAgICAgICAgICB0aGlzLmRlZmF1bHRQb2xpY3kgPSBuZXcgUG9saWN5KHRoaXMsICdQb2xpY3knKTtcbiAgICAgICAgICB0aGlzLmF0dGFjaElubGluZVBvbGljeSh0aGlzLmRlZmF1bHRQb2xpY3kpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZGVmYXVsdFBvbGljeS5hZGRTdGF0ZW1lbnRzKHN0YXRlbWVudCk7XG4gICAgICAgIHJldHVybiB7IHN0YXRlbWVudEFkZGVkOiB0cnVlLCBwb2xpY3lEZXBlbmRhYmxlOiB0aGlzLmRlZmF1bHRQb2xpY3kgfTtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGF0dGFjaElubGluZVBvbGljeShwb2xpY3k6IFBvbGljeSk6IHZvaWQge1xuICAgICAgICBjb25zdCB0aGlzQW5kUG9saWN5QWNjb3VudENvbXBhcmlzb24gPSBUb2tlbi5jb21wYXJlU3RyaW5ncyh0aGlzLmVudi5hY2NvdW50LCBwb2xpY3kuZW52LmFjY291bnQpO1xuICAgICAgICBjb25zdCBlcXVhbE9yQW55VW5yZXNvbHZlZCA9IHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLlNBTUUgfHxcbiAgICAgICAgICB0aGlzQW5kUG9saWN5QWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5CT1RIX1VOUkVTT0xWRUQgfHxcbiAgICAgICAgICB0aGlzQW5kUG9saWN5QWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5PTkVfVU5SRVNPTFZFRDtcbiAgICAgICAgaWYgKGVxdWFsT3JBbnlVbnJlc29sdmVkKSB7XG4gICAgICAgICAgdGhpcy5hdHRhY2hlZFBvbGljaWVzLmF0dGFjaChwb2xpY3kpO1xuICAgICAgICAgIHBvbGljeS5hdHRhY2hUb1JvbGUodGhpcyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcHVibGljIGFkZE1hbmFnZWRQb2xpY3koX3BvbGljeTogSU1hbmFnZWRQb2xpY3kpOiB2b2lkIHtcbiAgICAgICAgLy8gRklYTUU6IEFkZCB3YXJuaW5nIHRoYXQgd2UncmUgaWdub3JpbmcgdGhpc1xuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIEdyYW50IHBlcm1pc3Npb25zIHRvIHRoZSBnaXZlbiBwcmluY2lwYWwgdG8gcGFzcyB0aGlzIHJvbGUuXG4gICAgICAgKi9cbiAgICAgIHB1YmxpYyBncmFudFBhc3NSb2xlKGlkZW50aXR5OiBJUHJpbmNpcGFsKTogR3JhbnQge1xuICAgICAgICByZXR1cm4gdGhpcy5ncmFudChpZGVudGl0eSwgJ2lhbTpQYXNzUm9sZScpO1xuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIEdyYW50IHRoZSBhY3Rpb25zIGRlZmluZWQgaW4gYWN0aW9ucyB0byB0aGUgaWRlbnRpdHkgUHJpbmNpcGFsIG9uIHRoaXMgcmVzb3VyY2UuXG4gICAgICAgKi9cbiAgICAgIHB1YmxpYyBncmFudChncmFudGVlOiBJUHJpbmNpcGFsLCAuLi5hY3Rpb25zOiBzdHJpbmdbXSk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIEdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgICAgICBncmFudGVlLFxuICAgICAgICAgIGFjdGlvbnMsXG4gICAgICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy5yb2xlQXJuXSxcbiAgICAgICAgICBzY29wZTogdGhpcyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuYWRkR3JhbnRzVG9SZXNvdXJjZXMgIT09IHVuZGVmaW5lZCAmJiBvcHRpb25zLm11dGFibGUgIT09IGZhbHNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1xcJ2FkZEdyYW50c1RvUmVzb3VyY2VzXFwnIGNhbiBvbmx5IGJlIHBhc3NlZCBpZiBcXCdtdXRhYmxlOiBmYWxzZVxcJycpO1xuICAgIH1cblxuICAgIGNvbnN0IGltcG9ydGVkUm9sZSA9IG5ldyBJbXBvcnQoc2NvcGUsIGlkKTtcbiAgICBjb25zdCByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID0gVG9rZW4uY29tcGFyZVN0cmluZ3MoaW1wb3J0ZWRSb2xlLmVudi5hY2NvdW50LCBzY29wZVN0YWNrLmFjY291bnQpO1xuICAgIGNvbnN0IGVxdWFsT3JBbnlVbnJlc29sdmVkID0gcm9sZUFybkFuZFNjb3BlU3RhY2tBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLlNBTUUgfHxcbiAgICAgIHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5CT1RIX1VOUkVTT0xWRUQgfHxcbiAgICAgIHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5PTkVfVU5SRVNPTFZFRDtcbiAgICAvLyB3ZSBvbmx5IHJldHVybiBhbiBpbW11dGFibGUgUm9sZSBpZiBib3RoIGFjY291bnRzIHdlcmUgZXhwbGljaXRseSBwcm92aWRlZCwgYW5kIGRpZmZlcmVudFxuICAgIHJldHVybiBvcHRpb25zLm11dGFibGUgIT09IGZhbHNlICYmIGVxdWFsT3JBbnlVbnJlc29sdmVkXG4gICAgICA/IGltcG9ydGVkUm9sZVxuICAgICAgOiBuZXcgSW1tdXRhYmxlUm9sZShzY29wZSwgYEltbXV0YWJsZVJvbGUke2lkfWAsIGltcG9ydGVkUm9sZSwgb3B0aW9ucy5hZGRHcmFudHNUb1Jlc291cmNlcyA/PyBmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IGFuIGV4dGVybmFsIHJvbGUgYnkgbmFtZS5cbiAgICpcbiAgICogVGhlIGltcG9ydGVkIHJvbGUgaXMgYXNzdW1lZCB0byBleGlzdCBpbiB0aGUgc2FtZSBhY2NvdW50IGFzIHRoZSBhY2NvdW50XG4gICAqIHRoZSBzY29wZSdzIGNvbnRhaW5pbmcgU3RhY2sgaXMgYmVpbmcgZGVwbG95ZWQgdG8uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZyb21Sb2xlTmFtZShzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCByb2xlTmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIFJvbGUuZnJvbVJvbGVBcm4oc2NvcGUsIGlkLCBTdGFjay5vZihzY29wZSkuZm9ybWF0QXJuKHtcbiAgICAgIHJlZ2lvbjogJycsXG4gICAgICBzZXJ2aWNlOiAnaWFtJyxcbiAgICAgIHJlc291cmNlOiAncm9sZScsXG4gICAgICByZXNvdXJjZU5hbWU6IHJvbGVOYW1lLFxuICAgIH0pKTtcbiAgfVxuXG4gIHB1YmxpYyByZWFkb25seSBncmFudFByaW5jaXBhbDogSVByaW5jaXBhbCA9IHRoaXM7XG4gIHB1YmxpYyByZWFkb25seSBwcmluY2lwYWxBY2NvdW50OiBzdHJpbmcgfCB1bmRlZmluZWQgPSB0aGlzLmVudi5hY2NvdW50O1xuXG4gIHB1YmxpYyByZWFkb25seSBhc3N1bWVSb2xlQWN0aW9uOiBzdHJpbmcgPSAnc3RzOkFzc3VtZVJvbGUnO1xuXG4gIC8qKlxuICAgKiBUaGUgYXNzdW1lIHJvbGUgcG9saWN5IGRvY3VtZW50IGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYXNzdW1lUm9sZVBvbGljeT86IFBvbGljeURvY3VtZW50O1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBBUk4gb2YgdGhpcyByb2xlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJvbGVBcm46IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc3RhYmxlIGFuZCB1bmlxdWUgc3RyaW5nIGlkZW50aWZ5aW5nIHRoZSByb2xlLiBGb3IgZXhhbXBsZSxcbiAgICogQUlEQUpRQUJMWlM0QTNRRFU1NzZRLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcm9sZUlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhlIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcm9sZU5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgcm9sZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwb2xpY3lGcmFnbWVudDogUHJpbmNpcGFsUG9saWN5RnJhZ21lbnQ7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHBlcm1pc3Npb25zIGJvdW5kYXJ5IGF0dGFjaGVkIHRvIHRoaXMgcm9sZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBlcm1pc3Npb25zQm91bmRhcnk/OiBJTWFuYWdlZFBvbGljeTtcblxuICBwcml2YXRlIGRlZmF1bHRQb2xpY3k/OiBQb2xpY3k7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWFuYWdlZFBvbGljaWVzOiBJTWFuYWdlZFBvbGljeVtdID0gW107XG4gIHByaXZhdGUgcmVhZG9ubHkgYXR0YWNoZWRQb2xpY2llcyA9IG5ldyBBdHRhY2hlZFBvbGljaWVzKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgaW5saW5lUG9saWNpZXM6IHsgW25hbWU6IHN0cmluZ106IFBvbGljeURvY3VtZW50IH07XG4gIHByaXZhdGUgaW1tdXRhYmxlUm9sZT86IElSb2xlO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBSb2xlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIHBoeXNpY2FsTmFtZTogcHJvcHMucm9sZU5hbWUsXG4gICAgfSk7XG5cbiAgICBjb25zdCBleHRlcm5hbElkcyA9IHByb3BzLmV4dGVybmFsSWRzIHx8IFtdO1xuICAgIGlmIChwcm9wcy5leHRlcm5hbElkKSB7XG4gICAgICBleHRlcm5hbElkcy5wdXNoKHByb3BzLmV4dGVybmFsSWQpO1xuICAgIH1cblxuICAgIHRoaXMuYXNzdW1lUm9sZVBvbGljeSA9IGNyZWF0ZUFzc3VtZVJvbGVQb2xpY3kocHJvcHMuYXNzdW1lZEJ5LCBleHRlcm5hbElkcyk7XG4gICAgdGhpcy5tYW5hZ2VkUG9saWNpZXMucHVzaCguLi5wcm9wcy5tYW5hZ2VkUG9saWNpZXMgfHwgW10pO1xuICAgIHRoaXMuaW5saW5lUG9saWNpZXMgPSBwcm9wcy5pbmxpbmVQb2xpY2llcyB8fCB7fTtcbiAgICB0aGlzLnBlcm1pc3Npb25zQm91bmRhcnkgPSBwcm9wcy5wZXJtaXNzaW9uc0JvdW5kYXJ5O1xuICAgIGNvbnN0IG1heFNlc3Npb25EdXJhdGlvbiA9IHByb3BzLm1heFNlc3Npb25EdXJhdGlvbiAmJiBwcm9wcy5tYXhTZXNzaW9uRHVyYXRpb24udG9TZWNvbmRzKCk7XG4gICAgdmFsaWRhdGVNYXhTZXNzaW9uRHVyYXRpb24obWF4U2Vzc2lvbkR1cmF0aW9uKTtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IChwcm9wcy5kZXNjcmlwdGlvbiAmJiBwcm9wcy5kZXNjcmlwdGlvbj8ubGVuZ3RoID4gMCkgPyBwcm9wcy5kZXNjcmlwdGlvbiA6IHVuZGVmaW5lZDtcblxuICAgIGlmIChkZXNjcmlwdGlvbiAmJiBkZXNjcmlwdGlvbi5sZW5ndGggPiAxMDAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JvbGUgZGVzY3JpcHRpb24gbXVzdCBiZSBubyBsb25nZXIgdGhhbiAxMDAwIGNoYXJhY3RlcnMuJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgcm9sZSA9IG5ldyBDZm5Sb2xlKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIGFzc3VtZVJvbGVQb2xpY3lEb2N1bWVudDogdGhpcy5hc3N1bWVSb2xlUG9saWN5IGFzIGFueSxcbiAgICAgIG1hbmFnZWRQb2xpY3lBcm5zOiBVbmlxdWVTdHJpbmdTZXQuZnJvbSgoKSA9PiB0aGlzLm1hbmFnZWRQb2xpY2llcy5tYXAocCA9PiBwLm1hbmFnZWRQb2xpY3lBcm4pKSxcbiAgICAgIHBvbGljaWVzOiBfZmxhdHRlbih0aGlzLmlubGluZVBvbGljaWVzKSxcbiAgICAgIHBhdGg6IHByb3BzLnBhdGgsXG4gICAgICBwZXJtaXNzaW9uc0JvdW5kYXJ5OiB0aGlzLnBlcm1pc3Npb25zQm91bmRhcnkgPyB0aGlzLnBlcm1pc3Npb25zQm91bmRhcnkubWFuYWdlZFBvbGljeUFybiA6IHVuZGVmaW5lZCxcbiAgICAgIHJvbGVOYW1lOiB0aGlzLnBoeXNpY2FsTmFtZSxcbiAgICAgIG1heFNlc3Npb25EdXJhdGlvbixcbiAgICAgIGRlc2NyaXB0aW9uLFxuICAgIH0pO1xuXG4gICAgdGhpcy5yb2xlSWQgPSByb2xlLmF0dHJSb2xlSWQ7XG4gICAgdGhpcy5yb2xlQXJuID0gdGhpcy5nZXRSZXNvdXJjZUFybkF0dHJpYnV0ZShyb2xlLmF0dHJBcm4sIHtcbiAgICAgIHJlZ2lvbjogJycsIC8vIElBTSBpcyBnbG9iYWwgaW4gZWFjaCBwYXJ0aXRpb25cbiAgICAgIHNlcnZpY2U6ICdpYW0nLFxuICAgICAgcmVzb3VyY2U6ICdyb2xlJyxcbiAgICAgIC8vIFJlbW92ZXMgbGVhZGluZyBzbGFzaCBmcm9tIHBhdGhcbiAgICAgIHJlc291cmNlTmFtZTogYCR7cHJvcHMucGF0aCA/IHByb3BzLnBhdGguc3Vic3RyKHByb3BzLnBhdGguY2hhckF0KDApID09PSAnLycgPyAxIDogMCkgOiAnJ30ke3RoaXMucGh5c2ljYWxOYW1lfWAsXG4gICAgfSk7XG4gICAgdGhpcy5yb2xlTmFtZSA9IHRoaXMuZ2V0UmVzb3VyY2VOYW1lQXR0cmlidXRlKHJvbGUucmVmKTtcbiAgICB0aGlzLnBvbGljeUZyYWdtZW50ID0gbmV3IEFyblByaW5jaXBhbCh0aGlzLnJvbGVBcm4pLnBvbGljeUZyYWdtZW50O1xuXG4gICAgZnVuY3Rpb24gX2ZsYXR0ZW4ocG9saWNpZXM/OiB7IFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudCB9KSB7XG4gICAgICBpZiAocG9saWNpZXMgPT0gbnVsbCB8fCBPYmplY3Qua2V5cyhwb2xpY2llcykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8Q2ZuUm9sZS5Qb2xpY3lQcm9wZXJ0eT4oKTtcbiAgICAgIGZvciAoY29uc3QgcG9saWN5TmFtZSBvZiBPYmplY3Qua2V5cyhwb2xpY2llcykpIHtcbiAgICAgICAgY29uc3QgcG9saWN5RG9jdW1lbnQgPSBwb2xpY2llc1twb2xpY3lOYW1lXTtcbiAgICAgICAgcmVzdWx0LnB1c2goeyBwb2xpY3lOYW1lLCBwb2xpY3lEb2N1bWVudCB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBwZXJtaXNzaW9uIHRvIHRoZSByb2xlJ3MgZGVmYXVsdCBwb2xpY3kgZG9jdW1lbnQuXG4gICAqIElmIHRoZXJlIGlzIG5vIGRlZmF1bHQgcG9saWN5IGF0dGFjaGVkIHRvIHRoaXMgcm9sZSwgaXQgd2lsbCBiZSBjcmVhdGVkLlxuICAgKiBAcGFyYW0gc3RhdGVtZW50IFRoZSBwZXJtaXNzaW9uIHN0YXRlbWVudCB0byBhZGQgdG8gdGhlIHBvbGljeSBkb2N1bWVudFxuICAgKi9cbiAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQge1xuICAgIGlmICghdGhpcy5kZWZhdWx0UG9saWN5KSB7XG4gICAgICB0aGlzLmRlZmF1bHRQb2xpY3kgPSBuZXcgUG9saWN5KHRoaXMsICdEZWZhdWx0UG9saWN5Jyk7XG4gICAgICB0aGlzLmF0dGFjaElubGluZVBvbGljeSh0aGlzLmRlZmF1bHRQb2xpY3kpO1xuICAgIH1cbiAgICB0aGlzLmRlZmF1bHRQb2xpY3kuYWRkU3RhdGVtZW50cyhzdGF0ZW1lbnQpO1xuICAgIHJldHVybiB7IHN0YXRlbWVudEFkZGVkOiB0cnVlLCBwb2xpY3lEZXBlbmRhYmxlOiB0aGlzLmRlZmF1bHRQb2xpY3kgfTtcbiAgfVxuXG4gIHB1YmxpYyBhZGRUb1BvbGljeShzdGF0ZW1lbnQ6IFBvbGljeVN0YXRlbWVudCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudCkuc3RhdGVtZW50QWRkZWQ7XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoZXMgYSBtYW5hZ2VkIHBvbGljeSB0byB0aGlzIHJvbGUuXG4gICAqIEBwYXJhbSBwb2xpY3kgVGhlIHRoZSBtYW5hZ2VkIHBvbGljeSB0byBhdHRhY2guXG4gICAqL1xuICBwdWJsaWMgYWRkTWFuYWdlZFBvbGljeShwb2xpY3k6IElNYW5hZ2VkUG9saWN5KSB7XG4gICAgaWYgKHRoaXMubWFuYWdlZFBvbGljaWVzLmZpbmQobXAgPT4gbXAgPT09IHBvbGljeSkpIHsgcmV0dXJuOyB9XG4gICAgdGhpcy5tYW5hZ2VkUG9saWNpZXMucHVzaChwb2xpY3kpO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaGVzIGEgcG9saWN5IHRvIHRoaXMgcm9sZS5cbiAgICogQHBhcmFtIHBvbGljeSBUaGUgcG9saWN5IHRvIGF0dGFjaFxuICAgKi9cbiAgcHVibGljIGF0dGFjaElubGluZVBvbGljeShwb2xpY3k6IFBvbGljeSkge1xuICAgIHRoaXMuYXR0YWNoZWRQb2xpY2llcy5hdHRhY2gocG9saWN5KTtcbiAgICBwb2xpY3kuYXR0YWNoVG9Sb2xlKHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdyYW50IHRoZSBhY3Rpb25zIGRlZmluZWQgaW4gYWN0aW9ucyB0byB0aGUgaWRlbnRpdHkgUHJpbmNpcGFsIG9uIHRoaXMgcmVzb3VyY2UuXG4gICAqL1xuICBwdWJsaWMgZ3JhbnQoZ3JhbnRlZTogSVByaW5jaXBhbCwgLi4uYWN0aW9uczogc3RyaW5nW10pIHtcbiAgICByZXR1cm4gR3JhbnQuYWRkVG9QcmluY2lwYWwoe1xuICAgICAgZ3JhbnRlZSxcbiAgICAgIGFjdGlvbnMsXG4gICAgICByZXNvdXJjZUFybnM6IFt0aGlzLnJvbGVBcm5dLFxuICAgICAgc2NvcGU6IHRoaXMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICovXG4gIHB1YmxpYyBncmFudFBhc3NSb2xlKGlkZW50aXR5OiBJUHJpbmNpcGFsKSB7XG4gICAgcmV0dXJuIHRoaXMuZ3JhbnQoaWRlbnRpdHksICdpYW06UGFzc1JvbGUnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYSBjb3B5IG9mIHRoaXMgUm9sZSBvYmplY3Qgd2hvc2UgUG9saWNpZXMgd2lsbCBub3QgYmUgdXBkYXRlZFxuICAgKlxuICAgKiBVc2UgdGhlIG9iamVjdCByZXR1cm5lZCBieSB0aGlzIG1ldGhvZCBpZiB5b3Ugd2FudCB0aGlzIFJvbGUgdG8gYmUgdXNlZCBieVxuICAgKiBhIGNvbnN0cnVjdCB3aXRob3V0IGl0IGF1dG9tYXRpY2FsbHkgdXBkYXRpbmcgdGhlIFJvbGUncyBQb2xpY2llcy5cbiAgICpcbiAgICogSWYgeW91IGRvLCB5b3UgYXJlIHJlc3BvbnNpYmxlIGZvciBhZGRpbmcgdGhlIGNvcnJlY3Qgc3RhdGVtZW50cyB0byB0aGVcbiAgICogUm9sZSdzIHBvbGljaWVzIHlvdXJzZWxmLlxuICAgKi9cbiAgcHVibGljIHdpdGhvdXRQb2xpY3lVcGRhdGVzKG9wdGlvbnM6IFdpdGhvdXRQb2xpY3lVcGRhdGVzT3B0aW9ucyA9IHt9KTogSVJvbGUge1xuICAgIGlmICghdGhpcy5pbW11dGFibGVSb2xlKSB7XG4gICAgICB0aGlzLmltbXV0YWJsZVJvbGUgPSBuZXcgSW1tdXRhYmxlUm9sZShOb2RlLm9mKHRoaXMpLnNjb3BlIGFzIENvbnN0cnVjdCwgYEltbXV0YWJsZVJvbGUke3RoaXMubm9kZS5pZH1gLCB0aGlzLCBvcHRpb25zLmFkZEdyYW50c1RvUmVzb3VyY2VzID8/IGZhbHNlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5pbW11dGFibGVSb2xlO1xuICB9XG5cbiAgcHJvdGVjdGVkIHZhbGlkYXRlKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBlcnJvcnMgPSBzdXBlci52YWxpZGF0ZSgpO1xuICAgIGVycm9ycy5wdXNoKC4uLnRoaXMuYXNzdW1lUm9sZVBvbGljeT8udmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpIHx8IFtdKTtcbiAgICBmb3IgKGNvbnN0IHBvbGljeSBvZiBPYmplY3QudmFsdWVzKHRoaXMuaW5saW5lUG9saWNpZXMpKSB7XG4gICAgICBlcnJvcnMucHVzaCguLi5wb2xpY3kudmFsaWRhdGVGb3JJZGVudGl0eVBvbGljeSgpKTtcbiAgICB9XG4gICAgcmV0dXJuIGVycm9ycztcbiAgfVxufVxuXG4vKipcbiAqIEEgUm9sZSBvYmplY3RcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJUm9sZSBleHRlbmRzIElJZGVudGl0eSB7XG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBBUk4gb2YgdGhpcyByb2xlLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSByb2xlQXJuOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhpcyByb2xlLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSByb2xlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBHcmFudCB0aGUgYWN0aW9ucyBkZWZpbmVkIGluIGFjdGlvbnMgdG8gdGhlIGlkZW50aXR5IFByaW5jaXBhbCBvbiB0aGlzIHJlc291cmNlLlxuICAgKi9cbiAgZ3JhbnQoZ3JhbnRlZTogSVByaW5jaXBhbCwgLi4uYWN0aW9uczogc3RyaW5nW10pOiBHcmFudDtcblxuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICovXG4gIGdyYW50UGFzc1JvbGUoZ3JhbnRlZTogSVByaW5jaXBhbCk6IEdyYW50O1xufVxuXG5mdW5jdGlvbiBjcmVhdGVBc3N1bWVSb2xlUG9saWN5KHByaW5jaXBhbDogSVByaW5jaXBhbCwgZXh0ZXJuYWxJZHM6IHN0cmluZ1tdKSB7XG4gIGNvbnN0IGFjdHVhbERvYyA9IG5ldyBQb2xpY3lEb2N1bWVudCgpO1xuXG4gIC8vIElmIHJlcXVlc3RlZCwgYWRkIGV4dGVybmFsSWRzIHRvIGV2ZXJ5IHN0YXRlbWVudCBhZGRlZCB0byB0aGlzIGRvY1xuICBjb25zdCBhZGREb2MgPSBleHRlcm5hbElkcy5sZW5ndGggPT09IDBcbiAgICA/IGFjdHVhbERvY1xuICAgIDogbmV3IE11dGF0aW5nUG9saWN5RG9jdW1lbnRBZGFwdGVyKGFjdHVhbERvYywgKHN0YXRlbWVudCkgPT4ge1xuICAgICAgc3RhdGVtZW50LmFkZENvbmRpdGlvbignU3RyaW5nRXF1YWxzJywge1xuICAgICAgICAnc3RzOkV4dGVybmFsSWQnOiBleHRlcm5hbElkcy5sZW5ndGggPT09IDEgPyBleHRlcm5hbElkc1swXSA6IGV4dGVybmFsSWRzLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gc3RhdGVtZW50O1xuICAgIH0pO1xuXG4gIGRlZmF1bHRBZGRQcmluY2lwYWxUb0Fzc3VtZVJvbGUocHJpbmNpcGFsLCBhZGREb2MpO1xuXG4gIHJldHVybiBhY3R1YWxEb2M7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlTWF4U2Vzc2lvbkR1cmF0aW9uKGR1cmF0aW9uPzogbnVtYmVyKSB7XG4gIGlmIChkdXJhdGlvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKGR1cmF0aW9uIDwgMzYwMCB8fCBkdXJhdGlvbiA+IDQzMjAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBtYXhTZXNzaW9uRHVyYXRpb24gaXMgc2V0IHRvICR7ZHVyYXRpb259LCBidXQgbXVzdCBiZSA+PSAzNjAwc2VjICgxaHIpIGFuZCA8PSA0MzIwMHNlYyAoMTJocnMpYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciB0aGUgYHdpdGhvdXRQb2xpY3lVcGRhdGVzKClgIG1vZGlmaWVyIG9mIGEgUm9sZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdpdGhvdXRQb2xpY3lVcGRhdGVzT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBZGQgZ3JhbnRzIHRvIHJlc291cmNlcyBpbnN0ZWFkIG9mIGRyb3BwaW5nIHRoZW1cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgZmFsc2VgIG9yIG5vdCBzcGVjaWZpZWQsIGdyYW50IHBlcm1pc3Npb25zIGFkZGVkIHRvIHRoaXMgcm9sZSBhcmUgaWdub3JlZC5cbiAgICogSXQgaXMgeW91ciBvd24gcmVzcG9uc2liaWxpdHkgdG8gbWFrZSBzdXJlIHRoZSByb2xlIGhhcyB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMuXG4gICAqXG4gICAqIElmIHRoaXMgaXMgYHRydWVgLCBhbnkgZ3JhbnQgcGVybWlzc2lvbnMgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVzb3VyY2UgaW5zdGVhZC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFkZEdyYW50c1RvUmVzb3VyY2VzPzogYm9vbGVhbjtcbn0iXX0= |
\ | No newline at end of file |