UNPKG

66.6 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.Role = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const core_1 = require("@aws-cdk/core");
8const constructs_1 = require("constructs");
9const grant_1 = require("./grant");
10const iam_generated_1 = require("./iam.generated");
11const managed_policy_1 = require("./managed-policy");
12const policy_1 = require("./policy");
13const policy_document_1 = require("./policy-document");
14const principals_1 = require("./principals");
15const assume_role_policy_1 = require("./private/assume-role-policy");
16const immutable_role_1 = require("./private/immutable-role");
17const policydoc_adapter_1 = require("./private/policydoc-adapter");
18const util_1 = require("./util");
19const MAX_INLINE_SIZE = 10000;
20const MAX_MANAGEDPOL_SIZE = 6000;
21/**
22 * IAM Role
23 *
24 * Defines an IAM role. The role is created with an assume policy document associated with
25 * the specified AWS service principal defined in `serviceAssumeRole`.
26 */
27class Role extends core_1.Resource {
28 constructor(scope, id, props) {
29 super(scope, id, {
30 physicalName: props.roleName,
31 });
32 this.grantPrincipal = this;
33 this.principalAccount = this.env.account;
34 this.assumeRoleAction = 'sts:AssumeRole';
35 this.managedPolicies = [];
36 this.attachedPolicies = new util_1.AttachedPolicies();
37 this.dependables = new Map();
38 this._didSplit = false;
39 try {
40 jsiiDeprecationWarnings._aws_cdk_aws_iam_RoleProps(props);
41 }
42 catch (error) {
43 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
44 Error.captureStackTrace(error, Role);
45 }
46 throw error;
47 }
48 const externalIds = props.externalIds || [];
49 if (props.externalId) {
50 externalIds.push(props.externalId);
51 }
52 this.assumeRolePolicy = createAssumeRolePolicy(props.assumedBy, externalIds);
53 this.managedPolicies.push(...props.managedPolicies || []);
54 this.inlinePolicies = props.inlinePolicies || {};
55 this.permissionsBoundary = props.permissionsBoundary;
56 const maxSessionDuration = props.maxSessionDuration && props.maxSessionDuration.toSeconds();
57 validateMaxSessionDuration(maxSessionDuration);
58 const description = (props.description && props.description?.length > 0) ? props.description : undefined;
59 if (description && description.length > 1000) {
60 throw new Error('Role description must be no longer than 1000 characters.');
61 }
62 validateRolePath(props.path);
63 const role = new iam_generated_1.CfnRole(this, 'Resource', {
64 assumeRolePolicyDocument: this.assumeRolePolicy,
65 managedPolicyArns: util_1.UniqueStringSet.from(() => this.managedPolicies.map(p => p.managedPolicyArn)),
66 policies: _flatten(this.inlinePolicies),
67 path: props.path,
68 permissionsBoundary: this.permissionsBoundary ? this.permissionsBoundary.managedPolicyArn : undefined,
69 roleName: this.physicalName,
70 maxSessionDuration,
71 description,
72 });
73 this.roleId = role.attrRoleId;
74 this.roleArn = this.getResourceArnAttribute(role.attrArn, {
75 region: '',
76 service: 'iam',
77 resource: 'role',
78 // Removes leading slash from path
79 resourceName: `${props.path ? props.path.substr(props.path.charAt(0) === '/' ? 1 : 0) : ''}${this.physicalName}`,
80 });
81 this.roleName = this.getResourceNameAttribute(role.ref);
82 this.policyFragment = new principals_1.ArnPrincipal(this.roleArn).policyFragment;
83 function _flatten(policies) {
84 if (policies == null || Object.keys(policies).length === 0) {
85 return undefined;
86 }
87 const result = new Array();
88 for (const policyName of Object.keys(policies)) {
89 const policyDocument = policies[policyName];
90 result.push({ policyName, policyDocument });
91 }
92 return result;
93 }
94 core_1.Aspects.of(this).add({
95 visit: (c) => {
96 if (c === this) {
97 this.splitLargePolicy();
98 }
99 },
100 });
101 }
102 /**
103 * Import an external role by ARN.
104 *
105 * If the imported Role ARN is a Token (such as a
106 * `CfnParameter.valueAsString` or a `Fn.importValue()`) *and* the referenced
107 * role has a `path` (like `arn:...:role/AdminRoles/Alice`), the
108 * `roleName` property will not resolve to the correct value. Instead it
109 * will resolve to the first path component. We unfortunately cannot express
110 * the correct calculation of the full path name as a CloudFormation
111 * expression. In this scenario the Role ARN should be supplied without the
112 * `path` in order to resolve the correct role resource.
113 *
114 * @param scope construct scope
115 * @param id construct id
116 * @param roleArn the ARN of the role to import
117 * @param options allow customizing the behavior of the returned role
118 */
119 static fromRoleArn(scope, id, roleArn, options = {}) {
120 try {
121 jsiiDeprecationWarnings._aws_cdk_aws_iam_FromRoleArnOptions(options);
122 }
123 catch (error) {
124 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
125 Error.captureStackTrace(error, this.fromRoleArn);
126 }
127 throw error;
128 }
129 const scopeStack = core_1.Stack.of(scope);
130 const parsedArn = scopeStack.splitArn(roleArn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
131 const resourceName = parsedArn.resourceName;
132 const roleAccount = parsedArn.account;
133 // service roles have an ARN like 'arn:aws:iam::<account>:role/service-role/<roleName>'
134 // or 'arn:aws:iam::<account>:role/service-role/servicename.amazonaws.com/service-role/<roleName>'
135 // we want to support these as well, so we just use the element after the last slash as role name
136 const roleName = resourceName.split('/').pop();
137 class Import extends core_1.Resource {
138 constructor(_scope, _id) {
139 super(_scope, _id, {
140 account: roleAccount,
141 });
142 this.grantPrincipal = this;
143 this.principalAccount = roleAccount;
144 this.assumeRoleAction = 'sts:AssumeRole';
145 this.policyFragment = new principals_1.ArnPrincipal(roleArn).policyFragment;
146 this.roleArn = roleArn;
147 this.roleName = roleName;
148 this.attachedPolicies = new util_1.AttachedPolicies();
149 }
150 addToPolicy(statement) {
151 return this.addToPrincipalPolicy(statement).statementAdded;
152 }
153 addToPrincipalPolicy(statement) {
154 if (!this.defaultPolicy) {
155 this.defaultPolicy = new policy_1.Policy(this, 'Policy');
156 this.attachInlinePolicy(this.defaultPolicy);
157 }
158 this.defaultPolicy.addStatements(statement);
159 return { statementAdded: true, policyDependable: this.defaultPolicy };
160 }
161 attachInlinePolicy(policy) {
162 const thisAndPolicyAccountComparison = core_1.Token.compareStrings(this.env.account, policy.env.account);
163 const equalOrAnyUnresolved = thisAndPolicyAccountComparison === core_1.TokenComparison.SAME ||
164 thisAndPolicyAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
165 thisAndPolicyAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
166 if (equalOrAnyUnresolved) {
167 this.attachedPolicies.attach(policy);
168 policy.attachToRole(this);
169 }
170 }
171 addManagedPolicy(_policy) {
172 // FIXME: Add warning that we're ignoring this
173 }
174 /**
175 * Grant permissions to the given principal to pass this role.
176 */
177 grantPassRole(identity) {
178 return this.grant(identity, 'iam:PassRole');
179 }
180 /**
181 * Grant permissions to the given principal to pass this role.
182 */
183 grantAssumeRole(identity) {
184 return this.grant(identity, 'sts:AssumeRole');
185 }
186 /**
187 * Grant the actions defined in actions to the identity Principal on this resource.
188 */
189 grant(grantee, ...actions) {
190 return grant_1.Grant.addToPrincipal({
191 grantee,
192 actions,
193 resourceArns: [this.roleArn],
194 scope: this,
195 });
196 }
197 dedupeString() {
198 return `ImportedRole:${roleArn}`;
199 }
200 }
201 if (options.addGrantsToResources !== undefined && options.mutable !== false) {
202 throw new Error('\'addGrantsToResources\' can only be passed if \'mutable: false\'');
203 }
204 const roleArnAndScopeStackAccountComparison = core_1.Token.compareStrings(roleAccount ?? '', scopeStack.account);
205 const equalOrAnyUnresolved = roleArnAndScopeStackAccountComparison === core_1.TokenComparison.SAME ||
206 roleArnAndScopeStackAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
207 roleArnAndScopeStackAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
208 // if we are returning an immutable role then the 'importedRole' is just a throwaway construct
209 // so give it a different id
210 const mutableRoleId = (options.mutable !== false && equalOrAnyUnresolved) ? id : `MutableRole${id}`;
211 const importedRole = new Import(scope, mutableRoleId);
212 // we only return an immutable Role if both accounts were explicitly provided, and different
213 return options.mutable !== false && equalOrAnyUnresolved
214 ? importedRole
215 : new immutable_role_1.ImmutableRole(scope, id, importedRole, options.addGrantsToResources ?? false);
216 }
217 /**
218 * Import an external role by name.
219 *
220 * The imported role is assumed to exist in the same account as the account
221 * the scope's containing Stack is being deployed to.
222 */
223 static fromRoleName(scope, id, roleName) {
224 return Role.fromRoleArn(scope, id, core_1.Stack.of(scope).formatArn({
225 region: '',
226 service: 'iam',
227 resource: 'role',
228 resourceName: roleName,
229 }));
230 }
231 /**
232 * Adds a permission to the role's default policy document.
233 * If there is no default policy attached to this role, it will be created.
234 * @param statement The permission statement to add to the policy document
235 */
236 addToPrincipalPolicy(statement) {
237 try {
238 jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
239 }
240 catch (error) {
241 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
242 Error.captureStackTrace(error, this.addToPrincipalPolicy);
243 }
244 throw error;
245 }
246 if (!this.defaultPolicy) {
247 this.defaultPolicy = new policy_1.Policy(this, 'DefaultPolicy');
248 this.attachInlinePolicy(this.defaultPolicy);
249 }
250 this.defaultPolicy.addStatements(statement);
251 // We might split this statement off into a different policy, so we'll need to
252 // late-bind the dependable.
253 const policyDependable = new core_1.ConcreteDependable();
254 this.dependables.set(statement, policyDependable);
255 return { statementAdded: true, policyDependable };
256 }
257 addToPolicy(statement) {
258 try {
259 jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
260 }
261 catch (error) {
262 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
263 Error.captureStackTrace(error, this.addToPolicy);
264 }
265 throw error;
266 }
267 return this.addToPrincipalPolicy(statement).statementAdded;
268 }
269 /**
270 * Attaches a managed policy to this role.
271 * @param policy The the managed policy to attach.
272 */
273 addManagedPolicy(policy) {
274 try {
275 jsiiDeprecationWarnings._aws_cdk_aws_iam_IManagedPolicy(policy);
276 }
277 catch (error) {
278 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
279 Error.captureStackTrace(error, this.addManagedPolicy);
280 }
281 throw error;
282 }
283 if (this.managedPolicies.find(mp => mp === policy)) {
284 return;
285 }
286 this.managedPolicies.push(policy);
287 }
288 /**
289 * Attaches a policy to this role.
290 * @param policy The policy to attach
291 */
292 attachInlinePolicy(policy) {
293 try {
294 jsiiDeprecationWarnings._aws_cdk_aws_iam_Policy(policy);
295 }
296 catch (error) {
297 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
298 Error.captureStackTrace(error, this.attachInlinePolicy);
299 }
300 throw error;
301 }
302 this.attachedPolicies.attach(policy);
303 policy.attachToRole(this);
304 }
305 /**
306 * Grant the actions defined in actions to the identity Principal on this resource.
307 */
308 grant(grantee, ...actions) {
309 try {
310 jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(grantee);
311 }
312 catch (error) {
313 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
314 Error.captureStackTrace(error, this.grant);
315 }
316 throw error;
317 }
318 return grant_1.Grant.addToPrincipal({
319 grantee,
320 actions,
321 resourceArns: [this.roleArn],
322 scope: this,
323 });
324 }
325 /**
326 * Grant permissions to the given principal to pass this role.
327 */
328 grantPassRole(identity) {
329 try {
330 jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(identity);
331 }
332 catch (error) {
333 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
334 Error.captureStackTrace(error, this.grantPassRole);
335 }
336 throw error;
337 }
338 return this.grant(identity, 'iam:PassRole');
339 }
340 /**
341 * Grant permissions to the given principal to assume this role.
342 */
343 grantAssumeRole(identity) {
344 try {
345 jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(identity);
346 }
347 catch (error) {
348 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
349 Error.captureStackTrace(error, this.grantAssumeRole);
350 }
351 throw error;
352 }
353 return this.grant(identity, 'sts:AssumeRole');
354 }
355 /**
356 * Return a copy of this Role object whose Policies will not be updated
357 *
358 * Use the object returned by this method if you want this Role to be used by
359 * a construct without it automatically updating the Role's Policies.
360 *
361 * If you do, you are responsible for adding the correct statements to the
362 * Role's policies yourself.
363 */
364 withoutPolicyUpdates(options = {}) {
365 try {
366 jsiiDeprecationWarnings._aws_cdk_aws_iam_WithoutPolicyUpdatesOptions(options);
367 }
368 catch (error) {
369 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
370 Error.captureStackTrace(error, this.withoutPolicyUpdates);
371 }
372 throw error;
373 }
374 if (!this.immutableRole) {
375 this.immutableRole = new immutable_role_1.ImmutableRole(constructs_1.Node.of(this).scope, `ImmutableRole${this.node.id}`, this, options.addGrantsToResources ?? false);
376 }
377 return this.immutableRole;
378 }
379 validate() {
380 const errors = super.validate();
381 errors.push(...this.assumeRolePolicy?.validateForResourcePolicy() || []);
382 for (const policy of Object.values(this.inlinePolicies)) {
383 errors.push(...policy.validateForIdentityPolicy());
384 }
385 return errors;
386 }
387 /**
388 * Split large inline policies into managed policies
389 *
390 * This gets around the 10k bytes limit on role policies.
391 */
392 splitLargePolicy() {
393 if (!this.defaultPolicy || this._didSplit) {
394 return;
395 }
396 this._didSplit = true;
397 const self = this;
398 const originalDoc = this.defaultPolicy.document;
399 const splitOffDocs = originalDoc._splitDocument(this, MAX_INLINE_SIZE, MAX_MANAGEDPOL_SIZE);
400 // Includes the "current" document
401 const mpCount = this.managedPolicies.length + (splitOffDocs.size - 1);
402 if (mpCount > 20) {
403 core_1.Annotations.of(this).addWarning(`Policy too large: ${mpCount} exceeds the maximum of 20 managed policies attached to a Role`);
404 }
405 else if (mpCount > 10) {
406 core_1.Annotations.of(this).addWarning(`Policy large: ${mpCount} exceeds 10 managed policies attached to a Role, this requires a quota increase`);
407 }
408 // Create the managed policies and fix up the dependencies
409 markDeclaringConstruct(originalDoc, this.defaultPolicy);
410 let i = 1;
411 for (const newDoc of splitOffDocs.keys()) {
412 if (newDoc === originalDoc) {
413 continue;
414 }
415 const mp = new managed_policy_1.ManagedPolicy(this, `OverflowPolicy${i++}`, {
416 description: `Part of the policies for ${this.node.path}`,
417 document: newDoc,
418 roles: [this],
419 });
420 markDeclaringConstruct(newDoc, mp);
421 }
422 /**
423 * Update the Dependables for the statements in the given PolicyDocument to point to the actual declaring construct
424 */
425 function markDeclaringConstruct(doc, declaringConstruct) {
426 for (const original of splitOffDocs.get(doc) ?? []) {
427 self.dependables.get(original)?.add(declaringConstruct);
428 }
429 }
430 }
431}
432exports.Role = Role;
433_a = JSII_RTTI_SYMBOL_1;
434Role[_a] = { fqn: "@aws-cdk/aws-iam.Role", version: "1.161.0" };
435function createAssumeRolePolicy(principal, externalIds) {
436 const actualDoc = new policy_document_1.PolicyDocument();
437 // If requested, add externalIds to every statement added to this doc
438 const addDoc = externalIds.length === 0
439 ? actualDoc
440 : new policydoc_adapter_1.MutatingPolicyDocumentAdapter(actualDoc, (statement) => {
441 statement.addCondition('StringEquals', {
442 'sts:ExternalId': externalIds.length === 1 ? externalIds[0] : externalIds,
443 });
444 return statement;
445 });
446 assume_role_policy_1.defaultAddPrincipalToAssumeRole(principal, addDoc);
447 return actualDoc;
448}
449function validateRolePath(path) {
450 if (path === undefined || core_1.Token.isUnresolved(path)) {
451 return;
452 }
453 const validRolePath = /^(\/|\/[\u0021-\u007F]+\/)$/;
454 if (path.length == 0 || path.length > 512) {
455 throw new Error(`Role path must be between 1 and 512 characters. The provided role path is ${path.length} characters.`);
456 }
457 else if (!validRolePath.test(path)) {
458 throw new Error('Role path must be either a slash or valid characters (alphanumerics and symbols) surrounded by slashes. '
459 + `Valid characters are unicode characters in [\\u0021-\\u007F]. However, ${path} is provided.`);
460 }
461}
462function validateMaxSessionDuration(duration) {
463 if (duration === undefined) {
464 return;
465 }
466 if (duration < 3600 || duration > 43200) {
467 throw new Error(`maxSessionDuration is set to ${duration}, but must be >= 3600sec (1hr) and <= 43200sec (12hrs)`);
468 }
469}
470//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9sZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJvbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsd0NBQW1KO0FBQ25KLDJDQUE2QztBQUM3QyxtQ0FBZ0M7QUFDaEMsbURBQTBDO0FBRTFDLHFEQUFpRTtBQUNqRSxxQ0FBa0M7QUFDbEMsdURBQW1EO0FBRW5ELDZDQUFtSTtBQUNuSSxxRUFBK0U7QUFDL0UsNkRBQXlEO0FBQ3pELG1FQUE0RTtBQUM1RSxpQ0FBMkQ7QUFFM0QsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDO0FBQzlCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0FBc0pqQzs7Ozs7R0FLRztBQUNILE1BQWEsSUFBSyxTQUFRLGVBQVE7SUF3TGhDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBZ0I7UUFDeEQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixZQUFZLEVBQUUsS0FBSyxDQUFDLFFBQVE7U0FDN0IsQ0FBQyxDQUFDO1FBakRXLG1CQUFjLEdBQWUsSUFBSSxDQUFDO1FBQ2xDLHFCQUFnQixHQUF1QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUV4RCxxQkFBZ0IsR0FBVyxnQkFBZ0IsQ0FBQztRQW9DM0Msb0JBQWUsR0FBcUIsRUFBRSxDQUFDO1FBQ3ZDLHFCQUFnQixHQUFHLElBQUksdUJBQWdCLEVBQUUsQ0FBQztRQUUxQyxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUF1QyxDQUFDO1FBRXRFLGNBQVMsR0FBRyxLQUFLLENBQUM7Ozs7OzsrQ0F0TGYsSUFBSTs7OztRQTZMYixNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztRQUM1QyxJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUU7WUFDcEIsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7U0FDcEM7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLEdB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TCxvREFBK0IsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFFbkQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQUMsSUFBYTtJQUNyQyxJQUFJLElBQUksS0FBSyxTQUFTLElBQUksWUFBSyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUNsRCxPQUFPO0tBQ1I7SUFFRCxNQUFNLGFBQWEsR0FBRyw2QkFBNkIsQ0FBQztJQUVwRCxJQUFJLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFO1FBQ3pDLE1BQU0sSUFBSSxLQUFLLENBQUMsNkVBQTZFLElBQUksQ0FBQyxNQUFNLGNBQWMsQ0FBQyxDQUFDO0tBQ3pIO1NBQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7UUFDcEMsTUFBTSxJQUFJLEtBQUssQ0FDYiwwR0FBMEc7Y0FDeEcsMEVBQTBFLElBQUksZUFBZSxDQUFDLENBQUM7S0FDcEc7QUFDSCxDQUFDO0FBRUQsU0FBUywwQkFBMEIsQ0FBQyxRQUFpQjtJQUNuRCxJQUFJLFFBQVEsS0FBSyxTQUFTLEVBQUU7UUFDMUIsT0FBTztLQUNSO0lBRUQsSUFBSSxRQUFRLEdBQUcsSUFBSSxJQUFJLFFBQVEsR0FBRyxLQUFLLEVBQUU7UUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsUUFBUSx3REFBd0QsQ0FBQyxDQUFDO0tBQ25IO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFybkZvcm1hdCwgSUNvbnN0cnVjdCwgRHVyYXRpb24sIFJlc291cmNlLCBTdGFjaywgVG9rZW4sIFRva2VuQ29tcGFyaXNvbiwgQXNwZWN0cywgQ29uY3JldGVEZXBlbmRhYmxlLCBBbm5vdGF0aW9ucyB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBOb2RlIH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBHcmFudCB9IGZyb20gJy4vZ3JhbnQnO1xuaW1wb3J0IHsgQ2ZuUm9sZSB9IGZyb20gJy4vaWFtLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBJSWRlbnRpdHkgfSBmcm9tICcuL2lkZW50aXR5LWJhc2UnO1xuaW1wb3J0IHsgSU1hbmFnZWRQb2xpY3ksIE1hbmFnZWRQb2xpY3kgfSBmcm9tICcuL21hbmFnZWQtcG9saWN5JztcbmltcG9ydCB7IFBvbGljeSB9IGZyb20gJy4vcG9saWN5JztcbmltcG9ydCB7IFBvbGljeURvY3VtZW50IH0gZnJvbSAnLi9wb2xpY3ktZG9jdW1lbnQnO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50IH0gZnJvbSAnLi9wb2xpY3ktc3RhdGVtZW50JztcbmltcG9ydCB7IEFkZFRvUHJpbmNpcGFsUG9saWN5UmVzdWx0LCBBcm5QcmluY2lwYWwsIElQcmluY2lwYWwsIFByaW5jaXBhbFBvbGljeUZyYWdtZW50LCBJQ29tcGFyYWJsZVByaW5jaXBhbCB9IGZyb20gJy4vcHJpbmNpcGFscyc7XG5pbXBvcnQgeyBkZWZhdWx0QWRkUHJpbmNpcGFsVG9Bc3N1bWVSb2xlIH0gZnJvbSAnLi9wcml2YXRlL2Fzc3VtZS1yb2xlLXBvbGljeSc7XG5pbXBvcnQgeyBJbW11dGFibGVSb2xlIH0gZnJvbSAnLi9wcml2YXRlL2ltbXV0YWJsZS1yb2xlJztcbmltcG9ydCB7IE11dGF0aW5nUG9saWN5RG9jdW1lbnRBZGFwdGVyIH0gZnJvbSAnLi9wcml2YXRlL3BvbGljeWRvYy1hZGFwdGVyJztcbmltcG9ydCB7IEF0dGFjaGVkUG9saWNpZXMsIFVuaXF1ZVN0cmluZ1NldCB9IGZyb20gJy4vdXRpbCc7XG5cbmNvbnN0IE1BWF9JTkxJTkVfU0laRSA9IDEwMDAwO1xuY29uc3QgTUFYX01BTkFHRURQT0xfU0laRSA9IDYwMDA7XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgZGVmaW5pbmcgYW4gSUFNIFJvbGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb2xlUHJvcHMge1xuICAvKipcbiAgICogVGhlIElBTSBwcmluY2lwYWwgKGkuZS4gYG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdzbnMuYW1hem9uYXdzLmNvbScpYClcbiAgICogd2hpY2ggY2FuIGFzc3VtZSB0aGlzIHJvbGUuXG4gICAqXG4gICAqIFlvdSBjYW4gbGF0ZXIgbW9kaWZ5IHRoZSBhc3N1bWUgcm9sZSBwb2xpY3kgZG9jdW1lbnQgYnkgYWNjZXNzaW5nIGl0IHZpYVxuICAgKiB0aGUgYGFzc3VtZVJvbGVQb2xpY3lgIHByb3BlcnR5LlxuICAgKi9cbiAgcmVhZG9ubHkgYXNzdW1lZEJ5OiBJUHJpbmNpcGFsO1xuXG4gIC8qKlxuICAgKiBJRCB0aGF0IHRoZSByb2xlIGFzc3VtZXIgbmVlZHMgdG8gcHJvdmlkZSB3aGVuIGFzc3VtaW5nIHRoaXMgcm9sZVxuICAgKlxuICAgKiBJZiB0aGUgY29uZmlndXJlZCBhbmQgcHJvdmlkZWQgZXh0ZXJuYWwgSURzIGRvIG5vdCBtYXRjaCwgdGhlXG4gICAqIEFzc3VtZVJvbGUgb3BlcmF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgc2VlIHtAbGluayBleHRlcm5hbElkc31cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gZXh0ZXJuYWwgSUQgcmVxdWlyZWRcbiAgICovXG4gIHJlYWRvbmx5IGV4dGVybmFsSWQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgSURzIHRoYXQgdGhlIHJvbGUgYXNzdW1lciBuZWVkcyB0byBwcm92aWRlIG9uZSBvZiB3aGVuIGFzc3VtaW5nIHRoaXMgcm9sZVxuICAgKlxuICAgKiBJZiB0aGUgY29uZmlndXJlZCBhbmQgcHJvdmlkZWQgZXh0ZXJuYWwgSURzIGRvIG5vdCBtYXRjaCwgdGhlXG4gICAqIEFzc3VtZVJvbGUgb3BlcmF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gZXh0ZXJuYWwgSUQgcmVxdWlyZWRcbiAgICovXG4gIHJlYWRvbmx5IGV4dGVybmFsSWRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBtYW5hZ2VkIHBvbGljaWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJvbGUuXG4gICAqXG4gICAqIFlvdSBjYW4gYWRkIG1hbmFnZWQgcG9saWNpZXMgbGF0ZXIgdXNpbmdcbiAgICogYGFkZE1hbmFnZWRQb2xpY3koTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUocG9saWN5TmFtZSkpYC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBtYW5hZ2VkIHBvbGljaWVzLlxuICAgKi9cbiAgcmVhZG9ubHkgbWFuYWdlZFBvbGljaWVzPzogSU1hbmFnZWRQb2xpY3lbXTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIG5hbWVkIHBvbGljaWVzIHRvIGlubGluZSBpbnRvIHRoaXMgcm9sZS4gVGhlc2UgcG9saWNpZXMgd2lsbCBiZVxuICAgKiBjcmVhdGVkIHdpdGggdGhlIHJvbGUsIHdoZXJlYXMgdGhvc2UgYWRkZWQgYnkgYGBhZGRUb1BvbGljeWBgIGFyZSBhZGRlZFxuICAgKiB1c2luZyBhIHNlcGFyYXRlIENsb3VkRm9ybWF0aW9uIHJlc291cmNlIChhbGxvd2luZyBhIHdheSBhcm91bmQgY2lyY3VsYXJcbiAgICogZGVwZW5kZW5jaWVzIHRoYXQgY291bGQgb3RoZXJ3aXNlIGJlIGludHJvZHVjZWQpLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHBvbGljeSBpcyBpbmxpbmVkIGluIHRoZSBSb2xlIHJlc291cmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgaW5saW5lUG9saWNpZXM/OiB7IFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudCB9O1xuXG4gIC8qKlxuICAgKiBUaGUgcGF0aCBhc3NvY2lhdGVkIHdpdGggdGhpcyByb2xlLiBGb3IgaW5mb3JtYXRpb24gYWJvdXQgSUFNIHBhdGhzLCBzZWVcbiAgICogRnJpZW5kbHkgTmFtZXMgYW5kIFBhdGhzIGluIElBTSBVc2VyIEd1aWRlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAvXG4gICAqL1xuICByZWFkb25seSBwYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBV1Mgc3VwcG9ydHMgcGVybWlzc2lvbnMgYm91bmRhcmllcyBmb3IgSUFNIGVudGl0aWVzICh1c2VycyBvciByb2xlcykuXG4gICAqIEEgcGVybWlzc2lvbnMgYm91bmRhcnkgaXMgYW4gYWR2YW5jZWQgZmVhdHVyZSBmb3IgdXNpbmcgYSBtYW5hZ2VkIHBvbGljeVxuICAgKiB0byBzZXQgdGhlIG1heGltdW0gcGVybWlzc2lvbnMgdGhhdCBhbiBpZGVudGl0eS1iYXNlZCBwb2xpY3kgY2FuIGdyYW50IHRvXG4gICAqIGFuIElBTSBlbnRpdHkuIEFuIGVudGl0eSdzIHBlcm1pc3Npb25zIGJvdW5kYXJ5IGFsbG93cyBpdCB0byBwZXJmb3JtIG9ubHlcbiAgICogdGhlIGFjdGlvbnMgdGhhdCBhcmUgYWxsb3dlZCBieSBib3RoIGl0cyBpZGVudGl0eS1iYXNlZCBwb2xpY2llcyBhbmQgaXRzXG4gICAqIHBlcm1pc3Npb25zIGJvdW5kYXJpZXMuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2F3cy1yZXNvdXJjZS1pYW0tcm9sZS5odG1sI2Nmbi1pYW0tcm9sZS1wZXJtaXNzaW9uc2JvdW5kYXJ5XG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9hY2Nlc3NfcG9saWNpZXNfYm91bmRhcmllcy5odG1sXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcGVybWlzc2lvbnMgYm91bmRhcnkuXG4gICAqL1xuICByZWFkb25seSBwZXJtaXNzaW9uc0JvdW5kYXJ5PzogSU1hbmFnZWRQb2xpY3k7XG5cbiAgLyoqXG4gICAqIEEgbmFtZSBmb3IgdGhlIElBTSByb2xlLiBGb3IgdmFsaWQgdmFsdWVzLCBzZWUgdGhlIFJvbGVOYW1lIHBhcmFtZXRlciBmb3JcbiAgICogdGhlIENyZWF0ZVJvbGUgYWN0aW9uIGluIHRoZSBJQU0gQVBJIFJlZmVyZW5jZS5cbiAgICpcbiAgICogSU1QT1JUQU5UOiBJZiB5b3Ugc3BlY2lmeSBhIG5hbWUsIHlvdSBjYW5ub3QgcGVyZm9ybSB1cGRhdGVzIHRoYXQgcmVxdWlyZVxuICAgKiByZXBsYWNlbWVudCBvZiB0aGlzIHJlc291cmNlLiBZb3UgY2FuIHBlcmZvcm0gdXBkYXRlcyB0aGF0IHJlcXVpcmUgbm8gb3JcbiAgICogc29tZSBpbnRlcnJ1cHRpb24uIElmIHlvdSBtdXN0IHJlcGxhY2UgdGhlIHJlc291cmNlLCBzcGVjaWZ5IGEgbmV3IG5hbWUuXG4gICAqXG4gICAqIElmIHlvdSBzcGVjaWZ5IGEgbmFtZSwgeW91IG11c3Qgc3BlY2lmeSB0aGUgQ0FQQUJJTElUWV9OQU1FRF9JQU0gdmFsdWUgdG9cbiAgICogYWNrbm93bGVkZ2UgeW91ciB0ZW1wbGF0ZSdzIGNhcGFiaWxpdGllcy4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZVxuICAgKiBBY2tub3dsZWRnaW5nIElBTSBSZXNvdXJjZXMgaW4gQVdTIENsb3VkRm9ybWF0aW9uIFRlbXBsYXRlcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBV1MgQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzIGEgdW5pcXVlIHBoeXNpY2FsIElEIGFuZCB1c2VzIHRoYXQgSURcbiAgICogZm9yIHRoZSByb2xlIG5hbWUuXG4gICAqL1xuICByZWFkb25seSByb2xlTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG1heGltdW0gc2Vzc2lvbiBkdXJhdGlvbiB0aGF0IHlvdSB3YW50IHRvIHNldCBmb3IgdGhlIHNwZWNpZmllZCByb2xlLlxuICAgKiBUaGlzIHNldHRpbmcgY2FuIGhhdmUgYSB2YWx1ZSBmcm9tIDEgaG91ciAoMzYwMHNlYykgdG8gMTIgKDQzMjAwc2VjKSBob3Vycy5cbiAgICpcbiAgICogQW55b25lIHdobyBhc3N1bWVzIHRoZSByb2xlIGZyb20gdGhlIEFXUyBDTEkgb3IgQVBJIGNhbiB1c2UgdGhlXG4gICAqIER1cmF0aW9uU2Vjb25kcyBBUEkgcGFyYW1ldGVyIG9yIHRoZSBkdXJhdGlvbi1zZWNvbmRzIENMSSBwYXJhbWV0ZXIgdG9cbiAgICogcmVxdWVzdCBhIGxvbmdlciBzZXNzaW9uLiBUaGUgTWF4U2Vzc2lvbkR1cmF0aW9uIHNldHRpbmcgZGV0ZXJtaW5lcyB0aGVcbiAgICogbWF4aW11bSBkdXJhdGlvbiB0aGF0IGNhbiBiZSByZXF1ZXN0ZWQgdXNpbmcgdGhlIER1cmF0aW9uU2Vjb25kc1xuICAgKiBwYXJhbWV0ZXIuXG4gICAqXG4gICAqIElmIHVzZXJzIGRvbid0IHNwZWNpZnkgYSB2YWx1ZSBmb3IgdGhlIER1cmF0aW9uU2Vjb25kcyBwYXJhbWV0ZXIsIHRoZWlyXG4gICAqIHNlY3VyaXR5IGNyZWRlbnRpYWxzIGFyZSB2YWxpZCBmb3Igb25lIGhvdXIgYnkgZGVmYXVsdC4gVGhpcyBhcHBsaWVzIHdoZW5cbiAgICogeW91IHVzZSB0aGUgQXNzdW1lUm9sZSogQVBJIG9wZXJhdGlvbnMgb3IgdGhlIGFzc3VtZS1yb2xlKiBDTEkgb3BlcmF0aW9uc1xuICAgKiBidXQgZG9lcyBub3QgYXBwbHkgd2hlbiB5b3UgdXNlIHRob3NlIG9wZXJhdGlvbnMgdG8gY3JlYXRlIGEgY29uc29sZSBVUkwuXG4gICAqXG4gICAqIEBsaW5rIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9pZF9yb2xlc191c2UuaHRtbFxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5ob3VycygxKVxuICAgKi9cbiAgcmVhZG9ubHkgbWF4U2Vzc2lvbkR1cmF0aW9uPzogRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIEEgZGVzY3JpcHRpb24gb2YgdGhlIHJvbGUuIEl0IGNhbiBiZSB1cCB0byAxMDAwIGNoYXJhY3RlcnMgbG9uZy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBkZXNjcmlwdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgYWxsb3dpbmcgY3VzdG9taXppbmcgdGhlIGJlaGF2aW9yIG9mIHtAbGluayBSb2xlLmZyb21Sb2xlQXJufS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBGcm9tUm9sZUFybk9wdGlvbnMge1xuICAvKipcbiAgICogV2hldGhlciB0aGUgaW1wb3J0ZWQgcm9sZSBjYW4gYmUgbW9kaWZpZWQgYnkgYXR0YWNoaW5nIHBvbGljeSByZXNvdXJjZXMgdG8gaXQuXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IG11dGFibGU/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBGb3IgaW1tdXRhYmxlIHJvbGVzOiBhZGQgZ3JhbnRzIHRvIHJlc291cmNlcyBpbnN0ZWFkIG9mIGRyb3BwaW5nIHRoZW1cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgZmFsc2VgIG9yIG5vdCBzcGVjaWZpZWQsIGdyYW50IHBlcm1pc3Npb25zIGFkZGVkIHRvIHRoaXMgcm9sZSBhcmUgaWdub3JlZC5cbiAgICogSXQgaXMgeW91ciBvd24gcmVzcG9uc2liaWxpdHkgdG8gbWFrZSBzdXJlIHRoZSByb2xlIGhhcyB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMuXG4gICAqXG4gICAqIElmIHRoaXMgaXMgYHRydWVgLCBhbnkgZ3JhbnQgcGVybWlzc2lvbnMgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVzb3VyY2UgaW5zdGVhZC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFkZEdyYW50c1RvUmVzb3VyY2VzPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBJQU0gUm9sZVxuICpcbiAqIERlZmluZXMgYW4gSUFNIHJvbGUuIFRoZSByb2xlIGlzIGNyZWF0ZWQgd2l0aCBhbiBhc3N1bWUgcG9saWN5IGRvY3VtZW50IGFzc29jaWF0ZWQgd2l0aFxuICogdGhlIHNwZWNpZmllZCBBV1Mgc2VydmljZSBwcmluY2lwYWwgZGVmaW5lZCBpbiBgc2VydmljZUFzc3VtZVJvbGVgLlxuICovXG5leHBvcnQgY2xhc3MgUm9sZSBleHRlbmRzIFJlc291cmNlIGltcGxlbWVudHMgSVJvbGUge1xuICAvKipcbiAgICogSW1wb3J0IGFuIGV4dGVybmFsIHJvbGUgYnkgQVJOLlxuICAgKlxuICAgKiBJZiB0aGUgaW1wb3J0ZWQgUm9sZSBBUk4gaXMgYSBUb2tlbiAoc3VjaCBhcyBhXG4gICAqIGBDZm5QYXJhbWV0ZXIudmFsdWVBc1N0cmluZ2Agb3IgYSBgRm4uaW1wb3J0VmFsdWUoKWApICphbmQqIHRoZSByZWZlcmVuY2VkXG4gICAqIHJvbGUgaGFzIGEgYHBhdGhgIChsaWtlIGBhcm46Li4uOnJvbGUvQWRtaW5Sb2xlcy9BbGljZWApLCB0aGVcbiAgICogYHJvbGVOYW1lYCBwcm9wZXJ0eSB3aWxsIG5vdCByZXNvbHZlIHRvIHRoZSBjb3JyZWN0IHZhbHVlLiBJbnN0ZWFkIGl0XG4gICAqIHdpbGwgcmVzb2x2ZSB0byB0aGUgZmlyc3QgcGF0aCBjb21wb25lbnQuIFdlIHVuZm9ydHVuYXRlbHkgY2Fubm90IGV4cHJlc3NcbiAgICogdGhlIGNvcnJlY3QgY2FsY3VsYXRpb24gb2YgdGhlIGZ1bGwgcGF0aCBuYW1lIGFzIGEgQ2xvdWRGb3JtYXRpb25cbiAgICogZXhwcmVzc2lvbi4gSW4gdGhpcyBzY2VuYXJpbyB0aGUgUm9sZSBBUk4gc2hvdWxkIGJlIHN1cHBsaWVkIHdpdGhvdXQgdGhlXG4gICAqIGBwYXRoYCBpbiBvcmRlciB0byByZXNvbHZlIHRoZSBjb3JyZWN0IHJvbGUgcmVzb3VyY2UuXG4gICAqXG4gICAqIEBwYXJhbSBzY29wZSBjb25zdHJ1Y3Qgc2NvcGVcbiAgICogQHBhcmFtIGlkIGNvbnN0cnVjdCBpZFxuICAgKiBAcGFyYW0gcm9sZUFybiB0aGUgQVJOIG9mIHRoZSByb2xlIHRvIGltcG9ydFxuICAgKiBAcGFyYW0gb3B0aW9ucyBhbGxvdyBjdXN0b21pemluZyB0aGUgYmVoYXZpb3Igb2YgdGhlIHJldHVybmVkIHJvbGVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVJvbGVBcm4oc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcm9sZUFybjogc3RyaW5nLCBvcHRpb25zOiBGcm9tUm9sZUFybk9wdGlvbnMgPSB7fSk6IElSb2xlIHtcbiAgICBjb25zdCBzY29wZVN0YWNrID0gU3RhY2sub2Yoc2NvcGUpO1xuICAgIGNvbnN0IHBhcnNlZEFybiA9IHNjb3BlU3RhY2suc3BsaXRBcm4ocm9sZUFybiwgQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUpO1xuICAgIGNvbnN0IHJlc291cmNlTmFtZSA9IHBhcnNlZEFybi5yZXNvdXJjZU5hbWUhO1xuICAgIGNvbnN0IHJvbGVBY2NvdW50ID0gcGFyc2VkQXJuLmFjY291bnQ7XG4gICAgLy8gc2VydmljZSByb2xlcyBoYXZlIGFuIEFSTiBsaWtlICdhcm46YXdzOmlhbTo6PGFjY291bnQ+OnJvbGUvc2VydmljZS1yb2xlLzxyb2xlTmFtZT4nXG4gICAgLy8gb3IgJ2Fybjphd3M6aWFtOjo8YWNjb3VudD46cm9sZS9zZXJ2aWNlLXJvbGUvc2VydmljZW5hbWUuYW1hem9uYXdzLmNvbS9zZXJ2aWNlLXJvbGUvPHJvbGVOYW1lPidcbiAgICAvLyB3ZSB3YW50IHRvIHN1cHBvcnQgdGhlc2UgYXMgd2VsbCwgc28gd2UganVzdCB1c2UgdGhlIGVsZW1lbnQgYWZ0ZXIgdGhlIGxhc3Qgc2xhc2ggYXMgcm9sZSBuYW1lXG4gICAgY29uc3Qgcm9sZU5hbWUgPSByZXNvdXJjZU5hbWUuc3BsaXQoJy8nKS5wb3AoKSE7XG5cbiAgICBjbGFzcyBJbXBvcnQgZXh0ZW5kcyBSZXNvdXJjZSBpbXBsZW1lbnRzIElSb2xlLCBJQ29tcGFyYWJsZVByaW5jaXBhbCB7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgZ3JhbnRQcmluY2lwYWw6IElQcmluY2lwYWwgPSB0aGlzO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHByaW5jaXBhbEFjY291bnQgPSByb2xlQWNjb3VudDtcbiAgICAgIHB1YmxpYyByZWFkb25seSBhc3N1bWVSb2xlQWN0aW9uOiBzdHJpbmcgPSAnc3RzOkFzc3VtZVJvbGUnO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHBvbGljeUZyYWdtZW50ID0gbmV3IEFyblByaW5jaXBhbChyb2xlQXJuKS5wb2xpY3lGcmFnbWVudDtcbiAgICAgIHB1YmxpYyByZWFkb25seSByb2xlQXJuID0gcm9sZUFybjtcbiAgICAgIHB1YmxpYyByZWFkb25seSByb2xlTmFtZSA9IHJvbGVOYW1lO1xuICAgICAgcHJpdmF0ZSByZWFkb25seSBhdHRhY2hlZFBvbGljaWVzID0gbmV3IEF0dGFjaGVkUG9saWNpZXMoKTtcbiAgICAgIHByaXZhdGUgZGVmYXVsdFBvbGljeT86IFBvbGljeTtcblxuICAgICAgY29uc3RydWN0b3IoX3Njb3BlOiBDb25zdHJ1Y3QsIF9pZDogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKF9zY29wZSwgX2lkLCB7XG4gICAgICAgICAgYWNjb3VudDogcm9sZUFjY291bnQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYWRkVG9Qb2xpY3koc3RhdGVtZW50OiBQb2xpY3lTdGF0ZW1lbnQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkVG9QcmluY2lwYWxQb2xpY3koc3RhdGVtZW50KS5zdGF0ZW1lbnRBZGRlZDtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQge1xuICAgICAgICBpZiAoIXRoaXMuZGVmYXVsdFBvbGljeSkge1xuICAgICAgICAgIHRoaXMuZGVmYXVsdFBvbGljeSA9IG5ldyBQb2xpY3kodGhpcywgJ1BvbGljeScpO1xuICAgICAgICAgIHRoaXMuYXR0YWNoSW5saW5lUG9saWN5KHRoaXMuZGVmYXVsdFBvbGljeSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kZWZhdWx0UG9saWN5LmFkZFN0YXRlbWVudHMoc3RhdGVtZW50KTtcbiAgICAgICAgcmV0dXJuIHsgc3RhdGVtZW50QWRkZWQ6IHRydWUsIHBvbGljeURlcGVuZGFibGU6IHRoaXMuZGVmYXVsdFBvbGljeSB9O1xuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYXR0YWNoSW5saW5lUG9saWN5KHBvbGljeTogUG9saWN5KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9IFRva2VuLmNvbXBhcmVTdHJpbmdzKHRoaXMuZW52LmFjY291bnQsIHBvbGljeS5lbnYuYWNjb3VudCk7XG4gICAgICAgIGNvbnN0IGVxdWFsT3JBbnlVbnJlc29sdmVkID0gdGhpc0FuZFBvbGljeUFjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uU0FNRSB8fFxuICAgICAgICAgIHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLkJPVEhfVU5SRVNPTFZFRCB8fFxuICAgICAgICAgIHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLk9ORV9VTlJFU09MVkVEO1xuICAgICAgICBpZiAoZXF1YWxPckFueVVucmVzb2x2ZWQpIHtcbiAgICAgICAgICB0aGlzLmF0dGFjaGVkUG9saWNpZXMuYXR0YWNoKHBvbGljeSk7XG4gICAgICAgICAgcG9saWN5LmF0dGFjaFRvUm9sZSh0aGlzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBwdWJsaWMgYWRkTWFuYWdlZFBvbGljeShfcG9saWN5OiBJTWFuYWdlZFBvbGljeSk6IHZvaWQge1xuICAgICAgICAvLyBGSVhNRTogQWRkIHdhcm5pbmcgdGhhdCB3ZSdyZSBpZ25vcmluZyB0aGlzXG4gICAgICB9XG5cbiAgICAgIC8qKlxuICAgICAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICAgICAqL1xuICAgICAgcHVibGljIGdyYW50UGFzc1JvbGUoaWRlbnRpdHk6IElQcmluY2lwYWwpOiBHcmFudCB7XG4gICAgICAgIHJldHVybiB0aGlzLmdyYW50KGlkZW50aXR5LCAnaWFtOlBhc3NSb2xlJyk7XG4gICAgICB9XG5cbiAgICAgIC8qKlxuICAgICAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICAgICAqL1xuICAgICAgcHVibGljIGdyYW50QXNzdW1lUm9sZShpZGVudGl0eTogSVByaW5jaXBhbCk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ3JhbnQoaWRlbnRpdHksICdzdHM6QXNzdW1lUm9sZScpO1xuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIEdyYW50IHRoZSBhY3Rpb25zIGRlZmluZWQgaW4gYWN0aW9ucyB0byB0aGUgaWRlbnRpdHkgUHJpbmNpcGFsIG9uIHRoaXMgcmVzb3VyY2UuXG4gICAgICAgKi9cbiAgICAgIHB1YmxpYyBncmFudChncmFudGVlOiBJUHJpbmNpcGFsLCAuLi5hY3Rpb25zOiBzdHJpbmdbXSk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIEdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgICAgICBncmFudGVlLFxuICAgICAgICAgIGFjdGlvbnMsXG4gICAgICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy5yb2xlQXJuXSxcbiAgICAgICAgICBzY29wZTogdGhpcyxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyBkZWR1cGVTdHJpbmcoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIGBJbXBvcnRlZFJvbGU6JHtyb2xlQXJufWA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuYWRkR3JhbnRzVG9SZXNvdXJjZXMgIT09IHVuZGVmaW5lZCAmJiBvcHRpb25zLm11dGFibGUgIT09IGZhbHNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1xcJ2FkZEdyYW50c1RvUmVzb3VyY2VzXFwnIGNhbiBvbmx5IGJlIHBhc3NlZCBpZiBcXCdtdXRhYmxlOiBmYWxzZVxcJycpO1xuICAgIH1cblxuICAgIGNvbnN0IHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPSBUb2tlbi5jb21wYXJlU3RyaW5ncyhyb2xlQWNjb3VudCA/PyAnJywgc2NvcGVTdGFjay5hY2NvdW50KTtcbiAgICBjb25zdCBlcXVhbE9yQW55VW5yZXNvbHZlZCA9IHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5TQU1FIHx8XG4gICAgICByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uQk9USF9VTlJFU09MVkVEIHx8XG4gICAgICByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID09PSBUb2tlbkNvbXBhcmlzb24uT05FX1VOUkVTT0xWRUQ7XG5cbiAgICAvLyBpZiB3ZSBhcmUgcmV0dXJuaW5nIGFuIGltbXV0YWJsZSByb2xlIHRoZW4gdGhlICdpbXBvcnRlZFJvbGUnIGlzIGp1c3QgYSB0aHJvd2F3YXkgY29uc3RydWN0XG4gICAgLy8gc28gZ2l2ZSBpdCBhIGRpZmZlcmVudCBpZFxuICAgIGNvbnN0IG11dGFibGVSb2xlSWQgPSAob3B0aW9ucy5tdXRhYmxlICE9PSBmYWxzZSAmJiBlcXVhbE9yQW55VW5yZXNvbHZlZCkgPyBpZCA6IGBNdXRhYmxlUm9sZSR7aWR9YDtcbiAgICBjb25zdCBpbXBvcnRlZFJvbGUgPSBuZXcgSW1wb3J0KHNjb3BlLCBtdXRhYmxlUm9sZUlkKTtcblxuICAgIC8vIHdlIG9ubHkgcmV0dXJuIGFuIGltbXV0YWJsZSBSb2xlIGlmIGJvdGggYWNjb3VudHMgd2VyZSBleHBsaWNpdGx5IHByb3ZpZGVkLCBhbmQgZGlmZmVyZW50XG4gICAgcmV0dXJuIG9wdGlvbnMubXV0YWJsZSAhPT0gZmFsc2UgJiYgZXF1YWxPckFueVVucmVzb2x2ZWRcbiAgICAgID8gaW1wb3J0ZWRSb2xlXG4gICAgICA6IG5ldyBJbW11dGFibGVSb2xlKHNjb3BlLCBpZCwgaW1wb3J0ZWRSb2xlLCBvcHRpb25zLmFkZEdyYW50c1RvUmVzb3VyY2VzID8/IGZhbHNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBvcnQgYW4gZXh0ZXJuYWwgcm9sZSBieSBuYW1lLlxuICAgKlxuICAgKiBUaGUgaW1wb3J0ZWQgcm9sZSBpcyBhc3N1bWVkIHRvIGV4aXN0IGluIHRoZSBzYW1lIGFjY291bnQgYXMgdGhlIGFjY291bnRcbiAgICogdGhlIHNjb3BlJ3MgY29udGFpbmluZyBTdGFjayBpcyBiZWluZyBkZXBsb3llZCB0by5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVJvbGVOYW1lKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHJvbGVOYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gUm9sZS5mcm9tUm9sZUFybihzY29wZSwgaWQsIFN0YWNrLm9mKHNjb3BlKS5mb3JtYXRBcm4oe1xuICAgICAgcmVnaW9uOiAnJyxcbiAgICAgIHNlcnZpY2U6ICdpYW0nLFxuICAgICAgcmVzb3VyY2U6ICdyb2xlJyxcbiAgICAgIHJlc291cmNlTmFtZTogcm9sZU5hbWUsXG4gICAgfSkpO1xuICB9XG5cbiAgcHVibGljIHJlYWRvbmx5IGdyYW50UHJpbmNpcGFsOiBJUHJpbmNpcGFsID0gdGhpcztcbiAgcHVibGljIHJlYWRvbmx5IHByaW5jaXBhbEFjY291bnQ6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHRoaXMuZW52LmFjY291bnQ7XG5cbiAgcHVibGljIHJlYWRvbmx5IGFzc3VtZVJvbGVBY3Rpb246IHN0cmluZyA9ICdzdHM6QXNzdW1lUm9sZSc7XG5cbiAgLyoqXG4gICAqIFRoZSBhc3N1bWUgcm9sZSBwb2xpY3kgZG9jdW1lbnQgYXNzb2NpYXRlZCB3aXRoIHRoaXMgcm9sZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhc3N1bWVSb2xlUG9saWN5PzogUG9saWN5RG9jdW1lbnQ7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIEFSTiBvZiB0aGlzIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcm9sZUFybjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBzdGFibGUgYW5kIHVuaXF1ZSBzdHJpbmcgaWRlbnRpZnlpbmcgdGhlIHJvbGUuIEZvciBleGFtcGxlLFxuICAgKiBBSURBSlFBQkxaUzRBM1FEVTU3NlEuXG4gICAqXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSByb2xlSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbmFtZSBvZiB0aGUgcm9sZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSByb2xlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSByb2xlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBvbGljeUZyYWdtZW50OiBQcmluY2lwYWxQb2xpY3lGcmFnbWVudDtcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgcGVybWlzc2lvbnMgYm91bmRhcnkgYXR0YWNoZWQgdG8gdGhpcyByb2xlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcGVybWlzc2lvbnNCb3VuZGFyeT86IElNYW5hZ2VkUG9saWN5O1xuXG4gIHByaXZhdGUgZGVmYXVsdFBvbGljeT86IFBvbGljeTtcbiAgcHJpdmF0ZSByZWFkb25seSBtYW5hZ2VkUG9saWNpZXM6IElNYW5hZ2VkUG9saWN5W10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBhdHRhY2hlZFBvbGljaWVzID0gbmV3IEF0dGFjaGVkUG9saWNpZXMoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBpbmxpbmVQb2xpY2llczogeyBbbmFtZTogc3RyaW5nXTogUG9saWN5RG9jdW1lbnQgfTtcbiAgcHJpdmF0ZSByZWFkb25seSBkZXBlbmRhYmxlcyA9IG5ldyBNYXA8UG9saWN5U3RhdGVtZW50LCBDb25jcmV0ZURlcGVuZGFibGU+KCk7XG4gIHByaXZhdGUgaW1tdXRhYmxlUm9sZT86IElSb2xlO1xuICBwcml2YXRlIF9kaWRTcGxpdCA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBSb2xlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIHBoeXNpY2FsTmFtZTogcHJvcHMucm9sZU5hbWUsXG4gICAgfSk7XG5cbiAgICBjb25zdCBleHRlcm5hbElkcyA9IHByb3BzLmV4dGVybmFsSWRzIHx8IFtdO1xuICAgIGlmIChwcm9wcy5leHRlcm5hbElkKSB7XG4gICAgICBleHRlcm5hbElkcy5wdXNoKHByb3BzLmV4dGVybmFsSWQpO1xuICAgIH1cblxuICAgIHRoaXMuYXNzdW1lUm9sZVBvbGljeSA9IGNyZWF0ZUFzc3VtZVJvbGVQb2xpY3kocHJvcHMuYXNzdW1lZEJ5LCBleHRlcm5hbElkcyk7XG4gICAgdGhpcy5tYW5hZ2VkUG9saWNpZXMucHVzaCguLi5wcm9wcy5tYW5hZ2VkUG9saWNpZXMgfHwgW10pO1xuICAgIHRoaXMuaW5saW5lUG9saWNpZXMgPSBwcm9wcy5pbmxpbmVQb2xpY2llcyB8fCB7fTtcbiAgICB0aGlzLnBlcm1pc3Npb25zQm91bmRhcnkgPSBwcm9wcy5wZXJtaXNzaW9uc0JvdW5kYXJ5O1xuICAgIGNvbnN0IG1heFNlc3Npb25EdXJhdGlvbiA9IHByb3BzLm1heFNlc3Npb25EdXJhdGlvbiAmJiBwcm9wcy5tYXhTZXNzaW9uRHVyYXRpb24udG9TZWNvbmRzKCk7XG4gICAgdmFsaWRhdGVNYXhTZXNzaW9uRHVyYXRpb24obWF4U2Vzc2lvbkR1cmF0aW9uKTtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IChwcm9wcy5kZXNjcmlwdGlvbiAmJiBwcm9wcy5kZXNjcmlwdGlvbj8ubGVuZ3RoID4gMCkgPyBwcm9wcy5kZXNjcmlwdGlvbiA6IHVuZGVmaW5lZDtcblxuICAgIGlmIChkZXNjcmlwdGlvbiAmJiBkZXNjcmlwdGlvbi5sZW5ndGggPiAxMDAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JvbGUgZGVzY3JpcHRpb24gbXVzdCBiZSBubyBsb25nZXIgdGhhbiAxMDAwIGNoYXJhY3RlcnMuJyk7XG4gICAgfVxuXG4gICAgdmFsaWRhdGVSb2xlUGF0aChwcm9wcy5wYXRoKTtcblxuICAgIGNvbnN0IHJvbGUgPSBuZXcgQ2ZuUm9sZSh0aGlzLCAnUmVzb3VyY2UnLCB7XG4gICAgICBhc3N1bWVSb2xlUG9saWN5RG9jdW1lbnQ6IHRoaXMuYXNzdW1lUm9sZVBvbGljeSBhcyBhbnksXG4gICAgICBtYW5hZ2VkUG9saWN5QXJuczogVW5pcXVlU3RyaW5nU2V0LmZyb20oKCkgPT4gdGhpcy5tYW5hZ2VkUG9saWNpZXMubWFwKHAgPT4gcC5tYW5hZ2VkUG9saWN5QXJuKSksXG4gICAgICBwb2xpY2llczogX2ZsYXR0ZW4odGhpcy5pbmxpbmVQb2xpY2llcyksXG4gICAgICBwYXRoOiBwcm9wcy5wYXRoLFxuICAgICAgcGVybWlzc2lvbnNCb3VuZGFyeTogdGhpcy5wZXJtaXNzaW9uc0JvdW5kYXJ5ID8gdGhpcy5wZXJtaXNzaW9uc0JvdW5kYXJ5Lm1hbmFnZWRQb2xpY3lBcm4gOiB1bmRlZmluZWQsXG4gICAgICByb2xlTmFtZTogdGhpcy5waHlzaWNhbE5hbWUsXG4gICAgICBtYXhTZXNzaW9uRHVyYXRpb24sXG4gICAgICBkZXNjcmlwdGlvbixcbiAgICB9KTtcblxuICAgIHRoaXMucm9sZUlkID0gcm9sZS5hdHRyUm9sZUlkO1xuICAgIHRoaXMucm9sZUFybiA9IHRoaXMuZ2V0UmVzb3VyY2VBcm5BdHRyaWJ1dGUocm9sZS5hdHRyQXJuLCB7XG4gICAgICByZWdpb246ICcnLCAvLyBJQU0gaXMgZ2xvYmFsIGluIGVhY2ggcGFydGl0aW9uXG4gICAgICBzZXJ2aWNlOiAnaWFtJyxcbiAgICAgIHJlc291cmNlOiAncm9sZScsXG4gICAgICAvLyBSZW1vdmVzIGxlYWRpbmcgc2xhc2ggZnJvbSBwYXRoXG4gICAgICByZXNvdXJjZU5hbWU6IGAke3Byb3BzLnBhdGggPyBwcm9wcy5wYXRoLnN1YnN0cihwcm9wcy5wYXRoLmNoYXJBdCgwKSA9PT0gJy8nID8gMSA6IDApIDogJyd9JHt0aGlzLnBoeXNpY2FsTmFtZX1gLFxuICAgIH0pO1xuICAgIHRoaXMucm9sZU5hbWUgPSB0aGlzLmdldFJlc291cmNlTmFtZUF0dHJpYnV0ZShyb2xlLnJlZik7XG4gICAgdGhpcy5wb2xpY3lGcmFnbWVudCA9IG5ldyBBcm5QcmluY2lwYWwodGhpcy5yb2xlQXJuKS5wb2xpY3lGcmFnbWVudDtcblxuICAgIGZ1bmN0aW9uIF9mbGF0dGVuKHBvbGljaWVzPzogeyBbbmFtZTogc3RyaW5nXTogUG9saWN5RG9jdW1lbnQgfSkge1xuICAgICAgaWYgKHBvbGljaWVzID09IG51bGwgfHwgT2JqZWN0LmtleXMocG9saWNpZXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVzdWx0ID0gbmV3IEFycmF5PENmblJvbGUuUG9saWN5UHJvcGVydHk+KCk7XG4gICAgICBmb3IgKGNvbnN0IHBvbGljeU5hbWUgb2YgT2JqZWN0LmtleXMocG9saWNpZXMpKSB7XG4gICAgICAgIGNvbnN0IHBvbGljeURvY3VtZW50ID0gcG9saWNpZXNbcG9saWN5TmFtZV07XG4gICAgICAgIHJlc3VsdC5wdXNoKHsgcG9saWN5TmFtZSwgcG9saWN5RG9jdW1lbnQgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIEFzcGVjdHMub2YodGhpcykuYWRkKHtcbiAgICAgIHZpc2l0OiAoYykgPT4ge1xuICAgICAgICBpZiAoYyA9PT0gdGhpcykge1xuICAgICAgICAgIHRoaXMuc3BsaXRMYXJnZVBvbGljeSgpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBwZXJtaXNzaW9uIHRvIHRoZSByb2xlJ3MgZGVmYXVsdCBwb2xpY3kgZG9jdW1lbnQuXG4gICAqIElmIHRoZXJlIGlzIG5vIGRlZmF1bHQgcG9saWN5IGF0dGFjaGVkIHRvIHRoaXMgcm9sZSwgaXQgd2lsbCBiZSBjcmVhdGVkLlxuICAgKiBAcGFyYW0gc3RhdGVtZW50IFRoZSBwZXJtaXNzaW9uIHN0YXRlbWVudCB0byBhZGQgdG8gdGhlIHBvbGljeSBkb2N1bWVudFxuICAgKi9cbiAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQge1xuICAgIGlmICghdGhpcy5kZWZhdWx0UG9saWN5KSB7XG4gICAgICB0aGlzLmRlZmF1bHRQb2xpY3kgPSBuZXcgUG9saWN5KHRoaXMsICdEZWZhdWx0UG9saWN5Jyk7XG4gICAgICB0aGlzLmF0dGFjaElubGluZVBvbGljeSh0aGlzLmRlZmF1bHRQb2xpY3kpO1xuICAgIH1cbiAgICB0aGlzLmRlZmF1bHRQb2xpY3kuYWRkU3RhdGVtZW50cyhzdGF0ZW1lbnQpO1xuXG4gICAgLy8gV2UgbWlnaHQgc3BsaXQgdGhpcyBzdGF0ZW1lbnQgb2ZmIGludG8gYSBkaWZmZXJlbnQgcG9saWN5LCBzbyB3ZSdsbCBuZWVkIHRvXG4gICAgLy8gbGF0ZS1iaW5kIHRoZSBkZXBlbmRhYmxlLlxuICAgIGNvbnN0IHBvbGljeURlcGVuZGFibGUgPSBuZXcgQ29uY3JldGVEZXBlbmRhYmxlKCk7XG4gICAgdGhpcy5kZXBlbmRhYmxlcy5zZXQoc3RhdGVtZW50LCBwb2xpY3lEZXBlbmRhYmxlKTtcblxuICAgIHJldHVybiB7IHN0YXRlbWVudEFkZGVkOiB0cnVlLCBwb2xpY3lEZXBlbmRhYmxlIH07XG4gIH1cblxuICBwdWJsaWMgYWRkVG9Qb2xpY3koc3RhdGVtZW50OiBQb2xpY3lTdGF0ZW1lbnQpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5hZGRUb1ByaW5jaXBhbFBvbGljeShzdGF0ZW1lbnQpLnN0YXRlbWVudEFkZGVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaGVzIGEgbWFuYWdlZCBwb2xpY3kgdG8gdGhpcyByb2xlLlxuICAgKiBAcGFyYW0gcG9saWN5IFRoZSB0aGUgbWFuYWdlZCBwb2xpY3kgdG8gYXR0YWNoLlxuICAgKi9cbiAgcHVibGljIGFkZE1hbmFnZWRQb2xpY3kocG9saWN5OiBJTWFuYWdlZFBvbGljeSkge1xuICAgIGlmICh0aGlzLm1hbmFnZWRQb2xpY2llcy5maW5kKG1wID0+IG1wID09PSBwb2xpY3kpKSB7IHJldHVybjsgfVxuICAgIHRoaXMubWFuYWdlZFBvbGljaWVzLnB1c2gocG9saWN5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2hlcyBhIHBvbGljeSB0byB0aGlzIHJvbGUuXG4gICAqIEBwYXJhbSBwb2xpY3kgVGhlIHBvbGljeSB0byBhdHRhY2hcbiAgICovXG4gIHB1YmxpYyBhdHRhY2hJbmxpbmVQb2xpY3kocG9saWN5OiBQb2xpY3kpIHtcbiAgICB0aGlzLmF0dGFjaGVkUG9saWNpZXMuYXR0YWNoKHBvbGljeSk7XG4gICAgcG9saWN5LmF0dGFjaFRvUm9sZSh0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHcmFudCB0aGUgYWN0aW9ucyBkZWZpbmVkIGluIGFjdGlvbnMgdG8gdGhlIGlkZW50aXR5IFByaW5jaXBhbCBvbiB0aGlzIHJlc291cmNlLlxuICAgKi9cbiAgcHVibGljIGdyYW50KGdyYW50ZWU6IElQcmluY2lwYWwsIC4uLmFjdGlvbnM6IHN0cmluZ1tdKSB7XG4gICAgcmV0dXJuIEdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgIGdyYW50ZWUsXG4gICAgICBhY3Rpb25zLFxuICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy5yb2xlQXJuXSxcbiAgICAgIHNjb3BlOiB0aGlzLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdyYW50IHBlcm1pc3Npb25zIHRvIHRoZSBnaXZlbiBwcmluY2lwYWwgdG8gcGFzcyB0aGlzIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgZ3JhbnRQYXNzUm9sZShpZGVudGl0eTogSVByaW5jaXBhbCkge1xuICAgIHJldHVybiB0aGlzLmdyYW50KGlkZW50aXR5LCAnaWFtOlBhc3NSb2xlJyk7XG4gIH1cblxuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBhc3N1bWUgdGhpcyByb2xlLlxuICAgKi9cbiAgcHVibGljIGdyYW50QXNzdW1lUm9sZShpZGVudGl0eTogSVByaW5jaXBhbCkge1xuICAgIHJldHVybiB0aGlzLmdyYW50KGlkZW50aXR5LCAnc3RzOkFzc3VtZVJvbGUnKTtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGNvcHkgb2YgdGhpcyBSb2xlIG9iamVjdCB3aG9zZSBQb2xpY2llcyB3aWxsIG5vdCBiZSB1cGRhdGVkXG4gICAqXG4gICAqIFVzZSB0aGUgb2JqZWN0IHJldHVybmVkIGJ5IHRoaXMgbWV0aG9kIGlmIHlvdSB3YW50IHRoaXMgUm9sZSB0byBiZSB1c2VkIGJ5XG4gICAqIGEgY29uc3RydWN0IHdpdGhvdXQgaXQgYXV0b21hdGljYWxseSB1cGRhdGluZyB0aGUgUm9sZSdzIFBvbGljaWVzLlxuICAgKlxuICAgKiBJZiB5b3UgZG8sIHlvdSBhcmUgcmVzcG9uc2libGUgZm9yIGFkZGluZyB0aGUgY29ycmVjdCBzdGF0ZW1lbnRzIHRvIHRoZVxuICAgKiBSb2xlJ3MgcG9saWNpZXMgeW91cnNlbGYuXG4gICAqL1xuICBwdWJsaWMgd2l0aG91dFBvbGljeVVwZGF0ZXMob3B0aW9uczogV2l0aG91dFBvbGljeVVwZGF0ZXNPcHRpb25zID0ge30pOiBJUm9sZSB7XG4gICAgaWYgKCF0aGlzLmltbXV0YWJsZVJvbGUpIHtcbiAgICAgIHRoaXMuaW1tdXRhYmxlUm9sZSA9IG5ldyBJbW11dGFibGVSb2xlKE5vZGUub2YodGhpcykuc2NvcGUgYXMgQ29uc3RydWN0LCBgSW1tdXRhYmxlUm9sZSR7dGhpcy5ub2RlLmlkfWAsIHRoaXMsIG9wdGlvbnMuYWRkR3JhbnRzVG9SZXNvdXJjZXMgPz8gZmFsc2UpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmltbXV0YWJsZVJvbGU7XG4gIH1cblxuICBwcm90ZWN0ZWQgdmFsaWRhdGUoKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGVycm9ycyA9IHN1cGVyLnZhbGlkYXRlKCk7XG4gICAgZXJyb3JzLnB1c2goLi4udGhpcy5hc3N1bWVSb2xlUG9saWN5Py52YWxpZGF0ZUZvclJlc291cmNlUG9saWN5KCkgfHwgW10pO1xuICAgIGZvciAoY29uc3QgcG9saWN5IG9mIE9iamVjdC52YWx1ZXModGhpcy5pbmxpbmVQb2xpY2llcykpIHtcbiAgICAgIGVycm9ycy5wdXNoKC4uLnBvbGljeS52YWxpZGF0ZUZvcklkZW50aXR5UG9saWN5KCkpO1xuICAgIH1cblxuICAgIHJldHVybiBlcnJvcnM7XG4gIH1cblxuICAvKipcbiAgICogU3BsaXQgbGFyZ2UgaW5saW5lIHBvbGljaWVzIGludG8gbWFuYWdlZCBwb2xpY2llc1xuICAgKlxuICAgKiBUaGlzIGdldHMgYXJvdW5kIHRoZSAxMGsgYnl0ZXMgbGltaXQgb24gcm9sZSBwb2xpY2llcy5cbiAgICovXG4gIHByaXZhdGUgc3BsaXRMYXJnZVBvbGljeSgpIHtcbiAgICBpZiAoIXRoaXMuZGVmYXVsdFBvbGljeSB8fCB0aGlzLl9kaWRTcGxpdCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLl9kaWRTcGxpdCA9IHRydWU7XG5cbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICBjb25zdCBvcmlnaW5hbERvYyA9IHRoaXMuZGVmYXVsdFBvbGljeS5kb2N1bWVudDtcblxuICAgIGNvbnN0IHNwbGl0T2ZmRG9jcyA9IG9yaWdpbmFsRG9jLl9zcGxpdERvY3VtZW50KHRoaXMsIE1BWF9JTkxJTkVfU0laRSwgTUFYX01BTkFHRURQT0xfU0laRSk7XG4gICAgLy8gSW5jbHVkZXMgdGhlIFwiY3VycmVudFwiIGRvY3VtZW50XG5cbiAgICBjb25zdCBtcENvdW50ID0gdGhpcy5tYW5hZ2VkUG9saWNpZXMubGVuZ3RoICsgKHNwbGl0T2ZmRG9jcy5zaXplIC0gMSk7XG4gICAgaWYgKG1wQ291bnQgPiAyMCkge1xuICAgICAgQW5ub3RhdGlvbnMub2YodGhpcykuYWRkV2FybmluZyhgUG9saWN5IHRvbyBsYXJnZTogJHttcENvdW50fSBleGNlZWRzIHRoZSBtYXhpbXVtIG9mIDIwIG1hbmFnZWQgcG9saWNpZXMgYXR0YWNoZWQgdG8gYSBSb2xlYCk7XG4gICAgfSBlbHNlIGlmIChtcENvdW50ID4gMTApIHtcbiAgICAgIEFubm90YXRpb25zLm9mKHRoaXMpLmFkZFdhcm5pbmcoYFBvbGljeSBsYXJnZTogJHttcENvdW50fSBleGNlZWRzIDEwIG1hbmFnZWQgcG9saWNpZXMgYXR0YWNoZWQgdG8gYSBSb2xlLCB0aGlzIHJlcXVpcmVzIGEgcXVvdGEgaW5jcmVhc2VgKTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgdGhlIG1hbmFnZWQgcG9saWNpZXMgYW5kIGZpeCB1cCB0aGUgZGVwZW5kZW5jaWVzXG4gICAgbWFya0RlY2xhcmluZ0NvbnN0cnVjdChvcmlnaW5hbERvYywgdGhpcy5kZWZhdWx0UG9saWN5KTtcblxuICAgIGxldCBpID0gMTtcbiAgICBmb3IgKGNvbnN0IG5ld0RvYyBvZiBzcGxpdE9mZkRvY3Mua2V5cygpKSB7XG4gICAgICBpZiAobmV3RG9jID09PSBvcmlnaW5hbERvYykgeyBjb250aW51ZTsgfVxuXG4gICAgICBjb25zdCBtcCA9IG5ldyBNYW5hZ2VkUG9saWN5KHRoaXMsIGBPdmVyZmxvd1BvbGljeSR7aSsrfWAsIHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBQYXJ0IG9mIHRoZSBwb2xpY2llcyBmb3IgJHt0aGlzLm5vZGUucGF0aH1gLFxuICAgICAgICBkb2N1bWVudDogbmV3RG9jLFxuICAgICAgICByb2xlczogW3RoaXNdLFxuICAgICAgfSk7XG4gICAgICBtYXJrRGVjbGFyaW5nQ29uc3RydWN0KG5ld0RvYywgbXApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZSB0aGUgRGVwZW5kYWJsZXMgZm9yIHRoZSBzdGF0ZW1lbnRzIGluIHRoZSBnaXZlbiBQb2xpY3lEb2N1bWVudCB0byBwb2ludCB0byB0aGUgYWN0dWFsIGRlY2xhcmluZyBjb25zdHJ1Y3RcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtYXJrRGVjbGFyaW5nQ29uc3RydWN0KGRvYzogUG9saWN5RG9jdW1lbnQsIGRlY2xhcmluZ0NvbnN0cnVjdDogSUNvbnN0cnVjdCkge1xuICAgICAgZm9yIChjb25zdCBvcmlnaW5hbCBvZiBzcGxpdE9mZkRvY3MuZ2V0KGRvYykgPz8gW10pIHtcbiAgICAgICAgc2VsZi5kZXBlbmRhYmxlcy5nZXQob3JpZ2luYWwpPy5hZGQoZGVjbGFyaW5nQ29uc3RydWN0KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBBIFJvbGUgb2JqZWN0XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVJvbGUgZXh0ZW5kcyBJSWRlbnRpdHkge1xuICAvKipcbiAgICogUmV0dXJucyB0aGUgQVJOIG9mIHRoaXMgcm9sZS5cbiAgICpcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcmVhZG9ubHkgcm9sZUFybjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBuYW1lIG9mIHRoaXMgcm9sZS5cbiAgICpcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcmVhZG9ubHkgcm9sZU5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogR3JhbnQgdGhlIGFjdGlvbnMgZGVmaW5lZCBpbiBhY3Rpb25zIHRvIHRoZSBpZGVudGl0eSBQcmluY2lwYWwgb24gdGhpcyByZXNvdXJjZS5cbiAgICovXG4gIGdyYW50KGdyYW50ZWU6IElQcmluY2lwYWwsIC4uLmFjdGlvbnM6IHN0cmluZ1tdKTogR3JhbnQ7XG5cbiAgLyoqXG4gICAqIEdyYW50IHBlcm1pc3Npb25zIHRvIHRoZSBnaXZlbiBwcmluY2lwYWwgdG8gcGFzcyB0aGlzIHJvbGUuXG4gICAqL1xuICBncmFudFBhc3NSb2xlKGdyYW50ZWU6IElQcmluY2lwYWwpOiBHcmFudDtcblxuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBhc3N1bWUgdGhpcyByb2xlLlxuICAgKi9cbiAgZ3JhbnRBc3N1bWVSb2xlKGdyYW50ZWU6IElQcmluY2lwYWwpOiBHcmFudDtcbn1cblxuZnVuY3Rpb24gY3JlYXRlQXNzdW1lUm9sZVBvbGljeShwcmluY2lwYWw6IElQcmluY2lwYWwsIGV4dGVybmFsSWRzOiBzdHJpbmdbXSkge1xuICBjb25zdCBhY3R1YWxEb2MgPSBuZXcgUG9saWN5RG9jdW1lbnQoKTtcblxuICAvLyBJZiByZXF1ZXN0ZWQsIGFkZCBleHRlcm5hbElkcyB0byBldmVyeSBzdGF0ZW1lbnQgYWRkZWQgdG8gdGhpcyBkb2NcbiAgY29uc3QgYWRkRG9jID0gZXh0ZXJuYWxJZHMubGVuZ3RoID09PSAwXG4gICAgPyBhY3R1YWxEb2NcbiAgICA6IG5ldyBNdXRhdGluZ1BvbGljeURvY3VtZW50QWRhcHRlcihhY3R1YWxEb2MsIChzdGF0ZW1lbnQpID0+IHtcbiAgICAgIHN0YXRlbWVudC5hZGRDb25kaXRpb24oJ1N0cmluZ0VxdWFscycsIHtcbiAgICAgICAgJ3N0czpFeHRlcm5hbElkJzogZXh0ZXJuYWxJZHMubGVuZ3RoID09PSAxID8gZXh0ZXJuYWxJZHNbMF0gOiBleHRlcm5hbElkcyxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHN0YXRlbWVudDtcbiAgICB9KTtcblxuICBkZWZhdWx0QWRkUHJpbmNpcGFsVG9Bc3N1bWVSb2xlKHByaW5jaXBhbCwgYWRkRG9jKTtcblxuICByZXR1cm4gYWN0dWFsRG9jO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVJvbGVQYXRoKHBhdGg/OiBzdHJpbmcpIHtcbiAgaWYgKHBhdGggPT09IHVuZGVmaW5lZCB8fCBUb2tlbi5pc1VucmVzb2x2ZWQocGF0aCkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB2YWxpZFJvbGVQYXRoID0gL14oXFwvfFxcL1tcXHUwMDIxLVxcdTAwN0ZdK1xcLykkLztcblxuICBpZiAocGF0aC5sZW5ndGggPT0gMCB8fCBwYXRoLmxlbmd0aCA+IDUxMikge1xuICAgIHRocm93IG5ldyBFcnJvcihgUm9sZSBwYXRoIG11c3QgYmUgYmV0d2VlbiAxIGFuZCA1MTIgY2hhcmFjdGVycy4gVGhlIHByb3ZpZGVkIHJvbGUgcGF0aCBpcyAke3BhdGgubGVuZ3RofSBjaGFyYWN0ZXJzLmApO1xuICB9IGVsc2UgaWYgKCF2YWxpZFJvbGVQYXRoLnRlc3QocGF0aCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnUm9sZSBwYXRoIG11c3QgYmUgZWl0aGVyIGEgc2xhc2ggb3IgdmFsaWQgY2hhcmFjdGVycyAoYWxwaGFudW1lcmljcyBhbmQgc3ltYm9scykgc3Vycm91bmRlZCBieSBzbGFzaGVzLiAnXG4gICAgICArIGBWYWxpZCBjaGFyYWN0ZXJzIGFyZSB1bmljb2RlIGNoYXJhY3RlcnMgaW4gW1xcXFx1MDAyMS1cXFxcdTAwN0ZdLiBIb3dldmVyLCAke3BhdGh9IGlzIHByb3ZpZGVkLmApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlTWF4U2Vzc2lvbkR1cmF0aW9uKGR1cmF0aW9uPzogbnVtYmVyKSB7XG4gIGlmIChkdXJhdGlvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKGR1cmF0aW9uIDwgMzYwMCB8fCBkdXJhdGlvbiA+IDQzMjAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBtYXhTZXNzaW9uRHVyYXRpb24gaXMgc2V0IHRvICR7ZHVyYXRpb259LCBidXQgbXVzdCBiZSA+PSAzNjAwc2VjICgxaHIpIGFuZCA8PSA0MzIwMHNlYyAoMTJocnMpYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciB0aGUgYHdpdGhvdXRQb2xpY3lVcGRhdGVzKClgIG1vZGlmaWVyIG9mIGEgUm9sZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdpdGhvdXRQb2xpY3lVcGRhdGVzT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBZGQgZ3JhbnRzIHRvIHJlc291cmNlcyBpbnN0ZWFkIG9mIGRyb3BwaW5nIHRoZW1cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgZmFsc2VgIG9yIG5vdCBzcGVjaWZpZWQsIGdyYW50IHBlcm1pc3Npb25zIGFkZGVkIHRvIHRoaXMgcm9sZSBhcmUgaWdub3JlZC5cbiAgICogSXQgaXMgeW91ciBvd24gcmVzcG9uc2liaWxpdHkgdG8gbWFrZSBzdXJlIHRoZSByb2xlIGhhcyB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMuXG4gICAqXG4gICAqIElmIHRoaXMgaXMgYHRydWVgLCBhbnkgZ3JhbnQgcGVybWlzc2lvbnMgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVzb3VyY2UgaW5zdGVhZC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFkZEdyYW50c1RvUmVzb3VyY2VzPzogYm9vbGVhbjtcbn1cbiJdfQ==
\No newline at end of file