@cdklabs/cdk-appmod-catalog-blueprints 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +8644 -0
- package/LICENSE +202 -0
- package/README.md +212 -0
- package/lib/document-processing/agentic-document-processing.d.ts +16 -0
- package/lib/document-processing/agentic-document-processing.js +90 -0
- package/lib/document-processing/base-document-processing.d.ts +189 -0
- package/lib/document-processing/base-document-processing.js +509 -0
- package/lib/document-processing/bedrock-document-processing.d.ts +167 -0
- package/lib/document-processing/bedrock-document-processing.js +297 -0
- package/lib/document-processing/index.d.ts +3 -0
- package/lib/document-processing/index.js +20 -0
- package/lib/document-processing/resources/default-bedrock-invoke/index.py +63 -0
- package/lib/document-processing/resources/default-bedrock-invoke/requirements.txt +4 -0
- package/lib/document-processing/resources/default-doc-retrieval-lambda/index.mjs +92 -0
- package/lib/document-processing/resources/default-doc-retrieval-lambda/package.json +10 -0
- package/lib/document-processing/resources/default-error-handler/index.js +46 -0
- package/lib/document-processing/resources/default-error-handler/package.json +4 -0
- package/lib/document-processing/resources/default-image-processor/classifier.mjs +665 -0
- package/lib/document-processing/resources/default-image-processor/extractors.mjs +465 -0
- package/lib/document-processing/resources/default-image-processor/index.mjs +143 -0
- package/lib/document-processing/resources/default-image-processor/package-lock.json +12 -0
- package/lib/document-processing/resources/default-image-processor/package.json +4 -0
- package/lib/document-processing/resources/default-image-validator/index.mjs +76 -0
- package/lib/document-processing/resources/default-image-validator/package-lock.json +154 -0
- package/lib/document-processing/resources/default-image-validator/package.json +7 -0
- package/lib/document-processing/resources/default-pdf-processor/index.js +46 -0
- package/lib/document-processing/resources/default-pdf-validator/index.js +36 -0
- package/lib/document-processing/resources/default-sqs-consumer/index.py +111 -0
- package/lib/document-processing/resources/default-sqs-consumer/requirements.txt +4 -0
- package/lib/document-processing/resources/default-sqs-consumer/sample_payload.json +20 -0
- package/lib/document-processing/resources/default-sqs-consumer/sample_payload_multi.json +24 -0
- package/lib/document-processing/resources/default-strands-agent/index.py +111 -0
- package/lib/document-processing/resources/default-strands-agent/requirements.txt +6 -0
- package/lib/document-processing/tests/agentic-document-processing-nag.test.d.ts +1 -0
- package/lib/document-processing/tests/agentic-document-processing-nag.test.js +107 -0
- package/lib/document-processing/tests/agentic-document-processing.test.d.ts +1 -0
- package/lib/document-processing/tests/agentic-document-processing.test.js +125 -0
- package/lib/document-processing/tests/bedrock-document-processing-nag.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing-nag.test.js +101 -0
- package/lib/document-processing/tests/bedrock-document-processing.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing.test.js +79 -0
- package/lib/framework/custom-resource/default-runtimes.d.ts +21 -0
- package/lib/framework/custom-resource/default-runtimes.js +34 -0
- package/lib/framework/custom-resource/index.d.ts +1 -0
- package/lib/framework/custom-resource/index.js +18 -0
- package/lib/framework/foundation/access-log.d.ts +69 -0
- package/lib/framework/foundation/access-log.js +121 -0
- package/lib/framework/foundation/eventbridge-broker.d.ts +18 -0
- package/lib/framework/foundation/eventbridge-broker.js +42 -0
- package/lib/framework/foundation/index.d.ts +3 -0
- package/lib/framework/foundation/index.js +20 -0
- package/lib/framework/foundation/network.d.ts +19 -0
- package/lib/framework/foundation/network.js +83 -0
- package/lib/framework/index.d.ts +2 -0
- package/lib/framework/index.js +19 -0
- package/lib/framework/quickstart/base-quickstart.d.ts +30 -0
- package/lib/framework/quickstart/base-quickstart.js +30 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +21 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/utilities/cdk-nag-config.d.ts +42 -0
- package/lib/utilities/cdk-nag-config.js +194 -0
- package/lib/utilities/data-loader-lambda/index.py +282 -0
- package/lib/utilities/data-loader-lambda/requirements.txt +3 -0
- package/lib/utilities/data-loader.d.ts +173 -0
- package/lib/utilities/data-loader.js +447 -0
- package/lib/utilities/index.d.ts +3 -0
- package/lib/utilities/index.js +20 -0
- package/lib/utilities/lambda-iam-utils.d.ts +145 -0
- package/lib/utilities/lambda-iam-utils.js +235 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.d.ts +42 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.js +53 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.ts +88 -0
- package/lib/utilities/observability/bedrock-observability.d.ts +18 -0
- package/lib/utilities/observability/bedrock-observability.js +131 -0
- package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.d.ts +6 -0
- package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.js +22 -0
- package/lib/utilities/observability/index.d.ts +6 -0
- package/lib/utilities/observability/index.js +25 -0
- package/lib/utilities/observability/lambda-observability-property-injector.d.ts +8 -0
- package/lib/utilities/observability/lambda-observability-property-injector.js +43 -0
- package/lib/utilities/observability/log-group-data-protection-props.d.ts +19 -0
- package/lib/utilities/observability/log-group-data-protection-props.js +5 -0
- package/lib/utilities/observability/observability.d.ts +83 -0
- package/lib/utilities/observability/observability.js +278 -0
- package/lib/utilities/observability/observable.d.ts +32 -0
- package/lib/utilities/observability/observable.js +3 -0
- package/lib/utilities/observability/powertools-config.d.ts +3 -0
- package/lib/utilities/observability/powertools-config.js +25 -0
- package/lib/utilities/observability/resources/bedrock-manage-logging-configuration/index.py +27 -0
- package/lib/utilities/observability/state-machine-observability-property-injector.d.ts +8 -0
- package/lib/utilities/observability/state-machine-observability-property-injector.js +49 -0
- package/lib/utilities/tests/data-loader-nag.test.d.ts +1 -0
- package/lib/utilities/tests/data-loader-nag.test.js +432 -0
- package/lib/utilities/tests/data-loader.test.d.ts +1 -0
- package/lib/utilities/tests/data-loader.test.js +284 -0
- package/lib/webapp/frontend-construct.d.ts +136 -0
- package/lib/webapp/frontend-construct.js +253 -0
- package/lib/webapp/index.d.ts +1 -0
- package/lib/webapp/index.js +18 -0
- package/lib/webapp/tests/frontend-construct-nag.test.d.ts +1 -0
- package/lib/webapp/tests/frontend-construct-nag.test.js +266 -0
- package/lib/webapp/tests/frontend-construct.test.d.ts +1 -0
- package/lib/webapp/tests/frontend-construct.test.js +385 -0
- package/package.json +183 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.BaseDocumentProcessing = exports.DocumentProcessingPrefix = void 0;
|
|
5
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
6
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
7
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
8
|
+
const path = require("node:path");
|
|
9
|
+
const aws_lambda_python_alpha_1 = require("@aws-cdk/aws-lambda-python-alpha");
|
|
10
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
11
|
+
const aws_dynamodb_1 = require("aws-cdk-lib/aws-dynamodb");
|
|
12
|
+
const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
|
|
13
|
+
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
14
|
+
const aws_kms_1 = require("aws-cdk-lib/aws-kms");
|
|
15
|
+
const aws_lambda_event_sources_1 = require("aws-cdk-lib/aws-lambda-event-sources");
|
|
16
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
|
17
|
+
const aws_s3_notifications_1 = require("aws-cdk-lib/aws-s3-notifications");
|
|
18
|
+
const aws_sqs_1 = require("aws-cdk-lib/aws-sqs");
|
|
19
|
+
const aws_stepfunctions_1 = require("aws-cdk-lib/aws-stepfunctions");
|
|
20
|
+
const aws_stepfunctions_tasks_1 = require("aws-cdk-lib/aws-stepfunctions-tasks");
|
|
21
|
+
const constructs_1 = require("constructs");
|
|
22
|
+
const framework_1 = require("../framework");
|
|
23
|
+
const utilities_1 = require("../utilities");
|
|
24
|
+
const lambda_observability_property_injector_1 = require("../utilities/observability/lambda-observability-property-injector");
|
|
25
|
+
const powertools_config_1 = require("../utilities/observability/powertools-config");
|
|
26
|
+
const state_machine_observability_property_injector_1 = require("../utilities/observability/state-machine-observability-property-injector");
|
|
27
|
+
/**
|
|
28
|
+
* S3 prefix constants for organizing documents throughout the processing lifecycle.
|
|
29
|
+
*
|
|
30
|
+
* Documents flow through these prefixes based on processing outcomes:
|
|
31
|
+
* - Upload → raw/ (triggers processing)
|
|
32
|
+
* - Success → processed/ (workflow completed successfully)
|
|
33
|
+
* - Failure → failed/ (workflow encountered errors)
|
|
34
|
+
*/
|
|
35
|
+
var DocumentProcessingPrefix;
|
|
36
|
+
(function (DocumentProcessingPrefix) {
|
|
37
|
+
/** Prefix for newly uploaded documents awaiting processing */
|
|
38
|
+
DocumentProcessingPrefix["RAW"] = "raw/";
|
|
39
|
+
/** Prefix for documents that failed processing */
|
|
40
|
+
DocumentProcessingPrefix["FAILED"] = "failed/";
|
|
41
|
+
/** Prefix for successfully processed documents */
|
|
42
|
+
DocumentProcessingPrefix["PROCESSED"] = "processed/";
|
|
43
|
+
})(DocumentProcessingPrefix || (exports.DocumentProcessingPrefix = DocumentProcessingPrefix = {}));
|
|
44
|
+
/**
|
|
45
|
+
* Abstract base class for serverless document processing workflows.
|
|
46
|
+
*
|
|
47
|
+
* Provides a complete document processing pipeline with:
|
|
48
|
+
* - **S3 Storage**: Organized with prefixes (raw/, processed/, failed/) for document lifecycle management
|
|
49
|
+
* - **SQS Queue**: Reliable message processing with configurable visibility timeout and dead letter queue
|
|
50
|
+
* - **DynamoDB Table**: Workflow metadata tracking with DocumentId as partition key
|
|
51
|
+
* - **Step Functions**: Orchestrated workflow with automatic file movement based on processing outcome
|
|
52
|
+
* - **Auto-triggering**: S3 event notifications automatically start processing when files are uploaded to raw/ prefix
|
|
53
|
+
* - **Error Handling**: Failed documents are moved to failed/ prefix with error details stored in DynamoDB
|
|
54
|
+
* - **EventBridge Integration**: Optional custom event publishing for workflow state changes
|
|
55
|
+
*
|
|
56
|
+
* ## Architecture Flow
|
|
57
|
+
* S3 Upload (raw/) → SQS → Lambda Consumer → Step Functions → Processing Steps → S3 (processed/failed/)
|
|
58
|
+
*
|
|
59
|
+
* ## Implementation Requirements
|
|
60
|
+
* Subclasses must implement four abstract methods to define the processing workflow:
|
|
61
|
+
* - `classificationStep()`: Document type classification
|
|
62
|
+
* - `extractionStep()`: Data extraction from documents
|
|
63
|
+
* - `enrichmentStep()`: Optional data enrichment (return undefined to skip)
|
|
64
|
+
* - `postProcessingStep()`: Optional post-processing (return undefined to skip)
|
|
65
|
+
*/
|
|
66
|
+
class BaseDocumentProcessing extends constructs_1.Construct {
|
|
67
|
+
/**
|
|
68
|
+
* Creates a new BaseDocumentProcessing construct.
|
|
69
|
+
*
|
|
70
|
+
* Initializes the complete document processing infrastructure including S3 bucket,
|
|
71
|
+
* SQS queue, DynamoDB table, and sets up S3 event notifications to trigger processing.
|
|
72
|
+
*
|
|
73
|
+
* @param scope - The scope in which to define this construct
|
|
74
|
+
* @param id - The scoped construct ID. Must be unique within the scope.
|
|
75
|
+
* @param props - Configuration properties for the document processing pipeline
|
|
76
|
+
*/
|
|
77
|
+
constructor(scope, id, props) {
|
|
78
|
+
super(scope, id);
|
|
79
|
+
this.props = props;
|
|
80
|
+
if (props.network) {
|
|
81
|
+
props.network.createServiceEndpoint('vpce-sqs', aws_ec2_1.InterfaceVpcEndpointAwsService.SQS);
|
|
82
|
+
props.network.createServiceEndpoint('vpce-s3', aws_ec2_1.InterfaceVpcEndpointAwsService.S3);
|
|
83
|
+
props.network.createServiceEndpoint('vpce-sfn', aws_ec2_1.InterfaceVpcEndpointAwsService.STEP_FUNCTIONS);
|
|
84
|
+
props.network.createServiceEndpoint('vpce-eb', aws_ec2_1.InterfaceVpcEndpointAwsService.EVENTBRIDGE);
|
|
85
|
+
if (props.enableObservability) {
|
|
86
|
+
props.network.createServiceEndpoint('vpce-logs', aws_ec2_1.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS);
|
|
87
|
+
props.network.createServiceEndpoint('vpce-metrics', aws_ec2_1.InterfaceVpcEndpointAwsService.CLOUDWATCH_MONITORING);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.encryptionKey = props.encryptionKey || new aws_kms_1.Key(this, 'IDPEncryptionKey', {
|
|
91
|
+
enableKeyRotation: true,
|
|
92
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
93
|
+
});
|
|
94
|
+
const bucketName = `documentprocessingbucket-${aws_cdk_lib_1.Names.uniqueResourceName(this, {
|
|
95
|
+
maxLength: 60 - 'documentprocessingbucket-'.length,
|
|
96
|
+
})}`.toLowerCase();
|
|
97
|
+
const bucketArn = `arn:aws:s3:::${bucketName}`;
|
|
98
|
+
this.encryptionKey.grantEncryptDecrypt(new aws_iam_1.ServicePrincipal('s3.amazonaws.com', {
|
|
99
|
+
conditions: {
|
|
100
|
+
ArnEquals: {
|
|
101
|
+
'kms:EncryptionContext:aws:s3:arn': bucketArn,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
}));
|
|
105
|
+
this.bucket = props.bucket || new aws_s3_1.Bucket(this, 'DocumentProcessingBucket', {
|
|
106
|
+
bucketName,
|
|
107
|
+
autoDeleteObjects: (props.removalPolicy && props.removalPolicy === aws_cdk_lib_1.RemovalPolicy.DESTROY) || !props.removalPolicy ? true : false,
|
|
108
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
109
|
+
encryption: aws_s3_1.BucketEncryption.KMS,
|
|
110
|
+
enforceSSL: true,
|
|
111
|
+
bucketKeyEnabled: true,
|
|
112
|
+
});
|
|
113
|
+
this.bucketEncryptionKey = this.bucket.encryptionKey;
|
|
114
|
+
const tempLogGroupDataProtection = props.logGroupDataProtection || {
|
|
115
|
+
logGroupEncryptionKey: new aws_kms_1.Key(this, 'LogGroupEncryptionKey', {
|
|
116
|
+
enableKeyRotation: true,
|
|
117
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
118
|
+
}),
|
|
119
|
+
};
|
|
120
|
+
if (!tempLogGroupDataProtection.logGroupEncryptionKey) {
|
|
121
|
+
this.logGroupDataProtection = {
|
|
122
|
+
dataProtectionIdentifiers: tempLogGroupDataProtection.dataProtectionIdentifiers,
|
|
123
|
+
logGroupEncryptionKey: new aws_kms_1.Key(this, 'LogGroupEncryptionKey', {
|
|
124
|
+
enableKeyRotation: true,
|
|
125
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
this.logGroupDataProtection = tempLogGroupDataProtection;
|
|
131
|
+
}
|
|
132
|
+
this.deadLetterQueue = new aws_sqs_1.Queue(this, 'DocumentProcessingDLQ', {
|
|
133
|
+
visibilityTimeout: props.queueVisibilityTimeout || aws_cdk_lib_1.Duration.seconds(300),
|
|
134
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
135
|
+
enforceSSL: true,
|
|
136
|
+
encryption: aws_sqs_1.QueueEncryption.KMS,
|
|
137
|
+
encryptionMasterKey: this.encryptionKey,
|
|
138
|
+
});
|
|
139
|
+
this.queue = new aws_sqs_1.Queue(this, 'DocumentProcessingQueue', {
|
|
140
|
+
visibilityTimeout: props.queueVisibilityTimeout || aws_cdk_lib_1.Duration.seconds(300),
|
|
141
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
142
|
+
enforceSSL: true,
|
|
143
|
+
deadLetterQueue: {
|
|
144
|
+
maxReceiveCount: props.dlqMaxReceiveCount || 5,
|
|
145
|
+
queue: this.deadLetterQueue,
|
|
146
|
+
},
|
|
147
|
+
encryption: aws_sqs_1.QueueEncryption.KMS,
|
|
148
|
+
encryptionMasterKey: this.encryptionKey,
|
|
149
|
+
});
|
|
150
|
+
this.documentProcessingTable = props.documentProcessingTable || new aws_dynamodb_1.Table(this, 'DocumentProcessingTable', {
|
|
151
|
+
partitionKey: {
|
|
152
|
+
name: 'DocumentId',
|
|
153
|
+
type: aws_dynamodb_1.AttributeType.STRING,
|
|
154
|
+
},
|
|
155
|
+
billingMode: aws_dynamodb_1.BillingMode.PAY_PER_REQUEST,
|
|
156
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
157
|
+
pointInTimeRecoverySpecification: {
|
|
158
|
+
pointInTimeRecoveryEnabled: true,
|
|
159
|
+
},
|
|
160
|
+
encryption: aws_dynamodb_1.TableEncryption.CUSTOMER_MANAGED,
|
|
161
|
+
encryptionKey: this.encryptionKey,
|
|
162
|
+
});
|
|
163
|
+
if (props.enableObservability) {
|
|
164
|
+
aws_cdk_lib_1.PropertyInjectors.of(this).add(new state_machine_observability_property_injector_1.StateMachineObservabilityPropertyInjector(this.logGroupDataProtection), new lambda_observability_property_injector_1.LambdaObservabilityPropertyInjector(this.logGroupDataProtection));
|
|
165
|
+
}
|
|
166
|
+
this.metricNamespace = props.metricNamespace || 'appmod-catalog';
|
|
167
|
+
this.metricServiceName = props.metricServiceName || 'document-processing';
|
|
168
|
+
}
|
|
169
|
+
handleStateMachineCreation(stateMachineId) {
|
|
170
|
+
const classificationStep = this.classificationStep();
|
|
171
|
+
const processingStep = this.processingStep();
|
|
172
|
+
const enrichmentStep = this.enrichmentStep();
|
|
173
|
+
const postProcessingStep = this.postProcessingStep();
|
|
174
|
+
const initMetadataEntry = new aws_stepfunctions_tasks_1.DynamoPutItem(this, 'InitMetadataEntry', {
|
|
175
|
+
table: this.documentProcessingTable,
|
|
176
|
+
item: {
|
|
177
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
178
|
+
Bucket: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.bucket')),
|
|
179
|
+
Key: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.key')),
|
|
180
|
+
WorkflowStatus: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('pending'),
|
|
181
|
+
StateMachineExecId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$$.Execution.Id')),
|
|
182
|
+
},
|
|
183
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
184
|
+
});
|
|
185
|
+
// File movement operations
|
|
186
|
+
const moveToFailed = this.createMoveToFailedChain();
|
|
187
|
+
const moveToProcessed = this.createMoveToProcessedChain();
|
|
188
|
+
const processingChain = processingStep
|
|
189
|
+
.addCatch(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'ProcessingFailDDBUpdate', {
|
|
190
|
+
table: this.documentProcessingTable,
|
|
191
|
+
key: {
|
|
192
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
193
|
+
},
|
|
194
|
+
updateExpression: 'SET WorkflowStatus = :newStatus',
|
|
195
|
+
expressionAttributeValues: {
|
|
196
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('processing-failure'),
|
|
197
|
+
},
|
|
198
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
199
|
+
}).next(moveToFailed), {
|
|
200
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
201
|
+
})
|
|
202
|
+
.next(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'ProcessingSuccessUpdate', {
|
|
203
|
+
table: this.documentProcessingTable,
|
|
204
|
+
key: {
|
|
205
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
206
|
+
},
|
|
207
|
+
updateExpression: 'SET WorkflowStatus = :newStatus, ProcessingResult = :processingResult',
|
|
208
|
+
expressionAttributeValues: {
|
|
209
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('processing-complete'),
|
|
210
|
+
':processingResult': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.jsonToString(aws_stepfunctions_1.JsonPath.objectAt('$.processingResult'))),
|
|
211
|
+
},
|
|
212
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
213
|
+
}));
|
|
214
|
+
// Build the complete chain including optional steps
|
|
215
|
+
if (enrichmentStep) {
|
|
216
|
+
const enrichmentChain = enrichmentStep
|
|
217
|
+
.addCatch(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'EnrichmentFailDDBUpdate', {
|
|
218
|
+
table: this.documentProcessingTable,
|
|
219
|
+
key: {
|
|
220
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
221
|
+
},
|
|
222
|
+
updateExpression: 'SET WorkflowStatus = :newStatus',
|
|
223
|
+
expressionAttributeValues: {
|
|
224
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('enrichment-failure'),
|
|
225
|
+
},
|
|
226
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
227
|
+
}).next(moveToFailed), {
|
|
228
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
229
|
+
})
|
|
230
|
+
.next(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'EnrichmentSuccessUpdate', {
|
|
231
|
+
table: this.documentProcessingTable,
|
|
232
|
+
key: {
|
|
233
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
234
|
+
},
|
|
235
|
+
updateExpression: 'SET WorkflowStatus = :newStatus, EnrichmentResult = :enrichmentResult',
|
|
236
|
+
expressionAttributeValues: {
|
|
237
|
+
':newStatus': postProcessingStep ? aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('enrichment-complete') : aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('complete'),
|
|
238
|
+
':enrichmentResult': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.jsonToString(aws_stepfunctions_1.JsonPath.objectAt('$.enrichedResult'))),
|
|
239
|
+
},
|
|
240
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
241
|
+
}));
|
|
242
|
+
processingChain.next(enrichmentChain);
|
|
243
|
+
if (postProcessingStep) {
|
|
244
|
+
const postProcessingChain = postProcessingStep
|
|
245
|
+
.addCatch(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'PostProcessingFailDDBUpdate', {
|
|
246
|
+
table: this.documentProcessingTable,
|
|
247
|
+
key: {
|
|
248
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
249
|
+
},
|
|
250
|
+
updateExpression: 'SET WorkflowStatus = :newStatus',
|
|
251
|
+
expressionAttributeValues: {
|
|
252
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('post-processing-failure'),
|
|
253
|
+
},
|
|
254
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
255
|
+
}).next(moveToFailed), {
|
|
256
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
257
|
+
})
|
|
258
|
+
.next(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'PostProcessingSuccessUpdate', {
|
|
259
|
+
table: this.documentProcessingTable,
|
|
260
|
+
key: {
|
|
261
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
262
|
+
},
|
|
263
|
+
updateExpression: 'SET WorkflowStatus = :newStatus, PostProcessingResult = :postProcessingResult',
|
|
264
|
+
expressionAttributeValues: {
|
|
265
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('complete'),
|
|
266
|
+
':postProcessingResult': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.jsonToString(aws_stepfunctions_1.JsonPath.objectAt('$.postProcessedResult'))),
|
|
267
|
+
},
|
|
268
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
269
|
+
}).next(moveToProcessed));
|
|
270
|
+
enrichmentChain.next(postProcessingChain);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
enrichmentChain.next(moveToProcessed);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else if (postProcessingStep) {
|
|
277
|
+
const postProcessingChain = postProcessingStep
|
|
278
|
+
.addCatch(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'PostProcessingFailDDBUpdate', {
|
|
279
|
+
table: this.documentProcessingTable,
|
|
280
|
+
key: {
|
|
281
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
282
|
+
},
|
|
283
|
+
updateExpression: 'SET WorkflowStatus = :newStatus',
|
|
284
|
+
expressionAttributeValues: {
|
|
285
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('post-processing-failure'),
|
|
286
|
+
},
|
|
287
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
288
|
+
}).next(moveToFailed), {
|
|
289
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
290
|
+
})
|
|
291
|
+
.next(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'PostProcessingSuccessUpdate', {
|
|
292
|
+
table: this.documentProcessingTable,
|
|
293
|
+
key: {
|
|
294
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
295
|
+
},
|
|
296
|
+
updateExpression: 'SET WorkflowStatus = :newStatus, PostProcessingResult = :postProcessingResult',
|
|
297
|
+
expressionAttributeValues: {
|
|
298
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('complete'),
|
|
299
|
+
':postProcessingResult': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.jsonToString(aws_stepfunctions_1.JsonPath.objectAt('$.postProcessedResult'))),
|
|
300
|
+
},
|
|
301
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
302
|
+
}).next(moveToProcessed));
|
|
303
|
+
processingChain.next(postProcessingChain);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
// No optional steps - mark as complete after extraction
|
|
307
|
+
processingChain.next(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'WorkflowCompleteUpdate', {
|
|
308
|
+
table: this.documentProcessingTable,
|
|
309
|
+
key: {
|
|
310
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
311
|
+
},
|
|
312
|
+
updateExpression: 'SET WorkflowStatus = :newStatus',
|
|
313
|
+
expressionAttributeValues: {
|
|
314
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('complete'),
|
|
315
|
+
},
|
|
316
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
317
|
+
}).next(moveToProcessed));
|
|
318
|
+
}
|
|
319
|
+
const workflowDefinition = initMetadataEntry.next(classificationStep
|
|
320
|
+
.addCatch(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'ClassificationFailDDBUpdate', {
|
|
321
|
+
table: this.documentProcessingTable,
|
|
322
|
+
key: {
|
|
323
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
324
|
+
},
|
|
325
|
+
updateExpression: 'SET WorkflowStatus = :newStatus',
|
|
326
|
+
expressionAttributeValues: {
|
|
327
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('classification-failure'),
|
|
328
|
+
},
|
|
329
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
330
|
+
}).next(moveToFailed), {
|
|
331
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
332
|
+
})
|
|
333
|
+
.next(new aws_stepfunctions_tasks_1.DynamoUpdateItem(this, 'ClassificationSuccessUpdate', {
|
|
334
|
+
table: this.documentProcessingTable,
|
|
335
|
+
key: {
|
|
336
|
+
DocumentId: aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.stringAt('$.documentId')),
|
|
337
|
+
},
|
|
338
|
+
updateExpression: 'SET WorkflowStatus = :newStatus, ClassificationResult = :classificationResult',
|
|
339
|
+
expressionAttributeValues: {
|
|
340
|
+
':newStatus': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString('classification-complete'),
|
|
341
|
+
':classificationResult': aws_stepfunctions_tasks_1.DynamoAttributeValue.fromString(aws_stepfunctions_1.JsonPath.jsonToString(aws_stepfunctions_1.JsonPath.objectAt('$.classificationResult'))),
|
|
342
|
+
},
|
|
343
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
344
|
+
}))).next(processingChain);
|
|
345
|
+
const role = this.createStateMachineRole();
|
|
346
|
+
this.encryptionKey.grantEncryptDecrypt(role);
|
|
347
|
+
if (this.bucketEncryptionKey) {
|
|
348
|
+
this.bucketEncryptionKey.grantEncryptDecrypt(role);
|
|
349
|
+
}
|
|
350
|
+
const stateMachine = new aws_stepfunctions_1.StateMachine(this, stateMachineId, {
|
|
351
|
+
definitionBody: aws_stepfunctions_1.DefinitionBody.fromChainable(workflowDefinition),
|
|
352
|
+
timeout: this.props.workflowTimeout || aws_cdk_lib_1.Duration.minutes(15),
|
|
353
|
+
role,
|
|
354
|
+
encryptionConfiguration: new aws_stepfunctions_1.CustomerManagedEncryptionConfiguration(this.encryptionKey),
|
|
355
|
+
});
|
|
356
|
+
this.handleWorkflowTrigger(stateMachine);
|
|
357
|
+
return stateMachine;
|
|
358
|
+
}
|
|
359
|
+
handleWorkflowTrigger(stateMachine) {
|
|
360
|
+
this.bucket.addEventNotification(aws_s3_1.EventType.OBJECT_CREATED, new aws_s3_notifications_1.SqsDestination(this.queue), {
|
|
361
|
+
prefix: DocumentProcessingPrefix.RAW,
|
|
362
|
+
});
|
|
363
|
+
this.createSQSConsumerLambda(stateMachine);
|
|
364
|
+
}
|
|
365
|
+
createSQSConsumerLambda(stateMachine) {
|
|
366
|
+
const { region, account } = utilities_1.LambdaIamUtils.getStackInfo(this);
|
|
367
|
+
// Create logs permissions and get unique function name
|
|
368
|
+
const logsPermissions = utilities_1.LambdaIamUtils.createLogsPermissions({
|
|
369
|
+
scope: this,
|
|
370
|
+
functionName: 'SQSConsumer',
|
|
371
|
+
region,
|
|
372
|
+
account,
|
|
373
|
+
});
|
|
374
|
+
// Create policy statements for SQS consumer Lambda
|
|
375
|
+
const policyStatements = [
|
|
376
|
+
...logsPermissions.policyStatements,
|
|
377
|
+
new aws_iam_1.PolicyStatement({
|
|
378
|
+
effect: aws_iam_1.Effect.ALLOW,
|
|
379
|
+
actions: ['states:StartExecution'],
|
|
380
|
+
resources: [stateMachine.stateMachineArn],
|
|
381
|
+
}),
|
|
382
|
+
];
|
|
383
|
+
if (this.props.network) {
|
|
384
|
+
policyStatements.push(utilities_1.LambdaIamUtils.generateLambdaVPCPermissions());
|
|
385
|
+
}
|
|
386
|
+
// Create IAM role for SQS consumer Lambda
|
|
387
|
+
const sqsConsumerRole = new aws_iam_1.Role(this, 'SQSConsumerRole', {
|
|
388
|
+
assumedBy: new aws_iam_1.ServicePrincipal('lambda.amazonaws.com'),
|
|
389
|
+
inlinePolicies: {
|
|
390
|
+
SQSConsumerExecutionPolicy: new aws_iam_1.PolicyDocument({
|
|
391
|
+
statements: policyStatements,
|
|
392
|
+
}),
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
this.encryptionKey.grantEncryptDecrypt(sqsConsumerRole);
|
|
396
|
+
// Create SQS consumer Lambda function
|
|
397
|
+
const sqsConsumerLambda = new aws_lambda_python_alpha_1.PythonFunction(this, 'SQSConsumer', {
|
|
398
|
+
functionName: logsPermissions.uniqueFunctionName,
|
|
399
|
+
runtime: framework_1.DefaultRuntimes.PYTHON,
|
|
400
|
+
role: sqsConsumerRole,
|
|
401
|
+
entry: path.join(__dirname, '/resources/default-sqs-consumer'),
|
|
402
|
+
environment: {
|
|
403
|
+
STATE_MACHINE_ARN: stateMachine.stateMachineArn,
|
|
404
|
+
...powertools_config_1.PowertoolsConfig.generateDefaultLambdaConfig(this.props.enableObservability, this.metricNamespace, this.metricServiceName),
|
|
405
|
+
},
|
|
406
|
+
timeout: aws_cdk_lib_1.Duration.minutes(5),
|
|
407
|
+
description: 'Consumes SQS messages and triggers Step Functions executions for document processing',
|
|
408
|
+
environmentEncryption: this.encryptionKey,
|
|
409
|
+
vpc: this.props.network ? this.props.network.vpc : undefined,
|
|
410
|
+
vpcSubnets: this.props.network ? this.props.network.applicationSubnetSelection() : undefined,
|
|
411
|
+
});
|
|
412
|
+
// Add SQS event source to Lambda
|
|
413
|
+
sqsConsumerLambda.addEventSource(new aws_lambda_event_sources_1.SqsEventSource(this.queue, {
|
|
414
|
+
batchSize: 10,
|
|
415
|
+
maxBatchingWindow: aws_cdk_lib_1.Duration.seconds(5),
|
|
416
|
+
reportBatchItemFailures: true,
|
|
417
|
+
}));
|
|
418
|
+
return sqsConsumerLambda;
|
|
419
|
+
}
|
|
420
|
+
createStateMachineRole() {
|
|
421
|
+
return new aws_iam_1.Role(this, 'StateMachineRole', {
|
|
422
|
+
assumedBy: new aws_iam_1.ServicePrincipal('states.amazonaws.com'),
|
|
423
|
+
inlinePolicies: {
|
|
424
|
+
StateMachineExecutionPolicy: new aws_iam_1.PolicyDocument({
|
|
425
|
+
statements: [
|
|
426
|
+
new aws_iam_1.PolicyStatement({
|
|
427
|
+
effect: aws_iam_1.Effect.ALLOW,
|
|
428
|
+
actions: ['s3:GetObject', 's3:CopyObject', 's3:DeleteObject', 's3:PutObject'],
|
|
429
|
+
resources: [`${this.bucket.bucketArn}/*`],
|
|
430
|
+
}),
|
|
431
|
+
new aws_iam_1.PolicyStatement({
|
|
432
|
+
effect: aws_iam_1.Effect.ALLOW,
|
|
433
|
+
actions: ['dynamodb:PutItem', 'dynamodb:UpdateItem'],
|
|
434
|
+
resources: [this.documentProcessingTable.tableArn],
|
|
435
|
+
}),
|
|
436
|
+
],
|
|
437
|
+
}),
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
createMoveToFailedChain() {
|
|
442
|
+
const failedChain = new aws_stepfunctions_tasks_1.CallAwsService(this, 'CopyToFailed', {
|
|
443
|
+
service: 's3',
|
|
444
|
+
action: 'copyObject',
|
|
445
|
+
parameters: {
|
|
446
|
+
Bucket: aws_stepfunctions_1.JsonPath.stringAt('$.bucket'),
|
|
447
|
+
CopySource: aws_stepfunctions_1.JsonPath.format('{}/{}', aws_stepfunctions_1.JsonPath.stringAt('$.bucket'), aws_stepfunctions_1.JsonPath.stringAt('$.key')),
|
|
448
|
+
Key: aws_stepfunctions_1.JsonPath.format('failed/{}', aws_stepfunctions_1.JsonPath.stringAt('$.filename')),
|
|
449
|
+
},
|
|
450
|
+
iamResources: [`${this.bucket.bucketArn}/*`],
|
|
451
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
452
|
+
}).next(new aws_stepfunctions_tasks_1.CallAwsService(this, 'DeleteFromRaw', {
|
|
453
|
+
service: 's3',
|
|
454
|
+
action: 'deleteObject',
|
|
455
|
+
parameters: {
|
|
456
|
+
Bucket: aws_stepfunctions_1.JsonPath.stringAt('$.bucket'),
|
|
457
|
+
Key: aws_stepfunctions_1.JsonPath.stringAt('$.key'),
|
|
458
|
+
},
|
|
459
|
+
iamResources: [`${this.bucket.bucketArn}/*`],
|
|
460
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
461
|
+
}));
|
|
462
|
+
if (this.props.eventbridgeBroker) {
|
|
463
|
+
failedChain.next(this.props.eventbridgeBroker.sendViaSfnChain('document-processing-failed', {
|
|
464
|
+
documentId: aws_stepfunctions_1.JsonPath.stringAt('$.documentId'),
|
|
465
|
+
bucket: aws_stepfunctions_1.JsonPath.stringAt('$.bucket'),
|
|
466
|
+
filename: aws_stepfunctions_1.JsonPath.stringAt('$.filename'),
|
|
467
|
+
}));
|
|
468
|
+
}
|
|
469
|
+
return failedChain;
|
|
470
|
+
}
|
|
471
|
+
createMoveToProcessedChain() {
|
|
472
|
+
const processedChain = new aws_stepfunctions_tasks_1.CallAwsService(this, 'CopyToProcessed', {
|
|
473
|
+
service: 's3',
|
|
474
|
+
action: 'copyObject',
|
|
475
|
+
parameters: {
|
|
476
|
+
Bucket: aws_stepfunctions_1.JsonPath.stringAt('$.bucket'),
|
|
477
|
+
CopySource: aws_stepfunctions_1.JsonPath.format('{}/{}', aws_stepfunctions_1.JsonPath.stringAt('$.bucket'), aws_stepfunctions_1.JsonPath.stringAt('$.key')),
|
|
478
|
+
Key: aws_stepfunctions_1.JsonPath.format('processed/{}', aws_stepfunctions_1.JsonPath.stringAt('$.filename')),
|
|
479
|
+
},
|
|
480
|
+
iamResources: [`${this.bucket.bucketArn}/*`],
|
|
481
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
482
|
+
}).next(new aws_stepfunctions_tasks_1.CallAwsService(this, 'DeleteFromRawSuccess', {
|
|
483
|
+
service: 's3',
|
|
484
|
+
action: 'deleteObject',
|
|
485
|
+
parameters: {
|
|
486
|
+
Bucket: aws_stepfunctions_1.JsonPath.stringAt('$.bucket'),
|
|
487
|
+
Key: aws_stepfunctions_1.JsonPath.stringAt('$.key'),
|
|
488
|
+
},
|
|
489
|
+
iamResources: [`${this.bucket.bucketArn}/*`],
|
|
490
|
+
resultPath: aws_stepfunctions_1.JsonPath.DISCARD,
|
|
491
|
+
}));
|
|
492
|
+
if (this.props.eventbridgeBroker) {
|
|
493
|
+
processedChain.next(this.props.eventbridgeBroker.sendViaSfnChain('document-processed-successful', {
|
|
494
|
+
documentId: aws_stepfunctions_1.JsonPath.stringAt('$.documentId'),
|
|
495
|
+
bucket: aws_stepfunctions_1.JsonPath.stringAt('$.bucket'),
|
|
496
|
+
filename: aws_stepfunctions_1.JsonPath.stringAt('$.filename'),
|
|
497
|
+
classification: aws_stepfunctions_1.JsonPath.stringAt('$.classificationResult.documentClassification'),
|
|
498
|
+
}));
|
|
499
|
+
}
|
|
500
|
+
return processedChain;
|
|
501
|
+
}
|
|
502
|
+
metrics() {
|
|
503
|
+
return [];
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
exports.BaseDocumentProcessing = BaseDocumentProcessing;
|
|
507
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
508
|
+
BaseDocumentProcessing[_a] = { fqn: "@cdklabs/cdk-appmod-catalog-blueprints.BaseDocumentProcessing", version: "1.0.0" };
|
|
509
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1kb2N1bWVudC1wcm9jZXNzaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdXNlLWNhc2VzL2RvY3VtZW50LXByb2Nlc3NpbmcvYmFzZS1kb2N1bWVudC1wcm9jZXNzaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscUVBQXFFO0FBQ3JFLHNDQUFzQztBQUV0QyxrQ0FBa0M7QUFDbEMsOEVBQWtFO0FBQ2xFLDZDQUFnRjtBQUVoRiwyREFBOEY7QUFDOUYsaURBQXFFO0FBQ3JFLGlEQUFzRztBQUN0RyxpREFBZ0Q7QUFFaEQsbUZBQXNFO0FBQ3RFLCtDQUF5RTtBQUN6RSwyRUFBa0U7QUFDbEUsaURBQTZEO0FBQzdELHFFQUErSDtBQUMvSCxpRkFBMkw7QUFDM0wsMkNBQXVDO0FBQ3ZDLDRDQUF3RDtBQUV4RCw0Q0FBMkU7QUFDM0UsOEhBQXdIO0FBRXhILG9GQUFnRjtBQUNoRiw0SUFBcUk7QUFpRXJJOzs7Ozs7O0dBT0c7QUFDSCxJQUFZLHdCQU9YO0FBUEQsV0FBWSx3QkFBd0I7SUFDbEMsOERBQThEO0lBQzlELHdDQUFZLENBQUE7SUFDWixrREFBa0Q7SUFDbEQsOENBQWtCLENBQUE7SUFDbEIsa0RBQWtEO0lBQ2xELG9EQUF3QixDQUFBO0FBQzFCLENBQUMsRUFQVyx3QkFBd0Isd0NBQXhCLHdCQUF3QixRQU9uQztBQVFEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFzQixzQkFBdUIsU0FBUSxzQkFBUztJQXNCNUQ7Ozs7Ozs7OztPQVNHO0lBQ0gsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFrQztRQUMxRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2pCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2xCLEtBQUssQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsVUFBVSxFQUFFLHdDQUE4QixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3BGLEtBQUssQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsU0FBUyxFQUFFLHdDQUE4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2xGLEtBQUssQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsVUFBVSxFQUFFLHdDQUE4QixDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQy9GLEtBQUssQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsU0FBUyxFQUFFLHdDQUE4QixDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQzNGLElBQUksS0FBSyxDQUFDLG1CQUFtQixFQUFFLENBQUM7Z0JBQzlCLEtBQUssQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsV0FBVyxFQUFFLHdDQUE4QixDQUFDLGVBQWUsQ0FBQyxDQUFDO2dCQUNqRyxLQUFLLENBQUMsT0FBTyxDQUFDLHFCQUFxQixDQUFDLGNBQWMsRUFBRSx3Q0FBOEIsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1lBQzVHLENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLGFBQWEsR0FBRyxLQUFLLENBQUMsYUFBYSxJQUFJLElBQUksYUFBRyxDQUFDLElBQUksRUFBRSxrQkFBa0IsRUFBRTtZQUM1RSxpQkFBaUIsRUFBRSxJQUFJO1lBQ3ZCLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxJQUFJLDJCQUFhLENBQUMsT0FBTztTQUM1RCxDQUFDLENBQUM7UUFFSCxNQUFNLFVBQVUsR0FBRyw0QkFBNEIsbUJBQUssQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLEVBQUU7WUFDNUUsU0FBUyxFQUFFLEVBQUUsR0FBRywyQkFBMkIsQ0FBQyxNQUFNO1NBQ25ELENBQUMsRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRW5CLE1BQU0sU0FBUyxHQUFHLGdCQUFnQixVQUFVLEVBQUUsQ0FBQztRQUUvQyxJQUFJLENBQUMsYUFBYSxDQUFDLG1CQUFtQixDQUFDLElBQUksMEJBQWdCLENBQUMsa0JBQWtCLEVBQUU7WUFDOUUsVUFBVSxFQUFFO2dCQUNWLFNBQVMsRUFBRTtvQkFDVCxrQ0FBa0MsRUFBRSxTQUFTO2lCQUM5QzthQUNGO1NBQ0YsQ0FBQyxDQUFDLENBQUM7UUFFSixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLElBQUksSUFBSSxlQUFNLENBQUMsSUFBSSxFQUFFLDBCQUEwQixFQUFFO1lBQ3pFLFVBQVU7WUFDVixpQkFBaUIsRUFBRSxDQUFDLEtBQUssQ0FBQyxhQUFhLElBQUksS0FBSyxDQUFDLGFBQWEsS0FBSywyQkFBYSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLO1lBQ2hJLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxJQUFJLDJCQUFhLENBQUMsT0FBTztZQUMzRCxVQUFVLEVBQUUseUJBQWdCLENBQUMsR0FBRztZQUNoQyxVQUFVLEVBQUUsSUFBSTtZQUNoQixnQkFBZ0IsRUFBRSxJQUFJO1NBQ3ZCLENBQUMsQ0FBQztRQUdILElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQztRQUVyRCxNQUFNLDBCQUEwQixHQUFHLEtBQUssQ0FBQyxzQkFBc0IsSUFBSTtZQUNqRSxxQkFBcUIsRUFBRSxJQUFJLGFBQUcsQ0FBQyxJQUFJLEVBQUUsdUJBQXVCLEVBQUU7Z0JBQzVELGlCQUFpQixFQUFFLElBQUk7Z0JBQ3ZCLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxJQUFJLDJCQUFhLENBQUMsT0FBTzthQUM1RCxDQUFDO1NBQ0gsQ0FBQztRQUVGLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1lBQ3RELElBQUksQ0FBQyxzQkFBc0IsR0FBRztnQkFDNUIseUJBQXlCLEVBQUUsMEJBQTBCLENBQUMseUJBQXlCO2dCQUMvRSxxQkFBcUIsRUFBRSxJQUFJLGFBQUcsQ0FBQyxJQUFJLEVBQUUsdUJBQXVCLEVBQUU7b0JBQzVELGlCQUFpQixFQUFFLElBQUk7b0JBQ3ZCLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxJQUFJLDJCQUFhLENBQUMsT0FBTztpQkFDNUQsQ0FBQzthQUNILENBQUM7UUFDSixDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxzQkFBc0IsR0FBRywwQkFBMEIsQ0FBQztRQUMzRCxDQUFDO1FBRUQsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQUUsdUJBQXVCLEVBQUU7WUFDOUQsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLHNCQUFzQixJQUFJLHNCQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUN4RSxhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWEsSUFBSSwyQkFBYSxDQUFDLE9BQU87WUFDM0QsVUFBVSxFQUFFLElBQUk7WUFDaEIsVUFBVSxFQUFFLHlCQUFlLENBQUMsR0FBRztZQUMvQixtQkFBbUIsRUFBRSxJQUFJLENBQUMsYUFBYTtTQUN4QyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksZUFBSyxDQUFDLElBQUksRUFBRSx5QkFBeUIsRUFBRTtZQUN0RCxpQkFBaUIsRUFBRSxLQUFLLENBQUMsc0JBQXNCLElBQUksc0JBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDO1lBQ3hFLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxJQUFJLDJCQUFhLENBQUMsT0FBTztZQUMzRCxVQUFVLEVBQUUsSUFBSTtZQUNoQixlQUFlLEVBQUU7Z0JBQ2YsZUFBZSxFQUFFLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSxDQUFDO2dCQUM5QyxLQUFLLEVBQUUsSUFBSSxDQUFDLGVBQWU7YUFDNUI7WUFDRCxVQUFVLEVBQUUseUJBQWUsQ0FBQyxHQUFHO1lBQy9CLG1CQUFtQixFQUFFLElBQUksQ0FBQyxhQUFhO1NBQ3hDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyx1QkFBdUIsR0FBRyxLQUFLLENBQUMsdUJBQXVCLElBQUksSUFBSSxvQkFBSyxDQUFDLElBQUksRUFBRSx5QkFBeUIsRUFBRTtZQUN6RyxZQUFZLEVBQUU7Z0JBQ1osSUFBSSxFQUFFLFlBQVk7Z0JBQ2xCLElBQUksRUFBRSw0QkFBYSxDQUFDLE1BQU07YUFDM0I7WUFDRCxXQUFXLEVBQUUsMEJBQVcsQ0FBQyxlQUFlO1lBQ3hDLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxJQUFJLDJCQUFhLENBQUMsT0FBTztZQUMzRCxnQ0FBZ0MsRUFBRTtnQkFDaEMsMEJBQTBCLEVBQUUsSUFBSTthQUNqQztZQUNELFVBQVUsRUFBRSw4QkFBZSxDQUFDLGdCQUFnQjtZQUM1QyxhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7U0FDbEMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxLQUFLLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUM5QiwrQkFBaUIsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUM1QixJQUFJLHlGQUF5QyxDQUFDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxFQUMxRSxJQUFJLDRFQUFtQyxDQUFDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxDQUNyRSxDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksQ0FBQyxlQUFlLEdBQUcsS0FBSyxDQUFDLGVBQWUsSUFBSSxnQkFBZ0IsQ0FBQztRQUNqRSxJQUFJLENBQUMsaUJBQWlCLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixJQUFJLHFCQUFxQixDQUFDO0lBQzVFLENBQUM7SUFHUywwQkFBMEIsQ0FBQyxjQUFzQjtRQUN6RCxNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQ3JELE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUM3QyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDN0MsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUVyRCxNQUFNLGlCQUFpQixHQUFHLElBQUksdUNBQWEsQ0FBQyxJQUFJLEVBQUUsbUJBQW1CLEVBQUU7WUFDckUsS0FBSyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7WUFDbkMsSUFBSSxFQUFFO2dCQUNKLFVBQVUsRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsNEJBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUM7Z0JBQzlFLE1BQU0sRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsNEJBQVEsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQ3RFLEdBQUcsRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsNEJBQVEsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ2hFLGNBQWMsRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDO2dCQUMxRCxrQkFBa0IsRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsNEJBQVEsQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsQ0FBQzthQUMxRjtZQUNELFVBQVUsRUFBRSw0QkFBUSxDQUFDLE9BQU87U0FDN0IsQ0FBQyxDQUFDO1FBRUgsMkJBQTJCO1FBQzNCLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBQ3BELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1FBRTFELE1BQU0sZUFBZSxHQUFHLGNBQWM7YUFDbkMsUUFBUSxDQUFDLElBQUksMENBQWdCLENBQUMsSUFBSSxFQUFFLHlCQUF5QixFQUFFO1lBQzlELEtBQUssRUFBRSxJQUFJLENBQUMsdUJBQXVCO1lBQ25DLEdBQUcsRUFBRTtnQkFDSCxVQUFVLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO2FBQy9FO1lBQ0QsZ0JBQWdCLEVBQUUsaUNBQWlDO1lBQ25ELHlCQUF5QixFQUFFO2dCQUN6QixZQUFZLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLG9CQUFvQixDQUFDO2FBQ3BFO1lBQ0QsVUFBVSxFQUFFLDRCQUFRLENBQUMsT0FBTztTQUM3QixDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFO1lBQ3JCLFVBQVUsRUFBRSw0QkFBUSxDQUFDLE9BQU87U0FDN0IsQ0FBQzthQUNELElBQUksQ0FDSCxJQUFJLDBDQUFnQixDQUFDLElBQUksRUFBRSx5QkFBeUIsRUFBRTtZQUNwRCxLQUFLLEVBQUUsSUFBSSxDQUFDLHVCQUF1QjtZQUNuQyxHQUFHLEVBQUU7Z0JBQ0gsVUFBVSxFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQzthQUMvRTtZQUNELGdCQUFnQixFQUFFLHVFQUF1RTtZQUN6Rix5QkFBeUIsRUFBRTtnQkFDekIsWUFBWSxFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyxxQkFBcUIsQ0FBQztnQkFDcEUsbUJBQW1CLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsWUFBWSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQzthQUNySDtZQUNELFVBQVUsRUFBRSw0QkFBUSxDQUFDLE9BQU87U0FDN0IsQ0FBQyxDQUNILENBQUM7UUFFSixvREFBb0Q7UUFDcEQsSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUNuQixNQUFNLGVBQWUsR0FBRyxjQUFjO2lCQUNuQyxRQUFRLENBQUMsSUFBSSwwQ0FBZ0IsQ0FBQyxJQUFJLEVBQUUseUJBQXlCLEVBQUU7Z0JBQzlELEtBQUssRUFBRSxJQUFJLENBQUMsdUJBQXVCO2dCQUNuQyxHQUFHLEVBQUU7b0JBQ0gsVUFBVSxFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztpQkFDL0U7Z0JBQ0QsZ0JBQWdCLEVBQUUsaUNBQWlDO2dCQUNuRCx5QkFBeUIsRUFBRTtvQkFDekIsWUFBWSxFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyxvQkFBb0IsQ0FBQztpQkFDcEU7Z0JBQ0QsVUFBVSxFQUFFLDRCQUFRLENBQUMsT0FBTzthQUM3QixDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFO2dCQUNyQixVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO2FBQzdCLENBQUM7aUJBQ0QsSUFBSSxDQUNILElBQUksMENBQWdCLENBQUMsSUFBSSxFQUFFLHlCQUF5QixFQUFFO2dCQUNwRCxLQUFLLEVBQUUsSUFBSSxDQUFDLHVCQUF1QjtnQkFDbkMsR0FBRyxFQUFFO29CQUNILFVBQVUsRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsNEJBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUM7aUJBQy9FO2dCQUNELGdCQUFnQixFQUFFLHVFQUF1RTtnQkFDekYseUJBQXlCLEVBQUU7b0JBQ3pCLFlBQVksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsOENBQW9CLENBQUMsVUFBVSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFDLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7b0JBQ3ZJLG1CQUFtQixFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyw0QkFBUSxDQUFDLFlBQVksQ0FBQyw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUM7aUJBQ25IO2dCQUNELFVBQVUsRUFBRSw0QkFBUSxDQUFDLE9BQU87YUFDN0IsQ0FBQyxDQUNILENBQUM7WUFFSixlQUFlLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBRXRDLElBQUksa0JBQWtCLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxtQkFBbUIsR0FBRyxrQkFBa0I7cUJBQzNDLFFBQVEsQ0FBQyxJQUFJLDBDQUFnQixDQUFDLElBQUksRUFBRSw2QkFBNkIsRUFBRTtvQkFDbEUsS0FBSyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7b0JBQ25DLEdBQUcsRUFBRTt3QkFDSCxVQUFVLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO3FCQUMvRTtvQkFDRCxnQkFBZ0IsRUFBRSxpQ0FBaUM7b0JBQ25ELHlCQUF5QixFQUFFO3dCQUN6QixZQUFZLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLHlCQUF5QixDQUFDO3FCQUN6RTtvQkFDRCxVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO2lCQUM3QixDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFO29CQUNyQixVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO2lCQUM3QixDQUFDO3FCQUNELElBQUksQ0FDSCxJQUFJLDBDQUFnQixDQUFDLElBQUksRUFBRSw2QkFBNkIsRUFBRTtvQkFDeEQsS0FBSyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7b0JBQ25DLEdBQUcsRUFBRTt3QkFDSCxVQUFVLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO3FCQUMvRTtvQkFDRCxnQkFBZ0IsRUFBRSwrRUFBK0U7b0JBQ2pHLHlCQUF5QixFQUFFO3dCQUN6QixZQUFZLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQzt3QkFDekQsdUJBQXVCLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsWUFBWSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLHVCQUF1QixDQUFDLENBQUMsQ0FBQztxQkFDNUg7b0JBQ0QsVUFBVSxFQUFFLDRCQUFRLENBQUMsT0FBTztpQkFDN0IsQ0FBQyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FDekIsQ0FBQztnQkFDSixlQUFlLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDNUMsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLGVBQWUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7WUFDeEMsQ0FBQztRQUNILENBQUM7YUFBTSxJQUFJLGtCQUFrQixFQUFFLENBQUM7WUFDOUIsTUFBTSxtQkFBbUIsR0FBRyxrQkFBa0I7aUJBQzNDLFFBQVEsQ0FBQyxJQUFJLDBDQUFnQixDQUFDLElBQUksRUFBRSw2QkFBNkIsRUFBRTtnQkFDbEUsS0FBSyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7Z0JBQ25DLEdBQUcsRUFBRTtvQkFDSCxVQUFVLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO2lCQUMvRTtnQkFDRCxnQkFBZ0IsRUFBRSxpQ0FBaUM7Z0JBQ25ELHlCQUF5QixFQUFFO29CQUN6QixZQUFZLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLHlCQUF5QixDQUFDO2lCQUN6RTtnQkFDRCxVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO2FBQzdCLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUU7Z0JBQ3JCLFVBQVUsRUFBRSw0QkFBUSxDQUFDLE9BQU87YUFDN0IsQ0FBQztpQkFDRCxJQUFJLENBQ0gsSUFBSSwwQ0FBZ0IsQ0FBQyxJQUFJLEVBQUUsNkJBQTZCLEVBQUU7Z0JBQ3hELEtBQUssRUFBRSxJQUFJLENBQUMsdUJBQXVCO2dCQUNuQyxHQUFHLEVBQUU7b0JBQ0gsVUFBVSxFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztpQkFDL0U7Z0JBQ0QsZ0JBQWdCLEVBQUUsK0VBQStFO2dCQUNqRyx5QkFBeUIsRUFBRTtvQkFDekIsWUFBWSxFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7b0JBQ3pELHVCQUF1QixFQUFFLDhDQUFvQixDQUFDLFVBQVUsQ0FBQyw0QkFBUSxDQUFDLFlBQVksQ0FBQyw0QkFBUSxDQUFDLFFBQVEsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLENBQUM7aUJBQzVIO2dCQUNELFVBQVUsRUFBRSw0QkFBUSxDQUFDLE9BQU87YUFDN0IsQ0FBQyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FDekIsQ0FBQztZQUNKLGVBQWUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUM1QyxDQUFDO2FBQU0sQ0FBQztZQUNOLHdEQUF3RDtZQUN4RCxlQUFlLENBQUMsSUFBSSxDQUNsQixJQUFJLDBDQUFnQixDQUFDLElBQUksRUFBRSx3QkFBd0IsRUFBRTtnQkFDbkQsS0FBSyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7Z0JBQ25DLEdBQUcsRUFBRTtvQkFDSCxVQUFVLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO2lCQUMvRTtnQkFDRCxnQkFBZ0IsRUFBRSxpQ0FBaUM7Z0JBQ25ELHlCQUF5QixFQUFFO29CQUN6QixZQUFZLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQztpQkFDMUQ7Z0JBQ0QsVUFBVSxFQUFFLDRCQUFRLENBQUMsT0FBTzthQUM3QixDQUFDLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUN6QixDQUFDO1FBQ0osQ0FBQztRQUVELE1BQU0sa0JBQWtCLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUMvQyxrQkFBa0I7YUFDZixRQUFRLENBQUMsSUFBSSwwQ0FBZ0IsQ0FBQyxJQUFJLEVBQUUsNkJBQTZCLEVBQUU7WUFDbEUsS0FBSyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7WUFDbkMsR0FBRyxFQUFFO2dCQUNILFVBQVUsRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsNEJBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUM7YUFDL0U7WUFDRCxnQkFBZ0IsRUFBRSxpQ0FBaUM7WUFDbkQseUJBQXlCLEVBQUU7Z0JBQ3pCLFlBQVksRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsd0JBQXdCLENBQUM7YUFDeEU7WUFDRCxVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO1NBQzdCLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUU7WUFDckIsVUFBVSxFQUFFLDRCQUFRLENBQUMsT0FBTztTQUM3QixDQUFDO2FBQ0QsSUFBSSxDQUNILElBQUksMENBQWdCLENBQUMsSUFBSSxFQUFFLDZCQUE2QixFQUFFO1lBQ3hELEtBQUssRUFBRSxJQUFJLENBQUMsdUJBQXVCO1lBQ25DLEdBQUcsRUFBRTtnQkFDSCxVQUFVLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLDRCQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO2FBQy9FO1lBQ0QsZ0JBQWdCLEVBQUUsK0VBQStFO1lBQ2pHLHlCQUF5QixFQUFFO2dCQUN6QixZQUFZLEVBQUUsOENBQW9CLENBQUMsVUFBVSxDQUFDLHlCQUF5QixDQUFDO2dCQUN4RSx1QkFBdUIsRUFBRSw4Q0FBb0IsQ0FBQyxVQUFVLENBQUMsNEJBQVEsQ0FBQyxZQUFZLENBQUMsNEJBQVEsQ0FBQyxRQUFRLENBQUMsd0JBQXdCLENBQUMsQ0FBQyxDQUFDO2FBQzdIO1lBQ0QsVUFBVSxFQUFFLDRCQUFRLENBQUMsT0FBTztTQUM3QixDQUFDLENBQ0gsQ0FDSixDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUV4QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztRQUMzQyxJQUFJLENBQUMsYUFBYSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdDLElBQUksSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7WUFDN0IsSUFBSSxDQUFDLG1CQUFtQixDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFDRCxNQUFNLFlBQVksR0FBRyxJQUFJLGdDQUFZLENBQUMsSUFBSSxFQUFFLGNBQWMsRUFBRTtZQUMxRCxjQUFjLEVBQUUsa0NBQWMsQ0FBQyxhQUFhLENBQUMsa0JBQWtCLENBQUM7WUFDaEUsT0FBTyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxJQUFJLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUMzRCxJQUFJO1lBQ0osdUJBQXVCLEVBQUUsSUFBSSwwREFBc0MsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO1NBQ3hGLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUV6QyxPQUFPLFlBQVksQ0FBQztJQUN0QixDQUFDO0lBRVMscUJBQXFCLENBQUMsWUFBMEI7UUFDeEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxrQkFBUyxDQUFDLGNBQWMsRUFBRSxJQUFJLHFDQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ3pGLE1BQU0sRUFBRSx3QkFBd0IsQ0FBQyxHQUFHO1NBQ3JDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRU8sdUJBQXVCLENBQUMsWUFBMEI7UUFDeEQsTUFBTSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRywwQkFBYyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM5RCx1REFBdUQ7UUFDdkQsTUFBTSxlQUFlLEdBQUcsMEJBQWMsQ0FBQyxxQkFBcUIsQ0FBQztZQUMzRCxLQUFLLEVBQUUsSUFBSTtZQUNYLFlBQVksRUFBRSxhQUFhO1lBQzNCLE1BQU07WUFDTixPQUFPO1NBQ1IsQ0FBQyxDQUFDO1FBRUgsbURBQW1EO1FBQ25ELE1BQU0sZ0JBQWdCLEdBQUc7WUFDdkIsR0FBRyxlQUFlLENBQUMsZ0JBQWdCO1lBQ25DLElBQUkseUJBQWUsQ0FBQztnQkFDbEIsTUFBTSxFQUFFLGdCQUFNLENBQUMsS0FBSztnQkFDcEIsT0FBTyxFQUFFLENBQUMsdUJBQXVCLENBQUM7Z0JBQ2xDLFNBQVMsRUFBRSxDQUFDLFlBQVksQ0FBQyxlQUFlLENBQUM7YUFDMUMsQ0FBQztTQUNILENBQUM7UUFFRixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDdkIsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLDBCQUFjLENBQUMsNEJBQTRCLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZFLENBQUM7UUFFRCwwQ0FBMEM7UUFDMUMsTUFBTSxlQUFlLEdBQUcsSUFBSSxjQUFJLENBQUMsSUFBSSxFQUFFLGlCQUFpQixFQUFFO1lBQ3hELFNBQVMsRUFBRSxJQUFJLDBCQUFnQixDQUFDLHNCQUFzQixDQUFDO1lBQ3ZELGNBQWMsRUFBRTtnQkFDZCwwQkFBMEIsRUFBRSxJQUFJLHdCQUFjLENBQUM7b0JBQzdDLFVBQVUsRUFBRSxnQkFBZ0I7aUJBQzdCLENBQUM7YUFDSDtTQUNGLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxhQUFhLENBQUMsbUJBQW1CLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFeEQsc0NBQXNDO1FBQ3RDLE1BQU0saUJBQWlCLEdBQUcsSUFBSSx3Q0FBYyxDQUFDLElBQUksRUFBRSxhQUFhLEVBQUU7WUFDaEUsWUFBWSxFQUFFLGVBQWUsQ0FBQyxrQkFBa0I7WUFDaEQsT0FBTyxFQUFFLDJCQUFlLENBQUMsTUFBTTtZQUMvQixJQUFJLEVBQUUsZUFBZTtZQUNyQixLQUFLLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsaUNBQWlDLENBQUM7WUFDOUQsV0FBVyxFQUFFO2dCQUNYLGlCQUFpQixFQUFFLFlBQVksQ0FBQyxlQUFlO2dCQUMvQyxHQUFHLG9DQUFnQixDQUFDLDJCQUEyQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsaUJBQWlCLENBQUM7YUFDOUg7WUFDRCxPQUFPLEVBQUUsc0JBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBQzVCLFdBQVcsRUFBRSxzRkFBc0Y7WUFDbkcscUJBQXFCLEVBQUUsSUFBSSxDQUFDLGFBQWE7WUFDekMsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVM7WUFDNUQsVUFBVSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQywwQkFBMEIsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTO1NBQzdGLENBQUMsQ0FBQztRQUVILGlDQUFpQztRQUNqQyxpQkFBaUIsQ0FBQyxjQUFjLENBQzlCLElBQUkseUNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFO1lBQzdCLFNBQVMsRUFBRSxFQUFFO1lBQ2IsaUJBQWlCLEVBQUUsc0JBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBQ3RDLHVCQUF1QixFQUFFLElBQUk7U0FDOUIsQ0FBQyxDQUNILENBQUM7UUFFRixPQUFPLGlCQUFpQixDQUFDO0lBQzNCLENBQUM7SUFFTyxzQkFBc0I7UUFDNUIsT0FBTyxJQUFJLGNBQUksQ0FBQyxJQUFJLEVBQUUsa0JBQWtCLEVBQUU7WUFDeEMsU0FBUyxFQUFFLElBQUksMEJBQWdCLENBQUMsc0JBQXNCLENBQUM7WUFDdkQsY0FBYyxFQUFFO2dCQUNkLDJCQUEyQixFQUFFLElBQUksd0JBQWMsQ0FBQztvQkFDOUMsVUFBVSxFQUFFO3dCQUNWLElBQUkseUJBQWUsQ0FBQzs0QkFDbEIsTUFBTSxFQUFFLGdCQUFNLENBQUMsS0FBSzs0QkFDcEIsT0FBTyxFQUFFLENBQUMsY0FBYyxFQUFFLGVBQWUsRUFBRSxpQkFBaUIsRUFBRSxjQUFjLENBQUM7NEJBQzdFLFNBQVMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLElBQUksQ0FBQzt5QkFDMUMsQ0FBQzt3QkFDRixJQUFJLHlCQUFlLENBQUM7NEJBQ2xCLE1BQU0sRUFBRSxnQkFBTSxDQUFDLEtBQUs7NEJBQ3BCLE9BQU8sRUFBRSxDQUFDLGtCQUFrQixFQUFFLHFCQUFxQixDQUFDOzRCQUNwRCxTQUFTLEVBQUUsQ0FBQyxJQUFJLENBQUMsdUJBQXVCLENBQUMsUUFBUSxDQUFDO3lCQUNuRCxDQUFDO3FCQUNIO2lCQUNGLENBQUM7YUFDSDtTQUNGLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyx1QkFBdUI7UUFDN0IsTUFBTSxXQUFXLEdBQUcsSUFBSSx3Q0FBYyxDQUFDLElBQUksRUFBRSxjQUFjLEVBQUU7WUFDM0QsT0FBTyxFQUFFLElBQUk7WUFDYixNQUFNLEVBQUUsWUFBWTtZQUNwQixVQUFVLEVBQUU7Z0JBQ1YsTUFBTSxFQUFFLDRCQUFRLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQztnQkFDckMsVUFBVSxFQUFFLDRCQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDL0YsR0FBRyxFQUFFLDRCQUFRLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQzthQUNuRTtZQUNELFlBQVksRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLElBQUksQ0FBQztZQUM1QyxVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO1NBQzdCLENBQUMsQ0FBQyxJQUFJLENBQ0wsSUFBSSx3Q0FBYyxDQUFDLElBQUksRUFBRSxlQUFlLEVBQUU7WUFDeEMsT0FBTyxFQUFFLElBQUk7WUFDYixNQUFNLEVBQUUsY0FBYztZQUN0QixVQUFVLEVBQUU7Z0JBQ1YsTUFBTSxFQUFFLDRCQUFRLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQztnQkFDckMsR0FBRyxFQUFFLDRCQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQzthQUNoQztZQUNELFlBQVksRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLElBQUksQ0FBQztZQUM1QyxVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO1NBQzdCLENBQUMsQ0FDSCxDQUFDO1FBRUYsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDakMsV0FBVyxDQUFDLElBQUksQ0FDZCxJQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLGVBQWUsQ0FDMUMsNEJBQTRCLEVBQzVCO2dCQUNFLFVBQVUsRUFBRSw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUM7Z0JBQzdDLE1BQU0sRUFBRSw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7Z0JBQ3JDLFFBQVEsRUFBRSw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUM7YUFDMUMsQ0FDRixDQUNGLENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVPLDBCQUEwQjtRQUNoQyxNQUFNLGNBQWMsR0FBRyxJQUFJLHdDQUFjLENBQUMsSUFBSSxFQUFFLGlCQUFpQixFQUFFO1lBQ2pFLE9BQU8sRUFBRSxJQUFJO1lBQ2IsTUFBTSxFQUFFLFlBQVk7WUFDcEIsVUFBVSxFQUFFO2dCQUNWLE1BQU0sRUFBRSw0QkFBUSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7Z0JBQ3JDLFVBQVUsRUFBRSw0QkFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsNEJBQVEsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsNEJBQVEsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQy9GLEdBQUcsRUFBRSw0QkFBUSxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsNEJBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUM7YUFDdEU7WUFDRCxZQUFZLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxJQUFJLENBQUM7WUFDNUMsVUFBVSxFQUFFLDRCQUFRLENBQUMsT0FBTztTQUM3QixDQUFDLENBQUMsSUFBSSxDQUNMLElBQUksd0NBQWMsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLEVBQUU7WUFDL0MsT0FBTyxFQUFFLElBQUk7WUFDYixNQUFNLEVBQUUsY0FBYztZQUN0QixVQUFVLEVBQUU7Z0JBQ1YsTUFBTSxFQUFFLDRCQUFRLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQztnQkFDckMsR0FBRyxFQUFFLDRCQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQzthQUNoQztZQUNELFlBQVksRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLElBQUksQ0FBQztZQUM1QyxVQUFVLEVBQUUsNEJBQVEsQ0FBQyxPQUFPO1NBQzdCLENBQUMsQ0FDSCxDQUFDO1FBRUYsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDakMsY0FBYyxDQUFDLElBQUksQ0FDakIsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxlQUFlLENBQzFDLCtCQUErQixFQUMvQjtnQkFDRSxVQUFVLEVBQUUsNEJBQVEsQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDO2dCQUM3QyxNQUFNLEVBQUUsNEJBQVEsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDO2dCQUNyQyxRQUFRLEVBQUUsNEJBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDO2dCQUN6QyxjQUFjLEVBQUUsNEJBQVEsQ0FBQyxRQUFRLENBQUMsK0NBQStDLENBQUM7YUFDbkYsQ0FDRixDQUNGLENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTyxjQUFjLENBQUM7SUFDeEIsQ0FBQztJQUVNLE9BQU87UUFDWixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7O0FBbmhCSCx3REE0akJDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBQeXRob25GdW5jdGlvbiB9IGZyb20gJ0Bhd3MtY2RrL2F3cy1sYW1iZGEtcHl0aG9uLWFscGhhJztcbmltcG9ydCB7IER1cmF0aW9uLCBOYW1lcywgUHJvcGVydHlJbmplY3RvcnMsIFJlbW92YWxQb2xpY3kgfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBJTWV0cmljIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3Vkd2F0Y2gnO1xuaW1wb3J0IHsgQXR0cmlidXRlVHlwZSwgQmlsbGluZ01vZGUsIFRhYmxlLCBUYWJsZUVuY3J5cHRpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZHluYW1vZGInO1xuaW1wb3J0IHsgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWVjMic7XG5pbXBvcnQgeyBFZmZlY3QsIFBvbGljeURvY3VtZW50LCBQb2xpY3lTdGF0ZW1lbnQsIFJvbGUsIFNlcnZpY2VQcmluY2lwYWwgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCB7IElLZXksIEtleSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1rbXMnO1xuaW1wb3J0IHsgRnVuY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCB7IFNxc0V2ZW50U291cmNlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYS1ldmVudC1zb3VyY2VzJztcbmltcG9ydCB7IEJ1Y2tldCwgQnVja2V0RW5jcnlwdGlvbiwgRXZlbnRUeXBlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCB7IFNxc0Rlc3RpbmF0aW9uIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLW5vdGlmaWNhdGlvbnMnO1xuaW1wb3J0IHsgUXVldWUsIFF1ZXVlRW5jcnlwdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zcXMnO1xuaW1wb3J0IHsgQ3VzdG9tZXJNYW5hZ2VkRW5jcnlwdGlvbkNvbmZpZ3VyYXRpb24sIERlZmluaXRpb25Cb2R5LCBKc29uUGF0aCwgU3RhdGVNYWNoaW5lIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXN0ZXBmdW5jdGlvbnMnO1xuaW1wb3J0IHsgQmVkcm9ja0ludm9rZU1vZGVsLCBEeW5hbW9BdHRyaWJ1dGVWYWx1ZSwgRHluYW1vUHV0SXRlbSwgRHluYW1vVXBkYXRlSXRlbSwgTGFtYmRhSW52b2tlLCBDYWxsQXdzU2VydmljZSwgU3RlcEZ1bmN0aW9uc1N0YXJ0RXhlY3V0aW9uIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXN0ZXBmdW5jdGlvbnMtdGFza3MnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBEZWZhdWx0UnVudGltZXMsIE5ldHdvcmsgfSBmcm9tICcuLi9mcmFtZXdvcmsnO1xuaW1wb3J0IHsgRXZlbnRicmlkZ2VCcm9rZXIgfSBmcm9tICcuLi9mcmFtZXdvcmsvZm91bmRhdGlvbi9ldmVudGJyaWRnZS1icm9rZXInO1xuaW1wb3J0IHsgTGFtYmRhSWFtVXRpbHMsIExvZ0dyb3VwRGF0YVByb3RlY3Rpb25Qcm9wcyB9IGZyb20gJy4uL3V0aWxpdGllcyc7XG5pbXBvcnQgeyBMYW1iZGFPYnNlcnZhYmlsaXR5UHJvcGVydHlJbmplY3RvciB9IGZyb20gJy4uL3V0aWxpdGllcy9vYnNlcnZhYmlsaXR5L2xhbWJkYS1vYnNlcnZhYmlsaXR5LXByb3BlcnR5LWluamVjdG9yJztcbmltcG9ydCB7IElPYnNlcnZhYmxlLCBPYnNlcnZhYmxlUHJvcHMgfSBmcm9tICcuLi91dGlsaXRpZXMvb2JzZXJ2YWJpbGl0eS9vYnNlcnZhYmxlJztcbmltcG9ydCB7IFBvd2VydG9vbHNDb25maWcgfSBmcm9tICcuLi91dGlsaXRpZXMvb2JzZXJ2YWJpbGl0eS9wb3dlcnRvb2xzLWNvbmZpZyc7XG5pbXBvcnQgeyBTdGF0ZU1hY2hpbmVPYnNlcnZhYmlsaXR5UHJvcGVydHlJbmplY3RvciB9IGZyb20gJy4uL3V0aWxpdGllcy9vYnNlcnZhYmlsaXR5L3N0YXRlLW1hY2hpbmUtb2JzZXJ2YWJpbGl0eS1wcm9wZXJ0eS1pbmplY3Rvcic7XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBwcm9wZXJ0aWVzIGZvciBCYXNlRG9jdW1lbnRQcm9jZXNzaW5nIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMgZXh0ZW5kcyBPYnNlcnZhYmxlUHJvcHMge1xuICAvKipcbiAgICogUzMgYnVja2V0IGZvciBkb2N1bWVudCBzdG9yYWdlIHdpdGggb3JnYW5pemVkIHByZWZpeGVzIChyYXcvLCBwcm9jZXNzZWQvLCBmYWlsZWQvKS5cbiAgICogSWYgbm90IHByb3ZpZGVkLCBhIG5ldyBidWNrZXQgd2lsbCBiZSBjcmVhdGVkIHdpdGggYXV0by1kZWxldGUgZW5hYmxlZCBiYXNlZCBvbiByZW1vdmFsUG9saWN5LlxuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0PzogQnVja2V0O1xuICAvKipcbiAgICogRHluYW1vREIgdGFibGUgZm9yIHN0b3JpbmcgZG9jdW1lbnQgcHJvY2Vzc2luZyBtZXRhZGF0YSBhbmQgd29ya2Zsb3cgc3RhdGUuXG4gICAqIElmIG5vdCBwcm92aWRlZCwgYSBuZXcgdGFibGUgd2lsbCBiZSBjcmVhdGVkIHdpdGggRG9jdW1lbnRJZCBhcyBwYXJ0aXRpb24ga2V5LlxuICAgKi9cbiAgcmVhZG9ubHkgZG9jdW1lbnRQcm9jZXNzaW5nVGFibGU/OiBUYWJsZTtcbiAgLyoqXG4gICAqIFNRUyBxdWV1ZSB2aXNpYmlsaXR5IHRpbWVvdXQgZm9yIHByb2Nlc3NpbmcgbWVzc2FnZXMuXG4gICAqIFNob3VsZCBiZSBsb25nZXIgdGhhbiBleHBlY3RlZCBwcm9jZXNzaW5nIHRpbWUgdG8gcHJldmVudCBkdXBsaWNhdGUgcHJvY2Vzc2luZy5cbiAgICogQGRlZmF1bHQgRHVyYXRpb24uc2Vjb25kcygzMDApXG4gICAqL1xuICByZWFkb25seSBxdWV1ZVZpc2liaWxpdHlUaW1lb3V0PzogRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgdGltZXMgYSBtZXNzYWdlIGNhbiBiZSB1bnN1Y2Nlc3NmdWxseSBkZXF1ZXVlZCBiZWZvcmUgYmVpbmcgbW92ZWQgdG8gdGhlIGRlYWQtbGV0dGVyIHF1ZXVlLlxuICAgKlxuICAgKiBAZGVmYXVsdCA1XG4gICAqL1xuICByZWFkb25seSBkbHFNYXhSZWNlaXZlQ291bnQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIE1heGltdW0gZXhlY3V0aW9uIHRpbWUgZm9yIHRoZSBTdGVwIEZ1bmN0aW9ucyB3b3JrZmxvdy5cbiAgICogQGRlZmF1bHQgRHVyYXRpb24ubWludXRlcygzMClcbiAgICovXG4gIHJlYWRvbmx5IHdvcmtmbG93VGltZW91dD86IER1cmF0aW9uO1xuICAvKipcbiAgICogUmVtb3ZhbCBwb2xpY3kgZm9yIGNyZWF0ZWQgcmVzb3VyY2VzIChidWNrZXQsIHRhYmxlLCBxdWV1ZSkuXG4gICAqIEBkZWZhdWx0IFJlbW92YWxQb2xpY3kuREVTVFJPWVxuICAgKi9cbiAgcmVhZG9ubHkgcmVtb3ZhbFBvbGljeT86IFJlbW92YWxQb2xpY3k7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBFdmVudEJyaWRnZSBicm9rZXIgZm9yIHB1Ymxpc2hpbmcgY3VzdG9tIGV2ZW50cyBkdXJpbmcgcHJvY2Vzc2luZy5cbiAgICogSWYgbm90IHByb3ZpZGVkLCBubyBjdXN0b20gZXZlbnRzIHdpbGwgYmUgc2VudCBvdXQuXG4gICAqL1xuICByZWFkb25seSBldmVudGJyaWRnZUJyb2tlcj86IEV2ZW50YnJpZGdlQnJva2VyO1xuXG4gIC8qKlxuICAgKiBFbmFibGUgbG9nZ2luZyBhbmQgdHJhY2luZyBmb3IgYWxsIHN1cHBvcnRpbmcgcmVzb3VyY2VcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGVuYWJsZU9ic2VydmFiaWxpdHk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBSZXNvdXJjZXMgdGhhdCBjYW4gcnVuIGluc2lkZSBhIFZQQyB3aWxsIGZvbGxvdyB0aGUgcHJvdmlkZWQgbmV0d29yayBjb25maWd1cmF0aW9uXG4gICAqIEBkZWZhdWx0IHJlc291cmNlcyB3aWxsIHJ1biBvdXRzaWRlIG9mIGEgVlBDXG4gICAqL1xuICByZWFkb25seSBuZXR3b3JrPzogTmV0d29yaztcblxuICAvKipcbiAgICogS01TIGtleSB0byBiZSB1c2VkLlxuICAgKiBAZGVmYXVsdCBBIG5ldyBrZXkgd291bGQgYmUgY3JlYXRlZFxuICAgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbktleT86IEtleTtcbn1cblxuLyoqXG4gKiBTMyBwcmVmaXggY29uc3RhbnRzIGZvciBvcmdhbml6aW5nIGRvY3VtZW50cyB0aHJvdWdob3V0IHRoZSBwcm9jZXNzaW5nIGxpZmVjeWNsZS5cbiAqXG4gKiBEb2N1bWVudHMgZmxvdyB0aHJvdWdoIHRoZXNlIHByZWZpeGVzIGJhc2VkIG9uIHByb2Nlc3Npbmcgb3V0Y29tZXM6XG4gKiAtIFVwbG9hZCDihpIgcmF3LyAodHJpZ2dlcnMgcHJvY2Vzc2luZylcbiAqIC0gU3VjY2VzcyDihpIgcHJvY2Vzc2VkLyAod29ya2Zsb3cgY29tcGxldGVkIHN1Y2Nlc3NmdWxseSlcbiAqIC0gRmFpbHVyZSDihpIgZmFpbGVkLyAod29ya2Zsb3cgZW5jb3VudGVyZWQgZXJyb3JzKVxuICovXG5leHBvcnQgZW51bSBEb2N1bWVudFByb2Nlc3NpbmdQcmVmaXgge1xuICAvKiogUHJlZml4IGZvciBuZXdseSB1cGxvYWRlZCBkb2N1bWVudHMgYXdhaXRpbmcgcHJvY2Vzc2luZyAqL1xuICBSQVcgPSAncmF3LycsXG4gIC8qKiBQcmVmaXggZm9yIGRvY3VtZW50cyB0aGF0IGZhaWxlZCBwcm9jZXNzaW5nICovXG4gIEZBSUxFRCA9ICdmYWlsZWQvJyxcbiAgLyoqIFByZWZpeCBmb3Igc3VjY2Vzc2Z1bGx5IHByb2Nlc3NlZCBkb2N1bWVudHMgKi9cbiAgUFJPQ0VTU0VEID0gJ3Byb2Nlc3NlZC8nLFxufVxuXG4vKipcbiAqIFVuaW9uIHR5cGUgZm9yIFN0ZXAgRnVuY3Rpb25zIHRhc2tzIHRoYXQgY2FuIGJlIHVzZWQgaW4gZG9jdW1lbnQgcHJvY2Vzc2luZyB3b3JrZmxvd3MuXG4gKiBTdXBwb3J0cyBCZWRyb2NrIG1vZGVsIGludm9jYXRpb24sIExhbWJkYSBmdW5jdGlvbiBpbnZvY2F0aW9uLCBhbmQgbmVzdGVkIFN0ZXAgRnVuY3Rpb25zIGV4ZWN1dGlvbi5cbiAqL1xuZXhwb3J0IHR5cGUgRG9jdW1lbnRQcm9jZXNzaW5nU3RlcFR5cGUgPSBCZWRyb2NrSW52b2tlTW9kZWwgfCBMYW1iZGFJbnZva2UgfCBTdGVwRnVuY3Rpb25zU3RhcnRFeGVjdXRpb247XG5cbi8qKlxuICogQWJzdHJhY3QgYmFzZSBjbGFzcyBmb3Igc2VydmVybGVzcyBkb2N1bWVudCBwcm9jZXNzaW5nIHdvcmtmbG93cy5cbiAqXG4gKiBQcm92aWRlcyBhIGNvbXBsZXRlIGRvY3VtZW50IHByb2Nlc3NpbmcgcGlwZWxpbmUgd2l0aDpcbiAqIC0gKipTMyBTdG9yYWdlKio6IE9yZ2FuaXplZCB3aXRoIHByZWZpeGVzIChyYXcvLCBwcm9jZXNzZWQvLCBmYWlsZWQvKSBmb3IgZG9jdW1lbnQgbGlmZWN5Y2xlIG1hbmFnZW1lbnRcbiAqIC0gKipTUVMgUXVldWUqKjogUmVsaWFibGUgbWVzc2FnZSBwcm9jZXNzaW5nIHdpdGggY29uZmlndXJhYmxlIHZpc2liaWxpdHkgdGltZW91dCBhbmQgZGVhZCBsZXR0ZXIgcXVldWVcbiAqIC0gKipEeW5hbW9EQiBUYWJsZSoqOiBXb3JrZmxvdyBtZXRhZGF0YSB0cmFja2luZyB3aXRoIERvY3VtZW50SWQgYXMgcGFydGl0aW9uIGtleVxuICogLSAqKlN0ZXAgRnVuY3Rpb25zKio6IE9yY2hlc3RyYXRlZCB3b3JrZmxvdyB3aXRoIGF1dG9tYXRpYyBmaWxlIG1vdmVtZW50IGJhc2VkIG9uIHByb2Nlc3Npbmcgb3V0Y29tZVxuICogLSAqKkF1dG8tdHJpZ2dlcmluZyoqOiBTMyBldmVudCBub3RpZmljYXRpb25zIGF1dG9tYXRpY2FsbHkgc3RhcnQgcHJvY2Vzc2luZyB3aGVuIGZpbGVzIGFyZSB1cGxvYWRlZCB0byByYXcvIHByZWZpeFxuICogLSAqKkVycm9yIEhhbmRsaW5nKio6IEZhaWxlZCBkb2N1bWVudHMgYXJlIG1vdmVkIHRvIGZhaWxlZC8gcHJlZml4IHdpdGggZXJyb3IgZGV0YWlscyBzdG9yZWQgaW4gRHluYW1vREJcbiAqIC0gKipFdmVudEJyaWRnZSBJbnRlZ3JhdGlvbioqOiBPcHRpb25hbCBjdXN0b20gZXZlbnQgcHVibGlzaGluZyBmb3Igd29ya2Zsb3cgc3RhdGUgY2hhbmdlc1xuICpcbiAqICMjIEFyY2hpdGVjdHVyZSBGbG93XG4gKiBTMyBVcGxvYWQgKHJhdy8pIOKGkiBTUVMg4oaSIExhbWJkYSBDb25zdW1lciDihpIgU3RlcCBGdW5jdGlvbnMg4oaSIFByb2Nlc3NpbmcgU3RlcHMg4oaSIFMzIChwcm9jZXNzZWQvZmFpbGVkLylcbiAqXG4gKiAjIyBJbXBsZW1lbnRhdGlvbiBSZXF1aXJlbWVudHNcbiAqIFN1YmNsYXNzZXMgbXVzdCBpbXBsZW1lbnQgZm91ciBhYnN0cmFjdCBtZXRob2RzIHRvIGRlZmluZSB0aGUgcHJvY2Vzc2luZyB3b3JrZmxvdzpcbiAqIC0gYGNsYXNzaWZpY2F0aW9uU3RlcCgpYDogRG9jdW1lbnQgdHlwZSBjbGFzc2lmaWNhdGlvblxuICogLSBgZXh0cmFjdGlvblN0ZXAoKWA6IERhdGEgZXh0cmFjdGlvbiBmcm9tIGRvY3VtZW50c1xuICogLSBgZW5yaWNobWVudFN0ZXAoKWA6IE9wdGlvbmFsIGRhdGEgZW5yaWNobWVudCAocmV0dXJuIHVuZGVmaW5lZCB0byBza2lwKVxuICogLSBgcG9zdFByb2Nlc3NpbmdTdGVwKClgOiBPcHRpb25hbCBwb3N0LXByb2Nlc3NpbmcgKHJldHVybiB1bmRlZmluZWQgdG8gc2tpcClcbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJhc2VEb2N1bWVudFByb2Nlc3NpbmcgZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJT2JzZXJ2YWJsZSB7XG4gIC8qKiBCdXNpbmVzcyBtZXRyaWMgc2VydmljZSBuYW1lLiBUaGlzIGlzIHBhcnQgb2YgdGhlIGluaXRpYWwgc2VydmljZSBkaW1lbnNpb24gKi9cbiAgcmVhZG9ubHkgbWV0cmljU2VydmljZU5hbWU6IHN0cmluZztcbiAgLyoqIEJ1c2luZXNzIG1ldHJpYyBuYW1lc3BhY2UuICovXG4gIHJlYWRvbmx5IG1ldHJpY05hbWVzcGFjZTogc3RyaW5nO1xuICAvKiogbG9nIGdyb3VwIGRhdGEgcHJvdGVjdGlvbiBjb25maWd1cmF0aW9uICovXG4gIHJlYWRvbmx5IGxvZ0dyb3VwRGF0YVByb3RlY3Rpb246IExvZ0dyb3VwRGF0YVByb3RlY3Rpb25Qcm9wcztcbiAgLyoqIFMzIGJ1Y2tldCBmb3IgZG9jdW1lbnQgc3RvcmFnZSB3aXRoIG9yZ2FuaXplZCBwcmVmaXhlcyAocmF3LywgcHJvY2Vzc2VkLywgZmFpbGVkLykgKi9cbiAgcmVhZG9ubHkgYnVja2V0OiBCdWNrZXQ7XG4gIC8qKiBTUVMgcXVldWUgZm9yIHJlbGlhYmxlIG1lc3NhZ2UgcHJvY2Vzc2luZyB3aXRoIGRlYWQgbGV0dGVyIHF1ZXVlIHN1cHBvcnQgKi9cbiAgcmVhZG9ubHkgcXVldWU6IFF1ZXVlO1xuICAvKiogRHluYW1vREIgdGFibGUgZm9yIHN0b3JpbmcgZG9jdW1lbnQgcHJvY2Vzc2luZyBtZXRhZGF0YSBhbmQgd29ya2Zsb3cgc3RhdGUgKi9cbiAgcmVhZG9ubHkgZG9jdW1lbnRQcm9jZXNzaW5nVGFibGU6IFRhYmxlO1xuICAvKiogQ29uZmlndXJhdGlvbiBwcm9wZXJ0aWVzIGZvciB0aGUgZG9jdW1lbnQgcHJvY2Vzc2luZyBwaXBlbGluZSAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHByb3BzOiBCYXNlRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHM7XG4gIC8qKiBEZWFkIGxldHRlciBxdWV1ZSAgKi9cbiAgcmVhZG9ubHkgZGVhZExldHRlclF1ZXVlOiBRdWV1ZTtcbiAgLyoqIEtNUyBrZXkgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbktleTogS2V5O1xuICAvKiogRW5jcnlwdGlvbiBrZXkgdXNlZCBieSB0aGUgRG9jdW1lbnRQcm9jZXNzaW5nQnVja2V0ICovXG4gIHJlYWRvbmx5IGJ1Y2tldEVuY3J5cHRpb25LZXk/OiBJS2V5O1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IEJhc2VEb2N1bWVudFByb2Nlc3NpbmcgY29uc3RydWN0LlxuICAgKlxuICAgKiBJbml0aWFsaXplcyB0aGUgY29tcGxldGUgZG9jdW1lbnQgcHJvY2Vzc2luZyBpbmZyYXN0cnVjdHVyZSBpbmNsdWRpbmcgUzMgYnVja2V0LFxuICAgKiBTUVMgcXVldWUsIER5bmFtb0RCIHRhYmxlLCBhbmQgc2V0cyB1cCBTMyBldmVudCBub3RpZmljYXRpb25zIHRvIHRyaWdnZXIgcHJvY2Vzc2luZy5cbiAgICpcbiAgICogQHBhcmFtIHNjb3BlIC0gVGhlIHNjb3BlIGluIHdoaWNoIHRvIGRlZmluZSB0aGlzIGNvbnN0cnVjdFxuICAgKiBAcGFyYW0gaWQgLSBUaGUgc2NvcGVkIGNvbnN0cnVjdCBJRC4gTXVzdCBiZSB1bmlxdWUgd2l0aGluIHRoZSBzY29wZS5cbiAgICogQHBhcmFtIHByb3BzIC0gQ29uZmlndXJhdGlvbiBwcm9wZXJ0aWVzIGZvciB0aGUgZG9jdW1lbnQgcHJvY2Vzc2luZyBwaXBlbGluZVxuICAgKi9cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEJhc2VEb2N1bWVudFByb2Nlc3NpbmdQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuICAgIGlmIChwcm9wcy5uZXR3b3JrKSB7XG4gICAgICBwcm9wcy5uZXR3b3JrLmNyZWF0ZVNlcnZpY2VFbmRwb2ludCgndnBjZS1zcXMnLCBJbnRlcmZhY2VWcGNFbmRwb2ludEF3c1NlcnZpY2UuU1FTKTtcbiAgICAgIHByb3BzLm5ldHdvcmsuY3JlYXRlU2VydmljZUVuZHBvaW50KCd2cGNlLXMzJywgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlLlMzKTtcbiAgICAgIHByb3BzLm5ldHdvcmsuY3JlYXRlU2VydmljZUVuZHBvaW50KCd2cGNlLXNmbicsIEludGVyZmFjZVZwY0VuZHBvaW50QXdzU2VydmljZS5TVEVQX0ZVTkNUSU9OUyk7XG4gICAgICBwcm9wcy5uZXR3b3JrLmNyZWF0ZVNlcnZpY2VFbmRwb2ludCgndnBjZS1lYicsIEludGVyZmFjZVZwY0VuZHBvaW50QXdzU2VydmljZS5FVkVOVEJSSURHRSk7XG4gICAgICBpZiAocHJvcHMuZW5hYmxlT2JzZXJ2YWJpbGl0eSkge1xuICAgICAgICBwcm9wcy5uZXR3b3JrLmNyZWF0ZVNlcnZpY2VFbmRwb2ludCgndnBjZS1sb2dzJywgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlLkNMT1VEV0FUQ0hfTE9HUyk7XG4gICAgICAgIHByb3BzLm5ldHdvcmsuY3JlYXRlU2VydmljZUVuZHBvaW50KCd2cGNlLW1ldHJpY3MnLCBJbnRlcmZhY2VWcGNFbmRwb2ludEF3c1NlcnZpY2UuQ0xPVURXQVRDSF9NT05JVE9SSU5HKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmVuY3J5cHRpb25LZXkgPSBwcm9wcy5lbmNyeXB0aW9uS2V5IHx8IG5ldyBLZXkodGhpcywgJ0lEUEVuY3J5cHRpb25LZXknLCB7XG4gICAgICBlbmFibGVLZXlSb3RhdGlvbjogdHJ1ZSxcbiAgICAgIHJlbW92YWxQb2xpY3k6IHByb3BzLnJlbW92YWxQb2xpY3kgfHwgUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgIH0pO1xuXG4gICAgY29uc3QgYnVja2V0TmFtZSA9IGBkb2N1bWVudHByb2Nlc3NpbmdidWNrZXQtJHtOYW1lcy51bmlxdWVSZXNvdXJjZU5hbWUodGhpcywge1xuICAgICAgbWF4TGVuZ3RoOiA2MCAtICdkb2N1bWVudHByb2Nlc3NpbmdidWNrZXQtJy5sZW5ndGgsXG4gICAgfSl9YC50b0xvd2VyQ2FzZSgpO1xuXG4gICAgY29uc3QgYnVja2V0QXJuID0gYGFybjphd3M6czM6Ojoke2J1Y2tldE5hbWV9YDtcblxuICAgIHRoaXMuZW5jcnlwdGlvbktleS5ncmFudEVuY3J5cHREZWNyeXB0KG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdzMy5hbWF6b25hd3MuY29tJywge1xuICAgICAgY29uZGl0aW9uczoge1xuICAgICAgICBBcm5FcXVhbHM6IHtcbiAgICAgICAgICAna21zOkVuY3J5cHRpb25Db250ZXh0OmF3czpzMzphcm4nOiBidWNrZXRBcm4sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pKTtcblxuICAgIHRoaXMuYnVja2V0ID0gcHJvcHMuYnVja2V0IHx8IG5ldyBCdWNrZXQodGhpcywgJ0RvY3VtZW50UHJvY2Vzc2luZ0J1Y2tldCcsIHtcbiAgICAgIGJ1Y2tldE5hbWUsXG4gICAgICBhdXRvRGVsZXRlT2JqZWN0czogKHByb3BzLnJlbW92YWxQb2xpY3kgJiYgcHJvcHMucmVtb3ZhbFBvbGljeSA9PT0gUmVtb3ZhbFBvbGljeS5ERVNUUk9ZKSB8fCAhcHJvcHMucmVtb3ZhbFBvbGljeSA/IHRydWUgOiBmYWxzZSxcbiAgICAgIHJlbW92YWxQb2xpY3k6IHByb3BzLnJlbW92YWxQb2xpY3kgfHwgUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgZW5jcnlwdGlvbjogQnVja2V0RW5jcnlwdGlvbi5LTVMsXG4gICAgICBlbmZvcmNlU1NMOiB0cnVlLFxuICAgICAgYnVja2V0S2V5RW5hYmxlZDogdHJ1ZSxcbiAgICB9KTtcblxuXG4gICAgdGhpcy5idWNrZXRFbmNyeXB0aW9uS2V5ID0gdGhpcy5idWNrZXQuZW5jcnlwdGlvbktleTtcblxuICAgIGNvbnN0IHRlbXBMb2dHcm91cERhdGFQcm90ZWN0aW9uID0gcHJvcHMubG9nR3JvdXBEYXRhUHJvdGVjdGlvbiB8fCB7XG4gICAgICBsb2dHcm91cEVuY3J5cHRpb25LZXk6IG5ldyBLZXkodGhpcywgJ0xvZ0dyb3VwRW5jcnlwdGlvbktleScsIHtcbiAgICAgICAgZW5hYmxlS2V5Um90YXRpb246IHRydWUsXG4gICAgICAgIHJlbW92YWxQb2xpY3k6IHByb3BzLnJlbW92YWxQb2xpY3kgfHwgUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgfSksXG4gICAgfTtcblxuICAgIGlmICghdGVtcExvZ0dyb3VwRGF0YVByb3RlY3Rpb24ubG9nR3JvdXBFbmNyeXB0aW9uS2V5KSB7XG4gICAgICB0aGlzLmxvZ0dyb3VwRGF0YVByb3RlY3Rpb24gPSB7XG4gICAgICAgIGRhdGFQcm90ZWN0aW9uSWRlbnRpZmllcnM6IHRlbXBMb2dHcm91cERhdGFQcm90ZWN0aW9uLmRhdGFQcm90ZWN0aW9uSWRlbnRpZmllcnMsXG4gICAgICAgIGxvZ0dyb3VwRW5jcnlwdGlvbktleTogbmV3IEtleSh0aGlzLCAnTG9nR3JvdXBFbmNyeXB0aW9uS2V5Jywge1xuICAgICAgICAgIGVuYWJsZUtleVJvdGF0aW9uOiB0cnVlLFxuICAgICAgICAgIHJlbW92YWxQb2xpY3k6IHByb3BzLnJlbW92YWxQb2xpY3kgfHwgUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgICB9KSxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9nR3JvdXBEYXRhUHJvdGVjdGlvbiA9IHRlbXBMb2dHcm91cERhdGFQcm90ZWN0aW9uO1xuICAgIH1cblxuICAgIHRoaXMuZGVhZExldHRlclF1ZXVlID0gbmV3IFF1ZXVlKHRoaXMsICdEb2N1bWVudFByb2Nlc3NpbmdETFEnLCB7XG4gICAgICB2aXNpYmlsaXR5VGltZW91dDogcHJvcHMucXVldWVWaXNpYmlsaXR5VGltZW91dCB8fCBEdXJhdGlvbi5zZWNvbmRzKDMwMCksXG4gICAgICByZW1vdmFsUG9saWN5OiBwcm9wcy5yZW1vdmFsUG9saWN5IHx8IFJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIGVuZm9yY2VTU0w6IHRydWUsXG4gICAgICBlbmNyeXB0aW9uOiBRdWV1ZUVuY3J5cHRpb24uS01TLFxuICAgICAgZW5jcnlwdGlvbk1hc3RlcktleTogdGhpcy5lbmNyeXB0aW9uS2V5LFxuICAgIH0pO1xuXG4gICAgdGhpcy5xdWV1ZSA9IG5ldyBRdWV1ZSh0aGlzLCAnRG9jdW1lbnRQcm9jZXNzaW5nUXVldWUnLCB7XG4gICAgICB2aXNpYmlsaXR5VGltZW91dDogcHJvcHMucXVldWVWaXNpYmlsaXR5VGltZW91dCB8fCBEdXJhdGlvbi5zZWNvbmRzKDMwMCksXG4gICAgICByZW1vdmFsUG9saWN5OiBwcm9wcy5yZW1vdmFsUG9saWN5IHx8IFJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIGVuZm9yY2VTU0w6IHRydWUsXG4gICAgICBkZWFkTGV0dGVyUXVldWU6IHtcbiAgICAgICAgbWF4UmVjZWl2ZUNvdW50OiBwcm9wcy5kbHFNYXhSZWNlaXZlQ291bnQgfHwgNSxcbiAgICAgICAgcXVldWU6IHRoaXMuZGVhZExldHRlclF1ZXVlLFxuICAgICAgfSxcbiAgICAgIGVuY3J5cHRpb246IFF1ZXVlRW5jcnlwdGlvbi5LTVMsXG4gICAgICBlbmNyeXB0aW9uTWFzdGVyS2V5OiB0aGlzLmVuY3J5cHRpb25LZXksXG4gICAgfSk7XG5cbiAgICB0aGlzLmRvY3VtZW50UHJvY2Vzc2luZ1RhYmxlID0gcHJvcHMuZG9jdW1lbnRQcm9jZXNzaW5nVGFibGUgfHwgbmV3IFRhYmxlKHRoaXMsICdEb2N1bWVudFByb2Nlc3NpbmdUYWJsZScsIHtcbiAgICAgIHBhcnRpdGlvbktleToge1xuICAgICAgICBuYW1lOiAnRG9jdW1lbnRJZCcsXG4gICAgICAgIHR5cGU6IEF0dHJpYnV0ZVR5cGUuU1RSSU5HLFxuICAgICAgfSxcbiAgICAgIGJpbGxpbmdNb2RlOiBCaWxsaW5nTW9kZS5QQVlfUEVSX1JFUVVFU1QsXG4gICAgICByZW1vdmFsUG9saWN5OiBwcm9wcy5yZW1vdmFsUG9saWN5IHx8IFJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIHBvaW50SW5UaW1lUmVjb3ZlcnlTcGVjaWZpY2F0aW9uOiB7XG4gICAgICAgIHBvaW50SW5UaW1lUmVjb3ZlcnlFbmFibGVkOiB0cnVlLFxuICAgICAgfSxcbiAgICAgIGVuY3J5cHRpb246IFRhYmxlRW5jcnlwdGlvbi5DVVNUT01FUl9NQU5BR0VELFxuICAgICAgZW5jcnlwdGlvbktleTogdGhpcy5lbmNyeXB0aW9uS2V5LFxuICAgIH0pO1xuXG4gICAgaWYgKHByb3BzLmVuYWJsZU9ic2VydmFiaWxpdHkpIHtcbiAgICAgIFByb3BlcnR5SW5qZWN0b3JzLm9mKHRoaXMpLmFkZChcbiAgICAgICAgbmV3IFN0YXRlTWFjaGluZU9ic2VydmFiaWxpdHlQcm9wZXJ0eUluamVjdG9yKHRoaXMubG9nR3JvdXBEYXRhUHJvdGVjdGlvbiksXG4gICAgICAgIG5ldyBMYW1iZGFPYnNlcnZhYmlsaXR5UHJvcGVydHlJbmplY3Rvcih0aGlzLmxvZ0dyb3VwRGF0YVByb3RlY3Rpb24pLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLm1ldHJpY05hbWVzcGFjZSA9IHByb3BzLm1ldHJpY05hbWVzcGFjZSB8fCAnYXBwbW9kLWNhdGFsb2cnO1xuICAgIHRoaXMubWV0cmljU2VydmljZU5hbWUgPSBwcm9wcy5tZXRyaWNTZXJ2aWNlTmFtZSB8fCAnZG9jdW1lbnQtcHJvY2Vzc2luZyc7XG4gIH1cblxuXG4gIHByb3RlY3RlZCBoYW5kbGVTdGF0ZU1hY2hpbmVDcmVhdGlvbihzdGF0ZU1hY2hpbmVJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgY2xhc3NpZmljYXRpb25TdGVwID0gdGhpcy5jbGFzc2lmaWNhdGlvblN0ZXAoKTtcbiAgICBjb25zdCBwcm9jZXNzaW5nU3RlcCA9IHRoaXMucHJvY2Vzc2luZ1N0ZXAoKTtcbiAgICBjb25zdCBlbnJpY2htZW50U3RlcCA9IHRoaXMuZW5yaWNobWVudFN0ZXAoKTtcbiAgICBjb25zdCBwb3N0UHJvY2Vzc2luZ1N0ZXAgPSB0aGlzLnBvc3RQcm9jZXNzaW5nU3RlcCgpO1xuXG4gICAgY29uc3QgaW5pdE1ldGFkYXRhRW50cnkgPSBuZXcgRHluYW1vUHV0SXRlbSh0aGlzLCAnSW5pdE1ldGFkYXRhRW50cnknLCB7XG4gICAgICB0YWJsZTogdGhpcy5kb2N1bWVudFByb2Nlc3NpbmdUYWJsZSxcbiAgICAgIGl0ZW06IHtcbiAgICAgICAgRG9jdW1lbnRJZDogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5zdHJpbmdBdCgnJC5kb2N1bWVudElkJykpLFxuICAgICAgICBCdWNrZXQ6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoSnNvblBhdGguc3RyaW5nQXQoJyQuYnVja2V0JykpLFxuICAgICAgICBLZXk6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoSnNvblBhdGguc3RyaW5nQXQoJyQua2V5JykpLFxuICAgICAgICBXb3JrZmxvd1N0YXR1czogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZygncGVuZGluZycpLFxuICAgICAgICBTdGF0ZU1hY2hpbmVFeGVjSWQ6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoSnNvblBhdGguc3RyaW5nQXQoJyQkLkV4ZWN1dGlvbi5JZCcpKSxcbiAgICAgIH0sXG4gICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgIH0pO1xuXG4gICAgLy8gRmlsZSBtb3ZlbWVudCBvcGVyYXRpb25zXG4gICAgY29uc3QgbW92ZVRvRmFpbGVkID0gdGhpcy5jcmVhdGVNb3ZlVG9GYWlsZWRDaGFpbigpO1xuICAgIGNvbnN0IG1vdmVUb1Byb2Nlc3NlZCA9IHRoaXMuY3JlYXRlTW92ZVRvUHJvY2Vzc2VkQ2hhaW4oKTtcblxuICAgIGNvbnN0IHByb2Nlc3NpbmdDaGFpbiA9IHByb2Nlc3NpbmdTdGVwXG4gICAgICAuYWRkQ2F0Y2gobmV3IER5bmFtb1VwZGF0ZUl0ZW0odGhpcywgJ1Byb2Nlc3NpbmdGYWlsRERCVXBkYXRlJywge1xuICAgICAgICB0YWJsZTogdGhpcy5kb2N1bWVudFByb2Nlc3NpbmdUYWJsZSxcbiAgICAgICAga2V5OiB7XG4gICAgICAgICAgRG9jdW1lbnRJZDogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5zdHJpbmdBdCgnJC5kb2N1bWVudElkJykpLFxuICAgICAgICB9LFxuICAgICAgICB1cGRhdGVFeHByZXNzaW9uOiAnU0VUIFdvcmtmbG93U3RhdHVzID0gOm5ld1N0YXR1cycsXG4gICAgICAgIGV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXM6IHtcbiAgICAgICAgICAnOm5ld1N0YXR1cyc6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoJ3Byb2Nlc3NpbmctZmFpbHVyZScpLFxuICAgICAgICB9LFxuICAgICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgICAgfSkubmV4dChtb3ZlVG9GYWlsZWQpLCB7XG4gICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICB9KVxuICAgICAgLm5leHQoXG4gICAgICAgIG5ldyBEeW5hbW9VcGRhdGVJdGVtKHRoaXMsICdQcm9jZXNzaW5nU3VjY2Vzc1VwZGF0ZScsIHtcbiAgICAgICAgICB0YWJsZTogdGhpcy5kb2N1bWVudFByb2Nlc3NpbmdUYWJsZSxcbiAgICAgICAgICBrZXk6IHtcbiAgICAgICAgICAgIERvY3VtZW50SWQ6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoSnNvblBhdGguc3RyaW5nQXQoJyQuZG9jdW1lbnRJZCcpKSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHVwZGF0ZUV4cHJlc3Npb246ICdTRVQgV29ya2Zsb3dTdGF0dXMgPSA6bmV3U3RhdHVzLCBQcm9jZXNzaW5nUmVzdWx0ID0gOnByb2Nlc3NpbmdSZXN1bHQnLFxuICAgICAgICAgIGV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXM6IHtcbiAgICAgICAgICAgICc6bmV3U3RhdHVzJzogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZygncHJvY2Vzc2luZy1jb21wbGV0ZScpLFxuICAgICAgICAgICAgJzpwcm9jZXNzaW5nUmVzdWx0JzogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5qc29uVG9TdHJpbmcoSnNvblBhdGgub2JqZWN0QXQoJyQucHJvY2Vzc2luZ1Jlc3VsdCcpKSksXG4gICAgICAgICAgfSxcbiAgICAgICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAvLyBCdWlsZCB0aGUgY29tcGxldGUgY2hhaW4gaW5jbHVkaW5nIG9wdGlvbmFsIHN0ZXBzXG4gICAgaWYgKGVucmljaG1lbnRTdGVwKSB7XG4gICAgICBjb25zdCBlbnJpY2htZW50Q2hhaW4gPSBlbnJpY2htZW50U3RlcFxuICAgICAgICAuYWRkQ2F0Y2gobmV3IER5bmFtb1VwZGF0ZUl0ZW0odGhpcywgJ0VucmljaG1lbnRGYWlsRERCVXBkYXRlJywge1xuICAgICAgICAgIHRhYmxlOiB0aGlzLmRvY3VtZW50UHJvY2Vzc2luZ1RhYmxlLFxuICAgICAgICAgIGtleToge1xuICAgICAgICAgICAgRG9jdW1lbnRJZDogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5zdHJpbmdBdCgnJC5kb2N1bWVudElkJykpLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgdXBkYXRlRXhwcmVzc2lvbjogJ1NFVCBXb3JrZmxvd1N0YXR1cyA9IDpuZXdTdGF0dXMnLFxuICAgICAgICAgIGV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXM6IHtcbiAgICAgICAgICAgICc6bmV3U3RhdHVzJzogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZygnZW5yaWNobWVudC1mYWlsdXJlJyksXG4gICAgICAgICAgfSxcbiAgICAgICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgICAgICB9KS5uZXh0KG1vdmVUb0ZhaWxlZCksIHtcbiAgICAgICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgICAgICB9KVxuICAgICAgICAubmV4dChcbiAgICAgICAgICBuZXcgRHluYW1vVXBkYXRlSXRlbSh0aGlzLCAnRW5yaWNobWVudFN1Y2Nlc3NVcGRhdGUnLCB7XG4gICAgICAgICAgICB0YWJsZTogdGhpcy5kb2N1bWVudFByb2Nlc3NpbmdUYWJsZSxcbiAgICAgICAgICAgIGtleToge1xuICAgICAgICAgICAgICBEb2N1bWVudElkOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKEpzb25QYXRoLnN0cmluZ0F0KCckLmRvY3VtZW50SWQnKSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdXBkYXRlRXhwcmVzc2lvbjogJ1NFVCBXb3JrZmxvd1N0YXR1cyA9IDpuZXdTdGF0dXMsIEVucmljaG1lbnRSZXN1bHQgPSA6ZW5yaWNobWVudFJlc3VsdCcsXG4gICAgICAgICAgICBleHByZXNzaW9uQXR0cmlidXRlVmFsdWVzOiB7XG4gICAgICAgICAgICAgICc6bmV3U3RhdHVzJzogcG9zdFByb2Nlc3NpbmdTdGVwID8gRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZygnZW5yaWNobWVudC1jb21wbGV0ZScpIDogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZygnY29tcGxldGUnKSxcbiAgICAgICAgICAgICAgJzplbnJpY2htZW50UmVzdWx0JzogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5qc29uVG9TdHJpbmcoSnNvblBhdGgub2JqZWN0QXQoJyQuZW5yaWNoZWRSZXN1bHQnKSkpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG5cbiAgICAgIHByb2Nlc3NpbmdDaGFpbi5uZXh0KGVucmljaG1lbnRDaGFpbik7XG5cbiAgICAgIGlmIChwb3N0UHJvY2Vzc2luZ1N0ZXApIHtcbiAgICAgICAgY29uc3QgcG9zdFByb2Nlc3NpbmdDaGFpbiA9IHBvc3RQcm9jZXNzaW5nU3RlcFxuICAgICAgICAgIC5hZGRDYXRjaChuZXcgRHluYW1vVXBkYXRlSXRlbSh0aGlzLCAnUG9zdFByb2Nlc3NpbmdGYWlsRERCVXBkYXRlJywge1xuICAgICAgICAgICAgdGFibGU6IHRoaXMuZG9jdW1lbnRQcm9jZXNzaW5nVGFibGUsXG4gICAgICAgICAgICBrZXk6IHtcbiAgICAgICAgICAgICAgRG9jdW1lbnRJZDogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5zdHJpbmdBdCgnJC5kb2N1bWVudElkJykpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHVwZGF0ZUV4cHJlc3Npb246ICdTRVQgV29ya2Zsb3dTdGF0dXMgPSA6bmV3U3RhdHVzJyxcbiAgICAgICAgICAgIGV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXM6IHtcbiAgICAgICAgICAgICAgJzpuZXdTdGF0dXMnOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKCdwb3N0LXByb2Nlc3NpbmctZmFpbHVyZScpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICAgICAgfSkubmV4dChtb3ZlVG9GYWlsZWQpLCB7XG4gICAgICAgICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLm5leHQoXG4gICAgICAgICAgICBuZXcgRHluYW1vVXBkYXRlSXRlbSh0aGlzLCAnUG9zdFByb2Nlc3NpbmdTdWNjZXNzVXBkYXRlJywge1xuICAgICAgICAgICAgICB0YWJsZTogdGhpcy5kb2N1bWVudFByb2Nlc3NpbmdUYWJsZSxcbiAgICAgICAgICAgICAga2V5OiB7XG4gICAgICAgICAgICAgICAgRG9jdW1lbnRJZDogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5zdHJpbmdBdCgnJC5kb2N1bWVudElkJykpLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB1cGRhdGVFeHByZXNzaW9uOiAnU0VUIFdvcmtmbG93U3RhdHVzID0gOm5ld1N0YXR1cywgUG9zdFByb2Nlc3NpbmdSZXN1bHQgPSA6cG9zdFByb2Nlc3NpbmdSZXN1bHQnLFxuICAgICAgICAgICAgICBleHByZXNzaW9uQXR0cmlidXRlVmFsdWVzOiB7XG4gICAgICAgICAgICAgICAgJzpuZXdTdGF0dXMnOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKCdjb21wbGV0ZScpLFxuICAgICAgICAgICAgICAgICc6cG9zdFByb2Nlc3NpbmdSZXN1bHQnOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKEpzb25QYXRoLmpzb25Ub1N0cmluZyhKc29uUGF0aC5vYmplY3RBdCgnJC5wb3N0UHJvY2Vzc2VkUmVzdWx0JykpKSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgcmVzdWx0UGF0aDogSnNvblBhdGguRElTQ0FSRCxcbiAgICAgICAgICAgIH0pLm5leHQobW92ZVRvUHJvY2Vzc2VkKSxcbiAgICAgICAgICApO1xuICAgICAgICBlbnJpY2htZW50Q2hhaW4ubmV4dChwb3N0UHJvY2Vzc2luZ0NoYWluKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVucmljaG1lbnRDaGFpbi5uZXh0KG1vdmVUb1Byb2Nlc3NlZCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChwb3N0UHJvY2Vzc2luZ1N0ZXApIHtcbiAgICAgIGNvbnN0IHBvc3RQcm9jZXNzaW5nQ2hhaW4gPSBwb3N0UHJvY2Vzc2luZ1N0ZXBcbiAgICAgICAgLmFkZENhdGNoKG5ldyBEeW5hbW9VcGRhdGVJdGVtKHRoaXMsICdQb3N0UHJvY2Vzc2luZ0ZhaWxEREJVcGRhdGUnLCB7XG4gICAgICAgICAgdGFibGU6IHRoaXMuZG9jdW1lbnRQcm9jZXNzaW5nVGFibGUsXG4gICAgICAgICAga2V5OiB7XG4gICAgICAgICAgICBEb2N1bWVudElkOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKEpzb25QYXRoLnN0cmluZ0F0KCckLmRvY3VtZW50SWQnKSksXG4gICAgICAgICAgfSxcbiAgICAgICAgICB1cGRhdGVFeHByZXNzaW9uOiAnU0VUIFdvcmtmbG93U3RhdHVzID0gOm5ld1N0YXR1cycsXG4gICAgICAgICAgZXhwcmVzc2lvbkF0dHJpYnV0ZVZhbHVlczoge1xuICAgICAgICAgICAgJzpuZXdTdGF0dXMnOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKCdwb3N0LXByb2Nlc3NpbmctZmFpbHVyZScpLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgcmVzdWx0UGF0aDogSnNvblBhdGguRElTQ0FSRCxcbiAgICAgICAgfSkubmV4dChtb3ZlVG9GYWlsZWQpLCB7XG4gICAgICAgICAgcmVzdWx0UGF0aDogSnNvblBhdGguRElTQ0FSRCxcbiAgICAgICAgfSlcbiAgICAgICAgLm5leHQoXG4gICAgICAgICAgbmV3IER5bmFtb1VwZGF0ZUl0ZW0odGhpcywgJ1Bvc3RQcm9jZXNzaW5nU3VjY2Vzc1VwZGF0ZScsIHtcbiAgICAgICAgICAgIHRhYmxlOiB0aGlzLmRvY3VtZW50UHJvY2Vzc2luZ1RhYmxlLFxuICAgICAgICAgICAga2V5OiB7XG4gICAgICAgICAgICAgIERvY3VtZW50SWQ6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoSnNvblBhdGguc3RyaW5nQXQoJyQuZG9jdW1lbnRJZCcpKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB1cGRhdGVFeHByZXNzaW9uOiAnU0VUIFdvcmtmbG93U3RhdHVzID0gOm5ld1N0YXR1cywgUG9zdFByb2Nlc3NpbmdSZXN1bHQgPSA6cG9zdFByb2Nlc3NpbmdSZXN1bHQnLFxuICAgICAgICAgICAgZXhwcmVzc2lvbkF0dHJpYnV0ZVZhbHVlczoge1xuICAgICAgICAgICAgICAnOm5ld1N0YXR1cyc6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoJ2NvbXBsZXRlJyksXG4gICAgICAgICAgICAgICc6cG9zdFByb2Nlc3NpbmdSZXN1bHQnOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKEpzb25QYXRoLmpzb25Ub1N0cmluZyhKc29uUGF0aC5vYmplY3RBdCgnJC5wb3N0UHJvY2Vzc2VkUmVzdWx0JykpKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgICAgICAgIH0pLm5leHQobW92ZVRvUHJvY2Vzc2VkKSxcbiAgICAgICAgKTtcbiAgICAgIHByb2Nlc3NpbmdDaGFpbi5uZXh0KHBvc3RQcm9jZXNzaW5nQ2hhaW4pO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBObyBvcHRpb25hbCBzdGVwcyAtIG1hcmsgYXMgY29tcGxldGUgYWZ0ZXIgZXh0cmFjdGlvblxuICAgICAgcHJvY2Vzc2luZ0NoYWluLm5leHQoXG4gICAgICAgIG5ldyBEeW5hbW9VcGRhdGVJdGVtKHRoaXMsICdXb3JrZmxvd0NvbXBsZXRlVXBkYXRlJywge1xuICAgICAgICAgIHRhYmxlOiB0aGlzLmRvY3VtZW50UHJvY2Vzc2luZ1RhYmxlLFxuICAgICAgICAgIGtleToge1xuICAgICAgICAgICAgRG9jdW1lbnRJZDogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5zdHJpbmdBdCgnJC5kb2N1bWVudElkJykpLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgdXBkYXRlRXhwcmVzc2lvbjogJ1NFVCBXb3JrZmxvd1N0YXR1cyA9IDpuZXdTdGF0dXMnLFxuICAgICAgICAgIGV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXM6IHtcbiAgICAgICAgICAgICc6bmV3U3RhdHVzJzogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZygnY29tcGxldGUnKSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICAgIH0pLm5leHQobW92ZVRvUHJvY2Vzc2VkKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3Qgd29ya2Zsb3dEZWZpbml0aW9uID0gaW5pdE1ldGFkYXRhRW50cnkubmV4dChcbiAgICAgIGNsYXNzaWZpY2F0aW9uU3RlcFxuICAgICAgICAuYWRkQ2F0Y2gobmV3IER5bmFtb1VwZGF0ZUl0ZW0odGhpcywgJ0NsYXNzaWZpY2F0aW9uRmFpbEREQlVwZGF0ZScsIHtcbiAgICAgICAgICB0YWJsZTogdGhpcy5kb2N1bWVudFByb2Nlc3NpbmdUYWJsZSxcbiAgICAgICAgICBrZXk6IHtcbiAgICAgICAgICAgIERvY3VtZW50SWQ6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoSnNvblBhdGguc3RyaW5nQXQoJyQuZG9jdW1lbnRJZCcpKSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHVwZGF0ZUV4cHJlc3Npb246ICdTRVQgV29ya2Zsb3dTdGF0dXMgPSA6bmV3U3RhdHVzJyxcbiAgICAgICAgICBleHByZXNzaW9uQXR0cmlidXRlVmFsdWVzOiB7XG4gICAgICAgICAgICAnOm5ld1N0YXR1cyc6IER5bmFtb0F0dHJpYnV0ZVZhbHVlLmZyb21TdHJpbmcoJ2NsYXNzaWZpY2F0aW9uLWZhaWx1cmUnKSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICAgIH0pLm5leHQobW92ZVRvRmFpbGVkKSwge1xuICAgICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICAgIH0pXG4gICAgICAgIC5uZXh0KFxuICAgICAgICAgIG5ldyBEeW5hbW9VcGRhdGVJdGVtKHRoaXMsICdDbGFzc2lmaWNhdGlvblN1Y2Nlc3NVcGRhdGUnLCB7XG4gICAgICAgICAgICB0YWJsZTogdGhpcy5kb2N1bWVudFByb2Nlc3NpbmdUYWJsZSxcbiAgICAgICAgICAgIGtleToge1xuICAgICAgICAgICAgICBEb2N1bWVudElkOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKEpzb25QYXRoLnN0cmluZ0F0KCckLmRvY3VtZW50SWQnKSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdXBkYXRlRXhwcmVzc2lvbjogJ1NFVCBXb3JrZmxvd1N0YXR1cyA9IDpuZXdTdGF0dXMsIENsYXNzaWZpY2F0aW9uUmVzdWx0ID0gOmNsYXNzaWZpY2F0aW9uUmVzdWx0JyxcbiAgICAgICAgICAgIGV4cHJlc3Npb25BdHRyaWJ1dGVWYWx1ZXM6IHtcbiAgICAgICAgICAgICAgJzpuZXdTdGF0dXMnOiBEeW5hbW9BdHRyaWJ1dGVWYWx1ZS5mcm9tU3RyaW5nKCdjbGFzc2lmaWNhdGlvbi1jb21wbGV0ZScpLFxuICAgICAgICAgICAgICAnOmNsYXNzaWZpY2F0aW9uUmVzdWx0JzogRHluYW1vQXR0cmlidXRlVmFsdWUuZnJvbVN0cmluZyhKc29uUGF0aC5qc29uVG9TdHJpbmcoSnNvblBhdGgub2JqZWN0QXQoJyQuY2xhc3NpZmljYXRpb25SZXN1bHQnKSkpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICAgICAgfSksXG4gICAgICAgICksXG4gICAgKS5uZXh0KHByb2Nlc3NpbmdDaGFpbik7XG5cbiAgICBjb25zdCByb2xlID0gdGhpcy5jcmVhdGVTdGF0ZU1hY2hpbmVSb2xlKCk7XG4gICAgdGhpcy5lbmNyeXB0aW9uS2V5LmdyYW50RW5jcnlwdERlY3J5cHQocm9sZSk7XG4gICAgaWYgKHRoaXMuYnVja2V0RW5jcnlwdGlvbktleSkge1xuICAgICAgdGhpcy5idWNrZXRFbmNyeXB0aW9uS2V5LmdyYW50RW5jcnlwdERlY3J5cHQocm9sZSk7XG4gICAgfVxuICAgIGNvbnN0IHN0YXRlTWFjaGluZSA9IG5ldyBTdGF0ZU1hY2hpbmUodGhpcywgc3RhdGVNYWNoaW5lSWQsIHtcbiAgICAgIGRlZmluaXRpb25Cb2R5OiBEZWZpbml0aW9uQm9keS5mcm9tQ2hhaW5hYmxlKHdvcmtmbG93RGVmaW5pdGlvbiksXG4gICAgICB0aW1lb3V0OiB0aGlzLnByb3BzLndvcmtmbG93VGltZW91dCB8fCBEdXJhdGlvbi5taW51dGVzKDE1KSxcbiAgICAgIHJvbGUsXG4gICAgICBlbmNyeXB0aW9uQ29uZmlndXJhdGlvbjogbmV3IEN1c3RvbWVyTWFuYWdlZEVuY3J5cHRpb25Db25maWd1cmF0aW9uKHRoaXMuZW5jcnlwdGlvbktleSksXG4gICAgfSk7XG5cbiAgICB0aGlzLmhhbmRsZVdvcmtmbG93VHJpZ2dlcihzdGF0ZU1hY2hpbmUpO1xuXG4gICAgcmV0dXJuIHN0YXRlTWFjaGluZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVXb3JrZmxvd1RyaWdnZXIoc3RhdGVNYWNoaW5lOiBTdGF0ZU1hY2hpbmUpIHtcbiAgICB0aGlzLmJ1Y2tldC5hZGRFdmVudE5vdGlmaWNhdGlvbihFdmVudFR5cGUuT0JKRUNUX0NSRUFURUQsIG5ldyBTcXNEZXN0aW5hdGlvbih0aGlzLnF1ZXVlKSwge1xuICAgICAgcHJlZml4OiBEb2N1bWVudFByb2Nlc3NpbmdQcmVmaXguUkFXLFxuICAgIH0pO1xuICAgIHRoaXMuY3JlYXRlU1FTQ29uc3VtZXJMYW1iZGEoc3RhdGVNYWNoaW5lKTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlU1FTQ29uc3VtZXJMYW1iZGEoc3RhdGVNYWNoaW5lOiBTdGF0ZU1hY2hpbmUpOiBGdW5jdGlvbiB7XG4gICAgY29uc3QgeyByZWdpb24sIGFjY291bnQgfSA9IExhbWJkYUlhbVV0aWxzLmdldFN0YWNrSW5mbyh0aGlzKTtcbiAgICAvLyBDcmVhdGUgbG9ncyBwZXJtaXNzaW9ucyBhbmQgZ2V0IHVuaXF1ZSBmdW5jdGlvbiBuYW1lXG4gICAgY29uc3QgbG9nc1Blcm1pc3Npb25zID0gTGFtYmRhSWFtVXRpbHMuY3JlYXRlTG9nc1Blcm1pc3Npb25zKHtcbiAgICAgIHNjb3BlOiB0aGlzLFxuICAgICAgZnVuY3Rpb25OYW1lOiAnU1FTQ29uc3VtZXInLFxuICAgICAgcmVnaW9uLFxuICAgICAgYWNjb3VudCxcbiAgICB9KTtcblxuICAgIC8vIENyZWF0ZSBwb2xpY3kgc3RhdGVtZW50cyBmb3IgU1FTIGNvbnN1bWVyIExhbWJkYVxuICAgIGNvbnN0IHBvbGljeVN0YXRlbWVudHMgPSBbXG4gICAgICAuLi5sb2dzUGVybWlzc2lvbnMucG9saWN5U3RhdGVtZW50cyxcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogWydzdGF0ZXM6U3RhcnRFeGVjdXRpb24nXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbc3RhdGVNYWNoaW5lLnN0YXRlTWFjaGluZUFybl0sXG4gICAgICB9KSxcbiAgICBdO1xuXG4gICAgaWYgKHRoaXMucHJvcHMubmV0d29yaykge1xuICAgICAgcG9saWN5U3RhdGVtZW50cy5wdXNoKExhbWJkYUlhbVV0aWxzLmdlbmVyYXRlTGFtYmRhVlBDUGVybWlzc2lvbnMoKSk7XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIElBTSByb2xlIGZvciBTUVMgY29uc3VtZXIgTGFtYmRhXG4gICAgY29uc3Qgc3FzQ29uc3VtZXJSb2xlID0gbmV3IFJvbGUodGhpcywgJ1NRU0NvbnN1bWVyUm9sZScsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IFNlcnZpY2VQcmluY2lwYWwoJ2xhbWJkYS5hbWF6b25hd3MuY29tJyksXG4gICAgICBpbmxpbmVQb2xpY2llczoge1xuICAgICAgICBTUVNDb25zdW1lckV4ZWN1dGlvblBvbGljeTogbmV3IFBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICBzdGF0ZW1lbnRzOiBwb2xpY3lTdGF0ZW1lbnRzLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0aGlzLmVuY3J5cHRpb25LZXkuZ3JhbnRFbmNyeXB0RGVjcnlwdChzcXNDb25zdW1lclJvbGUpO1xuXG4gICAgLy8gQ3JlYXRlIFNRUyBjb25zdW1lciBMYW1iZGEgZnVuY3Rpb25cbiAgICBjb25zdCBzcXNDb25zdW1lckxhbWJkYSA9IG5ldyBQeXRob25GdW5jdGlvbih0aGlzLCAnU1FTQ29uc3VtZXInLCB7XG4gICAgICBmdW5jdGlvbk5hbWU6IGxvZ3NQZXJtaXNzaW9ucy51bmlxdWVGdW5jdGlvbk5hbWUsXG4gICAgICBydW50aW1lOiBEZWZhdWx0UnVudGltZXMuUFlUSE9OLFxuICAgICAgcm9sZTogc3FzQ29uc3VtZXJSb2xlLFxuICAgICAgZW50cnk6IHBhdGguam9pbihfX2Rpcm5hbWUsICcvcmVzb3VyY2VzL2RlZmF1bHQtc3FzLWNvbnN1bWVyJyksXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBTVEFURV9NQUNISU5FX0FSTjogc3RhdGVNYWNoaW5lLnN0YXRlTWFjaGluZUFybixcbiAgICAgICAgLi4uUG93ZXJ0b29sc0NvbmZpZy5nZW5lcmF0ZURlZmF1bHRMYW1iZGFDb25maWcodGhpcy5wcm9wcy5lbmFibGVPYnNlcnZhYmlsaXR5LCB0aGlzLm1ldHJpY05hbWVzcGFjZSwgdGhpcy5tZXRyaWNTZXJ2aWNlTmFtZSksXG4gICAgICB9LFxuICAgICAgdGltZW91dDogRHVyYXRpb24ubWludXRlcyg1KSxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQ29uc3VtZXMgU1FTIG1lc3NhZ2VzIGFuZCB0cmlnZ2VycyBTdGVwIEZ1bmN0aW9ucyBleGVjdXRpb25zIGZvciBkb2N1bWVudCBwcm9jZXNzaW5nJyxcbiAgICAgIGVudmlyb25tZW50RW5jcnlwdGlvbjogdGhpcy5lbmNyeXB0aW9uS2V5LFxuICAgICAgdnBjOiB0aGlzLnByb3BzLm5ldHdvcmsgPyB0aGlzLnByb3BzLm5ldHdvcmsudnBjIDogdW5kZWZpbmVkLFxuICAgICAgdnBjU3VibmV0czogdGhpcy5wcm9wcy5uZXR3b3JrID8gdGhpcy5wcm9wcy5uZXR3b3JrLmFwcGxpY2F0aW9uU3VibmV0U2VsZWN0aW9uKCkgOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICAvLyBBZGQgU1FTIGV2ZW50IHNvdXJjZSB0byBMYW1iZGFcbiAgICBzcXNDb25zdW1lckxhbWJkYS5hZGRFdmVudFNvdXJjZShcbiAgICAgIG5ldyBTcXNFdmVudFNvdXJjZSh0aGlzLnF1ZXVlLCB7XG4gICAgICAgIGJhdGNoU2l6ZTogMTAsXG4gICAgICAgIG1heEJhdGNoaW5nV2luZG93OiBEdXJhdGlvbi5zZWNvbmRzKDUpLFxuICAgICAgICByZXBvcnRCYXRjaEl0ZW1GYWlsdXJlczogdHJ1ZSxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICByZXR1cm4gc3FzQ29uc3VtZXJMYW1iZGE7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVN0YXRlTWFjaGluZVJvbGUoKTogUm9sZSB7XG4gICAgcmV0dXJuIG5ldyBSb2xlKHRoaXMsICdTdGF0ZU1hY2hpbmVSb2xlJywge1xuICAgICAgYXNzdW1lZEJ5OiBuZXcgU2VydmljZVByaW5jaXBhbCgnc3RhdGVzLmFtYXpvbmF3cy5jb20nKSxcbiAgICAgIGlubGluZVBvbGljaWVzOiB7XG4gICAgICAgIFN0YXRlTWFjaGluZUV4ZWN1dGlvblBvbGljeTogbmV3IFBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICBzdGF0ZW1lbnRzOiBbXG4gICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFsnczM6R2V0T2JqZWN0JywgJ3MzOkNvcHlPYmplY3QnLCAnczM6RGVsZXRlT2JqZWN0JywgJ3MzOlB1dE9iamVjdCddLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFtgJHt0aGlzLmJ1Y2tldC5idWNrZXRBcm59LypgXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbJ2R5bmFtb2RiOlB1dEl0ZW0nLCAnZHluYW1vZGI6VXBkYXRlSXRlbSddLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFt0aGlzLmRvY3VtZW50UHJvY2Vzc2luZ1RhYmxlLnRhYmxlQXJuXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlTW92ZVRvRmFpbGVkQ2hhaW4oKSB7XG4gICAgY29uc3QgZmFpbGVkQ2hhaW4gPSBuZXcgQ2FsbEF3c1NlcnZpY2UodGhpcywgJ0NvcHlUb0ZhaWxlZCcsIHtcbiAgICAgIHNlcnZpY2U6ICdzMycsXG4gICAgICBhY3Rpb246ICdjb3B5T2JqZWN0JyxcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgQnVja2V0OiBKc29uUGF0aC5zdHJpbmdBdCgnJC5idWNrZXQnKSxcbiAgICAgICAgQ29weVNvdXJjZTogSnNvblBhdGguZm9ybWF0KCd7fS97fScsIEpzb25QYXRoLnN0cmluZ0F0KCckLmJ1Y2tldCcpLCBKc29uUGF0aC5zdHJpbmdBdCgnJC5rZXknKSksXG4gICAgICAgIEtleTogSnNvblBhdGguZm9ybWF0KCdmYWlsZWQve30nLCBKc29uUGF0aC5zdHJpbmdBdCgnJC5maWxlbmFtZScpKSxcbiAgICAgIH0sXG4gICAgICBpYW1SZXNvdXJjZXM6IFtgJHt0aGlzLmJ1Y2tldC5idWNrZXRBcm59LypgXSxcbiAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgfSkubmV4dChcbiAgICAgIG5ldyBDYWxsQXdzU2VydmljZSh0aGlzLCAnRGVsZXRlRnJvbVJhdycsIHtcbiAgICAgICAgc2VydmljZTogJ3MzJyxcbiAgICAgICAgYWN0aW9uOiAnZGVsZXRlT2JqZWN0JyxcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIEJ1Y2tldDogSnNvblBhdGguc3RyaW5nQXQoJyQuYnVja2V0JyksXG4gICAgICAgICAgS2V5OiBKc29uUGF0aC5zdHJpbmdBdCgnJC5rZXknKSxcbiAgICAgICAgfSxcbiAgICAgICAgaWFtUmVzb3VyY2VzOiBbYCR7dGhpcy5idWNrZXQuYnVja2V0QXJufS8qYF0sXG4gICAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgaWYgKHRoaXMucHJvcHMuZXZlbnRicmlkZ2VCcm9rZXIpIHtcbiAgICAgIGZhaWxlZENoYWluLm5leHQoXG4gICAgICAgIHRoaXMucHJvcHMuZXZlbnRicmlkZ2VCcm9rZXIuc2VuZFZpYVNmbkNoYWluKFxuICAgICAgICAgICdkb2N1bWVudC1wcm9jZXNzaW5nLWZhaWxlZCcsXG4gICAgICAgICAge1xuICAgICAgICAgICAgZG9jdW1lbnRJZDogSnNvblBhdGguc3RyaW5nQXQoJyQuZG9jdW1lbnRJZCcpLFxuICAgICAgICAgICAgYnVja2V0OiBKc29uUGF0aC5zdHJpbmdBdCgnJC5idWNrZXQnKSxcbiAgICAgICAgICAgIGZpbGVuYW1lOiBKc29uUGF0aC5zdHJpbmdBdCgnJC5maWxlbmFtZScpLFxuICAgICAgICAgIH0sXG4gICAgICAgICksXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiBmYWlsZWRDaGFpbjtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlTW92ZVRvUHJvY2Vzc2VkQ2hhaW4oKSB7XG4gICAgY29uc3QgcHJvY2Vzc2VkQ2hhaW4gPSBuZXcgQ2FsbEF3c1NlcnZpY2UodGhpcywgJ0NvcHlUb1Byb2Nlc3NlZCcsIHtcbiAgICAgIHNlcnZpY2U6ICdzMycsXG4gICAgICBhY3Rpb246ICdjb3B5T2JqZWN0JyxcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgQnVja2V0OiBKc29uUGF0aC5zdHJpbmdBdCgnJC5idWNrZXQnKSxcbiAgICAgICAgQ29weVNvdXJjZTogSnNvblBhdGguZm9ybWF0KCd7fS97fScsIEpzb25QYXRoLnN0cmluZ0F0KCckLmJ1Y2tldCcpLCBKc29uUGF0aC5zdHJpbmdBdCgnJC5rZXknKSksXG4gICAgICAgIEtleTogSnNvblBhdGguZm9ybWF0KCdwcm9jZXNzZWQve30nLCBKc29uUGF0aC5zdHJpbmdBdCgnJC5maWxlbmFtZScpKSxcbiAgICAgIH0sXG4gICAgICBpYW1SZXNvdXJjZXM6IFtgJHt0aGlzLmJ1Y2tldC5idWNrZXRBcm59LypgXSxcbiAgICAgIHJlc3VsdFBhdGg6IEpzb25QYXRoLkRJU0NBUkQsXG4gICAgfSkubmV4dChcbiAgICAgIG5ldyBDYWxsQXdzU2VydmljZSh0aGlzLCAnRGVsZXRlRnJvbVJhd1N1Y2Nlc3MnLCB7XG4gICAgICAgIHNlcnZpY2U6ICdzMycsXG4gICAgICAgIGFjdGlvbjogJ2RlbGV0ZU9iamVjdCcsXG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBCdWNrZXQ6IEpzb25QYXRoLnN0cmluZ0F0KCckLmJ1Y2tldCcpLFxuICAgICAgICAgIEtleTogSnNvblBhdGguc3RyaW5nQXQoJyQua2V5JyksXG4gICAgICAgIH0sXG4gICAgICAgIGlhbVJlc291cmNlczogW2Ake3RoaXMuYnVja2V0LmJ1Y2tldEFybn0vKmBdLFxuICAgICAgICByZXN1bHRQYXRoOiBKc29uUGF0aC5ESVNDQVJELFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIGlmICh0aGlzLnByb3BzLmV2ZW50YnJpZGdlQnJva2VyKSB7XG4gICAgICBwcm9jZXNzZWRDaGFpbi5uZXh0KFxuICAgICAgICB0aGlzLnByb3BzLmV2ZW50YnJpZGdlQnJva2VyLnNlbmRWaWFTZm5DaGFpbihcbiAgICAgICAgICAnZG9jdW1lbnQtcHJvY2Vzc2VkLXN1Y2Nlc3NmdWwnLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGRvY3VtZW50SWQ6IEpzb25QYXRoLnN0cmluZ0F0KCckLmRvY3VtZW50SWQnKSxcbiAgICAgICAgICAgIGJ1Y2tldDogSnNvblBhdGguc3RyaW5nQXQoJyQuYnVja2V0JyksXG4gICAgICAgICAgICBmaWxlbmFtZTogSnNvblBhdGguc3RyaW5nQXQoJyQuZmlsZW5hbWUnKSxcbiAgICAgICAgICAgIGNsYXNzaWZpY2F0aW9uOiBKc29uUGF0aC5zdHJpbmdBdCgnJC5jbGFzc2lmaWNhdGlvblJlc3VsdC5kb2N1bWVudENsYXNzaWZpY2F0aW9uJyksXG4gICAgICAgICAgfSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHByb2Nlc3NlZENoYWluO1xuICB9XG5cbiAgcHVibGljIG1ldHJpY3MoKTogSU1ldHJpY1tdIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICAvKipcbiAgICogRGVmaW5lcyB0aGUgZG9jdW1lbnQgY2xhc3NpZmljYXRpb24gc3RlcCBvZiB0aGUgd29ya2Zsb3cuXG4gICAqXG4gICAqICoqQ1JJVElDQUwqKjogTXVzdCBzZXQgYG91dHB1dFBhdGhgIHRvIHByZXNlcnZlIHdvcmtmbG93IHN0YXRlIGZvciBzdWJzZXF1ZW50IHN0ZXBzLlxuICAgKiBUaGUgY2xhc3NpZmljYXRpb24gcmVzdWx0IHNob3VsZCBiZSBhdmFpbGFibGUgYXQgYCQuY2xhc3NpZmljYXRpb25SZXN1bHRgIGZvciBEeW5hbW9EQiBzdG9yYWdlLlxuICAgKlxuICAgKiBAcmV0dXJucyBTdGVwIEZ1bmN0aW9ucyB0YXNrIGZvciBkb2N1bWVudCBjbGFzc2lmaWNhdGlvblxuICAgKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGNsYXNzaWZpY2F0aW9uU3RlcCgpOiBEb2N1bWVudFByb2Nlc3NpbmdTdGVwVHlwZTtcblxuICAvKipcbiAgICogRGVmaW5lcyB0aGUgZG9jdW1lbnQgcHJvY2Vzc2luZyBzdGVwIG9mIHRoZSB3b3JrZmxvdy5cbiAgICpcbiAgICogKipDUklUSUNBTCoqOiBNdXN0IHNldCBgb3V0cHV0UGF0aGAgdG8gcHJlc2VydmUgd29ya2Zsb3cgc3RhdGUgZm9yIHN1YnNlcXVlbnQgc3RlcHMuXG4gICAqIFRoZSBleHRyYWN0aW9uIHJlc3VsdCBzaG91bGQgYmUgYXZhaWxhYmxlIGF0IGAkLnByb2Nlc3NpbmdSZXN1bHRgIGZvciBEeW5hbW9EQiBzdG9yYWdlLlxuICAgKlxuICAgKiBAcmV0dXJucyBTdGVwIEZ1bmN0aW9ucyB0YXNrIGZvciBkb2N1bWVudCBleHRyYWN0aW9uXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgcHJvY2Vzc2luZ1N0ZXAoKTogRG9jdW1lbnRQcm9jZXNzaW5nU3RlcFR5cGU7XG5cbiAgLyoqXG4gICAqIERlZmluZXMgdGhlIG9wdGlvbmFsIGRvY3VtZW50IGVucmljaG1lbnQgc3RlcCBvZiB0aGUgd29ya2Zsb3cuXG4gICAqXG4gICAqICoqQ1JJVElDQUwqKjogSWYgaW1wbGVtZW50ZWQsIG11c3Qgc2V0IGBvdXRwdXRQYXRoYCB0byBwcmVzZXJ2ZSB3b3JrZmxvdyBzdGF0ZS5cbiAgICogVGhlIGVucmljaG1lbnQgcmVzdWx0IHNob3VsZCBiZSBhdmFpbGFibGUgYXQgYCQuZW5yaWNoZWRSZXN1bHRgIGZvciBEeW5hbW9EQiBzdG9yYWdlLlxuICAgKlxuICAgKiBAcmV0dXJucyBTdGVwIEZ1bmN0aW9ucyB0YXNrIGZvciBkb2N1bWVudCBlbnJpY2htZW50LCBvciB1bmRlZmluZWQgdG8gc2tpcCB0aGlzIHN0ZXBcbiAgICovXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBlbnJpY2htZW50U3RlcCgpOiBEb2N1bWVudFByb2Nlc3NpbmdTdGVwVHlwZSB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogRGVmaW5lcyB0aGUgb3B0aW9uYWwgcG9zdC1wcm9jZXNzaW5nIHN0ZXAgb2YgdGhlIHdvcmtmbG93LlxuICAgKlxuICAgKiAqKkNSSVRJQ0FMKio6IElmIGltcGxlbWVudGVkLCBtdXN0IHNldCBgb3V0cHV0UGF0aGAgdG8gcHJlc2VydmUgd29ya2Zsb3cgc3RhdGUuXG4gICAqIFRoZSBwb3N0LXByb2Nlc3NpbmcgcmVzdWx0IHNob3VsZCBiZSBhdmFpbGFibGUgYXQgYCQucG9zdFByb2Nlc3NlZFJlc3VsdGAgZm9yIER5bmFtb0RCIHN0b3JhZ2UuXG4gICAqXG4gICAqIEByZXR1cm5zIFN0ZXAgRnVuY3Rpb25zIHRhc2sgZm9yIHBvc3QtcHJvY2Vzc2luZywgb3IgdW5kZWZpbmVkIHRvIHNraXAgdGhpcyBzdGVwXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgcG9zdFByb2Nlc3NpbmdTdGVwKCk6IERvY3VtZW50UHJvY2Vzc2luZ1N0ZXBUeXBlIHwgdW5kZWZpbmVkO1xufVxuIl19
|