UNPKG

122 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.Pipeline = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const notifications = require("@aws-cdk/aws-codestarnotifications");
8const events = require("@aws-cdk/aws-events");
9const iam = require("@aws-cdk/aws-iam");
10const kms = require("@aws-cdk/aws-kms");
11const s3 = require("@aws-cdk/aws-s3");
12const core_1 = require("@aws-cdk/core");
13const action_1 = require("./action");
14const codepipeline_generated_1 = require("./codepipeline.generated");
15const cross_region_support_stack_1 = require("./private/cross-region-support-stack");
16const full_action_descriptor_1 = require("./private/full-action-descriptor");
17const rich_action_1 = require("./private/rich-action");
18const stage_1 = require("./private/stage");
19const validation_1 = require("./private/validation");
20class PipelineBase extends core_1.Resource {
21 /**
22 * Defines an event rule triggered by this CodePipeline.
23 *
24 * @param id Identifier for this event handler.
25 * @param options Additional options to pass to the event rule.
26 */
27 onEvent(id, options = {}) {
28 const rule = new events.Rule(this, id, options);
29 rule.addTarget(options.target);
30 rule.addEventPattern({
31 source: ['aws.codepipeline'],
32 resources: [this.pipelineArn],
33 });
34 return rule;
35 }
36 /**
37 * Defines an event rule triggered by the "CodePipeline Pipeline Execution
38 * State Change" event emitted from this pipeline.
39 *
40 * @param id Identifier for this event handler.
41 * @param options Additional options to pass to the event rule.
42 */
43 onStateChange(id, options = {}) {
44 const rule = this.onEvent(id, options);
45 rule.addEventPattern({
46 detailType: ['CodePipeline Pipeline Execution State Change'],
47 });
48 return rule;
49 }
50 bindAsNotificationRuleSource(_scope) {
51 return {
52 sourceArn: this.pipelineArn,
53 };
54 }
55 notifyOn(id, target, options) {
56 return new notifications.NotificationRule(this, id, {
57 ...options,
58 source: this,
59 targets: [target],
60 });
61 }
62 notifyOnExecutionStateChange(id, target, options) {
63 return this.notifyOn(id, target, {
64 ...options,
65 events: [
66 action_1.PipelineNotificationEvents.PIPELINE_EXECUTION_FAILED,
67 action_1.PipelineNotificationEvents.PIPELINE_EXECUTION_CANCELED,
68 action_1.PipelineNotificationEvents.PIPELINE_EXECUTION_STARTED,
69 action_1.PipelineNotificationEvents.PIPELINE_EXECUTION_RESUMED,
70 action_1.PipelineNotificationEvents.PIPELINE_EXECUTION_SUCCEEDED,
71 action_1.PipelineNotificationEvents.PIPELINE_EXECUTION_SUPERSEDED,
72 ],
73 });
74 }
75 notifyOnAnyStageStateChange(id, target, options) {
76 return this.notifyOn(id, target, {
77 ...options,
78 events: [
79 action_1.PipelineNotificationEvents.STAGE_EXECUTION_CANCELED,
80 action_1.PipelineNotificationEvents.STAGE_EXECUTION_FAILED,
81 action_1.PipelineNotificationEvents.STAGE_EXECUTION_RESUMED,
82 action_1.PipelineNotificationEvents.STAGE_EXECUTION_STARTED,
83 action_1.PipelineNotificationEvents.STAGE_EXECUTION_SUCCEEDED,
84 ],
85 });
86 }
87 notifyOnAnyActionStateChange(id, target, options) {
88 return this.notifyOn(id, target, {
89 ...options,
90 events: [
91 action_1.PipelineNotificationEvents.ACTION_EXECUTION_CANCELED,
92 action_1.PipelineNotificationEvents.ACTION_EXECUTION_FAILED,
93 action_1.PipelineNotificationEvents.ACTION_EXECUTION_STARTED,
94 action_1.PipelineNotificationEvents.ACTION_EXECUTION_SUCCEEDED,
95 ],
96 });
97 }
98 notifyOnAnyManualApprovalStateChange(id, target, options) {
99 return this.notifyOn(id, target, {
100 ...options,
101 events: [
102 action_1.PipelineNotificationEvents.MANUAL_APPROVAL_FAILED,
103 action_1.PipelineNotificationEvents.MANUAL_APPROVAL_NEEDED,
104 action_1.PipelineNotificationEvents.MANUAL_APPROVAL_SUCCEEDED,
105 ],
106 });
107 }
108}
109/**
110 * An AWS CodePipeline pipeline with its associated IAM role and S3 bucket.
111 *
112 * @example
113 * // create a pipeline
114 * import * as codecommit from '@aws-cdk/aws-codecommit';
115 *
116 * const pipeline = new codepipeline.Pipeline(this, 'Pipeline');
117 *
118 * // add a stage
119 * const sourceStage = pipeline.addStage({ stageName: 'Source' });
120 *
121 * // add a source action to the stage
122 * declare const repo: codecommit.Repository;
123 * declare const sourceArtifact: codepipeline.Artifact;
124 * sourceStage.addAction(new codepipeline_actions.CodeCommitSourceAction({
125 * actionName: 'Source',
126 * output: sourceArtifact,
127 * repository: repo,
128 * }));
129 *
130 * // ... add more stages
131 */
132class Pipeline extends PipelineBase {
133 constructor(scope, id, props = {}) {
134 super(scope, id, {
135 physicalName: props.pipelineName,
136 });
137 this._stages = new Array();
138 this._crossRegionSupport = {};
139 this._crossAccountSupport = {};
140 try {
141 jsiiDeprecationWarnings._aws_cdk_aws_codepipeline_PipelineProps(props);
142 }
143 catch (error) {
144 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
145 Error.captureStackTrace(error, Pipeline);
146 }
147 throw error;
148 }
149 validation_1.validateName('Pipeline', this.physicalName);
150 // only one of artifactBucket and crossRegionReplicationBuckets can be supplied
151 if (props.artifactBucket && props.crossRegionReplicationBuckets) {
152 throw new Error('Only one of artifactBucket and crossRegionReplicationBuckets can be specified!');
153 }
154 // @deprecated(v2): switch to default false
155 this.crossAccountKeys = props.crossAccountKeys ?? true;
156 this.enableKeyRotation = props.enableKeyRotation;
157 // Cross account keys must be set for key rotation to be enabled
158 if (this.enableKeyRotation && !this.crossAccountKeys) {
159 throw new Error("Setting 'enableKeyRotation' to true also requires 'crossAccountKeys' to be enabled");
160 }
161 this.reuseCrossRegionSupportStacks = props.reuseCrossRegionSupportStacks ?? true;
162 // If a bucket has been provided, use it - otherwise, create a bucket.
163 let propsBucket = this.getArtifactBucketFromProps(props);
164 if (!propsBucket) {
165 let encryptionKey;
166 if (this.crossAccountKeys) {
167 encryptionKey = new kms.Key(this, 'ArtifactsBucketEncryptionKey', {
168 // remove the key - there is a grace period of a few days before it's gone for good,
169 // that should be enough for any emergency access to the bucket artifacts
170 removalPolicy: core_1.RemovalPolicy.DESTROY,
171 enableKeyRotation: this.enableKeyRotation,
172 });
173 // add an alias to make finding the key in the console easier
174 new kms.Alias(this, 'ArtifactsBucketEncryptionKeyAlias', {
175 aliasName: this.generateNameForDefaultBucketKeyAlias(),
176 targetKey: encryptionKey,
177 removalPolicy: core_1.RemovalPolicy.DESTROY,
178 });
179 }
180 propsBucket = new s3.Bucket(this, 'ArtifactsBucket', {
181 bucketName: core_1.PhysicalName.GENERATE_IF_NEEDED,
182 encryptionKey,
183 encryption: encryptionKey ? s3.BucketEncryption.KMS : s3.BucketEncryption.KMS_MANAGED,
184 enforceSSL: true,
185 blockPublicAccess: new s3.BlockPublicAccess(s3.BlockPublicAccess.BLOCK_ALL),
186 removalPolicy: core_1.RemovalPolicy.RETAIN,
187 });
188 }
189 this.artifactBucket = propsBucket;
190 // If a role has been provided, use it - otherwise, create a role.
191 this.role = props.role || new iam.Role(this, 'Role', {
192 assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com'),
193 });
194 this.codePipeline = new codepipeline_generated_1.CfnPipeline(this, 'Resource', {
195 artifactStore: core_1.Lazy.any({ produce: () => this.renderArtifactStoreProperty() }),
196 artifactStores: core_1.Lazy.any({ produce: () => this.renderArtifactStoresProperty() }),
197 stages: core_1.Lazy.any({ produce: () => this.renderStages() }),
198 disableInboundStageTransitions: core_1.Lazy.any({ produce: () => this.renderDisabledTransitions() }, { omitEmptyArray: true }),
199 roleArn: this.role.roleArn,
200 restartExecutionOnUpdate: props && props.restartExecutionOnUpdate,
201 name: this.physicalName,
202 });
203 // this will produce a DependsOn for both the role and the policy resources.
204 this.codePipeline.node.addDependency(this.role);
205 this.artifactBucket.grantReadWrite(this.role);
206 this.pipelineName = this.getResourceNameAttribute(this.codePipeline.ref);
207 this.pipelineVersion = this.codePipeline.attrVersion;
208 this.crossRegionBucketsPassed = !!props.crossRegionReplicationBuckets;
209 for (const [region, replicationBucket] of Object.entries(props.crossRegionReplicationBuckets || {})) {
210 this._crossRegionSupport[region] = {
211 replicationBucket,
212 stack: core_1.Stack.of(replicationBucket),
213 };
214 }
215 // Does not expose a Fn::GetAtt for the ARN so we'll have to make it ourselves
216 this.pipelineArn = core_1.Stack.of(this).formatArn({
217 service: 'codepipeline',
218 resource: this.pipelineName,
219 });
220 for (const stage of props.stages || []) {
221 this.addStage(stage);
222 }
223 }
224 /**
225 * Import a pipeline into this app.
226 *
227 * @param scope the scope into which to import this pipeline
228 * @param id the logical ID of the returned pipeline construct
229 * @param pipelineArn The ARN of the pipeline (e.g. `arn:aws:codepipeline:us-east-1:123456789012:MyDemoPipeline`)
230 */
231 static fromPipelineArn(scope, id, pipelineArn) {
232 class Import extends PipelineBase {
233 constructor() {
234 super(...arguments);
235 this.pipelineName = core_1.Stack.of(scope).splitArn(pipelineArn, core_1.ArnFormat.SLASH_RESOURCE_NAME).resource;
236 this.pipelineArn = pipelineArn;
237 }
238 }
239 return new Import(scope, id);
240 }
241 /**
242 * Creates a new Stage, and adds it to this Pipeline.
243 *
244 * @param props the creation properties of the new Stage
245 * @returns the newly created Stage
246 */
247 addStage(props) {
248 try {
249 jsiiDeprecationWarnings._aws_cdk_aws_codepipeline_StageOptions(props);
250 }
251 catch (error) {
252 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
253 Error.captureStackTrace(error, this.addStage);
254 }
255 throw error;
256 }
257 // check for duplicate Stages and names
258 if (this._stages.find(s => s.stageName === props.stageName)) {
259 throw new Error(`Stage with duplicate name '${props.stageName}' added to the Pipeline`);
260 }
261 const stage = new stage_1.Stage(props, this);
262 const index = props.placement
263 ? this.calculateInsertIndexFromPlacement(props.placement)
264 : this.stageCount;
265 this._stages.splice(index, 0, stage);
266 return stage;
267 }
268 /**
269 * Adds a statement to the pipeline role.
270 */
271 addToRolePolicy(statement) {
272 this.role.addToPrincipalPolicy(statement);
273 }
274 /**
275 * Get the number of Stages in this Pipeline.
276 */
277 get stageCount() {
278 return this._stages.length;
279 }
280 /**
281 * Returns the stages that comprise the pipeline.
282 *
283 * **Note**: the returned array is a defensive copy,
284 * so adding elements to it has no effect.
285 * Instead, use the {@link addStage} method if you want to add more stages
286 * to the pipeline.
287 */
288 get stages() {
289 return this._stages.slice();
290 }
291 /**
292 * Access one of the pipeline's stages by stage name
293 */
294 stage(stageName) {
295 for (const stage of this._stages) {
296 if (stage.stageName === stageName) {
297 return stage;
298 }
299 }
300 throw new Error(`Pipeline does not contain a stage named '${stageName}'. Available stages: ${this._stages.map(s => s.stageName).join(', ')}`);
301 }
302 /**
303 * Returns all of the {@link CrossRegionSupportStack}s that were generated automatically
304 * when dealing with Actions that reside in a different region than the Pipeline itself.
305 *
306 */
307 get crossRegionSupport() {
308 const ret = {};
309 Object.keys(this._crossRegionSupport).forEach((key) => {
310 ret[key] = this._crossRegionSupport[key];
311 });
312 return ret;
313 }
314 /** @internal */
315 _attachActionToPipeline(stage, action, actionScope) {
316 const richAction = new rich_action_1.RichAction(action, this);
317 // handle cross-region actions here
318 const crossRegionInfo = this.ensureReplicationResourcesExistFor(richAction);
319 // get the role for the given action, handling if it's cross-account
320 const actionRole = this.getRoleForAction(stage, richAction, actionScope);
321 // // CodePipeline Variables
322 validation_1.validateNamespaceName(richAction.actionProperties.variablesNamespace);
323 // bind the Action (type h4x)
324 const actionConfig = richAction.bind(actionScope, stage, {
325 role: actionRole ? actionRole : this.role,
326 bucket: crossRegionInfo.artifactBucket,
327 });
328 return new full_action_descriptor_1.FullActionDescriptor({
329 // must be 'action', not 'richAction',
330 // as those are returned by the IStage.actions property,
331 // and it's important customers of Pipeline get the same instance
332 // back as they added to the pipeline
333 action,
334 actionConfig,
335 actionRole,
336 actionRegion: crossRegionInfo.region,
337 });
338 }
339 /**
340 * Validate the pipeline structure
341 *
342 * Validation happens according to the rules documented at
343 *
344 * https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#pipeline-requirements
345 * @override
346 */
347 validate() {
348 return [
349 ...this.validateSourceActionLocations(),
350 ...this.validateHasStages(),
351 ...this.validateStages(),
352 ...this.validateArtifacts(),
353 ];
354 }
355 ensureReplicationResourcesExistFor(action) {
356 if (!action.isCrossRegion) {
357 return {
358 artifactBucket: this.artifactBucket,
359 };
360 }
361 // The action has a specific region,
362 // require the pipeline to have a known region as well.
363 this.requireRegion();
364 // source actions have to be in the same region as the pipeline
365 if (action.actionProperties.category === action_1.ActionCategory.SOURCE) {
366 throw new Error(`Source action '${action.actionProperties.actionName}' must be in the same region as the pipeline`);
367 }
368 // check whether we already have a bucket in that region,
369 // either passed from the outside or previously created
370 const crossRegionSupport = this.obtainCrossRegionSupportFor(action);
371 // the stack containing the replication bucket must be deployed before the pipeline
372 core_1.Stack.of(this).addDependency(crossRegionSupport.stack);
373 // The Pipeline role must be able to replicate to that bucket
374 crossRegionSupport.replicationBucket.grantReadWrite(this.role);
375 return {
376 artifactBucket: crossRegionSupport.replicationBucket,
377 region: action.effectiveRegion,
378 };
379 }
380 /**
381 * Get or create the cross-region support construct for the given action
382 */
383 obtainCrossRegionSupportFor(action) {
384 // this method is never called for non cross-region actions
385 const actionRegion = action.effectiveRegion;
386 let crossRegionSupport = this._crossRegionSupport[actionRegion];
387 if (!crossRegionSupport) {
388 // we need to create scaffolding resources for this region
389 const otherStack = action.resourceStack;
390 crossRegionSupport = this.createSupportResourcesForRegion(otherStack, actionRegion);
391 this._crossRegionSupport[actionRegion] = crossRegionSupport;
392 }
393 return crossRegionSupport;
394 }
395 createSupportResourcesForRegion(otherStack, actionRegion) {
396 // if we have a stack from the resource passed - use that!
397 if (otherStack) {
398 // check if the stack doesn't have this magic construct already
399 const id = `CrossRegionReplicationSupport-d823f1d8-a990-4e5c-be18-4ac698532e65-${actionRegion}`;
400 let crossRegionSupportConstruct = otherStack.node.tryFindChild(id);
401 if (!crossRegionSupportConstruct) {
402 crossRegionSupportConstruct = new cross_region_support_stack_1.CrossRegionSupportConstruct(otherStack, id, {
403 createKmsKey: this.crossAccountKeys,
404 enableKeyRotation: this.enableKeyRotation,
405 });
406 }
407 return {
408 replicationBucket: crossRegionSupportConstruct.replicationBucket,
409 stack: otherStack,
410 };
411 }
412 // otherwise - create a stack with the resources needed for replication across regions
413 const pipelineStack = core_1.Stack.of(this);
414 const pipelineAccount = pipelineStack.account;
415 if (core_1.Token.isUnresolved(pipelineAccount)) {
416 throw new Error("You need to specify an explicit account when using CodePipeline's cross-region support");
417 }
418 const app = this.supportScope();
419 const supportStackId = `cross-region-stack-${this.reuseCrossRegionSupportStacks ? pipelineAccount : pipelineStack.stackName}:${actionRegion}`;
420 let supportStack = app.node.tryFindChild(supportStackId);
421 if (!supportStack) {
422 supportStack = new cross_region_support_stack_1.CrossRegionSupportStack(app, supportStackId, {
423 pipelineStackName: pipelineStack.stackName,
424 region: actionRegion,
425 account: pipelineAccount,
426 synthesizer: this.getCrossRegionSupportSynthesizer(),
427 createKmsKey: this.crossAccountKeys,
428 enableKeyRotation: this.enableKeyRotation,
429 });
430 }
431 return {
432 stack: supportStack,
433 replicationBucket: supportStack.replicationBucket,
434 };
435 }
436 getCrossRegionSupportSynthesizer() {
437 if (this.stack.synthesizer instanceof core_1.DefaultStackSynthesizer) {
438 // if we have the new synthesizer,
439 // we need a bootstrapless copy of it,
440 // because we don't want to require bootstrapping the environment
441 // of the pipeline account in this replication region
442 return new core_1.BootstraplessSynthesizer({
443 deployRoleArn: this.stack.synthesizer.deployRoleArn,
444 cloudFormationExecutionRoleArn: this.stack.synthesizer.cloudFormationExecutionRoleArn,
445 });
446 }
447 else {
448 // any other synthesizer: just return undefined
449 // (ie., use the default based on the context settings)
450 return undefined;
451 }
452 }
453 generateNameForDefaultBucketKeyAlias() {
454 const prefix = 'alias/codepipeline-';
455 const maxAliasLength = 256;
456 const uniqueId = core_1.Names.uniqueId(this);
457 // take the last 256 - (prefix length) characters of uniqueId
458 const startIndex = Math.max(0, uniqueId.length - (maxAliasLength - prefix.length));
459 return prefix + uniqueId.substring(startIndex).toLowerCase();
460 }
461 /**
462 * Gets the role used for this action,
463 * including handling the case when the action is supposed to be cross-account.
464 *
465 * @param stage the stage the action belongs to
466 * @param action the action to return/create a role for
467 * @param actionScope the scope, unique to the action, to create new resources in
468 */
469 getRoleForAction(stage, action, actionScope) {
470 const pipelineStack = core_1.Stack.of(this);
471 let actionRole = this.getRoleFromActionPropsOrGenerateIfCrossAccount(stage, action);
472 if (!actionRole && this.isAwsOwned(action)) {
473 // generate a Role for this specific Action
474 actionRole = new iam.Role(actionScope, 'CodePipelineActionRole', {
475 assumedBy: new iam.AccountPrincipal(pipelineStack.account),
476 });
477 }
478 // the pipeline role needs assumeRole permissions to the action role
479 const grant = actionRole?.grantAssumeRole(this.role);
480 grant?.applyBefore(this.codePipeline);
481 return actionRole;
482 }
483 getRoleFromActionPropsOrGenerateIfCrossAccount(stage, action) {
484 const pipelineStack = core_1.Stack.of(this);
485 // if we have a cross-account action, the pipeline's bucket must have a KMS key
486 // (otherwise we can't configure cross-account trust policies)
487 if (action.isCrossAccount) {
488 const artifactBucket = this.ensureReplicationResourcesExistFor(action).artifactBucket;
489 if (!artifactBucket.encryptionKey) {
490 throw new Error(`Artifact Bucket must have a KMS Key to add cross-account action '${action.actionProperties.actionName}' ` +
491 `(pipeline account: '${renderEnvDimension(this.env.account)}', action account: '${renderEnvDimension(action.effectiveAccount)}'). ` +
492 'Create Pipeline with \'crossAccountKeys: true\' (or pass an existing Bucket with a key)');
493 }
494 }
495 // if a Role has been passed explicitly, always use it
496 // (even if the backing resource is from a different account -
497 // this is how the user can override our default support logic)
498 if (action.actionProperties.role) {
499 if (this.isAwsOwned(action)) {
500 // the role has to be deployed before the pipeline
501 // (our magical cross-stack dependencies will not work,
502 // because the role might be from a different environment),
503 // but _only_ if it's a new Role -
504 // an imported Role should not add the dependency
505 if (action.actionProperties.role instanceof iam.Role) {
506 const roleStack = core_1.Stack.of(action.actionProperties.role);
507 pipelineStack.addDependency(roleStack);
508 }
509 return action.actionProperties.role;
510 }
511 else {
512 // ...except if the Action is not owned by 'AWS',
513 // as that would be rejected by CodePipeline at deploy time
514 throw new Error("Specifying a Role is not supported for actions with an owner different than 'AWS' - " +
515 `got '${action.actionProperties.owner}' (Action: '${action.actionProperties.actionName}' in Stage: '${stage.stageName}')`);
516 }
517 }
518 // if we don't have a Role passed,
519 // and the action is cross-account,
520 // generate a Role in that other account stack
521 const otherAccountStack = this.getOtherStackIfActionIsCrossAccount(action);
522 if (!otherAccountStack) {
523 return undefined;
524 }
525 // generate a role in the other stack, that the Pipeline will assume for executing this action
526 const ret = new iam.Role(otherAccountStack, `${core_1.Names.uniqueId(this)}-${stage.stageName}-${action.actionProperties.actionName}-ActionRole`, {
527 assumedBy: new iam.AccountPrincipal(pipelineStack.account),
528 roleName: core_1.PhysicalName.GENERATE_IF_NEEDED,
529 });
530 // the other stack with the role has to be deployed before the pipeline stack
531 // (CodePipeline verifies you can assume the action Role on creation)
532 pipelineStack.addDependency(otherAccountStack);
533 return ret;
534 }
535 /**
536 * Returns the Stack this Action belongs to if this is a cross-account Action.
537 * If this Action is not cross-account (i.e., it lives in the same account as the Pipeline),
538 * it returns undefined.
539 *
540 * @param action the Action to return the Stack for
541 */
542 getOtherStackIfActionIsCrossAccount(action) {
543 const targetAccount = action.actionProperties.resource
544 ? action.actionProperties.resource.env.account
545 : action.actionProperties.account;
546 if (targetAccount === undefined) {
547 // if the account of the Action is not specified,
548 // then it defaults to the same account the pipeline itself is in
549 return undefined;
550 }
551 // check whether the action's account is a static string
552 if (core_1.Token.isUnresolved(targetAccount)) {
553 if (core_1.Token.isUnresolved(this.env.account)) {
554 // the pipeline is also env-agnostic, so that's fine
555 return undefined;
556 }
557 else {
558 throw new Error(`The 'account' property must be a concrete value (action: '${action.actionProperties.actionName}')`);
559 }
560 }
561 // At this point, we know that the action's account is a static string.
562 // In this case, the pipeline's account must also be a static string.
563 if (core_1.Token.isUnresolved(this.env.account)) {
564 throw new Error('Pipeline stack which uses cross-environment actions must have an explicitly set account');
565 }
566 // at this point, we know that both the Pipeline's account,
567 // and the action-backing resource's account are static strings
568 // if they are identical - nothing to do (the action is not cross-account)
569 if (this.env.account === targetAccount) {
570 return undefined;
571 }
572 // at this point, we know that the action is certainly cross-account,
573 // so we need to return a Stack in its account to create the helper Role in
574 const candidateActionResourceStack = action.actionProperties.resource
575 ? core_1.Stack.of(action.actionProperties.resource)
576 : undefined;
577 if (candidateActionResourceStack?.account === targetAccount) {
578 // we always use the "latest" action-backing resource's Stack for this account,
579 // even if a different one was used earlier
580 this._crossAccountSupport[targetAccount] = candidateActionResourceStack;
581 return candidateActionResourceStack;
582 }
583 let targetAccountStack = this._crossAccountSupport[targetAccount];
584 if (!targetAccountStack) {
585 const stackId = `cross-account-support-stack-${targetAccount}`;
586 const app = this.supportScope();
587 targetAccountStack = app.node.tryFindChild(stackId);
588 if (!targetAccountStack) {
589 const actionRegion = action.actionProperties.resource
590 ? action.actionProperties.resource.env.region
591 : action.actionProperties.region;
592 const pipelineStack = core_1.Stack.of(this);
593 targetAccountStack = new core_1.Stack(app, stackId, {
594 stackName: `${pipelineStack.stackName}-support-${targetAccount}`,
595 env: {
596 account: targetAccount,
597 region: actionRegion ?? pipelineStack.region,
598 },
599 });
600 }
601 this._crossAccountSupport[targetAccount] = targetAccountStack;
602 }
603 return targetAccountStack;
604 }
605 isAwsOwned(action) {
606 const owner = action.actionProperties.owner;
607 return !owner || owner === 'AWS';
608 }
609 getArtifactBucketFromProps(props) {
610 if (props.artifactBucket) {
611 return props.artifactBucket;
612 }
613 if (props.crossRegionReplicationBuckets) {
614 const pipelineRegion = this.requireRegion();
615 return props.crossRegionReplicationBuckets[pipelineRegion];
616 }
617 return undefined;
618 }
619 calculateInsertIndexFromPlacement(placement) {
620 // check if at most one placement property was provided
621 const providedPlacementProps = ['rightBefore', 'justAfter', 'atIndex']
622 .filter((prop) => placement[prop] !== undefined);
623 if (providedPlacementProps.length > 1) {
624 throw new Error('Error adding Stage to the Pipeline: ' +
625 'you can only provide at most one placement property, but ' +
626 `'${providedPlacementProps.join(', ')}' were given`);
627 }
628 if (placement.rightBefore !== undefined) {
629 const targetIndex = this.findStageIndex(placement.rightBefore);
630 if (targetIndex === -1) {
631 throw new Error('Error adding Stage to the Pipeline: ' +
632 `the requested Stage to add it before, '${placement.rightBefore.stageName}', was not found`);
633 }
634 return targetIndex;
635 }
636 if (placement.justAfter !== undefined) {
637 const targetIndex = this.findStageIndex(placement.justAfter);
638 if (targetIndex === -1) {
639 throw new Error('Error adding Stage to the Pipeline: ' +
640 `the requested Stage to add it after, '${placement.justAfter.stageName}', was not found`);
641 }
642 return targetIndex + 1;
643 }
644 return this.stageCount;
645 }
646 findStageIndex(targetStage) {
647 return this._stages.findIndex(stage => stage === targetStage);
648 }
649 validateSourceActionLocations() {
650 const errors = new Array();
651 let firstStage = true;
652 for (const stage of this._stages) {
653 const onlySourceActionsPermitted = firstStage;
654 for (const action of stage.actionDescriptors) {
655 errors.push(...validation_1.validateSourceAction(onlySourceActionsPermitted, action.category, action.actionName, stage.stageName));
656 }
657 firstStage = false;
658 }
659 return errors;
660 }
661 validateHasStages() {
662 if (this.stageCount < 2) {
663 return ['Pipeline must have at least two stages'];
664 }
665 return [];
666 }
667 validateStages() {
668 const ret = new Array();
669 for (const stage of this._stages) {
670 ret.push(...stage.validate());
671 }
672 return ret;
673 }
674 validateArtifacts() {
675 const ret = new Array();
676 const producers = {};
677 const firstConsumers = {};
678 for (const [stageIndex, stage] of enumerate(this._stages)) {
679 // For every output artifact, get the producer
680 for (const action of stage.actionDescriptors) {
681 const actionLoc = new PipelineLocation(stageIndex, stage, action);
682 for (const outputArtifact of action.outputs) {
683 // output Artifacts always have a name set
684 const name = outputArtifact.artifactName;
685 if (producers[name]) {
686 ret.push(`Both Actions '${producers[name].actionName}' and '${action.actionName}' are producting Artifact '${name}'. Every artifact can only be produced once.`);
687 continue;
688 }
689 producers[name] = actionLoc;
690 }
691 // For every input artifact, get the first consumer
692 for (const inputArtifact of action.inputs) {
693 const name = inputArtifact.artifactName;
694 if (!name) {
695 ret.push(`Action '${action.actionName}' is using an unnamed input Artifact, which is not being produced in this pipeline`);
696 continue;
697 }
698 firstConsumers[name] = firstConsumers[name] ? firstConsumers[name].first(actionLoc) : actionLoc;
699 }
700 }
701 }
702 // Now validate that every input artifact is produced before it's
703 // being consumed.
704 for (const [artifactName, consumerLoc] of Object.entries(firstConsumers)) {
705 const producerLoc = producers[artifactName];
706 if (!producerLoc) {
707 ret.push(`Action '${consumerLoc.actionName}' is using input Artifact '${artifactName}', which is not being produced in this pipeline`);
708 continue;
709 }
710 if (consumerLoc.beforeOrEqual(producerLoc)) {
711 ret.push(`${consumerLoc} is consuming input Artifact '${artifactName}' before it is being produced at ${producerLoc}`);
712 }
713 }
714 return ret;
715 }
716 renderArtifactStoresProperty() {
717 if (!this.crossRegion) {
718 return undefined;
719 }
720 // add the Pipeline's artifact store
721 const primaryRegion = this.requireRegion();
722 this._crossRegionSupport[primaryRegion] = {
723 replicationBucket: this.artifactBucket,
724 stack: core_1.Stack.of(this),
725 };
726 return Object.entries(this._crossRegionSupport).map(([region, support]) => ({
727 region,
728 artifactStore: this.renderArtifactStore(support.replicationBucket),
729 }));
730 }
731 renderArtifactStoreProperty() {
732 if (this.crossRegion) {
733 return undefined;
734 }
735 return this.renderPrimaryArtifactStore();
736 }
737 renderPrimaryArtifactStore() {
738 return this.renderArtifactStore(this.artifactBucket);
739 }
740 renderArtifactStore(bucket) {
741 let encryptionKey;
742 const bucketKey = bucket.encryptionKey;
743 if (bucketKey) {
744 encryptionKey = {
745 type: 'KMS',
746 id: bucketKey.keyArn,
747 };
748 }
749 return {
750 type: 'S3',
751 location: bucket.bucketName,
752 encryptionKey,
753 };
754 }
755 get crossRegion() {
756 if (this.crossRegionBucketsPassed) {
757 return true;
758 }
759 return this._stages.some(stage => stage.actionDescriptors.some(action => action.region !== undefined));
760 }
761 renderStages() {
762 return this._stages.map(stage => stage.render());
763 }
764 renderDisabledTransitions() {
765 return this._stages
766 .filter(stage => !stage.transitionToEnabled)
767 .map(stage => ({
768 reason: stage.transitionDisabledReason,
769 stageName: stage.stageName,
770 }));
771 }
772 requireRegion() {
773 const region = this.env.region;
774 if (core_1.Token.isUnresolved(region)) {
775 throw new Error('Pipeline stack which uses cross-environment actions must have an explicitly set region');
776 }
777 return region;
778 }
779 supportScope() {
780 const scope = core_1.Stage.of(this);
781 if (!scope) {
782 throw new Error('Pipeline stack which uses cross-environment actions must be part of a CDK App or Stage');
783 }
784 return scope;
785 }
786}
787exports.Pipeline = Pipeline;
788_a = JSII_RTTI_SYMBOL_1;
789Pipeline[_a] = { fqn: "@aws-cdk/aws-codepipeline.Pipeline", version: "1.204.0" };
790function enumerate(xs) {
791 const ret = new Array();
792 for (let i = 0; i < xs.length; i++) {
793 ret.push([i, xs[i]]);
794 }
795 return ret;
796}
797class PipelineLocation {
798 constructor(stageIndex, stage, action) {
799 this.stageIndex = stageIndex;
800 this.stage = stage;
801 this.action = action;
802 }
803 get stageName() {
804 return this.stage.stageName;
805 }
806 get actionName() {
807 return this.action.actionName;
808 }
809 /**
810 * Returns whether a is before or the same order as b
811 */
812 beforeOrEqual(rhs) {
813 if (this.stageIndex !== rhs.stageIndex) {
814 return rhs.stageIndex < rhs.stageIndex;
815 }
816 return this.action.runOrder <= rhs.action.runOrder;
817 }
818 /**
819 * Returns the first location between this and the other one
820 */
821 first(rhs) {
822 return this.beforeOrEqual(rhs) ? this : rhs;
823 }
824 toString() {
825 // runOrders are 1-based, so make the stageIndex also 1-based otherwise it's going to be confusing.
826 return `Stage ${this.stageIndex + 1} Action ${this.action.runOrder} ('${this.stageName}'/'${this.actionName}')`;
827 }
828}
829/**
830 * Render an env dimension without showing the ugly stringified tokens
831 */
832function renderEnvDimension(s) {
833 return core_1.Token.isUnresolved(s) ? '(current)' : s;
834}
835//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGlwZWxpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJwaXBlbGluZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvRUFBb0U7QUFDcEUsOENBQThDO0FBQzlDLHdDQUF3QztBQUN4Qyx3Q0FBd0M7QUFDeEMsc0NBQXNDO0FBQ3RDLHdDQWF1QjtBQUV2QixxQ0FBMkg7QUFDM0gscUVBQXVEO0FBQ3ZELHFGQUE0RztBQUM1Ryw2RUFBd0U7QUFDeEUsdURBQW1EO0FBQ25ELDJDQUF3QztBQUN4QyxxREFBaUc7QUFrSmpHLE1BQWUsWUFBYSxTQUFRLGVBQVE7SUFJMUM7Ozs7O09BS0c7SUFDSSxPQUFPLENBQUMsRUFBVSxFQUFFLFVBQWlDLEVBQUU7UUFDNUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDL0IsSUFBSSxDQUFDLGVBQWUsQ0FBQztZQUNuQixNQUFNLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQztZQUM1QixTQUFTLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO1NBQzlCLENBQUMsQ0FBQztRQUNILE9BQU8sSUFBSSxDQUFDO0tBQ2I7SUFFRDs7Ozs7O09BTUc7SUFDSSxhQUFhLENBQUMsRUFBVSxFQUFFLFVBQWlDLEVBQUU7UUFDbEUsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLGVBQWUsQ0FBQztZQUNuQixVQUFVLEVBQUUsQ0FBQyw4Q0FBOEMsQ0FBQztTQUM3RCxDQUFDLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQztLQUNiO0lBRU0sNEJBQTRCLENBQUMsTUFBaUI7UUFDbkQsT0FBTztZQUNMLFNBQVMsRUFBRSxJQUFJLENBQUMs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QUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNqRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgbm90aWZpY2F0aW9ucyBmcm9tICdAYXdzLWNkay9hd3MtY29kZXN0YXJub3RpZmljYXRpb25zJztcbmltcG9ydCAqIGFzIGV2ZW50cyBmcm9tICdAYXdzLWNkay9hd3MtZXZlbnRzJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdAYXdzLWNkay9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGttcyBmcm9tICdAYXdzLWNkay9hd3Mta21zJztcbmltcG9ydCAqIGFzIHMzIGZyb20gJ0Bhd3MtY2RrL2F3cy1zMyc7XG5pbXBvcnQge1xuICBBcm5Gb3JtYXQsXG4gIEJvb3RzdHJhcGxlc3NTeW50aGVzaXplcixcbiAgRGVmYXVsdFN0YWNrU3ludGhlc2l6ZXIsXG4gIElTdGFja1N5bnRoZXNpemVyLFxuICBMYXp5LFxuICBOYW1lcyxcbiAgUGh5c2ljYWxOYW1lLFxuICBSZW1vdmFsUG9saWN5LFxuICBSZXNvdXJjZSxcbiAgU3RhY2ssXG4gIFN0YWdlIGFzIENka1N0YWdlLFxuICBUb2tlbixcbn0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IEFjdGlvbkNhdGVnb3J5LCBJQWN0aW9uLCBJUGlwZWxpbmUsIElTdGFnZSwgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMsIFBpcGVsaW5lTm90aWZ5T25PcHRpb25zIH0gZnJvbSAnLi9hY3Rpb24nO1xuaW1wb3J0IHsgQ2ZuUGlwZWxpbmUgfSBmcm9tICcuL2NvZGVwaXBlbGluZS5nZW5lcmF0ZWQnO1xuaW1wb3J0IHsgQ3Jvc3NSZWdpb25TdXBwb3J0Q29uc3RydWN0LCBDcm9zc1JlZ2lvblN1cHBvcnRTdGFjayB9IGZyb20gJy4vcHJpdmF0ZS9jcm9zcy1yZWdpb24tc3VwcG9ydC1zdGFjayc7XG5pbXBvcnQgeyBGdWxsQWN0aW9uRGVzY3JpcHRvciB9IGZyb20gJy4vcHJpdmF0ZS9mdWxsLWFjdGlvbi1kZXNjcmlwdG9yJztcbmltcG9ydCB7IFJpY2hBY3Rpb24gfSBmcm9tICcuL3ByaXZhdGUvcmljaC1hY3Rpb24nO1xuaW1wb3J0IHsgU3RhZ2UgfSBmcm9tICcuL3ByaXZhdGUvc3RhZ2UnO1xuaW1wb3J0IHsgdmFsaWRhdGVOYW1lLCB2YWxpZGF0ZU5hbWVzcGFjZU5hbWUsIHZhbGlkYXRlU291cmNlQWN0aW9uIH0gZnJvbSAnLi9wcml2YXRlL3ZhbGlkYXRpb24nO1xuXG4vLyBrZWVwIHRoaXMgaW1wb3J0IHNlcGFyYXRlIGZyb20gb3RoZXIgaW1wb3J0cyB0byByZWR1Y2UgY2hhbmNlIGZvciBtZXJnZSBjb25mbGljdHMgd2l0aCB2Mi1tYWluXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tZHVwbGljYXRlLWltcG9ydHMsIGltcG9ydC9vcmRlclxuaW1wb3J0IHsgQ29uc3RydWN0IGFzIENvcmVDb25zdHJ1Y3QgfSBmcm9tICdAYXdzLWNkay9jb3JlJztcblxuLyoqXG4gKiBBbGxvd3MgeW91IHRvIGNvbnRyb2wgd2hlcmUgdG8gcGxhY2UgYSBuZXcgU3RhZ2Ugd2hlbiBpdCdzIGFkZGVkIHRvIHRoZSBQaXBlbGluZS5cbiAqIE5vdGUgdGhhdCB5b3UgY2FuIHByb3ZpZGUgb25seSBvbmUgb2YgdGhlIGJlbG93IHByb3BlcnRpZXMgLVxuICogc3BlY2lmeWluZyBtb3JlIHRoYW4gb25lIHdpbGwgcmVzdWx0IGluIGEgdmFsaWRhdGlvbiBlcnJvci5cbiAqXG4gKiBAc2VlICNyaWdodEJlZm9yZVxuICogQHNlZSAjanVzdEFmdGVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhZ2VQbGFjZW1lbnQge1xuICAvKipcbiAgICogSW5zZXJ0cyB0aGUgbmV3IFN0YWdlIGFzIGEgcGFyZW50IG9mIHRoZSBnaXZlbiBTdGFnZVxuICAgKiAoY2hhbmdpbmcgaXRzIGN1cnJlbnQgcGFyZW50IFN0YWdlLCBpZiBpdCBoYWQgb25lKS5cbiAgICovXG4gIHJlYWRvbmx5IHJpZ2h0QmVmb3JlPzogSVN0YWdlO1xuXG4gIC8qKlxuICAgKiBJbnNlcnRzIHRoZSBuZXcgU3RhZ2UgYXMgYSBjaGlsZCBvZiB0aGUgZ2l2ZW4gU3RhZ2VcbiAgICogKGNoYW5naW5nIGl0cyBjdXJyZW50IGNoaWxkIFN0YWdlLCBpZiBpdCBoYWQgb25lKS5cbiAgICovXG4gIHJlYWRvbmx5IGp1c3RBZnRlcj86IElTdGFnZTtcbn1cblxuLyoqXG4gKiBDb25zdHJ1Y3Rpb24gcHJvcGVydGllcyBvZiBhIFBpcGVsaW5lIFN0YWdlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0YWdlUHJvcHMge1xuICAvKipcbiAgICogVGhlIHBoeXNpY2FsLCBodW1hbi1yZWFkYWJsZSBuYW1lIHRvIGFzc2lnbiB0byB0aGlzIFBpcGVsaW5lIFN0YWdlLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhZ2VOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBsaXN0IG9mIEFjdGlvbnMgdG8gY3JlYXRlIHRoaXMgU3RhZ2Ugd2l0aC5cbiAgICogWW91IGNhbiBhbHdheXMgYWRkIG1vcmUgQWN0aW9ucyBsYXRlciBieSBjYWxsaW5nIHtAbGluayBJU3RhZ2UjYWRkQWN0aW9ufS5cbiAgICovXG4gIHJlYWRvbmx5IGFjdGlvbnM/OiBJQWN0aW9uW107XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZW5hYmxlIHRyYW5zaXRpb24gdG8gdGhpcyBzdGFnZS5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgdHJhbnNpdGlvblRvRW5hYmxlZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSByZWFzb24gZm9yIGRpc2FibGluZyB0cmFuc2l0aW9uIHRvIHRoaXMgc3RhZ2UuIE9ubHkgYXBwbGljYWJsZVxuICAgKiBpZiBgdHJhbnNpdGlvblRvRW5hYmxlZGAgaXMgc2V0IHRvIGBmYWxzZWAuXG4gICAqXG4gICAqIEBkZWZhdWx0ICdUcmFuc2l0aW9uIGRpc2FibGVkJ1xuICAgKi9cbiAgcmVhZG9ubHkgdHJhbnNpdGlvbkRpc2FibGVkUmVhc29uPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN0YWdlT3B0aW9ucyBleHRlbmRzIFN0YWdlUHJvcHMge1xuICByZWFkb25seSBwbGFjZW1lbnQ/OiBTdGFnZVBsYWNlbWVudDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQaXBlbGluZVByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBTMyBidWNrZXQgdXNlZCBieSB0aGlzIFBpcGVsaW5lIHRvIHN0b3JlIGFydGlmYWN0cy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBIG5ldyBTMyBidWNrZXQgd2lsbCBiZSBjcmVhdGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgYXJ0aWZhY3RCdWNrZXQ/OiBzMy5JQnVja2V0O1xuXG4gIC8qKlxuICAgKiBUaGUgSUFNIHJvbGUgdG8gYmUgYXNzdW1lZCBieSB0aGlzIFBpcGVsaW5lLlxuICAgKlxuICAgKiBAZGVmYXVsdCBhIG5ldyBJQU0gcm9sZSB3aWxsIGJlIGNyZWF0ZWQuXG4gICAqL1xuICByZWFkb25seSByb2xlPzogaWFtLklSb2xlO1xuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgd2hldGhlciB0byByZXJ1biB0aGUgQVdTIENvZGVQaXBlbGluZSBwaXBlbGluZSBhZnRlciB5b3UgdXBkYXRlIGl0LlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgcmVzdGFydEV4ZWN1dGlvbk9uVXBkYXRlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogTmFtZSBvZiB0aGUgcGlwZWxpbmUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQVdTIENsb3VkRm9ybWF0aW9uIGdlbmVyYXRlcyBhbiBJRCBhbmQgdXNlcyB0aGF0IGZvciB0aGUgcGlwZWxpbmUgbmFtZS5cbiAgICovXG4gIHJlYWRvbmx5IHBpcGVsaW5lTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogQSBtYXAgb2YgcmVnaW9uIHRvIFMzIGJ1Y2tldCBuYW1lIHVzZWQgZm9yIGNyb3NzLXJlZ2lvbiBDb2RlUGlwZWxpbmUuXG4gICAqIEZvciBldmVyeSBBY3Rpb24gdGhhdCB5b3Ugc3BlY2lmeSB0YXJnZXRpbmcgYSBkaWZmZXJlbnQgcmVnaW9uIHRoYW4gdGhlIFBpcGVsaW5lIGl0c2VsZixcbiAgICogaWYgeW91IGRvbid0IHByb3ZpZGUgYW4gZXhwbGljaXQgQnVja2V0IGZvciB0aGF0IHJlZ2lvbiB1c2luZyB0aGlzIHByb3BlcnR5LFxuICAgKiB0aGUgY29uc3RydWN0IHdpbGwgYXV0b21hdGljYWxseSBjcmVhdGUgYSBTdGFjayBjb250YWluaW5nIGFuIFMzIEJ1Y2tldCBpbiB0aGF0IHJlZ2lvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBOb25lLlxuICAgKi9cbiAgcmVhZG9ubHkgY3Jvc3NSZWdpb25SZXBsaWNhdGlvbkJ1Y2tldHM/OiB7IFtyZWdpb246IHN0cmluZ106IHMzLklCdWNrZXQgfTtcblxuICAvKipcbiAgICogVGhlIGxpc3Qgb2YgU3RhZ2VzLCBpbiBvcmRlcixcbiAgICogdG8gY3JlYXRlIHRoaXMgUGlwZWxpbmUgd2l0aC5cbiAgICogWW91IGNhbiBhbHdheXMgYWRkIG1vcmUgU3RhZ2VzIGxhdGVyIGJ5IGNhbGxpbmcge0BsaW5rIFBpcGVsaW5lI2FkZFN0YWdlfS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBOb25lLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhZ2VzPzogU3RhZ2VQcm9wc1tdO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgS01TIGtleXMgZm9yIGNyb3NzLWFjY291bnQgZGVwbG95bWVudHMuXG4gICAqXG4gICAqIFRoaXMgY29udHJvbHMgd2hldGhlciB0aGUgcGlwZWxpbmUgaXMgZW5hYmxlZCBmb3IgY3Jvc3MtYWNjb3VudCBkZXBsb3ltZW50cy5cbiAgICpcbiAgICogQnkgZGVmYXVsdCBjcm9zcy1hY2NvdW50IGRlcGxveW1lbnRzIGFyZSBlbmFibGVkLCBidXQgdGhpcyBmZWF0dXJlIHJlcXVpcmVzXG4gICAqIHRoYXQgS01TIEN1c3RvbWVyIE1hc3RlciBLZXlzIGFyZSBjcmVhdGVkIHdoaWNoIGhhdmUgYSBjb3N0IG9mICQxL21vbnRoLlxuICAgKlxuICAgKiBJZiB5b3UgZG8gbm90IG5lZWQgY3Jvc3MtYWNjb3VudCBkZXBsb3ltZW50cywgeW91IGNhbiBzZXQgdGhpcyB0byBgZmFsc2VgIHRvXG4gICAqIG5vdCBjcmVhdGUgdGhvc2Uga2V5cyBhbmQgc2F2ZSBvbiB0aGF0IGNvc3QgKHRoZSBhcnRpZmFjdCBidWNrZXQgd2lsbCBiZVxuICAgKiBlbmNyeXB0ZWQgd2l0aCBhbiBBV1MtbWFuYWdlZCBrZXkpLiBIb3dldmVyLCBjcm9zcy1hY2NvdW50IGRlcGxveW1lbnRzIHdpbGxcbiAgICogbm8gbG9uZ2VyIGJlIHBvc3NpYmxlLlxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBjcm9zc0FjY291bnRLZXlzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRW5hYmxlIEtNUyBrZXkgcm90YXRpb24gZm9yIHRoZSBnZW5lcmF0ZWQgS01TIGtleXMuXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQgS01TIGtleSByb3RhdGlvbiBpcyBkaXNhYmxlZCwgYnV0IHdpbGwgYWRkIGFuIGFkZGl0aW9uYWwgJDEvbW9udGhcbiAgICogZm9yIGVhY2ggeWVhciB0aGUga2V5IGV4aXN0cyB3aGVuIGVuYWJsZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gZmFsc2UgKGtleSByb3RhdGlvbiBpcyBkaXNhYmxlZClcbiAgICovXG4gIHJlYWRvbmx5IGVuYWJsZUtleVJvdGF0aW9uPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUmV1c2UgdGhlIHNhbWUgY3Jvc3MgcmVnaW9uIHN1cHBvcnQgc3RhY2sgZm9yIGFsbCBwaXBlbGluZXMgaW4gdGhlIEFwcC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSB0cnVlIChVc2UgdGhlIHNhbWUgc3VwcG9ydCBzdGFjayBmb3IgYWxsIHBpcGVsaW5lcyBpbiBBcHApXG4gICAqL1xuICByZWFkb25seSByZXVzZUNyb3NzUmVnaW9uU3VwcG9ydFN0YWNrcz86IGJvb2xlYW47XG59XG5cbmFic3RyYWN0IGNsYXNzIFBpcGVsaW5lQmFzZSBleHRlbmRzIFJlc291cmNlIGltcGxlbWVudHMgSVBpcGVsaW5lIHtcbiAgcHVibGljIGFic3RyYWN0IHJlYWRvbmx5IHBpcGVsaW5lTmFtZTogc3RyaW5nO1xuICBwdWJsaWMgYWJzdHJhY3QgcmVhZG9ubHkgcGlwZWxpbmVBcm46IHN0cmluZztcblxuICAvKipcbiAgICogRGVmaW5lcyBhbiBldmVudCBydWxlIHRyaWdnZXJlZCBieSB0aGlzIENvZGVQaXBlbGluZS5cbiAgICpcbiAgICogQHBhcmFtIGlkIElkZW50aWZpZXIgZm9yIHRoaXMgZXZlbnQgaGFuZGxlci5cbiAgICogQHBhcmFtIG9wdGlvbnMgQWRkaXRpb25hbCBvcHRpb25zIHRvIHBhc3MgdG8gdGhlIGV2ZW50IHJ1bGUuXG4gICAqL1xuICBwdWJsaWMgb25FdmVudChpZDogc3RyaW5nLCBvcHRpb25zOiBldmVudHMuT25FdmVudE9wdGlvbnMgPSB7fSk6IGV2ZW50cy5SdWxlIHtcbiAgICBjb25zdCBydWxlID0gbmV3IGV2ZW50cy5SdWxlKHRoaXMsIGlkLCBvcHRpb25zKTtcbiAgICBydWxlLmFkZFRhcmdldChvcHRpb25zLnRhcmdldCk7XG4gICAgcnVsZS5hZGRFdmVudFBhdHRlcm4oe1xuICAgICAgc291cmNlOiBbJ2F3cy5jb2RlcGlwZWxpbmUnXSxcbiAgICAgIHJlc291cmNlczogW3RoaXMucGlwZWxpbmVBcm5dLFxuICAgIH0pO1xuICAgIHJldHVybiBydWxlO1xuICB9XG5cbiAgLyoqXG4gICAqIERlZmluZXMgYW4gZXZlbnQgcnVsZSB0cmlnZ2VyZWQgYnkgdGhlIFwiQ29kZVBpcGVsaW5lIFBpcGVsaW5lIEV4ZWN1dGlvblxuICAgKiBTdGF0ZSBDaGFuZ2VcIiBldmVudCBlbWl0dGVkIGZyb20gdGhpcyBwaXBlbGluZS5cbiAgICpcbiAgICogQHBhcmFtIGlkIElkZW50aWZpZXIgZm9yIHRoaXMgZXZlbnQgaGFuZGxlci5cbiAgICogQHBhcmFtIG9wdGlvbnMgQWRkaXRpb25hbCBvcHRpb25zIHRvIHBhc3MgdG8gdGhlIGV2ZW50IHJ1bGUuXG4gICAqL1xuICBwdWJsaWMgb25TdGF0ZUNoYW5nZShpZDogc3RyaW5nLCBvcHRpb25zOiBldmVudHMuT25FdmVudE9wdGlvbnMgPSB7fSk6IGV2ZW50cy5SdWxlIHtcbiAgICBjb25zdCBydWxlID0gdGhpcy5vbkV2ZW50KGlkLCBvcHRpb25zKTtcbiAgICBydWxlLmFkZEV2ZW50UGF0dGVybih7XG4gICAgICBkZXRhaWxUeXBlOiBbJ0NvZGVQaXBlbGluZSBQaXBlbGluZSBFeGVjdXRpb24gU3RhdGUgQ2hhbmdlJ10sXG4gICAgfSk7XG4gICAgcmV0dXJuIHJ1bGU7XG4gIH1cblxuICBwdWJsaWMgYmluZEFzTm90aWZpY2F0aW9uUnVsZVNvdXJjZShfc2NvcGU6IENvbnN0cnVjdCk6IG5vdGlmaWNhdGlvbnMuTm90aWZpY2F0aW9uUnVsZVNvdXJjZUNvbmZpZyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNvdXJjZUFybjogdGhpcy5waXBlbGluZUFybixcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIG5vdGlmeU9uKFxuICAgIGlkOiBzdHJpbmcsXG4gICAgdGFyZ2V0OiBub3RpZmljYXRpb25zLklOb3RpZmljYXRpb25SdWxlVGFyZ2V0LFxuICAgIG9wdGlvbnM6IFBpcGVsaW5lTm90aWZ5T25PcHRpb25zLFxuICApOiBub3RpZmljYXRpb25zLklOb3RpZmljYXRpb25SdWxlIHtcbiAgICByZXR1cm4gbmV3IG5vdGlmaWNhdGlvbnMuTm90aWZpY2F0aW9uUnVsZSh0aGlzLCBpZCwge1xuICAgICAgLi4ub3B0aW9ucyxcbiAgICAgIHNvdXJjZTogdGhpcyxcbiAgICAgIHRhcmdldHM6IFt0YXJnZXRdLFxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIG5vdGlmeU9uRXhlY3V0aW9uU3RhdGVDaGFuZ2UoXG4gICAgaWQ6IHN0cmluZyxcbiAgICB0YXJnZXQ6IG5vdGlmaWNhdGlvbnMuSU5vdGlmaWNhdGlvblJ1bGVUYXJnZXQsXG4gICAgb3B0aW9ucz86IG5vdGlmaWNhdGlvbnMuTm90aWZpY2F0aW9uUnVsZU9wdGlvbnMsXG4gICk6IG5vdGlmaWNhdGlvbnMuSU5vdGlmaWNhdGlvblJ1bGUge1xuICAgIHJldHVybiB0aGlzLm5vdGlmeU9uKGlkLCB0YXJnZXQsIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBldmVudHM6IFtcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuUElQRUxJTkVfRVhFQ1VUSU9OX0ZBSUxFRCxcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuUElQRUxJTkVfRVhFQ1VUSU9OX0NBTkNFTEVELFxuICAgICAgICBQaXBlbGluZU5vdGlmaWNhdGlvbkV2ZW50cy5QSVBFTElORV9FWEVDVVRJT05fU1RBUlRFRCxcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuUElQRUxJTkVfRVhFQ1VUSU9OX1JFU1VNRUQsXG4gICAgICAgIFBpcGVsaW5lTm90aWZpY2F0aW9uRXZlbnRzLlBJUEVMSU5FX0VYRUNVVElPTl9TVUNDRUVERUQsXG4gICAgICAgIFBpcGVsaW5lTm90aWZpY2F0aW9uRXZlbnRzLlBJUEVMSU5FX0VYRUNVVElPTl9TVVBFUlNFREVELFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBub3RpZnlPbkFueVN0YWdlU3RhdGVDaGFuZ2UoXG4gICAgaWQ6IHN0cmluZyxcbiAgICB0YXJnZXQ6IG5vdGlmaWNhdGlvbnMuSU5vdGlmaWNhdGlvblJ1bGVUYXJnZXQsXG4gICAgb3B0aW9ucz86IG5vdGlmaWNhdGlvbnMuTm90aWZpY2F0aW9uUnVsZU9wdGlvbnMsXG4gICk6IG5vdGlmaWNhdGlvbnMuSU5vdGlmaWNhdGlvblJ1bGUge1xuICAgIHJldHVybiB0aGlzLm5vdGlmeU9uKGlkLCB0YXJnZXQsIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBldmVudHM6IFtcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuU1RBR0VfRVhFQ1VUSU9OX0NBTkNFTEVELFxuICAgICAgICBQaXBlbGluZU5vdGlmaWNhdGlvbkV2ZW50cy5TVEFHRV9FWEVDVVRJT05fRkFJTEVELFxuICAgICAgICBQaXBlbGluZU5vdGlmaWNhdGlvbkV2ZW50cy5TVEFHRV9FWEVDVVRJT05fUkVTVU1FRCxcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuU1RBR0VfRVhFQ1VUSU9OX1NUQVJURUQsXG4gICAgICAgIFBpcGVsaW5lTm90aWZpY2F0aW9uRXZlbnRzLlNUQUdFX0VYRUNVVElPTl9TVUNDRUVERUQsXG4gICAgICBdLFxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIG5vdGlmeU9uQW55QWN0aW9uU3RhdGVDaGFuZ2UoXG4gICAgaWQ6IHN0cmluZyxcbiAgICB0YXJnZXQ6IG5vdGlmaWNhdGlvbnMuSU5vdGlmaWNhdGlvblJ1bGVUYXJnZXQsXG4gICAgb3B0aW9ucz86IG5vdGlmaWNhdGlvbnMuTm90aWZpY2F0aW9uUnVsZU9wdGlvbnMsXG4gICk6IG5vdGlmaWNhdGlvbnMuSU5vdGlmaWNhdGlvblJ1bGUge1xuICAgIHJldHVybiB0aGlzLm5vdGlmeU9uKGlkLCB0YXJnZXQsIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBldmVudHM6IFtcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuQUNUSU9OX0VYRUNVVElPTl9DQU5DRUxFRCxcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuQUNUSU9OX0VYRUNVVElPTl9GQUlMRUQsXG4gICAgICAgIFBpcGVsaW5lTm90aWZpY2F0aW9uRXZlbnRzLkFDVElPTl9FWEVDVVRJT05fU1RBUlRFRCxcbiAgICAgICAgUGlwZWxpbmVOb3RpZmljYXRpb25FdmVudHMuQUNUSU9OX0VYRUNVVElPTl9TVUNDRUVERUQsXG4gICAgICBdLFxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIG5vdGlmeU9uQW55TWFudWFsQXBwcm92YWxTdGF0ZUNoYW5nZShcbiAgICBpZDogc3RyaW5nLFxuICAgIHRhcmdldDogbm90aWZpY2F0aW9ucy5JTm90aWZpY2F0aW9uUnVsZVRhcmdldCxcbiAgICBvcHRpb25zPzogbm90aWZpY2F0aW9ucy5Ob3RpZmljYXRpb25SdWxlT3B0aW9ucyxcbiAgKTogbm90aWZpY2F0aW9ucy5JTm90aWZpY2F0aW9uUnVsZSB7XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5T24oaWQsIHRhcmdldCwge1xuICAgICAgLi4ub3B0aW9ucyxcbiAgICAgIGV2ZW50czogW1xuICAgICAgICBQaXBlbGluZU5vdGlmaWNhdGlvbkV2ZW50cy5NQU5VQUxfQVBQUk9WQUxfRkFJTEVELFxuICAgICAgICBQaXBlbGluZU5vdGlmaWNhdGlvbkV2ZW50cy5NQU5VQUxfQVBQUk9WQUxfTkVFREVELFxuICAgICAgICBQaXBlbGluZU5vdGlmaWNhdGlvbkV2ZW50cy5NQU5VQUxfQVBQUk9WQUxfU1VDQ0VFREVELFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxufVxuXG4vKipcbiAqIEFuIEFXUyBDb2RlUGlwZWxpbmUgcGlwZWxpbmUgd2l0aCBpdHMgYXNzb2NpYXRlZCBJQU0gcm9sZSBhbmQgUzMgYnVja2V0LlxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBjcmVhdGUgYSBwaXBlbGluZVxuICogaW1wb3J0ICogYXMgY29kZWNvbW1pdCBmcm9tICdAYXdzLWNkay9hd3MtY29kZWNvbW1pdCc7XG4gKlxuICogY29uc3QgcGlwZWxpbmUgPSBuZXcgY29kZXBpcGVsaW5lLlBpcGVsaW5lKHRoaXMsICdQaXBlbGluZScpO1xuICpcbiAqIC8vIGFkZCBhIHN0YWdlXG4gKiBjb25zdCBzb3VyY2VTdGFnZSA9IHBpcGVsaW5lLmFkZFN0YWdlKHsgc3RhZ2VOYW1lOiAnU291cmNlJyB9KTtcbiAqXG4gKiAvLyBhZGQgYSBzb3VyY2UgYWN0aW9uIHRvIHRoZSBzdGFnZVxuICogZGVjbGFyZSBjb25zdCByZXBvOiBjb2RlY29tbWl0LlJlcG9zaXRvcnk7XG4gKiBkZWNsYXJlIGNvbnN0IHNvdXJjZUFydGlmYWN0OiBjb2RlcGlwZWxpbmUuQXJ0aWZhY3Q7XG4gKiBzb3VyY2VTdGFnZS5hZGRBY3Rpb24obmV3IGNvZGVwaXBlbGluZV9hY3Rpb25zLkNvZGVDb21taXRTb3VyY2VBY3Rpb24oe1xuICogICBhY3Rpb25OYW1lOiAnU291cmNlJyxcbiAqICAgb3V0cHV0OiBzb3VyY2VBcnRpZmFjdCxcbiAqICAgcmVwb3NpdG9yeTogcmVwbyxcbiAqIH0pKTtcbiAqXG4gKiAvLyAuLi4gYWRkIG1vcmUgc3RhZ2VzXG4gKi9cbmV4cG9ydCBjbGFzcyBQaXBlbGluZSBleHRlbmRzIFBpcGVsaW5lQmFzZSB7XG4gIC8qKlxuICAgKiBJbXBvcnQgYSBwaXBlbGluZSBpbnRvIHRoaXMgYXBwLlxuICAgKlxuICAgKiBAcGFyYW0gc2NvcGUgdGhlIHNjb3BlIGludG8gd2hpY2ggdG8gaW1wb3J0IHRoaXMgcGlwZWxpbmVcbiAgICogQHBhcmFtIGlkIHRoZSBsb2dpY2FsIElEIG9mIHRoZSByZXR1cm5lZCBwaXBlbGluZSBjb25zdHJ1Y3RcbiAgICogQHBhcmFtIHBpcGVsaW5lQXJuIFRoZSBBUk4gb2YgdGhlIHBpcGVsaW5lIChlLmcuIGBhcm46YXdzOmNvZGVwaXBlbGluZTp1cy1lYXN0LTE6MTIzNDU2Nzg5MDEyOk15RGVtb1BpcGVsaW5lYClcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVBpcGVsaW5lQXJuKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHBpcGVsaW5lQXJuOiBzdHJpbmcpOiBJUGlwZWxpbmUge1xuICAgIGNsYXNzIEltcG9ydCBleHRlbmRzIFBpcGVsaW5lQmFzZSB7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgcGlwZWxpbmVOYW1lID0gU3RhY2sub2Yoc2NvcGUpLnNwbGl0QXJuKHBpcGVsaW5lQXJuLCBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSkucmVzb3VyY2U7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgcGlwZWxpbmVBcm4gPSBwaXBlbGluZUFybjtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IEltcG9ydChzY29wZSwgaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBJQU0gcm9sZSBBV1MgQ29kZVBpcGVsaW5lIHdpbGwgdXNlIHRvIHBlcmZvcm0gYWN0aW9ucyBvciBhc3N1bWUgcm9sZXMgZm9yIGFjdGlvbnMgd2l0aFxuICAgKiBhIG1vcmUgc3BlY2lmaWMgSUFNIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcm9sZTogaWFtLklSb2xlO1xuXG4gIC8qKlxuICAgKiBBUk4gb2YgdGhpcyBwaXBlbGluZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBpcGVsaW5lQXJuOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBwaXBlbGluZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBpcGVsaW5lTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgdmVyc2lvbiBvZiB0aGUgcGlwZWxpbmVcbiAgICpcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBpcGVsaW5lVmVyc2lvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBCdWNrZXQgdXNlZCB0byBzdG9yZSBvdXRwdXQgYXJ0aWZhY3RzXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYXJ0aWZhY3RCdWNrZXQ6IHMzLklCdWNrZXQ7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfc3RhZ2VzID0gbmV3IEFycmF5PFN0YWdlPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGNyb3NzUmVnaW9uQnVja2V0c1Bhc3NlZDogYm9vbGVhbjtcbiAgcHJpdmF0ZSByZWFkb25seSBfY3Jvc3NSZWdpb25TdXBwb3J0OiB7IFtyZWdpb246IHN0cmluZ106IENyb3NzUmVnaW9uU3VwcG9ydCB9ID0ge307XG4gIHByaXZhdGUgcmVhZG9ubHkgX2Nyb3NzQWNjb3VudFN1cHBvcnQ6IHsgW2FjY291bnQ6IHN0cmluZ106IFN0YWNrIH0gPSB7fTtcbiAgcHJpdmF0ZSByZWFkb25seSBjcm9zc0FjY291bnRLZXlzOiBib29sZWFuO1xuICBwcml2YXRlIHJlYWRvbmx5IGVuYWJsZUtleVJvdGF0aW9uPzogYm9vbGVhbjtcbiAgcHJpdmF0ZSByZWFkb25seSByZXVzZUNyb3NzUmVnaW9uU3VwcG9ydFN0YWNrczogYm9vbGVhbjtcbiAgcHJpdmF0ZSByZWFkb25seSBjb2RlUGlwZWxpbmU6IENmblBpcGVsaW5lO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBQaXBlbGluZVByb3BzID0ge30pIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIHBoeXNpY2FsTmFtZTogcHJvcHMucGlwZWxpbmVOYW1lLFxuICAgIH0pO1xuXG4gICAgdmFsaWRhdGVOYW1lKCdQaXBlbGluZScsIHRoaXMucGh5c2ljYWxOYW1lKTtcblxuICAgIC8vIG9ubHkgb25lIG9mIGFydGlmYWN0QnVja2V0IGFuZCBjcm9zc1JlZ2lvblJlcGxpY2F0aW9uQnVja2V0cyBjYW4gYmUgc3VwcGxpZWRcbiAgICBpZiAocHJvcHMuYXJ0aWZhY3RCdWNrZXQgJiYgcHJvcHMuY3Jvc3NSZWdpb25SZXBsaWNhdGlvbkJ1Y2tldHMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignT25seSBvbmUgb2YgYXJ0aWZhY3RCdWNrZXQgYW5kIGNyb3NzUmVnaW9uUmVwbGljYXRpb25CdWNrZXRzIGNhbiBiZSBzcGVjaWZpZWQhJyk7XG4gICAgfVxuXG4gICAgLy8gQGRlcHJlY2F0ZWQodjIpOiBzd2l0Y2ggdG8gZGVmYXVsdCBmYWxzZVxuICAgIHRoaXMuY3Jvc3NBY2NvdW50S2V5cyA9IHByb3BzLmNyb3NzQWNjb3VudEtleXMgPz8gdHJ1ZTtcbiAgICB0aGlzLmVuYWJsZUtleVJvdGF0aW9uID0gcHJvcHMuZW5hYmxlS2V5Um90YXRpb247XG5cbiAgICAvLyBDcm9zcyBhY2NvdW50IGtleXMgbXVzdCBiZSBzZXQgZm9yIGtleSByb3RhdGlvbiB0byBiZSBlbmFibGVkXG4gICAgaWYgKHRoaXMuZW5hYmxlS2V5Um90YXRpb24gJiYgIXRoaXMuY3Jvc3NBY2NvdW50S2V5cykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2V0dGluZyAnZW5hYmxlS2V5Um90YXRpb24nIHRvIHRydWUgYWxzbyByZXF1aXJlcyAnY3Jvc3NBY2NvdW50S2V5cycgdG8gYmUgZW5hYmxlZFwiKTtcbiAgICB9XG5cbiAgICB0aGlzLnJldXNlQ3Jvc3NSZWdpb25TdXBwb3J0U3RhY2tzID0gcHJvcHMucmV1c2VDcm9zc1JlZ2lvblN1cHBvcnRTdGFja3MgPz8gdHJ1ZTtcblxuICAgIC8vIElmIGEgYnVja2V0IGhhcyBiZWVuIHByb3ZpZGVkLCB1c2UgaXQgLSBvdGhlcndpc2UsIGNyZWF0ZSBhIGJ1Y2tldC5cbiAgICBsZXQgcHJvcHNCdWNrZXQgPSB0aGlzLmdldEFydGlmYWN0QnVja2V0RnJvbVByb3BzKHByb3BzKTtcblxuICAgIGlmICghcHJvcHNCdWNrZXQpIHtcbiAgICAgIGxldCBlbmNyeXB0aW9uS2V5O1xuXG4gICAgICBpZiAodGhpcy5jcm9zc0FjY291bnRLZXlzKSB7XG4gICAgICAgIGVuY3J5cHRpb25LZXkgPSBuZXcga21zLktleSh0aGlzLCAnQXJ0aWZhY3RzQnVja2V0RW5jcnlwdGlvbktleScsIHtcbiAgICAgICAgICAvLyByZW1vdmUgdGhlIGtleSAtIHRoZXJlIGlzIGEgZ3JhY2UgcGVyaW9kIG9mIGEgZmV3IGRheXMgYmVmb3JlIGl0J3MgZ29uZSBmb3IgZ29vZCxcbiAgICAgICAgICAvLyB0aGF0IHNob3VsZCBiZSBlbm91Z2ggZm9yIGFueSBlbWVyZ2VuY3kgYWNjZXNzIHRvIHRoZSBidWNrZXQgYXJ0aWZhY3RzXG4gICAgICAgICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgICAgIGVuYWJsZUtleVJvdGF0aW9uOiB0aGlzLmVuYWJsZUtleVJvdGF0aW9uLFxuICAgICAgICB9KTtcbiAgICAgICAgLy8gYWRkIGFuIGFsaWFzIHRvIG1ha2UgZmluZGluZyB0aGUga2V5IGluIHRoZSBjb25zb2xlIGVhc2llclxuICAgICAgICBuZXcga21zLkFsaWFzKHRoaXMsICdBcnRpZmFjdHNCdWNrZXRFbmNyeXB0aW9uS2V5QWxpYXMnLCB7XG4gICAgICAgICAgYWxpYXNOYW1lOiB0aGlzLmdlbmVyYXRlTmFtZUZvckRlZmF1bHRCdWNrZXRLZXlBbGlhcygpLFxuICAgICAgICAgIHRhcmdldEtleTogZW5jcnlwdGlvbktleSxcbiAgICAgICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksIC8vIGRlc3Ryb3kgdGhlIGFsaWFzIGFsb25nIHdpdGggdGhlIGtleVxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcHJvcHNCdWNrZXQgPSBuZXcgczMuQnVja2V0KHRoaXMsICdBcnRpZmFjdHNCdWNrZXQnLCB7XG4gICAgICAgIGJ1Y2tldE5hbWU6IFBoeXNpY2FsTmFtZS5HRU5FUkFURV9JRl9ORUVERUQsXG4gICAgICAgIGVuY3J5cHRpb25LZXksXG4gICAgICAgIGVuY3J5cHRpb246IGVuY3J5cHRpb25LZXkgPyBzMy5CdWNrZXRFbmNyeXB0aW9uLktNUyA6IHMzLkJ1Y2tldEVuY3J5cHRpb24uS01TX01BTkFHRUQsXG4gICAgICAgIGVuZm9yY2VTU0w6IHRydWUsXG4gICAgICAgIGJsb2NrUHVibGljQWNjZXNzOiBuZXcgczMuQmxvY2tQdWJsaWNBY2Nlc3MoczMuQmxvY2tQdWJsaWNBY2Nlc3MuQkxPQ0tfQUxMKSxcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5SRVRBSU4sXG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5hcnRpZmFjdEJ1Y2tldCA9IHByb3BzQnVja2V0O1xuXG4gICAgLy8gSWYgYSByb2xlIGhhcyBiZWVuIHByb3ZpZGVkLCB1c2UgaXQgLSBvdGhlcndpc2UsIGNyZWF0ZSBhIHJvbGUuXG4gICAgdGhpcy5yb2xlID0gcHJvcHMucm9sZSB8fCBuZXcgaWFtLlJvbGUodGhpcywgJ1JvbGUnLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnY29kZXBpcGVsaW5lLmFtYXpvbmF3cy5jb20nKSxcbiAgICB9KTtcblxuICAgIHRoaXMuY29kZVBpcGVsaW5lID0gbmV3IENmblBpcGVsaW5lKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIGFydGlmYWN0U3RvcmU6IExhenkuYW55KHsgcHJvZHVjZTogKCkgPT4gdGhpcy5yZW5kZXJBcnRpZmFjdFN0b3JlUHJvcGVydHkoKSB9KSxcbiAgICAgIGFydGlmYWN0U3RvcmVzOiBMYXp5LmFueSh7IHByb2R1Y2U6ICgpID0+IHRoaXMucmVuZGVyQXJ0aWZhY3RTdG9yZXNQcm9wZXJ0eSgpIH0pLFxuICAgICAgc3RhZ2VzOiBMYXp5LmFueSh7IHByb2R1Y2U6ICgpID0+IHRoaXMucmVuZGVyU3RhZ2VzKCkgfSksXG4gICAgICBkaXNhYmxlSW5ib3VuZFN0YWdlVHJhbnNpdGlvbnM6IExhenkuYW55KHsgcHJvZHVjZTogKCkgPT4gdGhpcy5yZW5kZXJEaXNhYmxlZFRyYW5zaXRpb25zKCkgfSwgeyBvbWl0RW1wdHlBcnJheTogdHJ1ZSB9KSxcbiAgICAgIHJvbGVBcm46IHRoaXMucm9sZS5yb2xlQXJuLFxuICAgICAgcmVzdGFydEV4ZWN1dGlvbk9uVXBkYXRlOiBwcm9wcyAmJiBwcm9wcy5yZXN0YXJ0RXhlY3V0aW9uT25VcGRhdGUsXG4gICAgICBuYW1lOiB0aGlzLnBoeXNpY2FsTmFtZSxcbiAgICB9KTtcblxuICAgIC8vIHRoaXMgd2lsbCBwcm9kdWNlIGEgRGVwZW5kc09uIGZvciBib3RoIHRoZSByb2xlIGFuZCB0aGUgcG9saWN5IHJlc291cmNlcy5cbiAgICB0aGlzLmNvZGVQaXBlbGluZS5ub2RlLmFkZERlcGVuZGVuY3kodGhpcy5yb2xlKTtcblxuICAgIHRoaXMuYXJ0aWZhY3RCdWNrZXQuZ3JhbnRSZWFkV3JpdGUodGhpcy5yb2xlKTtcbiAgICB0aGlzLnBpcGVsaW5lTmFtZSA9IHRoaXMuZ2V0UmVzb3VyY2VOYW1lQXR0cmlidXRlKHRoaXMuY29kZVBpcGVsaW5lLnJlZik7XG4gICAgdGhpcy5waXBlbGluZVZlcnNpb24gPSB0aGlzLmNvZGVQaXBlbGluZS5hdHRyVmVyc2lvbjtcbiAgICB0aGlzLmNyb3NzUmVnaW9uQnVja2V0c1Bhc3NlZCA9ICEhcHJvcHMuY3Jvc3NSZWdpb25SZXBsaWNhdGlvbkJ1Y2tldHM7XG5cbiAgICBmb3IgKGNvbnN0IFtyZWdpb24sIHJlcGxpY2F0aW9uQnVja2V0XSBvZiBPYmplY3QuZW50cmllcyhwcm9wcy5jcm9zc1JlZ2lvblJlcGxpY2F0aW9uQnVja2V0cyB8fCB7fSkpIHtcbiAgICAgIHRoaXMuX2Nyb3NzUmVnaW9uU3VwcG9ydFtyZWdpb25dID0ge1xuICAgICAgICByZXBsaWNhdGlvbkJ1Y2tldCxcbiAgICAgICAgc3RhY2s6IFN0YWNrLm9mKHJlcGxpY2F0aW9uQnVja2V0KSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gRG9lcyBub3QgZXhwb3NlIGEgRm46OkdldEF0dCBmb3IgdGhlIEFSTiBzbyB3ZSdsbCBoYXZlIHRvIG1ha2UgaXQgb3Vyc2VsdmVzXG4gICAgdGhpcy5waXBlbGluZUFybiA9IFN0YWNrLm9mKHRoaXMpLmZvcm1hdEFybih7XG4gICAgICBzZXJ2aWNlOiAnY29kZXBpcGVsaW5lJyxcbiAgICAgIHJlc291cmNlOiB0aGlzLnBpcGVsaW5lTmFtZSxcbiAgICB9KTtcblxuICAgIGZvciAoY29uc3Qgc3RhZ2Ugb2YgcHJvcHMuc3RhZ2VzIHx8IFtdKSB7XG4gICAgICB0aGlzLmFkZFN0YWdlKHN0YWdlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIG5ldyBTdGFnZSwgYW5kIGFkZHMgaXQgdG8gdGhpcyBQaXBlbGluZS5cbiAgICpcbiAgICogQHBhcmFtIHByb3BzIHRoZSBjcmVhdGlvbiBwcm9wZXJ0aWVzIG9mIHRoZSBuZXcgU3RhZ2VcbiAgICogQHJldHVybnMgdGhlIG5ld2x5IGNyZWF0ZWQgU3RhZ2VcbiAgICovXG4gIHB1YmxpYyBhZGRTdGFnZShwcm9wczogU3RhZ2VPcHRpb25zKTogSVN0YWdlIHtcbiAgICAvLyBjaGVjayBmb3IgZHVwbGljYXRlIFN0YWdlcyBhbmQgbmFtZXNcbiAgICBpZiAodGhpcy5fc3RhZ2VzLmZpbmQocyA9PiBzLnN0YWdlTmFtZSA9PT0gcHJvcHMuc3RhZ2VOYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBTdGFnZSB3aXRoIGR1cGxpY2F0ZSBuYW1lICcke3Byb3BzLnN0YWdlTmFtZX0nIGFkZGVkIHRvIHRoZSBQaXBlbGluZWApO1xuICAgIH1cblxuICAgIGNvbnN0IHN0YWdlID0gbmV3IFN0YWdlKHByb3BzLCB0aGlzKTtcblxuICAgIGNvbnN0IGluZGV4ID0gcHJvcHMucGxhY2VtZW50XG4gICAgICA/IHRoaXMuY2FsY3VsYXRlSW5zZXJ0SW5kZXhGcm9tUGxhY2VtZW50KHByb3BzLnBsYWNlbWVudClcbiAgICAgIDogdGhpcy5zdGFnZUNvdW50O1xuXG4gICAgdGhpcy5fc3RhZ2VzLnNwbGljZShpbmRleCwgMCwgc3RhZ2UpO1xuXG4gICAgcmV0dXJuIHN0YWdlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBzdGF0ZW1lbnQgdG8gdGhlIHBpcGVsaW5lIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgYWRkVG9Sb2xlUG9saWN5KHN0YXRlbWVudDogaWFtLlBvbGljeVN0YXRlbWVudCkge1xuICAgIHRoaXMucm9sZS5hZGRUb1ByaW5jaXBhbFBvbGljeShzdGF0ZW1lbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgbnVtYmVyIG9mIFN0YWdlcyBpbiB0aGlzIFBpcGVsaW5lLlxuICAgKi9cbiAgcHVibGljIGdldCBzdGFnZUNvdW50KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YWdlcy5sZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc3RhZ2VzIHRoYXQgY29tcHJpc2UgdGhlIHBpcGVsaW5lLlxuICAgKlxuICAgKiAqKk5vdGUqKjogdGhlIHJldHVybmVkIGFycmF5IGlzIGEgZGVmZW5zaXZlIGNvcHksXG4gICAqIHNvIGFkZGluZyBlbGVtZW50cyB0byBpdCBoYXMgbm8gZWZmZWN0LlxuICAgKiBJbnN0ZWFkLCB1c2UgdGhlIHtAbGluayBhZGRTdGFnZX0gbWV0aG9kIGlmIHlvdSB3YW50IHRvIGFkZCBtb3JlIHN0YWdlc1xuICAgKiB0byB0aGUgcGlwZWxpbmUuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHN0YWdlcygpOiBJU3RhZ2VbXSB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YWdlcy5zbGljZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFjY2VzcyBvbmUgb2YgdGhlIHBpcGVsaW5lJ3Mgc3RhZ2VzIGJ5IHN0YWdlIG5hbWVcbiAgICovXG4gIHB1YmxpYyBzdGFnZShzdGFnZU5hbWU6IHN0cmluZyk6IElTdGFnZSB7XG4gICAgZm9yIChjb25zdCBzdGFnZSBvZiB0aGlzLl9zdGFnZXMpIHtcbiAgICAgIGlmIChzdGFnZS5zdGFnZU5hbWUgPT09IHN0YWdlTmFtZSkge1xuICAgICAgICByZXR1cm4gc3RhZ2U7XG4gICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgUGlwZWxpbmUgZG9lcyBub3QgY29udGFpbiBhIHN0YWdlIG5hbWVkICcke3N0YWdlTmFtZX0nLiBBdmFpbGFibGUgc3RhZ2VzOiAke3RoaXMuX3N0YWdlcy5tYXAocyA9PiBzLnN0YWdlTmFtZSkuam9pbignLCAnKX1gKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFsbCBvZiB0aGUge0BsaW5rIENyb3NzUmVnaW9uU3VwcG9ydFN0YWNrfXMgdGhhdCB3ZXJlIGdlbmVyYXRlZCBhdXRvbWF0aWNhbGx5XG4gICAqIHdoZW4gZGVhbGluZyB3aXRoIEFjdGlvbnMgdGhhdCByZXNpZGUgaW4gYSBkaWZmZXJlbnQgcmVnaW9uIHRoYW4gdGhlIFBpcGVsaW5lIGl0c2VsZi5cbiAgICpcbiAgICovXG4gIHB1YmxpYyBnZXQgY3Jvc3NSZWdpb25TdXBwb3J0KCk6IHsgW3JlZ2lvbjogc3RyaW5nXTogQ3Jvc3NSZWdpb25TdXBwb3J0IH0ge1xuICAgIGNvbnN0IHJldDogeyBbcmVnaW9uOiBzdHJpbmddOiBDcm9zc1JlZ2lvblN1cHBvcnQgfSA9IHt9O1xuICAgIE9iamVjdC5rZXlzKHRoaXMuX2Nyb3NzUmVnaW9uU3VwcG9ydCkuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICByZXRba2V5XSA9IHRoaXMuX2Nyb3NzUmVnaW9uU3VwcG9ydFtrZXldO1xuICAgIH0pO1xuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIHB1YmxpYyBfYXR0YWNoQWN0aW9uVG9QaXBlbGluZShzdGFnZTogU3RhZ2UsIGFjdGlvbjogSUFjdGlvbiwgYWN0aW9uU2NvcGU6IENvbnN0cnVjdCk6IEZ1bGxBY3Rpb25EZXNjcmlwdG9yIHtcbiAgICBjb25zdCByaWNoQWN0aW9uID0gbmV3IFJpY2hBY3Rpb24oYWN0aW9uLCB0aGlzKTtcblxuICAgIC8vIGhhbmRsZSBjcm9zcy1yZWdpb24gYWN0aW9ucyBoZXJlXG4gICAgY29uc3QgY3Jvc3NSZWdpb25JbmZvID0gdGhpcy5lbnN1cmVSZXBsaWNhdGlvblJlc291cmNlc0V4aXN0Rm9yKHJpY2hBY3Rpb24pO1xuXG4gICAgLy8gZ2V0IHRoZSByb2xlIGZvciB0aGUgZ2l2ZW4gYWN0aW9uLCBoYW5kbGluZyBpZiBpdCdzIGNyb3NzLWFjY291bnRcbiAgICBjb25zdCBhY3Rpb25Sb2xlID0gdGhpcy5nZXRSb2xlRm9yQWN0aW9uKHN0YWdlLCByaWNoQWN0aW9uLCBhY3Rpb25TY29wZSk7XG5cbiAgICAvLyAvLyBDb2RlUGlwZWxpbmUgVmFyaWFibGVzXG4gICAgdmFsaWRhdGVOYW1lc3BhY2VOYW1lKHJpY2hBY3Rpb24uYWN0aW9uUHJvcGVydGllcy52YXJpYWJsZXNOYW1lc3BhY2UpO1xuXG4gICAgLy8gYmluZCB0aGUgQWN0aW9uICh0eXBlIGg0eClcbiAgICBjb25zdCBhY3Rpb25Db25maWcgPSByaWNoQWN0aW9uLmJpbmQoYWN0aW9uU2NvcGUgYXMgQ29yZUNvbnN0cnVjdCwgc3RhZ2UsIHtcbiAgICAgIHJvbGU6IGFjdGlvblJvbGUgPyBhY3Rpb25Sb2xlIDogdGhpcy5yb2xlLFxuICAgICAgYnVja2V0OiBjcm9zc1JlZ2lvbkluZm8uYXJ0aWZhY3RCdWNrZXQsXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbmV3IEZ1bGxBY3Rpb25EZXNjcmlwdG9yKHtcbiAgICAgIC8vIG11c3QgYmUgJ2FjdGlvbicsIG5vdCAncmljaEFjdGlvbicsXG4gICAgICAvLyBhcyB0aG9zZSBhcmUgcmV0dXJuZWQgYnkgdGhlIElTdGFnZS5hY3Rpb25zIHByb3BlcnR5LFxuICAgICAgLy8gYW5kIGl0J3MgaW1wb3J0YW50IGN1c3RvbWVycyBvZiBQaXBlbGluZSBnZXQgdGhlIHNhbWUgaW5zdGFuY2VcbiAgICAgIC8vIGJhY2sgYXMgdGhleSBhZGRlZCB0byB0aGUgcGlwZWxpbmVcbiAgICAgIGFjdGlvbixcbiAgICAgIGFjdGlvbkNvbmZpZyxcbiAgICAgIGFjdGlvblJvbGUsXG4gICAgICBhY3Rpb25SZWdpb246IGNyb3NzUmVnaW9uSW5mby5yZWdpb24sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGhlIHBpcGVsaW5lIHN0cnVjdHVyZVxuICAgKlxuICAgKiBWYWxpZGF0aW9uIGhhcHBlbnMgYWNjb3JkaW5nIHRvIHRoZSBydWxlcyBkb2N1bWVudGVkIGF0XG4gICAqXG4gICAqIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9jb2RlcGlwZWxpbmUvbGF0ZXN0L3VzZXJndWlkZS9yZWZlcmVuY2UtcGlwZWxpbmUtc3RydWN0dXJlLmh0bWwjcGlwZWxpbmUtcmVxdWlyZW1lbnRzXG4gICAqIEBvdmVycmlkZVxuICAgKi9cbiAgcHJvdGVjdGVkIHZhbGlkYXRlKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gW1xuICAgICAgLi4udGhpcy52YWxpZGF0ZVNvdXJjZUFjdGlvbkxvY2F0aW9ucygpLFxuICAgICAgLi4udGhpcy52YWxpZGF0ZUhhc1N0YWdlcygpLFxuICAgICAgLi4udGhpcy52YWxpZGF0ZVN0YWdlcygpLFxuICAgICAgLi4udGhpcy52YWxpZGF0ZUFydGlmYWN0cygpLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIGVuc3VyZVJlcGxpY2F0aW9uUmVzb3VyY2VzRXhpc3RGb3IoYWN0aW9uOiBSaWNoQWN0aW9uKTogQ3Jvc3NSZWdpb25JbmZvIHtcbiAgICBpZiAoIWFjdGlvbi5pc0Nyb3NzUmVnaW9uKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhcnRpZmFjdEJ1Y2tldDogdGhpcy5hcnRpZmFjdEJ1Y2tldCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gVGhlIGFjdGlvbiBoYXMgYSBzcGVjaWZpYyByZWdpb24sXG4gICAgLy8gcmVxdWlyZSB0aGUgcGlwZWxpbmUgdG8gaGF2ZSBhIGtub3duIHJlZ2lvbiBhcyB3ZWxsLlxuICAgIHRoaXMucmVxdWlyZVJlZ2lvbigpO1xuXG4gICAgLy8gc291cmNlIGFjdGlvbnMgaGF2ZSB0byBiZSBpbiB0aGUgc2FtZSByZWdpb24gYXMgdGhlIHBpcGVsaW5lXG4gICAgaWYgKGFjdGlvbi5hY3Rpb25Qcm9wZXJ0aWVzLmNhdGVnb3J5ID09PSBBY3Rpb25DYXRlZ29yeS5TT1VSQ0UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgU291cmNlIGFjdGlvbiAnJHthY3Rpb24uYWN0aW9uUHJvcGVydGllcy5hY3Rpb25OYW1lfScgbXVzdCBiZSBpbiB0aGUgc2FtZSByZWdpb24gYXMgdGhlIHBpcGVsaW5lYCk7XG4gICAgfVxuXG4gICAgLy8gY2hlY2sgd2hldGhlciB3ZSBhbHJlYWR5IGhhdmUgYSBidWNrZXQgaW4gdGhhdCByZWdpb24sXG4gICAgLy8gZWl0aGVyIHBhc3NlZCBmcm9tIHRoZSBvdXRzaWRlIG9yIHByZXZpb3VzbHkgY3JlYXRlZFxuICAgIGNvbnN0IGNyb3NzUmVnaW9uU3VwcG9ydCA9IHRoaXMub2J0YWluQ3Jvc3NSZWdpb25TdXBwb3J0Rm9yKGFjdGlvbik7XG5cbiAgICAvLyB0aGUgc3RhY2sgY29udGFpbmluZyB0aGUgcmVwbGljYXRpb24gYnVja2V0IG11c3QgYmUgZGVwbG95ZWQgYmVmb3JlIHRoZSBwaXBlbGluZVxuICAgIFN0YWNrLm9mKHRoaXMpLmFkZERlcGVuZGVuY3koY3Jvc3NSZWdpb25TdXBwb3J0LnN0YWNrKTtcbiAgICAvLyBUaGUgUGlwZWxpbmUgcm9sZSBtdXN0IGJlIGFibGUgdG8gcmVwbGljYXRlIHRvIHRoYXQgYnVja2V0XG4gICAgY3Jvc3NSZWdpb25TdXBwb3J0LnJlcGxpY2F0aW9uQnVja2V0LmdyYW50UmVhZFdyaXRlKHRoaXMucm9sZSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgYXJ0aWZhY3RCdWNrZXQ6IGNyb3NzUmVnaW9uU3VwcG9ydC5yZXBsaWNhdGlvbkJ1Y2tldCxcbiAgICAgIHJlZ2lvbjogYWN0aW9uLmVmZmVjdGl2ZVJlZ2lvbixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBvciBjcmVhdGUgdGhlIGNyb3NzLXJlZ2lvbiBzdXBwb3J0IGNvbnN0cnVjdCBmb3IgdGhlIGdpdmVuIGFjdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBvYnRhaW5Dcm9zc1JlZ2lvblN1cHBvcnRGb3IoYWN0aW9uOiBSaWNoQWN0aW9uKSB7XG4gICAgLy8gdGhpcyBtZXRob2QgaXMgbmV2ZXIgY2FsbGVkIGZvciBub24gY3Jvc3MtcmVnaW9uIGFjdGlvbnNcbiAgICBjb25zdCBhY3Rpb25SZWdpb24gPSBhY3Rpb24uZWZmZWN0aXZlUmVnaW9uITtcbiAgICBsZXQgY3Jvc3NSZWdpb25TdXBwb3J0ID0gdGhpcy5fY3Jvc3NSZWdpb25TdXBwb3J0W2FjdGlvblJlZ2lvbl07XG4gICAgaWYgKCFjcm9zc1JlZ2lvblN1cHBvcnQpIHtcbiAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHNjYWZmb2xkaW5nIHJlc291cmNlcyBmb3IgdGhpcyByZWdpb25cbiAgICAgIGNvbnN0IG90aGVyU3RhY2sgPSBhY3Rpb24ucmVzb3VyY2VTdGFjaztcbiAgICAgIGNyb3NzUmVnaW9uU3VwcG9ydCA9IHRoaXMuY3JlYXRlU3VwcG9ydFJlc291cmNlc0ZvclJlZ2lvbihvdGhlclN0YWNrLCBhY3Rpb25SZWdpb24pO1xuICAgICAgdGhpcy5fY3Jvc3NSZWdpb25TdXBwb3J0W2FjdGlvblJlZ2lvbl0gPSBjcm9zc1JlZ2lvblN1cHBvcnQ7XG4gICAgfVxuICAgIHJldHVybiBjcm9zc1JlZ2lvblN1cHBvcnQ7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVN1cHBvcnRSZXNvdXJjZXNGb3JSZWdpb24ob3RoZXJTdGFjazogU3RhY2sgfCB1bmRlZmluZWQsIGFjdGlvblJlZ2lvbjogc3RyaW5nKTogQ3Jvc3NSZWdpb25TdXBwb3J0IHtcbiAgICAvLyBpZiB3ZSBoYXZlIGEgc3RhY2sgZnJvbSB0aGUgcmVzb3VyY2UgcGFzc2VkIC0gdXNlIHRoYXQhXG4gICAgaWYgKG90aGVyU3RhY2spIHtcbiAgICAgIC8vIGNoZWNrIGlmIHRoZSBzdGFjayBkb2Vzbid0IGhhdmUgdGhpcyBtYWdpYyBjb25zdHJ1Y3QgYWxyZWFkeVxuICAgICAgY29uc3QgaWQgPSBgQ3Jvc3NSZWdpb25SZXBsaWNhdGlvblN1cHBvcnQtZDgyM2YxZDgtYTk5MC00ZTVjLWJlMTgtNGFjNjk4NTMyZTY1LSR7YWN0aW9uUmVnaW9ufWA7XG4gICAgICBsZXQgY3Jvc3NSZWdpb25TdXBwb3J0Q29uc3RydWN0ID0gb3RoZXJTdGFjay5ub2RlLnRyeUZpbmRDaGlsZChpZCkgYXMgQ3Jvc3NSZWdpb25TdXBwb3J0Q29uc3RydWN0O1xuICAgICAgaWYgKCFjcm9zc1JlZ2lvblN1cHBvcnRDb25zdHJ1Y3QpIHtcbiAgICAgICAgY3Jvc3NSZWdpb25TdXBwb3J0Q29uc3RydWN0ID0gbmV3IENyb3NzUmVnaW9uU3VwcG9ydENvbnN0cnVjdChvdGhlclN0YWNrLCBpZCwge1xuICAgICAgICAgIGNyZWF0ZUttc0tleTogdGhpcy5jcm9zc0FjY291bnRLZXlzLFxuICAgICAgICAgIGVuYWJsZUtleVJvdGF0aW9uOiB0aGlzLmVuYWJsZUtleVJvdGF0aW9uLFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcmVwbGljYXRpb25CdWNrZXQ6IGNyb3NzUmVnaW9uU3VwcG9ydENvbnN0cnVjdC5yZXBsaWNhdGlvbkJ1Y2tldCxcbiAgICAgICAgc3RhY2s6IG90aGVyU3RhY2ssXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIG90aGVyd2lzZSAtIGNyZWF0ZSBhIHN0YWNrIHdpdGggdGhlIHJlc291cmNlcyBuZWVkZWQgZm9yIHJlcGxpY2F0aW9uIGFjcm9zcyByZWdpb25zXG4gICAgY29uc3QgcGlwZWxpbmVTdGFjayA9IFN0YWNrLm9mKHRoaXMpO1xuICAgIGNvbnN0IHBpcGVsaW5lQWNjb3VudCA9IHBpcGVsaW5lU3RhY2suYWNjb3VudDtcbiAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKHBpcGVsaW5lQWNjb3VudCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIllvdSBuZWVkIHRvIHNwZWNpZnkgYW4gZXhwbGljaXQgYWNjb3VudCB3aGVuIHVzaW5nIENvZGVQaXBlbGluZSdzIGNyb3NzLXJlZ2lvbiBzdXBwb3J0XCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGFwcCA9IHRoaXMuc3VwcG9ydFNjb3BlKCk7XG4gICAgY29uc3Qgc3VwcG9ydFN0YWNrSWQgPSBgY3Jvc3MtcmVnaW9uLXN0YWNrLSR7dGhpcy5yZXVzZUNyb3NzUmVnaW9uU3VwcG9ydFN0YWNrcyA/IHBpcGVsaW5lQWNjb3VudCA6IHBpcGVsaW5lU3RhY2suc3RhY2tOYW1lfToke2FjdGlvblJlZ2lvbn1gO1xuICAgIGxldCBzdXBwb3J0U3RhY2sgPSBhcHAubm9kZS50cnlGaW5kQ2hpbGQoc3VwcG9ydFN0YWNrSWQpIGFzIENyb3NzUmVnaW9uU3VwcG9ydFN0YWNrO1xuICAgIGlmICghc3VwcG9ydFN0YWNrKSB7XG4gICAgICBzdXBwb3J0U3RhY2sgPSBuZXcgQ3Jvc3NSZWdpb25TdXBwb3J0U3RhY2soYXBwLCBzdXBwb3J0U3RhY2tJZCwge1xuICAgICAgICBwaXBlbGluZVN0YWNrTmFtZTogcGlwZWxpbmVTdGFjay5zdGFja05hbWUsXG4gICAgICAgIHJlZ2lvbjogYWN0aW9uUmVnaW9uLFxuICAgICAgICBhY2NvdW50OiBwaXBlbGluZUFjY291bnQsXG4gICAgICAgIHN5bnRoZXNpemVyOiB0aGlzLmdldENyb3NzUmVnaW9uU3VwcG9ydFN5bnRoZXNpemVyKCksXG4gICAgICAgIGNyZWF0ZUttc0tleTogdGhpcy5jcm9zc0FjY291bnRLZXlzLFxuICAgICAgICBlbmFibGVLZXlSb3RhdGlvbjogdGhpcy5lbmFibGVLZXlSb3RhdGlvbixcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBzdGFjazogc3VwcG9ydFN0YWNrLFxuICAgICAgcmVwbGljYXRpb25CdWNrZXQ6IHN1cHBvcnRTdGFjay5yZXBsaWNhdGlvbkJ1Y2tldCxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRDcm9zc1JlZ2lvblN1cHBvcnRTeW50aGVzaXplcigpOiBJU3RhY2tTeW50aGVzaXplciB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKHRoaXMuc3RhY2suc3ludGhlc2l6ZXIgaW5zdGFuY2VvZiBEZWZhdWx0U3RhY2tTeW50aGVzaXplcikge1xuICAgICAgLy8gaWYgd2UgaGF2ZSB0aGUgbmV3IHN5bnRoZXNpemVyLFxuICAgICAgLy8gd2UgbmVlZCBhIGJvb3RzdHJhcGxlc3MgY29weSBvZiBpdCxcbiAgICAgIC8vIGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudCB0byByZXF1aXJlIGJvb3RzdHJhcHBpbmcgdGhlIGVudmlyb25tZW50XG4gICAgICAvLyBvZiB0aGUgcGlwZWxpbmUgYWNjb3VudCBpbiB0aGlzIHJlcGxpY2F0aW9uIHJlZ2lvblxuICAgICAgcmV0dXJuIG5ldyBCb290c3RyYXBsZXNzU3ludGhlc2l6ZXIoe1xuICAgICAgICBkZXBsb3lSb2xlQXJuOiB0aGlzLnN0YWNrLnN5bnRoZXNpemVyLmRlcGxveVJvbGVBcm4sXG4gICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUm9sZUFybjogdGhpcy5zdGFjay5zeW50aGVzaXplci5jbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblJvbGVBcm4sXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gYW55IG90aGVyIHN5bnRoZXNpemVyOiBqdXN0IHJldHVybiB1bmRlZmluZWRcbiAgICAgIC8vIChpZS4sIHVzZSB0aGUgZGVmYXVsdCBiYXNlZCBvbiB0aGUgY29udGV4dCBzZXR0aW5ncylcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZW5lcmF0ZU5hbWVGb3JEZWZhdWx0QnVja2V0S2V5QWxpYXMoKTogc3RyaW5nIHtcbiAgICBjb25zdCBwcmVmaXggPSAnYWxpYXMvY29kZXBpcGVsaW5lLSc7XG4gICAgY29uc3QgbWF4QWxpYXNMZW5ndGggPSAyNTY7XG4gICAgY29uc3QgdW5pcXVlSWQgPSBOYW1lcy51bmlxdWVJZCh0aGlzKTtcbiAgICAvLyB0YWtlIHRoZSBsYXN0IDI1NiAtIChwcmVmaXggbGVuZ3RoKSBjaGFyYWN0ZXJzIG9mIHVuaXF1ZUlkXG4gICAgY29uc3Qgc3RhcnRJbmRleCA9IE1hdGgubWF4KDAsIHVuaXF1ZUlkLmxlbmd0aCAtIChtYXhBbGlhc0xlbmd0aCAtIHByZWZpeC5sZW5ndGgpKTtcbiAgICByZXR1cm4gcHJlZml4ICsgdW5pcXVlSWQuc3Vic3RyaW5nKHN0YXJ0SW5kZXgpLnRvTG93ZXJDYXNlKCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgcm9sZSB1c2VkIGZvciB0aGlzIGFjdGlvbixcbiAgICogaW5jbHVkaW5nIGhhbmRsaW5nIHRoZSBjYXNlIHdoZW4gdGhlIGFjdGlvbiBpcyBzdXBwb3NlZCB0byBiZSBjcm9zcy1hY2NvdW50LlxuICAgKlxuICAgKiBAcGFyYW0gc3RhZ2UgdGhlIHN0YWdlIHRoZSBhY3Rpb24gYmVsb25ncyB0b1xuICAgKiBAcGFyYW0gYWN0aW9uIHRoZSBhY3Rpb24gdG8gcmV0dXJuL2NyZWF0ZSBhIHJvbGUgZm9yXG4gICAqIEBwYXJhbSBhY3Rpb25TY29wZSB0aGUgc2NvcGUsIHVuaXF1ZSB0byB0aGUgYWN0aW9uLCB0byBjcmVhdGUgbmV3IHJlc291cmNlcyBpblxuICAgKi9cbiAgcHJpdmF0ZSBnZXRSb2xlRm9yQWN0aW9uKHN0YWdlOiBTdGFnZSwgYWN0aW9uOiBSaWNoQWN0aW9uLCBhY3Rpb25TY29wZTogQ29uc3RydWN0KTogaWFtLklSb2xlIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBwaXBlbGluZVN0YWNrID0gU3RhY2sub2YodGhpcyk7XG5cbiAgICBsZXQgYWN0aW9uUm9sZSA9IHRoaXMuZ2V0Um9sZUZyb21BY3Rpb25Qcm9wc09yR2VuZXJhdGVJZkNyb3NzQWNjb3VudChzdGFnZSwgYWN0aW9uKTtcblxuICAgIGlmICghYWN0aW9uUm9sZSAmJiB0aGlzLmlzQXdzT3duZWQoYWN0aW9uKSkge1xuICAgICAgLy8gZ2VuZXJhdGUgYSBSb2xlIGZvciB0aGlzIHNwZWNpZmljIEFjdGlvblxuICAgICAgYWN0aW9uUm9sZSA9IG5ldyBpYW0uUm9sZShhY3Rpb25TY29wZSwgJ0NvZGVQaXBlbGluZUFjdGlvblJvbGUnLCB7XG4gICAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5BY2NvdW50UHJpbmNpcGFsKHBpcGVsaW5lU3RhY2suYWNjb3VudCksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyB0aGUgcGlwZWxpbmUgcm9sZSBuZWVkcyBhc3N1bWVSb2xlIHBlcm1pc3Npb25zIHRvIHRoZSBhY3Rpb24gcm9sZVxuICAgIGNvbnN0IGdyYW50ID0gYWN0aW9uUm9sZT8uZ3JhbnRBc3N1bWVSb2xlKHRoaXMucm9sZSk7XG4gICAgZ3JhbnQ/LmFwcGx5QmVmb3JlKHRoaXMuY29kZVBpcGVsaW5lKTtcbiAgICByZXR1cm4gYWN0aW9uUm9sZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Um9sZUZyb21BY3Rpb25Qcm9wc09yR2VuZXJhdGVJZkNyb3NzQWNjb3VudChzdGFnZTogU3RhZ2UsIGFjdGlvbjogUmljaEFjdGlvbik6IGlhbS5JUm9sZSB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgcGlwZWxpbmVTdGFjayA9IFN0YWNrLm9mKHRoaXMpO1xuXG4gICAgLy8gaWYgd2UgaGF2ZSBhIGNyb3NzLWFjY291bnQgYWN0aW9uLCB0aGUgcGlwZWxpbmUncyBidWNrZXQgbXVzdCBoYXZlIGEgS01TIGtleVxuICAgIC8vIChvdGhlcndpc2Ugd2UgY2FuJ3QgY29uZmlndXJlIGNyb3NzLWFjY291bnQgdHJ1c3QgcG9saWNpZXMpXG4gICAgaWYgKGFjdGlvbi5pc0Nyb3NzQWNjb3VudCkge1xuICAgICAgY29uc3QgYXJ0aWZhY3RCdWNrZXQgPSB0aGlzLmVuc3VyZVJlcGxpY2F0aW9uUmVzb3VyY2VzRXhpc3RGb3IoYWN0aW9uKS5hcnRpZmFjdEJ1Y2tldDtcbiAgICAgIGlmICghYXJ0aWZhY3RCdWNrZXQuZW5jcnlwdGlvbktleSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYEFydGlmYWN0IEJ1Y2tldCBtdXN0IGhhdmUgYSBLTVMgS2V5IHRvIGFkZCBjcm9zcy1hY2NvdW50IGFjdGlvbiAnJHthY3Rpb24uYWN0aW9uUHJvcGVydGllcy5hY3Rpb25OYW1lfScgYCArXG4gICAgICAgICAgYChwaXBlbGluZSBhY2NvdW50OiAnJHtyZW5kZXJFbnZEaW1lbnNpb24odGhpcy5lbnYuYWNjb3VudCl9JywgYWN0aW9uIGFjY291bnQ6ICcke3JlbmRlckVudkRpbWVuc2lvbihhY3Rpb24uZWZmZWN0aXZlQWNjb3VudCl9JykuIGAgK1xuICAgICAgICAgICdDcmVhdGUgUGlwZWxpbmUgd2l0aCBcXCdjcm9zc0FjY291bnRLZXlzOiB0cnVlXFwnIChvciBwYXNzIGFuIGV4aXN0aW5nIEJ1Y2tldCB3aXRoIGEga2V5KScsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gaWYgYSBSb2xlIGhhcyBiZWVuIHBhc3NlZCBleHBsaWNpdGx5LCBhbHdheXMgdXNlIGl0XG4gICAgLy8gKGV2ZW4gaWYgdGhlIGJhY2tpbmcgcmVzb3VyY2UgaXMgZnJvbSBhIGRpZmZlcmVudCBhY2NvdW50IC1cbiAgICAvLyB0aGlzIGlzIGhvdyB0aGUgdXNlciBjYW4gb3ZlcnJpZGUgb3VyIGRlZmF1bHQgc3VwcG9ydCBsb2dpYylcbiAgICBpZiAoYWN0aW9uLmFjdGlvblByb3BlcnRpZXMucm9sZSkge1xuICAgICAgaWYgKHRoaXMuaXNBd3NPd25lZChhY3Rpb24pKSB7XG4gICAgICAgIC8vIHRoZSByb2xlIGhhcyB0byBiZSBkZXBsb3llZCBiZWZvcmUgdGhlIHBpcGVsaW5lXG4gICAgICAgIC8vIChvdXIgbWFnaWNhbCBjcm9zcy1zdGFjayBkZXBlbmRlbmNpZXMgd2lsbCBub3Qgd29yayxcbiAgICAgICAgLy8gYmVjYXVzZSB0aGUgcm9sZSBtaWdodCBiZSBmcm9tIGEgZGlmZmVyZW50IGVudmlyb25tZW50KSxcbiAgICAgICAgLy8gYnV0IF9vbmx5XyBpZiBpdCdzIGEgbmV3IFJvbGUgLVxuICAgICAgICAvLyBhbiBpbXBvcnRlZCBSb2xlIHNob3VsZCBub3QgYWRkIHRoZSBkZXBlbmRlbmN5XG4gICAgICAgIGlmIChhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yb2xlIGluc3RhbmNlb2YgaWFtLlJvbGUpIHtcbiAgICAgICAgICBjb25zdCByb2xlU3RhY2sgPSBTdGFjay5vZihhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yb2xlKTtcbiAgICAgICAgICBwaXBlbGluZVN0YWNrLmFkZERlcGVuZGVuY3kocm9sZVN0YWNrKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yb2xlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gLi4uZXhjZXB0IGlmIHRoZSBBY3Rpb24gaXMgbm90IG93bmVkIGJ5ICdBV1MnLFxuICAgICAgICAvLyBhcyB0aGF0IHdvdWxkIGJlIHJlamVjdGVkIGJ5IENvZGVQaXBlbGluZSBhdCBkZXBsb3kgdGltZVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTcGVjaWZ5aW5nIGEgUm9sZSBpcyBub3Qgc3VwcG9ydGVkIGZvciBhY3Rpb25zIHdpdGggYW4gb3duZXIgZGlmZmVyZW50IHRoYW4gJ0FXUycgLSBcIiArXG4gICAgICAgICAgYGdvdCAnJHthY3Rpb24uYWN0aW9uUHJvcGVydGllcy5vd25lcn0nIChBY3Rpb246ICcke2FjdGlvbi5hY3Rpb25Qcm9wZXJ0aWVzLmFjdGlvbk5hbWV9JyBpbiBTdGFnZTogJyR7c3RhZ2Uuc3RhZ2VOYW1lfScpYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gaWYgd2UgZG9uJ3QgaGF2ZSBhIFJvbGUgcGFzc2VkLFxuICAgIC8vIGFuZCB0aGUgYWN0aW9uIGlzIGNyb3NzLWFjY291bnQsXG4gICAgLy8gZ2VuZXJhdGUgYSBSb2xlIGluIHRoYXQgb3RoZXIgYWNjb3VudCBzdGFja1xuICAgIGNvbnN0IG90aGVyQWNjb3VudFN0YWNrID0gdGhpcy5nZXRPdGhlclN0YWNrSWZBY3Rpb25Jc0Nyb3NzQWNjb3VudChhY3Rpb24pO1xuICAgIGlmICghb3RoZXJBY2NvdW50U3RhY2spIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gZ2VuZXJhdGUgYSByb2xlIGluIHRoZSBvdGhlciBzdGFjaywgdGhhdCB0aGUgUGlwZWxpbmUgd2lsbCBhc3N1bWUgZm9yIGV4ZWN1dGluZyB0aGlzIGFjdGlvblxuICAgIGNvbnN0IHJldCA9IG5ldyBpYW0uUm9sZShvdGhlckFjY291bnRTdGFjayxcbiAgICAgIGAke05hbWVzLnVuaXF1ZUlkKHRoaXMpfS0ke3N0YWdlLnN0YWdlTmFtZX0tJHthY3Rpb24uYWN0aW9uUHJvcGVydGllcy5hY3Rpb25OYW1lfS1BY3Rpb25Sb2xlYCwge1xuICAgICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uQWNjb3VudFByaW5jaXBhbChwaXBlbGluZVN0YWNrLmFjY291bnQpLFxuICAgICAgICByb2xlTmFtZTogUGh5c2ljYWxOYW1lLkdFTkVSQVRFX0lGX05FRURFRCxcbiAgICAgIH0pO1xuICAgIC8vIHRoZSBvdGhlciBzdGFjayB3aXRoIHRoZSByb2xlIGhhcyB0byBiZSBkZXBsb3llZCBiZWZvcmUgdGhlIHBpcGVsaW5lIHN0YWNrXG4gICAgLy8gKENvZGVQaXBlbGluZSB2ZXJpZmllcyB5b3UgY2FuIGFzc3VtZSB0aGUgYWN0aW9uIFJvbGUgb24gY3JlYXRpb24pXG4gICAgcGlwZWxpbmVTdGFjay5hZGREZXBlbmRlbmN5KG90aGVyQWNjb3VudFN0YWNrKTtcblxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgU3RhY2sgdGhpcyBBY3Rpb24gYmVsb25ncyB0byBpZiB0aGlzIGlzIGEgY3Jvc3MtYWNjb3VudCBBY3Rpb24uXG4gICAqIElmIHRoaXMgQWN0aW9uIGlzIG5vdCBjcm9zcy1hY2NvdW50IChpLmUuLCBpdCBsaXZlcyBpbiB0aGUgc2FtZSBhY2NvdW50IGFzIHRoZSBQaXBlbGluZSksXG4gICAqIGl0IHJldHVybnMgdW5kZWZpbmVkLlxuICAgKlxuICAgKiBAcGFyYW0gYWN0aW9uIHRoZSBBY3Rpb24gdG8gcmV0dXJuIHRoZSBTdGFjayBmb3JcbiAgICovXG4gIHByaXZhdGUgZ2V0T3RoZXJTdGFja0lmQWN0aW9uSXNDcm9zc0FjY291bnQoYWN0aW9uOiBJQWN0aW9uKTogU3RhY2sgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHRhcmdldEFjY291bnQgPSBhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yZXNvdXJjZVxuICAgICAgPyBhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yZXNvdXJjZS5lbnYuYWNjb3VudFxuICAgICAgOiBhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5hY2NvdW50O1xuXG4gICAgaWYgKHRhcmdldEFjY291bnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgLy8gaWYgdGhlIGFjY291bnQgb2YgdGhlIEFjdGlvbiBpcyBub3Qgc3BlY2lmaWVkLFxuICAgICAgLy8gdGhlbiBpdCBkZWZhdWx0cyB0byB0aGUgc2FtZSBhY2NvdW50IHRoZSBwaXBlbGluZSBpdHNlbGYgaXMgaW5cbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gY2hlY2sgd2hldGhlciB0aGUgYWN0aW9uJ3MgYWNjb3VudCBpcyBhIHN0YXRpYyBzdHJpbmdcbiAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKHRhcmdldEFjY291bnQpKSB7XG4gICAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKHRoaXMuZW52LmFjY291bnQpKSB7XG4gICAgICAgIC8vIHRoZSBwaXBlbGluZSBpcyBhbHNvIGVudi1hZ25vc3RpYywgc28gdGhhdCdzIGZpbmVcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlICdhY2NvdW50JyBwcm9wZXJ0eSBtdXN0IGJlIGEgY29uY3JldGUgdmFsdWUgKGFjdGlvbjogJyR7YWN0aW9uLmFjdGlvblByb3BlcnRpZXMuYWN0aW9uTmFtZX0nKWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEF0IHRoaXMgcG9pbnQsIHdlIGtub3cgdGhhdCB0aGUgYWN0aW9uJ3MgYWNjb3VudCBpcyBhIHN0YXRpYyBzdHJpbmcuXG4gICAgLy8gSW4gdGhpcyBjYXNlLCB0aGUgcGlwZWxpbmUncyBhY2NvdW50IG11c3QgYWxzbyBiZSBhIHN0YXRpYyBzdHJpbmcuXG4gICAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZCh0aGlzLmVudi5hY2NvdW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdQaXBlbGluZSBzdGFjayB3aGljaCB1c2VzIGNyb3NzLWVudmlyb25tZW50IGFjdGlvbnMgbXVzdCBoYXZlIGFuIGV4cGxpY2l0bHkgc2V0IGFjY291bnQnKTtcbiAgICB9XG5cbiAgICAvLyBhdCB0aGlzIHBvaW50LCB3ZSBrbm93IHRoYXQgYm90aCB0aGUgUGlwZWxpbmUncyBhY2NvdW50LFxuICAgIC8vIGFuZCB0aGUgYWN0aW9uLWJhY2tpbmcgcmVzb3VyY2UncyBhY2NvdW50IGFyZSBzdGF0aWMgc3RyaW5nc1xuXG4gICAgLy8gaWYgdGhleSBhcmUgaWRlbnRpY2FsIC0gbm90aGluZyB0byBkbyAodGhlIGFjdGlvbiBpcyBub3QgY3Jvc3MtYWNjb3VudClcbiAgICBpZiAodGhpcy5lbnYuYWNjb3VudCA9PT0gdGFyZ2V0QWNjb3VudCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICAvLyBhdCB0aGlzIHBvaW50LCB3ZSBrbm93IHRoYXQgdGhlIGFjdGlvbiBpcyBjZXJ0YWlubHkgY3Jvc3MtYWNjb3VudCxcbiAgICAvLyBzbyB3ZSBuZWVkIHRvIHJldHVybiBhIFN0YWNrIGluIGl0cyBhY2NvdW50IHRvIGNyZWF0ZSB0aGUgaGVscGVyIFJvbGUgaW5cblxuICAgIGNvbnN0IGNhbmRpZGF0ZUFjdGlvblJlc291cmNlU3RhY2sgPSBhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yZXNvdXJjZVxuICAgICAgPyBTdGFjay5vZihhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yZXNvdXJjZSlcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGlmIChjYW5kaWRhdGVBY3Rpb25SZXNvdXJjZVN0YWNrPy5hY2NvdW50ID09PSB0YXJnZXRBY2NvdW50KSB7XG4gICAgICAvLyB3ZSBhbHdheXMgdXNlIHRoZSBcImxhdGVzdFwiIGFjdGlvbi1iYWNraW5nIHJlc291cmNlJ3MgU3RhY2sgZm9yIHRoaXMgYWNjb3VudCxcbiAgICAgIC8vIGV2ZW4gaWYgYSBkaWZmZXJlbnQgb25lIHdhcyB1c2VkIGVhcmxpZXJcbiAgICAgIHRoaXMuX2Nyb3NzQWNjb3VudFN1cHBvcnRbdGFyZ2V0QWNjb3VudF0gPSBjYW5kaWRhdGVBY3Rpb25SZXNvdXJjZVN0YWNrO1xuICAgICAgcmV0dXJuIGNhbmRpZGF0ZUFjdGlvblJlc291cmNlU3RhY2s7XG4gICAgfVxuXG4gICAgbGV0IHRhcmdldEFjY291bnRTdGFjazogU3RhY2sgfCB1bmRlZmluZWQgPSB0aGlzLl9jcm9zc0FjY291bnRTdXBwb3J0W3RhcmdldEFjY291bnRdO1xuICAgIGlmICghdGFyZ2V0QWNjb3VudFN0YWNrKSB7XG4gICAgICBjb25zdCBzdGFja0lkID0gYGNyb3NzLWFjY291bnQtc3VwcG9ydC1zdGFjay0ke3RhcmdldEFjY291bnR9YDtcbiAgICAgIGNvbnN0IGFwcCA9IHRoaXMuc3VwcG9ydFNjb3BlKCk7XG4gICAgICB0YXJnZXRBY2NvdW50U3RhY2sgPSBhcHAubm9kZS50cnlGaW5kQ2hpbGQoc3RhY2tJZCkgYXMgU3RhY2s7XG4gICAgICBpZiAoIXRhcmdldEFjY291bnRTdGFjaykge1xuICAgICAgICBjb25zdCBhY3Rpb25SZWdpb24gPSBhY3Rpb24uYWN0aW9uUHJvcGVydGllcy5yZXNvdXJjZVxuICAgICAgICAgID8gYWN0aW9uLmFjdGlvblByb3BlcnRpZXMucmVzb3VyY2UuZW52LnJlZ2lvblxuICAgICAgICAgIDogYWN0aW9uLmFjdGlvblByb3BlcnRpZXMucmVnaW9uO1xuICAgICAgICBjb25zdCBwaXBlbGluZVN0YWNrID0gU3RhY2sub2YodGhpcyk7XG4gICAgICAgIHRhcmdldEFjY291bnRTdGFjayA9IG5ldyBTdGFjayhhcHAsIHN0YWNrSWQsIHtcbiAgICAgICAgICBzdGFja05hbWU6IGAke3BpcGVsaW5lU3RhY2suc3RhY2tOYW1lfS1zdXBwb3J0LSR7dGFyZ2V0QWNjb3VudH1gLFxuICAgICAgICAgIGVudjoge1xuICAgICAgICAgICAgYWNjb3VudDogdGFyZ2V0QWNjb3VudCxcbiAgICAgICAgICAgIHJlZ2lvbjogYWN0aW9uUmVnaW9uID8/IHBpcGVsaW5lU3RhY2sucmVnaW9uLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgdGhpcy5fY3Jvc3NBY2NvdW50U3VwcG9ydFt0YXJnZXRBY2NvdW50XSA9IHRhcmdldEFjY291bnRTdGFjaztcbiAgICB9XG4gICAgcmV0dXJuIHRhcmdldEFjY291bnRTdGFjaztcbiAgfVxuXG4gIHByaXZhdGUgaXNBd3NPd25lZChhY3Rpb246IElBY3Rpb24pIHtcbiAgICBjb25zdCBvd25lciA9IGFjdGlvbi5hY3Rpb25Qcm9wZXJ0aWVzLm93bmVyO1xuICAgIHJldHVybiAhb3duZXIgfHwgb3duZXIgPT09ICdBV1MnO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRBcnRpZmFjdEJ1Y2tldEZyb21Qcm9wcyhwcm9wczogUGlwZWxpbmVQcm9wcyk6IHMzLklCdWNrZXQgfCB1bmRlZmluZWQge1xuICAgIGlmIChwcm9wcy5hcnRpZmFjdEJ1Y2tldCkge1xuICAgICAgcmV0dXJuIHByb3BzLmFydGlmYWN0QnVja2V0O1xuICAgIH1cbiAgICBpZiAocHJvcHMuY3Jvc3NSZWdpb25SZXBsaWNhdGlvbkJ1Y2tldHMpIHtcbiAgICAgIGNvbnN0IHBpcGVsaW5lUmVnaW9uID0gdGhpcy5yZXF1aXJlUmVnaW9uKCk7XG4gICAgICByZXR1cm4gcHJvcHMuY3Jvc3NSZWdpb25SZXBsaWNhdGlvbkJ1Y2tldHNbcGlwZWxpbmVSZWdpb25dO1xuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgcHJpdmF0ZSBjYWxjdWxhdGVJbnNlcnRJbmRleEZyb21QbGFjZW1lbnQocGxhY2VtZW50OiBTdGFnZVBsYWNlbWVudCk6IG51bWJlciB7XG4gICAgLy8gY2hlY2sgaWYgYXQgbW9zdCBvbmUgcGxhY2VtZW50IHByb3BlcnR5IHdhcyBwcm92aWRlZFxuICAgIGNvbnN0IHByb3ZpZGVkUGxhY2VtZW50UHJvcHMgPSBbJ3JpZ2h0QmVmb3JlJywgJ2p1c3RBZnRlcicsICdhdEluZGV4J11cbiAgICAgIC5maWx0ZXIoKHByb3ApID0+IChwbGFjZW1lbnQgYXMgYW55KVtwcm9wXSAhPT0gdW5kZWZpbmVkKTtcbiAgICBpZiAocHJvdmlkZWRQbGFjZW1lbnRQcm9wcy5sZW5ndGggPiAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Vycm9yIGFkZGluZyBTdGFnZSB0byB0aGUgUGlwZWxpbmU6ICcgK1xuICAgICAgICAneW91IGNhbiBvbmx5IHByb3ZpZGUgYXQgbW9zdCBvbmUgcGxhY2VtZW50IHByb3BlcnR5LCBidXQgJyArXG4gICAgICAgIGAnJHtwcm92aWRlZFBsYWNlbWVudFByb3BzLmpvaW4oJywgJyl9JyB3ZXJlIGdpdmVuYCk7XG4gICAgfVxuXG4gICAgaWYgKHBsYWNlbWVudC5yaWdodEJlZm9yZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCB0YXJnZXRJbmRleCA9IHRoaXMuZmluZFN0YWdlSW5kZXgocGxhY2VtZW50LnJpZ2h0QmVmb3JlKTtcbiAgICAgIGlmICh0YXJnZXRJbmRleCA9PT0gLTEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdFcnJvciBhZGRpbmcgU3RhZ2UgdG8gdGhlIFBpcGVsaW5lOiAnICtcbiAgICAgICAgICBgdGhlIHJlcXVlc3RlZCBTdGFnZSB0byBhZGQgaXQgYmVmb3JlLCAnJHtwbGFjZW1lbnQucmlnaHRCZWZvcmUuc3RhZ2VOYW1lfScsIHdhcyBub3QgZm91bmRgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0YXJnZXRJbmRleDtcbiAgICB9XG5cbiAgICBpZiAocGxhY2VtZW50Lmp1c3RBZnRlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCB0YXJnZXRJbmRleCA9IHRoaXMuZmluZFN0YWdlSW5kZXgocGxhY2VtZW50Lmp1c3RBZnRlcik7XG4gICAgICBpZiAodGFyZ2V0SW5kZXggPT09IC0xKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignRXJyb3IgYWRkaW5nIFN0YWdlIHRvIHRoZSBQaXBlbGluZTogJyArXG4gICAgICAgICAgYHRoZSByZXF1ZXN0ZWQgU3RhZ2UgdG8gYWRkIGl0IGFmdGVyLCAnJHtwbGFjZW1lbnQuanVzdEFmdGVyLnN0YWdlTmFtZX0nLCB3YXMgbm90IGZvdW5kYCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGFyZ2V0SW5kZXggKyAxO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnN0YWdlQ291bnQ7XG4gIH1cblxuICBwcml2YXRlIGZpbmRTdGFnZUluZGV4KHRhcmdldFN0YWdlOiBJU3RhZ2UpIHtcbiAgICByZXR1cm4gdGhpcy5fc3RhZ2VzLmZpbmRJbmRleChzdGFnZSA9PiBzdGFnZSA9PT0gdGFyZ2V0U3RhZ2UpO1xuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZVNvdXJjZUFjdGlvbkxvY2F0aW9ucygpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgZXJyb3JzID0gbmV3IEFycmF5PHN0cmluZz4oKTtcbiAgICBsZXQgZmlyc3RTdGFnZSA9IHRydWU7XG4gICAgZm9yIChjb25zdCBzdGFnZSBvZiB0aGlzLl9zdGFnZXMpIHtcbiAgICAgIGNvbnN0IG9ubHlTb3VyY2VBY3Rpb25zUGVybWl0dGVkID0gZmlyc3RTdGFnZTtcbiAgICAgIGZvciAoY29uc3QgYWN0aW9uIG9mIHN0YWdlLmFjdGlvbkRlc2NyaXB0b3JzKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLnZhbGlkYXRlU291cmNlQWN0aW9uKG9ubHlTb3VyY2VBY3Rpb25zUGVybWl0dGVkLCBhY3Rpb24uY2F0ZWdvcnksIGFjdGlvbi5hY3Rpb25OYW1lLCBzdGFnZS5zdGFnZU5hbWUpKTtcbiAgICAgIH1cbiAgICAgIGZpcnN0U3RhZ2UgPSBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIGVycm9ycztcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVIYXNTdGFnZXMoKTogc3RyaW5nW10ge1xuICAgIGlmICh0aGlzLnN0YWdlQ291bnQgPCAyKSB7XG4gICAgICByZXR1cm4gWydQaXBlbGluZSBtdXN0IGhhdmUgYXQgbGVhc3QgdHdvIHN0YWdlcyddO1xuICAgIH1cbiAgICByZXR1cm4gW107XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlU3RhZ2VzKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCByZXQgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuICAgIGZvciAoY29uc3Qgc3RhZ2Ugb2YgdGhpcy5fc3RhZ2VzKSB7XG4gICAgICByZXQucHVzaCguLi5zdGFnZS52YWxpZGF0ZSgpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVBcnRpZmFjdHMoKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHJldCA9IG5ldyBBcnJheTxzdHJpbmc+KCk7XG5cbiAgICBjb25zdCBwcm9kdWNlcnM6IFJlY29yZDxzdHJpbmcsIFBpcGVsaW5lTG9jYXRpb24+ID0ge307XG4gICAgY29uc3QgZmlyc3RDb25zdW1lcnM6IFJlY29yZDxzdHJpbmcsIFBpcGVsaW5lTG9jYXRpb24+ID0ge307XG5cbiAgICBmb3IgKGNvbnN0IFtzdGFnZUluZGV4LCBzdGFnZV0gb2YgZW51bWVyYXRlKHRoaXMuX3N0YWdlcykpIHtcbiAgICAgIC8vIEZvciBldmVyeSBvdXRwdXQgYXJ0aWZhY3QsIGdldCB0aGUgcHJvZHVjZXJcbiAgICAgIGZvciAoY29uc3QgYWN0aW9uIG9mIHN0YWdlLmFjdGlvbkRlc2NyaXB0b3JzKSB7XG4gICAgICAgIGNvbnN0IGFjdGlvbkxvYyA9IG5ldyBQaXBlbGluZUxvY2F0aW9uKHN0YWdlSW5kZXgsIHN0YWdlLCBhY3Rpb24pO1xuXG4gICAgICAgIGZvciAoY29uc3Qgb3V0cHV0QXJ0aWZhY3Qgb2YgYWN0aW9uLm91dHB1dHMpIHtcbiAgICAgICAgICAvLyBvdXRwdXQgQXJ0aWZhY3RzIGFsd2F5cyBoYXZlIGEgbmFtZSBzZXRcbiAgICAgICAgICBjb25zdCBuYW1lID0gb3V0cHV0QXJ0aWZhY3QuYXJ0aWZhY3ROYW1lITtcbiAgICAgICAgICBpZiAocHJvZHVjZXJzW25hbWVdKSB7XG4gICAgICAgICAgICByZXQucHVzaChgQm90aCBBY3Rpb25zICcke3Byb2R1Y2Vyc1tuYW1lXS5hY3Rpb25OYW1lfScgYW5kICcke2FjdGlvbi5hY3Rpb25OYW1lfScgYXJlIHByb2R1Y3RpbmcgQXJ0aWZhY3QgJyR7bmFtZX0nLiBFdmVyeSBhcnRpZmFjdCBjYW4gb25seSBiZSBwcm9kdWNlZCBvbmNlLmApO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcHJvZHVjZXJzW25hbWVdID0gYWN0aW9uTG9jO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRm9yIGV2ZXJ5IGlucHV0IGFydGlmYWN0LCBnZXQgdGhlIGZpcnN0IGNvbnN1bWVyXG4gICAgICAgIGZvciAoY29uc3QgaW5wdXRBcnRpZmFjdCBvZiBhY3Rpb24uaW5wdXRzKSB7XG4gICAgICAgICAgY29uc3QgbmFtZSA9IGlucHV0QXJ0aWZhY3QuYXJ0aWZhY3ROYW1lO1xuICAgICAgICAgIGlmICghbmFtZSkge1xuICAgICAgICAgICAgcmV0LnB1c2goYEFjdGlvbiAnJHthY3Rpb24uYWN0aW9uTmFtZX0nIGlzIHVzaW5nIGFuIHVubmFtZWQgaW5wdXQgQXJ0aWZhY3QsIHdoaWNoIGlzIG5vdCBiZWluZyBwcm9kdWNlZCBpbiB0aGlzIHBpcGVsaW5lYCk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmaXJzdENvbnN1bWVyc1tuYW1lXSA9IGZpcnN0Q29uc3VtZXJzW25hbWVdID8gZmlyc3RDb25zdW1lcnNbbmFtZV0uZmlyc3QoYWN0aW9uTG9jKSA6IGFjdGlvbkxvYztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIE5vdyB2YWxpZGF0ZSB0aGF0IGV2ZXJ5IGlucHV0IGFydGlmYWN0IGlzIHByb2R1Y2VkIGJlZm9yZSBpdCdzXG4gICAgLy8gYmVpbmcgY29uc3VtZWQuXG4gICAgZm9yIChjb25zdCBbYXJ0aWZhY3ROYW1lLCBjb25zdW1lckxvY10gb2YgT2JqZWN0LmVudHJpZXMoZmlyc3RDb25zdW1lcnMpKSB7XG4gICAgICBjb25zdCBwcm9kdWNlckxvYyA9IHByb2R1Y2Vyc1thcnRpZmFjdE5hbWVdO1xuICAgICAgaWYgKCFwcm9kdWNlckxvYykge1xuICAgICAgICByZXQucHVzaChgQWN0aW9uICcke2NvbnN1bWVyTG9jLmFjdGlvbk5hbWV9JyBpcyB1c2luZyBpbnB1dCBBcnRpZmFjdCAnJHthcnRpZmFjdE5hbWV9Jywgd2hpY2ggaXMgbm90IGJlaW5nIHByb2R1Y2VkIGluIHRoaXMgcGlwZWxpbmVgKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChjb25zdW1lckxvYy5iZWZvcmVPckVxdWFsKHByb2R1Y2VyTG9jKSkge1xuICAgICAgICByZXQucHVzaChgJHtjb25zdW1lckxvY30gaXMgY29uc3VtaW5nIGlucHV0IEFydGlmYWN0ICcke2FydGlmYWN0TmFtZX0nIGJlZm9yZSBpdCBpcyBiZWluZyBwcm9kdWNlZCBhdCAke3Byb2R1Y2VyTG9jfWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICBwcml2YXRlIHJlbmRlckFydGlmYWN0U3RvcmVzUHJvcGVydHkoKTogQ2ZuUGlwZWxpbmUuQXJ0aWZhY3RTdG9yZU1hcFByb3BlcnR5W10gfCB1bmRlZmluZWQge1xuICAgIGlmICghdGhpcy5jcm9zc1JlZ2lvbikgeyByZXR1cm4gdW5kZWZpbmVkOyB9XG5cbiAgICAvLyBhZGQgdGhlIFBpcGVsaW5lJ3MgYXJ0aWZhY3Qgc3RvcmVcbiAgICBjb25zdCBwcmltYXJ5UmVnaW9uID0gdGhpcy5yZXF1aXJlUmVnaW9uKCk7XG4gICAgdGhpcy5fY3Jvc3NSZWdpb25TdXBwb3J0W3ByaW1hcnlSZWdpb25dID0ge1xuICAgICAgcmVwbGljYXRpb25CdWNrZXQ6IHRoaXMuYXJ0aWZhY3RCdWNrZXQsXG4gICAgICBzdGFjazogU3RhY2sub2YodGhpcyksXG4gICAgfTtcblxuICAgIHJldHVybiBPYmplY3QuZW50cmllcyh0aGlzLl9jcm9zc1JlZ2lvblN1cHBvcnQpLm1hcCgoW3JlZ2lvbiwgc3VwcG9ydF0pID0+ICh7XG4gICAgICByZWdpb24sXG4gICAgICBhcnRpZmFjdFN0b3JlOiB0aGlzLnJlbmRlckFydGlmYWN0U3RvcmUoc3VwcG9ydC5yZXBsaWNhdGlvbkJ1Y2tldCksXG4gICAgfSkpO1xuICB9XG5cbiAgcHJpdmF0ZSByZW5kZXJBcnRpZmFjdFN0b3JlUHJvcGVydHkoKTogQ2ZuUGlwZWxpbmUuQXJ0aWZhY3RTdG9yZVByb3BlcnR5IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAodGhpcy5jcm9zc1JlZ2lvbikgeyByZXR1cm4gdW5kZWZpbmVkOyB9XG4gICAgcmV0dXJuIHRoaXMucmVuZGVyUHJpbWFyeUFydGlmYWN0U3RvcmUoKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVuZGVyUHJpbWFyeUFydGlmYWN0U3RvcmUoKTogQ2ZuUGlwZWxpbmUuQXJ0aWZhY3RTdG9yZVByb3BlcnR5IHtcbiAgICByZXR1cm4gdGhpcy5yZW5kZXJBcnRpZmFjdFN0b3JlKHRoaXMuYXJ0aWZhY3RCdWNrZXQpO1xuICB9XG5cbiAgcHJpdmF0ZSByZW5kZXJBcnRpZmFjdFN0b3JlKGJ1Y2tldDogczMuSUJ1Y2tldCk6IENmblBpcGVsaW5lLkFydGlmYWN0U3RvcmVQcm9wZXJ0eSB7XG4gICAgbGV0IGVuY3J5cHRpb25LZXk6IENmblBpcGVsaW5lLkVuY3J5cHRpb25LZXlQcm9wZXJ0eSB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCBidWNrZXRLZXkgPSBidWNrZXQuZW5jcnlwdGlvbktleTtcbiAgICBpZiAoYnVja2V0S2V5KSB7XG4gICAgICBlbmNyeXB0aW9uS2V5ID0ge1xuICAgICAgICB0eXBlOiAnS01TJyxcbiAgICAgICAgaWQ6IGJ1Y2tldEtleS5rZXlBcm4sXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICB0eXBlOiAnUzMnLFxuICAgICAgbG9jYXRpb246IGJ1Y2tldC5idWNrZXROYW1lLFxuICAgICAgZW5jcnlwdGlvbktleSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXQgY3Jvc3NSZWdpb24oKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuY3Jvc3NSZWdpb25CdWNrZXRzUGFzc2VkKSB7IHJldHVybiB0cnVlOyB9XG4gICAgcmV0dXJuIHRoaXMuX3N0YWdlcy5zb21lKHN0YWdlID0+IHN0YWdlLmFjdGlvbkRlc2NyaXB0b3JzLnNvbWUoYWN0aW9uID0+IGFjdGlvbi5yZWdpb24gIT09IHVuZGVmaW5lZCkpO1xuICB9XG5cbiAgcHJpdmF0ZSByZW5kZXJTdGFnZXMoKTogQ2ZuUGlwZWxpbmUuU3RhZ2VEZWNsYXJhdGlvblByb3BlcnR5W10ge1xuICAgIHJldHVybiB0aGlzLl9zdGFnZXMubWFwKHN0YWdlID0+IHN0YWdlLnJlbmRlcigpKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVuZGVyRGlzYWJsZWRUcmFuc2l0aW9ucygpOiBDZm5QaXBlbGluZS5TdGFnZVRyYW5zaXRpb25Qcm9wZXJ0eVtdIHtcbiAgICByZXR1cm4gdGhpcy5fc3RhZ2VzXG4gICAgICAuZmlsdGVyKHN0YWdlID0+ICFzdGFnZS50cmFuc2l0aW9uVG9FbmFibGVkKVxuICAgICAgLm1hcChzdGFnZSA9PiAoe1xuICAgICAgICByZWFzb246IHN0YWdlLnRyYW5zaXRpb25EaXNhYmxlZFJlYXNvbixcbiAgICAgICAgc3RhZ2VOYW1lOiBzdGFnZS5zdGFnZU5hbWUsXG4gICAgICB9KSk7XG4gIH1cblxuICBwcml2YXRlIHJlcXVpcmVSZWdpb24oKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb24gPSB0aGlzLmVudi5yZWdpb247XG4gICAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChyZWdpb24pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BpcGVsaW5lIHN0YWNrIHdoaWNoIHVzZXMgY3Jvc3MtZW52aXJvbm1lbnQgYWN0aW9ucyBtdXN0IGhhdmUgYW4gZXhwbGljaXRseSBzZXQgcmVnaW9uJyk7XG4gICAgfVxuICAgIHJldHVybiByZWdpb247XG4gIH1cblxuICBwcml2YXRlIHN1cHBvcnRTY29wZSgpOiBDZGtTdGFnZSB7XG4gICAgY29uc3Qgc2NvcGUgPSBDZGtTdGFnZS5vZih0aGlzKTtcbiAgICBpZiAoIXNjb3BlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BpcGVsaW5lIHN0YWNrIHdoaWNoIHVzZXMgY3Jvc3MtZW52aXJvbm1lbnQgYWN0aW9ucyBtdXN0IGJlIHBhcnQgb2YgYSBDREsgQXBwIG9yIFN0YWdlJyk7XG4gICAgfVxuICAgIHJldHVybiBzY29wZTtcbiAgfVxufVxuXG4vKipcbiAqIEFuIGludGVyZmFjZSByZXByZXNlbnRpbmcgcmVzb3VyY2VzIGdlbmVyYXRlZCBpbiBvcmRlciB0byBzdXBwb3J0XG4gKiB0aGUgY3Jvc3MtcmVnaW9uIGNhcGFiaWxpdGllcyBvZiBDb2RlUGlwZWxpbmUuXG4gKiBZb3UgZ2V0IGluc3RhbmNlcyBvZiB0aGlzIGludGVyZmFjZSBmcm9tIHRoZSB7QGxpbmsgUGlwZWxpbmUjY3Jvc3NSZWdpb25TdXBwb3J0fSBwcm9wZXJ0eS5cbiAqXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3Jvc3NSZWdpb25TdXBwb3J0IHtcbiAgLyoqXG4gICAqIFRoZSBTdGFjayB0aGF0IGhhcyBiZWVuIGNyZWF0ZWQgdG8gaG91c2UgdGhlIHJlcGxpY2F0aW9uIEJ1Y2tldFxuICAgKiByZXF1aXJlZCBmb3IgdGhpcyAgcmVnaW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhY2s6IFN0YWNrO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVwbGljYXRpb24gQnVja2V0IHVzZWQgYnkgQ29kZVBpcGVsaW5lIHRvIG9wZXJhdGUgaW4gdGhpcyByZWdpb24uXG4gICAqIEJlbG9uZ3MgdG8ge0BsaW5rIHN0YWNrfS5cbiAgICovXG4gIHJlYWRvbmx5IHJlcGxpY2F0aW9uQnVja2V0OiBzMy5JQnVja2V0O1xufVxuXG5pbnRlcmZhY2UgQ3Jvc3NSZWdpb25JbmZvIHtcbiAgcmVhZG9ubHkgYXJ0aWZhY3RCdWNrZXQ6IHMzLklCdWNrZXQ7XG5cbiAgcmVhZG9ubHkgcmVnaW9uPzogc3RyaW5nO1xufVxuXG5mdW5jdGlvbiBlbnVtZXJhdGU8QT4oeHM6IEFbXSk6IEFycmF5PFtudW1iZXIsIEFdPiB7XG4gIGNvbnN0IHJldCA9IG5ldyBBcnJheTxbbnVtYmVyLCBBXT4oKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB4cy5sZW5ndGg7IGkrKykge1xuICAgIHJldC5wdXNoKFtpLCB4c1tpXV0pO1xuICB9XG4gIHJldHVybiByZXQ7XG59XG5cbmNsYXNzIFBpcGVsaW5lTG9jYXRpb24ge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHN0YWdlSW5kZXg6IG51bWJlciwgcHJpdmF0ZSByZWFkb25seSBzdGFnZTogSVN0YWdlLCBwcml2YXRlIHJlYWRvbmx5IGFjdGlvbjogRnVsbEFjdGlvbkRlc2NyaXB0b3IpIHtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgc3RhZ2VOYW1lKCkge1xuICAgIHJldHVybiB0aGlzLnN0YWdlLnN0YWdlTmFtZTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgYWN0aW9uTmFtZSgpIHtcbiAgICByZXR1cm4gdGhpcy5hY3Rpb24uYWN0aW9uTmFtZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHdoZXRoZXIgYSBpcyBiZWZvcmUgb3IgdGhlIHNhbWUgb3JkZXIgYXMgYlxuICAgKi9cbiAgcHVibGljIGJlZm9yZU9yRXF1YWwocmhzOiBQaXBlbGluZUxvY2F0aW9uKSB7XG4gICAgaWYgKHRoaXMuc3RhZ2VJbmRleCAhPT0gcmhzLnN0YWdlSW5kZXgpIHsgcmV0dXJuIHJocy5zdGFnZUluZGV4IDwgcmhzLnN0YWdlSW5kZXg7IH1cbiAgICByZXR1cm4gdGhpcy5hY3Rpb24ucnVuT3JkZXIgPD0gcmhzLmFjdGlvbi5ydW5PcmRlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBmaXJzdCBsb2NhdGlvbiBiZXR3ZWVuIHRoaXMgYW5kIHRoZSBvdGhlciBvbmVcbiAgICovXG4gIHB1YmxpYyBmaXJzdChyaHM6IFBpcGVsaW5lTG9jYXRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5iZWZvcmVPckVxdWFsKHJocykgPyB0aGlzIDogcmhzO1xuICB9XG5cbiAgcHVibGljIHRvU3RyaW5nKCkge1xuICAgIC8vIHJ1bk9yZGVycyBhcmUgMS1iYXNlZCwgc28gbWFrZSB0aGUgc3RhZ2VJbmRleCBhbHNvIDEtYmFzZWQgb3RoZXJ3aXNlIGl0J3MgZ29pbmcgdG8gYmUgY29uZnVzaW5nLlxuICAgIHJldHVybiBgU3RhZ2UgJHt0aGlzLnN0YWdlSW5kZXggKyAxfSBBY3Rpb24gJHt0aGlzLmFjdGlvbi5ydW5PcmRlcn0gKCcke3RoaXMuc3RhZ2VOYW1lfScvJyR7dGhpcy5hY3Rpb25OYW1lfScpYDtcbiAgfVxufVxuXG4vKipcbiAqIFJlbmRlciBhbiBlbnYgZGltZW5zaW9uIHdpdGhvdXQgc2hvd2luZyB0aGUgdWdseSBzdHJpbmdpZmllZCB0b2tlbnNcbiAqL1xuZnVuY3Rpb24gcmVuZGVyRW52RGltZW5zaW9uKHM6IHN0cmluZyB8IHVuZGVmaW5lZCkge1xuICByZXR1cm4gVG9rZW4uaXNVbnJlc29sdmVkKHMpID8gJyhjdXJyZW50KScgOiBzO1xufVxuIl19
\No newline at end of file