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 managed_policy_1 = require("./managed-policy");
|
12 | const policy_1 = require("./policy");
|
13 | const policy_document_1 = require("./policy-document");
|
14 | const principals_1 = require("./principals");
|
15 | const assume_role_policy_1 = require("./private/assume-role-policy");
|
16 | const immutable_role_1 = require("./private/immutable-role");
|
17 | const policydoc_adapter_1 = require("./private/policydoc-adapter");
|
18 | const util_1 = require("./util");
|
19 | const MAX_INLINE_SIZE = 10000;
|
20 | const 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 | */
|
27 | class 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 | }
|
432 | exports.Role = Role;
|
433 | _a = JSII_RTTI_SYMBOL_1;
|
434 | Role[_a] = { fqn: "@aws-cdk/aws-iam.Role", version: "1.161.0" };
|
435 | function 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 | }
|
449 | function 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 | }
|
462 | function 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 |