aws-cdk-neuronx-patterns 0.2.1 → 0.3.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 +604 -99
- package/API.md +990 -210
- package/README.ja.md +18 -6
- package/README.md +16 -5
- package/lib/base/aws-batch/neuronx-batch-compute-environment.js +1 -1
- package/lib/base/aws-batch/neuronx-batch-ecs-job-definition.js +1 -1
- package/lib/base/aws-batch/neuronx-batch.js +1 -1
- package/lib/base/aws-ecs-patterns/application-load-balanced-neuronx-service.js +4 -4
- package/lib/base/neuronx/deep-learning-containers.js +3 -3
- package/lib/base/neuronx/model.js +2 -2
- package/lib/base/neuronx/neuron-optimized-machine-image.js +1 -1
- package/lib/base/neuronx/neuronx-instance-type.js +4 -4
- package/lib/base/neuronx-compiler/index.d.ts +3 -1
- package/lib/base/neuronx-compiler/index.js +4 -2
- package/lib/base/neuronx-compiler/{neuronx-compiler.d.ts → neuronx-compiler-base.d.ts} +74 -32
- package/lib/base/neuronx-compiler/neuronx-compiler-base.js +129 -0
- package/lib/base/neuronx-compiler/neuronx-cross-compiler.d.ts +30 -0
- package/lib/base/neuronx-compiler/neuronx-cross-compiler.js +83 -0
- package/lib/base/neuronx-compiler/neuronx-native-compiler.d.ts +18 -0
- package/lib/base/neuronx-compiler/neuronx-native-compiler.js +69 -0
- package/lib/base/server-engine/vllm-engine/vllm-engine-argments.js +1 -1
- package/lib/sagemaker-inference-toolkit-tnx/sagemaker-inference-toolkit-tnx-compiler.js +2 -2
- package/lib/sagemaker-inference-toolkit-tnx/sagemaker-inference-toolkit-tnx-sagemaker.d.ts +1 -1
- package/lib/sagemaker-inference-toolkit-tnx/sagemaker-inference-toolkit-tnx-sagemaker.js +2 -2
- package/lib/vllm-nxd-inference/vllm-nxd-inference-compiler.d.ts +8 -0
- package/lib/vllm-nxd-inference/vllm-nxd-inference-compiler.js +32 -4
- package/lib/vllm-nxd-inference/vllm-nxd-inference-ecs-patterns.js +6 -6
- package/package.json +5 -5
- package/scripts/compile/vllm-nxd-inference/Dockerfile +5 -0
- package/scripts/compile/vllm-nxd-inference/entrypoint.sh +39 -14
- package/lib/base/neuronx-compiler/neuronx-compiler.js +0 -166
|
@@ -2,18 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
LOG_FILE=~/vllm.log
|
|
4
4
|
touch $LOG_FILE
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return 0
|
|
12
|
-
else
|
|
13
|
-
echo "Compile failed."
|
|
14
|
-
return 1
|
|
15
|
-
fi
|
|
16
|
-
}
|
|
5
|
+
|
|
6
|
+
# Create a dummy neuron device for vllm-neuron plugin registration
|
|
7
|
+
# when running on a non-Neuron instance (cross-compilation)
|
|
8
|
+
if [ ! -e /dev/neuron0 ]; then
|
|
9
|
+
mknod /dev/neuron0 c 10 200 2>/dev/null || true
|
|
10
|
+
fi
|
|
17
11
|
|
|
18
12
|
mkdir compile
|
|
19
13
|
cd compile
|
|
@@ -27,11 +21,42 @@ fi
|
|
|
27
21
|
python ~/vllm/quantize.py "$@"
|
|
28
22
|
|
|
29
23
|
vllm serve "$@" 2>&1 | tee $LOG_FILE &
|
|
24
|
+
VLLM_PID=$!
|
|
25
|
+
|
|
26
|
+
# Wait for either successful startup or compilation artifacts to appear
|
|
27
|
+
while true; do
|
|
28
|
+
# Check if vllm serve has started successfully (native Neuron instance)
|
|
29
|
+
if grep -q "Application startup complete" "$LOG_FILE" 2>/dev/null; then
|
|
30
|
+
echo "Detected 'Application startup complete'. Server started successfully."
|
|
31
|
+
break
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Check if compilation artifacts exist but load failed (cross-compilation)
|
|
35
|
+
if grep -q "Cannot find Neuron devices\|Neuron Runtime could not be initialized\|nrt_init" "$LOG_FILE" 2>/dev/null; then
|
|
36
|
+
if [ -d "$NEURON_COMPILED_ARTIFACTS" ] && [ -f "$NEURON_COMPILED_ARTIFACTS/model.pt" ]; then
|
|
37
|
+
echo "Compilation succeeded but Neuron device not available (cross-compilation mode)."
|
|
38
|
+
echo "Artifacts found at $NEURON_COMPILED_ARTIFACTS"
|
|
39
|
+
break
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Check if vllm process has exited
|
|
44
|
+
if ! kill -0 $VLLM_PID 2>/dev/null; then
|
|
45
|
+
# Process exited - check if artifacts exist
|
|
46
|
+
if [ -d "$NEURON_COMPILED_ARTIFACTS" ] && [ -f "$NEURON_COMPILED_ARTIFACTS/model.pt" ]; then
|
|
47
|
+
echo "vllm serve exited but compilation artifacts found (cross-compilation mode)."
|
|
48
|
+
break
|
|
49
|
+
else
|
|
50
|
+
echo "Compile failed. No artifacts found."
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
fi
|
|
30
54
|
|
|
31
|
-
|
|
55
|
+
sleep 5
|
|
56
|
+
done
|
|
32
57
|
|
|
33
58
|
aws s3 cp --no-progress --recursive ./ $COMPILED_ARTIFACTS_S3_URI \
|
|
34
59
|
--exclude "**/.cache/*" \
|
|
35
60
|
--exclude global_metric_store.json
|
|
36
61
|
|
|
37
|
-
echo 'Compile completed.'
|
|
62
|
+
echo 'Compile completed.'
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var _a;
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.NeuronxCompiler = void 0;
|
|
5
|
-
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
6
|
-
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
7
|
-
const batch = require("aws-cdk-lib/aws-batch");
|
|
8
|
-
const ec2 = require("aws-cdk-lib/aws-ec2");
|
|
9
|
-
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
10
|
-
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
|
|
11
|
-
const custom_resources_1 = require("aws-cdk-lib/custom-resources");
|
|
12
|
-
const constructs_1 = require("constructs");
|
|
13
|
-
const path_1 = require("path");
|
|
14
|
-
const aws_batch_1 = require("../aws-batch");
|
|
15
|
-
const neuronx_1 = require("../neuronx");
|
|
16
|
-
/**
|
|
17
|
-
* Neuronx compiler construct.
|
|
18
|
-
* Compile the model to work with Inferentia2 and Trainium1 and upload it to an S3 bucket.
|
|
19
|
-
*/
|
|
20
|
-
class NeuronxCompiler extends constructs_1.Construct {
|
|
21
|
-
constructor(scope, id, props) {
|
|
22
|
-
super(scope, id);
|
|
23
|
-
const weightSize = aws_cdk_lib_1.Size.gibibytes(props.model.options.parameters.toBillion() * 2.5);
|
|
24
|
-
const volumeSize = props.volumeSize?.toGibibytes() ??
|
|
25
|
-
Math.ceil(weightSize.toGibibytes() +
|
|
26
|
-
neuronx_1.PytorchTrainingNeuronxImage.size.toGibibytes() +
|
|
27
|
-
neuronx_1.NeuronOptimizedMachineImage.size.toGibibytes());
|
|
28
|
-
const launchTemplate = new ec2.LaunchTemplate(this, "LaunchTemplate", {
|
|
29
|
-
blockDevices: [
|
|
30
|
-
{
|
|
31
|
-
deviceName: "/dev/xvda",
|
|
32
|
-
volume: ec2.BlockDeviceVolume.ebs(volumeSize, {
|
|
33
|
-
volumeType: ec2.EbsDeviceVolumeType.GP3,
|
|
34
|
-
encrypted: true,
|
|
35
|
-
}),
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
});
|
|
39
|
-
const neuronxInstanceType = props.neuronxInstanceType ?? neuronx_1.NeuronxInstanceType.INF2_48XLARGE;
|
|
40
|
-
const computeEnvironment = new aws_batch_1.NeuronxBatchComputeEnvironment(this, "ComputeEnvironment", {
|
|
41
|
-
vpc: props.vpc,
|
|
42
|
-
vpcSubnets: props.vpcSubnets,
|
|
43
|
-
instanceTypes: [neuronxInstanceType.instanceType],
|
|
44
|
-
useOptimalInstanceClasses: false,
|
|
45
|
-
launchTemplate,
|
|
46
|
-
spot: props.spot,
|
|
47
|
-
});
|
|
48
|
-
aws_cdk_lib_1.Tags.of(computeEnvironment).add("Name", "neuronx-compile-worker");
|
|
49
|
-
this.jobQueue = new batch.JobQueue(this, "JobQueue", {
|
|
50
|
-
computeEnvironments: [
|
|
51
|
-
{
|
|
52
|
-
computeEnvironment,
|
|
53
|
-
order: 1,
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
jobStateTimeLimitActions: [
|
|
57
|
-
{
|
|
58
|
-
state: batch.JobStateTimeLimitActionsState.RUNNABLE,
|
|
59
|
-
reason: batch.JobStateTimeLimitActionsReason.JOB_RESOURCE_REQUIREMENT,
|
|
60
|
-
maxTime: aws_cdk_lib_1.Duration.minutes(10),
|
|
61
|
-
action: batch.JobStateTimeLimitActionsAction.CANCEL,
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
});
|
|
65
|
-
props.model.bucket?.grantRead(computeEnvironment.instanceRole);
|
|
66
|
-
props.bucket.grantReadWrite(computeEnvironment.instanceRole);
|
|
67
|
-
this.jobDefinition = new aws_batch_1.NeuronxBatchEcsJobDefinition(this, "JobDefinition", {
|
|
68
|
-
neuronxInstanceType,
|
|
69
|
-
image: props.image.image,
|
|
70
|
-
// The fllowing command was executed on inf2.8xlarge
|
|
71
|
-
// sh-5.2$ free -b
|
|
72
|
-
// total used free shared buff/cache available
|
|
73
|
-
// Mem: 132265766912 866320384 130341785600 667648 1057660928 130529148928
|
|
74
|
-
// https://docs.aws.amazon.com/batch/latest/userguide/memory-management.html
|
|
75
|
-
memory: aws_cdk_lib_1.Size.mebibytes(Math.ceil(neuronxInstanceType.memory.toMebibytes() * 0.95)),
|
|
76
|
-
cpu: neuronxInstanceType.vCpu,
|
|
77
|
-
environment: {
|
|
78
|
-
NEURON_COMPILE_CACHE_URL: `${props.bucket.s3UrlForObject("neuron-compile-cache")}`,
|
|
79
|
-
...props.environment,
|
|
80
|
-
},
|
|
81
|
-
command: props.command,
|
|
82
|
-
secrets: props.secrets,
|
|
83
|
-
});
|
|
84
|
-
const jobSubmitFunction = new aws_lambda_1.SingletonFunction(this, "JobSubmitFunction", {
|
|
85
|
-
code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, "private/await-compile-job")),
|
|
86
|
-
handler: "index.onEvent",
|
|
87
|
-
runtime: aws_lambda_1.Runtime.NODEJS_LATEST,
|
|
88
|
-
uuid: "1361f469-5c92-4c46-9e11-5d1dbf925bac",
|
|
89
|
-
environment: {
|
|
90
|
-
JOB_DEFINITION_ARN: this.jobDefinition.jobDefinitionArn,
|
|
91
|
-
JOB_QUEUE_ARN: this.jobQueue.jobQueueArn,
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
this.jobDefinition.grantSubmitJob(jobSubmitFunction, this.jobQueue);
|
|
95
|
-
const jobMonitoringFunction = new aws_lambda_1.SingletonFunction(this, "JobMonitoringFunction", {
|
|
96
|
-
code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, "private/await-compile-job")),
|
|
97
|
-
handler: "index.isComplete",
|
|
98
|
-
runtime: aws_lambda_1.Runtime.NODEJS_LATEST,
|
|
99
|
-
uuid: "df16dba8-5f77-480c-a6ad-cfdf74c3de62",
|
|
100
|
-
environment: {
|
|
101
|
-
ARTIFACT_S3_PREFIX: props.artifactS3Prefix,
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
aws_iam_1.Grant.addToPrincipal({
|
|
105
|
-
resourceArns: ["*"],
|
|
106
|
-
grantee: jobMonitoringFunction,
|
|
107
|
-
actions: ["batch:DescribeJobs"],
|
|
108
|
-
});
|
|
109
|
-
const provider = new custom_resources_1.Provider(this, "CompileJobProvider", {
|
|
110
|
-
onEventHandler: jobSubmitFunction,
|
|
111
|
-
isCompleteHandler: jobMonitoringFunction,
|
|
112
|
-
queryInterval: aws_cdk_lib_1.Duration.minutes(1),
|
|
113
|
-
totalTimeout: aws_cdk_lib_1.Duration.hours(12),
|
|
114
|
-
});
|
|
115
|
-
this.entrypoint = new aws_lambda_1.SingletonFunction(this, "JobEntrypointFunction", {
|
|
116
|
-
code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, "private/await-compile-job")),
|
|
117
|
-
handler: "index.entrypoint",
|
|
118
|
-
environment: {
|
|
119
|
-
PROVIDER_ARN: provider.serviceToken,
|
|
120
|
-
},
|
|
121
|
-
timeout: aws_cdk_lib_1.Duration.minutes(15),
|
|
122
|
-
runtime: aws_lambda_1.Runtime.NODEJS_LATEST,
|
|
123
|
-
uuid: "f6e66997-5042-4df1-8781-bd68b3ac5313",
|
|
124
|
-
});
|
|
125
|
-
aws_lambda_1.Function.fromFunctionArn(this, "ProviderFunction", provider.serviceToken).grantInvoke(this.entrypoint);
|
|
126
|
-
this.model = props.model;
|
|
127
|
-
this.bucket = props.bucket;
|
|
128
|
-
this.artifactS3Prefix = props.artifactS3Prefix;
|
|
129
|
-
this.weightSize = weightSize;
|
|
130
|
-
this.neuronxInstanceType = neuronxInstanceType;
|
|
131
|
-
}
|
|
132
|
-
compile() {
|
|
133
|
-
// when invoke multiple times
|
|
134
|
-
if (this.compiledModel) {
|
|
135
|
-
return this.compiledModel;
|
|
136
|
-
}
|
|
137
|
-
const waitConditionHandle = new aws_cdk_lib_1.CfnWaitConditionHandle(this, `WaitConditionHandle${this.artifactS3Prefix}`);
|
|
138
|
-
const compileJob = new aws_cdk_lib_1.CustomResource(this, "NeuronxCompile", {
|
|
139
|
-
serviceToken: this.entrypoint.functionArn,
|
|
140
|
-
resourceType: "Custom::NeuronxCompile",
|
|
141
|
-
properties: {
|
|
142
|
-
waitConditionCallbackURL: waitConditionHandle.ref,
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
const wait = new aws_cdk_lib_1.CfnWaitCondition(this, `WaitCondition${this.artifactS3Prefix}`, {
|
|
146
|
-
count: 1,
|
|
147
|
-
timeout: aws_cdk_lib_1.Duration.hours(12).toSeconds().toString(),
|
|
148
|
-
handle: waitConditionHandle.ref,
|
|
149
|
-
});
|
|
150
|
-
wait.node.addDependency(compileJob);
|
|
151
|
-
const s3Prefix = aws_cdk_lib_1.Fn.select(3, aws_cdk_lib_1.Fn.split('"', wait.attrData.toString()));
|
|
152
|
-
this.compiledModel = {
|
|
153
|
-
modelName: this.model.modelName,
|
|
154
|
-
compileTimeInstanceType: this.neuronxInstanceType,
|
|
155
|
-
bucket: this.bucket,
|
|
156
|
-
s3Prefix,
|
|
157
|
-
s3Uri: this.bucket.s3UrlForObject(s3Prefix),
|
|
158
|
-
weightSize: this.weightSize,
|
|
159
|
-
};
|
|
160
|
-
return this.compiledModel;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
exports.NeuronxCompiler = NeuronxCompiler;
|
|
164
|
-
_a = JSII_RTTI_SYMBOL_1;
|
|
165
|
-
NeuronxCompiler[_a] = { fqn: "aws-cdk-neuronx-patterns.NeuronxCompiler", version: "0.2.1" };
|
|
166
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV1cm9ueC1jb21waWxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYXNlL25ldXJvbngtY29tcGlsZXIvbmV1cm9ueC1jb21waWxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQVFxQjtBQUNyQiwrQ0FBK0M7QUFDL0MsMkNBQTJDO0FBRTNDLGlEQUE0QztBQUM1Qyx1REFLZ0M7QUFFaEMsbUVBQXdEO0FBQ3hELDJDQUF1QztBQUN2QywrQkFBNEI7QUFDNUIsNENBR3NCO0FBQ3RCLHdDQU1vQjtBQW1HcEI7OztHQUdHO0FBQ0gsTUFBYSxlQUFnQixTQUFRLHNCQUFTO0lBVTVDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBMkI7UUFDbkUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixNQUFNLFVBQVUsR0FBRyxrQkFBSSxDQUFDLFNBQVMsQ0FDL0IsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxHQUFHLEdBQUcsQ0FDakQsQ0FBQztRQUNGLE1BQU0sVUFBVSxHQUNkLEtBQUssQ0FBQyxVQUFVLEVBQUUsV0FBVyxFQUFFO1lBQy9CLElBQUksQ0FBQyxJQUFJLENBQ1AsVUFBVSxDQUFDLFdBQVcsRUFBRTtnQkFDdEIscUNBQTJCLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRTtnQkFDOUMscUNBQTJCLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUNqRCxDQUFDO1FBQ0osTUFBTSxjQUFjLEdBQUcsSUFBSSxHQUFHLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUNwRSxZQUFZLEVBQUU7Z0JBQ1o7b0JBQ0UsVUFBVSxFQUFFLFdBQVc7b0JBQ3ZCLE1BQU0sRUFBRSxHQUFHLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRTt3QkFDNUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxt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QUMsQ0FBQztRQUNILE1BQU0sSUFBSSxHQUFHLElBQUksOEJBQWdCLENBQy9CLElBQUksRUFDSixnQkFBZ0IsSUFBSSxDQUFDLGdCQUFnQixFQUFFLEVBQ3ZDO1lBQ0UsS0FBSyxFQUFFLENBQUM7WUFDUixPQUFPLEVBQUUsc0JBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxFQUFFO1lBQ2xELE1BQU0sRUFBRSxtQkFBbUIsQ0FBQyxHQUFHO1NBQ2hDLENBQ0YsQ0FBQztRQUNGLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sUUFBUSxHQUFHLGdCQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxnQkFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFdkUsSUFBSSxDQUFDLGFBQWEsR0FBRztZQUNuQixTQUFTLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTO1lBQy9CLHVCQUF1QixFQUFFLElBQUksQ0FBQyxtQkFBbUI7WUFDakQsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ25CLFFBQVE7WUFDUixLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDO1lBQzNDLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVTtTQUM1QixDQUFDO1FBQ0YsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDO0lBQzVCLENBQUM7O0FBMUxILDBDQTJMQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENmbldhaXRDb25kaXRpb24sXG4gIENmbldhaXRDb25kaXRpb25IYW5kbGUsXG4gIEN1c3RvbVJlc291cmNlLFxuICBEdXJhdGlvbixcbiAgRm4sXG4gIFNpemUsXG4gIFRhZ3MsXG59IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0ICogYXMgYmF0Y2ggZnJvbSBcImF3cy1jZGstbGliL2F3cy1iYXRjaFwiO1xuaW1wb3J0ICogYXMgZWMyIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWMyXCI7XG5pbXBvcnQgeyBDb250YWluZXJJbWFnZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQgeyBHcmFudCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQge1xuICBDb2RlLFxuICBGdW5jdGlvbixcbiAgUnVudGltZSxcbiAgU2luZ2xldG9uRnVuY3Rpb24sXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCI7XG5pbXBvcnQgeyBJQnVja2V0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zM1wiO1xuaW1wb3J0IHsgUHJvdmlkZXIgfSBmcm9tIFwiYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHtcbiAgTmV1cm9ueEJhdGNoQ29tcHV0ZUVudmlyb25tZW50LFxuICBOZXVyb254QmF0Y2hFY3NKb2JEZWZpbml0aW9uLFxufSBmcm9tIFwiLi4vYXdzLWJhdGNoXCI7XG5pbXBvcnQge1xuICBJTmV1cm9ueEluc3RhbmNlVHlwZSxcbiAgTW9kZWwsXG4gIE5ldXJvbk9wdGltaXplZE1hY2hpbmVJbWFnZSxcbiAgTmV1cm9ueEluc3RhbmNlVHlwZSxcbiAgUHl0b3JjaFRyYWluaW5nTmV1cm9ueEltYWdlLFxufSBmcm9tIFwiLi4vbmV1cm9ueFwiO1xuXG4vKipcbiAqIENvbXBpbGUgcnVudGltZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJTmV1cm9ueENvbnRhaW5lckltYWdlIHtcbiAgLyoqXG4gICAqIEFuIGltYWdlIG9mIHRoZSBjb250YWluZXIgd2hlcmUgdGhlIGNvbXBpbGUgam9iIGlzIGV4ZWN1dGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2U6IENvbnRhaW5lckltYWdlO1xuICAvKipcbiAgICogTmV1cm9ueCB2ZXJzaW9uIGluY2x1ZGVkIGluIGNvbnRhaW5lciBpbWFnZS5cbiAgICovXG4gIHJlYWRvbmx5IG5ldXJvblNka1ZlcnNpb246IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wcyBvZiBOZXVyb254Q29tcGlsZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTmV1cm9ueENvbXBpbGVyUHJvcHMge1xuICAvKipcbiAgICogVlBDIGluIHdoaWNoIHRoaXMgd2lsbCBsYXVuY2ggY29tcGlsZSB3b3JrZXIgaW5zdGFuY2UuXG4gICAqL1xuICByZWFkb25seSB2cGM6IGVjMi5JVnBjO1xuICAvKipcbiAgICogVGhlIGJ1Y2tldCB0byB1cGxvYWQgY29tcGlsZWQgYXJ0aWZhY3RzLlxuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0OiBJQnVja2V0O1xuICAvKipcbiAgICogU2VjcmV0cyB0byBwYXNzIHRvIHRoZSBjb250YWluZXIuXG4gICAqL1xuICByZWFkb25seSBzZWNyZXRzPzogeyBba2V5OiBzdHJpbmddOiBiYXRjaC5TZWNyZXQgfTtcbiAgLyoqXG4gICAqIFMzIFByZWZpeCB0aGF0IGNvbXBpbGVkIGFydGlmYWN0IHVwbG9hZGVkLlxuICAgKiBUaGlzIHByb3BlcnR5IGlzIG5vdCBkZXBlbmRzIG9uIGNvbXBpbGUgam9iIGZpbmlzaC5cbiAgICovXG4gIHJlYWRvbmx5IGFydGlmYWN0UzNQcmVmaXg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBpbnN0YW5jZSB0eXBlIG9mIGNvbXBpbGUgd29ya2VyIGluc3RhbmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgbmV1cm9ueEluc3RhbmNlVHlwZTogSU5ldXJvbnhJbnN0YW5jZVR5cGU7XG4gIC8qKlxuICAgKiBUaGUgbW9kZWwgdG8gYmUgY29tcGlsZWQuXG4gICAqL1xuICByZWFkb25seSBtb2RlbDogTW9kZWw7XG4gIC8qKlxuICAgKiBBbiBpbWFnZSBvZiB0aGUgY29udGFpbmVyIHdoZXJlIHRoZSBjb21waWxlIGpvYiBpcyBleGVjdXRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGltYWdlOiBJTmV1cm9ueENvbnRhaW5lckltYWdlO1xuICByZWFkb25seSBjb21tYW5kPzogc3RyaW5nW107XG4gIC8qKlxuICAgKiBUaGUgcm9vdCB2b2x1bWUgb2Ygd29ya2VyIGluc3RhbmNlLlxuICAgKiBAZGVmYXVsdCAtIE4gYmlsaW9uIHBhcmFtZXRlcnMgKiA1R2lCIEVCU1xuICAgKi9cbiAgcmVhZG9ubHkgdm9sdW1lU2l6ZT86IFNpemU7XG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCB0byB1c2Ugc3BvdCBpbnN0YW5jZXMuIFNwb3QgaW5zdGFuY2VzIGFyZSBsZXNzIGV4cGVuc2l2ZSBFQzIgaW5zdGFuY2VzIHRoYXQgY2FuIGJlIHJlY2xhaW1lZCBieSBFQzIgYXQgYW55IHRpbWU7IHlvdXIgam9iIHdpbGwgYmUgZ2l2ZW4gdHdvIG1pbnV0ZXMgb2Ygbm90aWNlIGJlZm9yZSByZWNsYW1hdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHNwb3Q/OiBib29sZWFuO1xuICAvKipcbiAgICogVGhlIFZQQyBTdWJuZXRzIHRoaXMgQ29tcHV0ZSBFbnZpcm9ubWVudCB3aWxsIGxhdW5jaCBpbnN0YW5jZXMgaW4uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbmV3IHN1Ym5ldHMgd2lsbCBiZSBjcmVhdGVkXG4gICAqL1xuICByZWFkb25seSB2cGNTdWJuZXRzPzogZWMyLlN1Ym5ldFNlbGVjdGlvbjtcbiAgLyoqXG4gICAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gcGFzcyB0byB0aGUgY29udGFpbmVyLlxuICAgKiBUaGlzIGlzIG9ubHkgYXBwbGljYWJsZSB3aGVuIHVzaW5nIGNvbnRhaW5lciBydW50aW1lLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAgICovXG4gIHJlYWRvbmx5IGVudmlyb25tZW50Pzoge1xuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZztcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOZXVyb254Q29tcGlsZWRNb2RlbCB7XG4gIHJlYWRvbmx5IGNvbXBpbGVUaW1lSW5zdGFuY2VUeXBlOiBJTmV1cm9ueEluc3RhbmNlVHlwZTtcbiAgLyoqXG4gICAqIFRoZSBidWNrZXQgdG8gdXBsb2FkIGNvbXBpbGVkIGFydGlmYWN0cy5cbiAgICovXG4gIHJlYWRvbmx5IGJ1Y2tldDogSUJ1Y2tldDtcbiAgLyoqXG4gICAqIFMzIFVSTCB0aGF0IGNvbXBpbGVkIGFydGlmYWN0IHVwbG9hZGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgczNVcmk6IHN0cmluZztcbiAgLyoqXG4gICAqIFMzIHByZWZpeCB0aGF0IGNvbXBpbGVkIGFydGlmYWN0IHVwbG9hZGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgczNQcmVmaXg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBtb2RlbCBuYW1lLlxuICAgKi9cbiAgcmVhZG9ubHkgbW9kZWxOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHdlaWdodFNpemU6IFNpemU7XG59XG5cbi8qKlxuICogTmV1cm9ueCBjb21waWxlciBjb25zdHJ1Y3QuXG4gKiBDb21waWxlIHRoZSBtb2RlbCB0byB3b3JrIHdpdGggSW5mZXJlbnRpYTIgYW5kIFRyYWluaXVtMSBhbmQgdXBsb2FkIGl0IHRvIGFuIFMzIGJ1Y2tldC5cbiAqL1xuZXhwb3J0IGNsYXNzIE5ldXJvbnhDb21waWxlciBleHRlbmRzIENvbnN0cnVjdCB7XG4gIHByaXZhdGUgY29tcGlsZWRNb2RlbD86IE5ldXJvbnhDb21waWxlZE1vZGVsO1xuICBwcml2YXRlIHJlYWRvbmx5IGVudHJ5cG9pbnQ6IFNpbmdsZXRvbkZ1bmN0aW9uO1xuICBwcml2YXRlIHJlYWRvbmx5IGpvYkRlZmluaXRpb246IE5ldXJvbnhCYXRjaEVjc0pvYkRlZmluaXRpb247XG4gIHByaXZhdGUgcmVhZG9ubHkgam9iUXVldWU6IGJhdGNoLkpvYlF1ZXVlO1xuICBwcml2YXRlIHJlYWRvbmx5IGFydGlmYWN0UzNQcmVmaXg6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSB3ZWlnaHRTaXplOiBTaXplO1xuICBwcml2YXRlIHJlYWRvbmx5IG5ldXJvbnhJbnN0YW5jZVR5cGU6IElOZXVyb254SW5zdGFuY2VUeXBlO1xuICBwcml2YXRlIHJlYWRvbmx5IG1vZGVsOiBNb2RlbDtcbiAgcHJpdmF0ZSByZWFkb25seSBidWNrZXQ6IElCdWNrZXQ7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOZXVyb254Q29tcGlsZXJQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgY29uc3Qgd2VpZ2h0U2l6ZSA9IFNpemUuZ2liaWJ5dGVzKFxuICAgICAgcHJvcHMubW9kZWwub3B0aW9ucy5wYXJhbWV0ZXJzLnRvQmlsbGlvbigpICogMi41LFxuICAgICk7XG4gICAgY29uc3Qgdm9sdW1lU2l6ZSA9XG4gICAgICBwcm9wcy52b2x1bWVTaXplPy50b0dpYmlieXRlcygpID8/XG4gICAgICBNYXRoLmNlaWwoXG4gICAgICAgIHdlaWdodFNpemUudG9HaWJpYnl0ZXMoKSArXG4gICAgICAgICAgUHl0b3JjaFRyYWluaW5nTmV1cm9ueEltYWdlLnNpemUudG9HaWJpYnl0ZXMoKSArXG4gICAgICAgICAgTmV1cm9uT3B0aW1pemVkTWFjaGluZUltYWdlLnNpemUudG9HaWJpYnl0ZXMoKSxcbiAgICAgICk7XG4gICAgY29uc3QgbGF1bmNoVGVtcGxhdGUgPSBuZXcgZWMyLkxhdW5jaFRlbXBsYXRlKHRoaXMsIFwiTGF1bmNoVGVtcGxhdGVcIiwge1xuICAgICAgYmxvY2tEZXZpY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBkZXZpY2VOYW1lOiBcIi9kZXYveHZkYVwiLFxuICAgICAgICAgIHZvbHVtZTogZWMyLkJsb2NrRGV2aWNlVm9sdW1lLmVicyh2b2x1bWVTaXplLCB7XG4gICAgICAgICAgICB2b2x1bWVUeXBlOiBlYzIuRWJzRGV2aWNlVm9sdW1lVHlwZS5HUDMsXG4gICAgICAgICAgICBlbmNyeXB0ZWQ6IHRydWUsXG4gICAgICAgICAgfSksXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuXG4gICAgY29uc3QgbmV1cm9ueEluc3RhbmNlVHlwZSA9XG4gICAgICBwcm9wcy5uZXVyb254SW5zdGFuY2VUeXBlID8/IE5ldXJvbnhJbnN0YW5jZVR5cGUuSU5GMl80OFhMQVJHRTtcbiAgICBjb25zdCBjb21wdXRlRW52aXJvbm1lbnQgPSBuZXcgTmV1cm9ueEJhdGNoQ29tcHV0ZUVudmlyb25tZW50KFxuICAgICAgdGhpcyxcbiAgICAgIFwiQ29tcHV0ZUVudmlyb25tZW50XCIsXG4gICAgICB7XG4gICAgICAgIHZwYzogcHJvcHMudnBjLFxuICAgICAgICB2cGNTdWJuZXRzOiBwcm9wcy52cGNTdWJuZXRzLFxuICAgICAgICBpbnN0YW5jZVR5cGVzOiBbbmV1cm9ueEluc3RhbmNlVHlwZS5pbnN0YW5jZVR5cGVdLFxuICAgICAgICB1c2VPcHRpbWFsSW5zdGFuY2VDbGFzc2VzOiBmYWxzZSxcbiAgICAgICAgbGF1bmNoVGVtcGxhdGUsXG4gICAgICAgIHNwb3Q6IHByb3BzLnNwb3QsXG4gICAgICB9LFxuICAgICk7XG5cbiAgICBUYWdzLm9mKGNvbXB1dGVFbnZpcm9ubWVudCkuYWRkKFwiTmFtZVwiLCBcIm5ldXJvbngtY29tcGlsZS13b3JrZXJcIik7XG4gICAgdGhpcy5qb2JRdWV1ZSA9IG5ldyBiYXRjaC5Kb2JRdWV1ZSh0aGlzLCBcIkpvYlF1ZXVlXCIsIHtcbiAgICAgIGNvbXB1dGVFbnZpcm9ubWVudHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGNvbXB1dGVFbnZpcm9ubWVudCxcbiAgICAgICAgICBvcmRlcjogMSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBqb2JTdGF0ZVRpbWVMaW1pdEFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHN0YXRlOiBiYXRjaC5Kb2JTdGF0ZVRpbWVMaW1pdEFjdGlvbnNTdGF0ZS5SVU5OQUJMRSxcbiAgICAgICAgICByZWFzb246IGJhdGNoLkpvYlN0YXRlVGltZUxpbWl0QWN0aW9uc1JlYXNvbi5KT0JfUkVTT1VSQ0VfUkVRVUlSRU1FTlQsXG4gICAgICAgICAgbWF4VGltZTogRHVyYXRpb24ubWludXRlcygxMCksXG4gICAgICAgICAgYWN0aW9uOiBiYXRjaC5Kb2JTdGF0ZVRpbWVMaW1pdEFjdGlvbnNBY3Rpb24uQ0FOQ0VMLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBwcm9wcy5tb2RlbC5idWNrZXQ/LmdyYW50UmVhZChjb21wdXRlRW52aXJvbm1lbnQuaW5zdGFuY2VSb2xlKTtcbiAgICBwcm9wcy5idWNrZXQuZ3JhbnRSZWFkV3JpdGUoY29tcHV0ZUVudmlyb25tZW50Lmluc3RhbmNlUm9sZSk7XG4gICAgdGhpcy5qb2JEZWZpbml0aW9uID0gbmV3IE5ldXJvbnhCYXRjaEVjc0pvYkRlZmluaXRpb24oXG4gICAgICB0aGlzLFxuICAgICAgXCJKb2JEZWZpbml0aW9uXCIsXG4gICAgICB7XG4gICAgICAgIG5ldXJvbnhJbnN0YW5jZVR5cGUsXG4gICAgICAgIGltYWdlOiBwcm9wcy5pbWFnZS5pbWFnZSxcbiAgICAgICAgLy8gVGhlIGZsbG93aW5nIGNvbW1hbmQgd2FzIGV4ZWN1dGVkIG9uIGluZjIuOHhsYXJnZVxuICAgICAgICAvLyBzaC01LjIkIGZyZWUgLWJcbiAgICAgICAgLy8gXHRcdFx0dG90YWxcdFx0XHRcdFx0dXNlZFx0XHRcdGZyZWVcdFx0XHRcdFx0c2hhcmVkXHRidWZmL2NhY2hlXHRhdmFpbGFibGVcbiAgICAgICAgLy8gTWVtOlx0MTMyMjY1NzY2OTEyXHQ4NjYzMjAzODRcdDEzMDM0MTc4NTYwMFx0NjY3NjQ4XHQxMDU3NjYwOTI4XHQxMzA1MjkxNDg5MjhcbiAgICAgICAgLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2JhdGNoL2xhdGVzdC91c2VyZ3VpZGUvbWVtb3J5LW1hbmFnZW1lbnQuaHRtbFxuICAgICAgICBtZW1vcnk6IFNpemUubWViaWJ5dGVzKFxuICAgICAgICAgIE1hdGguY2VpbChuZXVyb254SW5zdGFuY2VUeXBlLm1lbW9yeS50b01lYmlieXRlcygpICogMC45NSksXG4gICAgICAgICksXG4gICAgICAgIGNwdTogbmV1cm9ueEluc3RhbmNlVHlwZS52Q3B1LFxuICAgICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICAgIE5FVVJPTl9DT01QSUxFX0NBQ0hFX1VSTDogYCR7cHJvcHMuYnVja2V0LnMzVXJsRm9yT2JqZWN0KFwibmV1cm9uLWNvbXBpbGUtY2FjaGVcIil9YCxcbiAgICAgICAgICAuLi5wcm9wcy5lbnZpcm9ubWVudCxcbiAgICAgICAgfSxcbiAgICAgICAgY29tbWFuZDogcHJvcHMuY29tbWFuZCxcbiAgICAgICAgc2VjcmV0czogcHJvcHMuc2VjcmV0cyxcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIGNvbnN0IGpvYlN1Ym1pdEZ1bmN0aW9uID0gbmV3IFNpbmdsZXRvbkZ1bmN0aW9uKHRoaXMsIFwiSm9iU3VibWl0RnVuY3Rpb25cIiwge1xuICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQoam9pbihfX2Rpcm5hbWUsIFwicHJpdmF0ZS9hd2FpdC1jb21waWxlLWpvYlwiKSksXG4gICAgICBoYW5kbGVyOiBcImluZGV4Lm9uRXZlbnRcIixcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTX0xBVEVTVCxcbiAgICAgIHV1aWQ6IFwiMTM2MWY0NjktNWM5Mi00YzQ2LTllMTEtNWQxZGJmOTI1YmFjXCIsXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBKT0JfREVGSU5JVElPTl9BUk46IHRoaXMuam9iRGVmaW5pdGlvbi5qb2JEZWZpbml0aW9uQXJuLFxuICAgICAgICBKT0JfUVVFVUVfQVJOOiB0aGlzLmpvYlF1ZXVlLmpvYlF1ZXVlQXJuLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICB0aGlzLmpvYkRlZmluaXRpb24uZ3JhbnRTdWJtaXRKb2Ioam9iU3VibWl0RnVuY3Rpb24sIHRoaXMuam9iUXVldWUpO1xuICAgIGNvbnN0IGpvYk1vbml0b3JpbmdGdW5jdGlvbiA9IG5ldyBTaW5nbGV0b25GdW5jdGlvbihcbiAgICAgIHRoaXMsXG4gICAgICBcIkpvYk1vbml0b3JpbmdGdW5jdGlvblwiLFxuICAgICAge1xuICAgICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldChqb2luKF9fZGlybmFtZSwgXCJwcml2YXRlL2F3YWl0LWNvbXBpbGUtam9iXCIpKSxcbiAgICAgICAgaGFuZGxlcjogXCJpbmRleC5pc0NvbXBsZXRlXCIsXG4gICAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTX0xBVEVTVCxcbiAgICAgICAgdXVpZDogXCJkZjE2ZGJhOC01Zjc3LTQ4MGMtYTZhZC1jZmRmNzRjM2RlNjJcIixcbiAgICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgICBBUlRJRkFDVF9TM19QUkVGSVg6IHByb3BzLmFydGlmYWN0UzNQcmVmaXgsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICk7XG4gICAgR3JhbnQuYWRkVG9QcmluY2lwYWwoe1xuICAgICAgcmVzb3VyY2VBcm5zOiBbXCIqXCJdLFxuICAgICAgZ3JhbnRlZTogam9iTW9uaXRvcmluZ0Z1bmN0aW9uLFxuICAgICAgYWN0aW9uczogW1wiYmF0Y2g6RGVzY3JpYmVKb2JzXCJdLFxuICAgIH0pO1xuICAgIGNvbnN0IHByb3ZpZGVyID0gbmV3IFByb3ZpZGVyKHRoaXMsIFwiQ29tcGlsZUpvYlByb3ZpZGVyXCIsIHtcbiAgICAgIG9uRXZlbnRIYW5kbGVyOiBqb2JTdWJtaXRGdW5jdGlvbixcbiAgICAgIGlzQ29tcGxldGVIYW5kbGVyOiBqb2JNb25pdG9yaW5nRnVuY3Rpb24sXG4gICAgICBxdWVyeUludGVydmFsOiBEdXJhdGlvbi5taW51dGVzKDEpLFxuICAgICAgdG90YWxUaW1lb3V0OiBEdXJhdGlvbi5ob3VycygxMiksXG4gICAgfSk7XG4gICAgdGhpcy5lbnRyeXBvaW50ID0gbmV3IFNpbmdsZXRvbkZ1bmN0aW9uKHRoaXMsIFwiSm9iRW50cnlwb2ludEZ1bmN0aW9uXCIsIHtcbiAgICAgIGNvZGU6IENvZGUuZnJvbUFzc2V0KGpvaW4oX19kaXJuYW1lLCBcInByaXZhdGUvYXdhaXQtY29tcGlsZS1qb2JcIikpLFxuICAgICAgaGFuZGxlcjogXCJpbmRleC5lbnRyeXBvaW50XCIsXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBQUk9WSURFUl9BUk46IHByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgIH0sXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5taW51dGVzKDE1KSxcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTX0xBVEVTVCxcbiAgICAgIHV1aWQ6IFwiZjZlNjY5OTctNTA0Mi00ZGYxLTg3ODEtYmQ2OGIzYWM1MzEzXCIsXG4gICAgfSk7XG4gICAgRnVuY3Rpb24uZnJvbUZ1bmN0aW9uQXJuKFxuICAgICAgdGhpcyxcbiAgICAgIFwiUHJvdmlkZXJGdW5jdGlvblwiLFxuICAgICAgcHJvdmlkZXIuc2VydmljZVRva2VuLFxuICAgICkuZ3JhbnRJbnZva2UodGhpcy5lbnRyeXBvaW50KTtcblxuICAgIHRoaXMubW9kZWwgPSBwcm9wcy5tb2RlbDtcbiAgICB0aGlzLmJ1Y2tldCA9IHByb3BzLmJ1Y2tldDtcbiAgICB0aGlzLmFydGlmYWN0UzNQcmVmaXggPSBwcm9wcy5hcnRpZmFjdFMzUHJlZml4O1xuICAgIHRoaXMud2VpZ2h0U2l6ZSA9IHdlaWdodFNpemU7XG4gICAgdGhpcy5uZXVyb254SW5zdGFuY2VUeXBlID0gbmV1cm9ueEluc3RhbmNlVHlwZTtcbiAgfVxuICBjb21waWxlKCkge1xuICAgIC8vIHdoZW4gaW52b2tlIG11bHRpcGxlIHRpbWVzXG4gICAgaWYgKHRoaXMuY29tcGlsZWRNb2RlbCkge1xuICAgICAgcmV0dXJuIHRoaXMuY29tcGlsZWRNb2RlbDtcbiAgICB9XG4gICAgY29uc3Qgd2FpdENvbmRpdGlvbkhhbmRsZSA9IG5ldyBDZm5XYWl0Q29uZGl0aW9uSGFuZGxlKFxuICAgICAgdGhpcyxcbiAgICAgIGBXYWl0Q29uZGl0aW9uSGFuZGxlJHt0aGlzLmFydGlmYWN0UzNQcmVmaXh9YCxcbiAgICApO1xuICAgIGNvbnN0IGNvbXBpbGVKb2IgPSBuZXcgQ3VzdG9tUmVzb3VyY2UodGhpcywgXCJOZXVyb254Q29tcGlsZVwiLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IHRoaXMuZW50cnlwb2ludC5mdW5jdGlvbkFybixcbiAgICAgIHJlc291cmNlVHlwZTogXCJDdXN0b206Ok5ldXJvbnhDb21waWxlXCIsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIHdhaXRDb25kaXRpb25DYWxsYmFja1VSTDogd2FpdENvbmRpdGlvbkhhbmRsZS5yZWYsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGNvbnN0IHdhaXQgPSBuZXcgQ2ZuV2FpdENvbmRpdGlvbihcbiAgICAgIHRoaXMsXG4gICAgICBgV2FpdENvbmRpdGlvbiR7dGhpcy5hcnRpZmFjdFMzUHJlZml4fWAsXG4gICAgICB7XG4gICAgICAgIGNvdW50OiAxLFxuICAgICAgICB0aW1lb3V0OiBEdXJhdGlvbi5ob3VycygxMikudG9TZWNvbmRzKCkudG9TdHJpbmcoKSxcbiAgICAgICAgaGFuZGxlOiB3YWl0Q29uZGl0aW9uSGFuZGxlLnJlZixcbiAgICAgIH0sXG4gICAgKTtcbiAgICB3YWl0Lm5vZGUuYWRkRGVwZW5kZW5jeShjb21waWxlSm9iKTtcbiAgICBjb25zdCBzM1ByZWZpeCA9IEZuLnNlbGVjdCgzLCBGbi5zcGxpdCgnXCInLCB3YWl0LmF0dHJEYXRhLnRvU3RyaW5nKCkpKTtcblxuICAgIHRoaXMuY29tcGlsZWRNb2RlbCA9IHtcbiAgICAgIG1vZGVsTmFtZTogdGhpcy5tb2RlbC5tb2RlbE5hbWUsXG4gICAgICBjb21waWxlVGltZUluc3RhbmNlVHlwZTogdGhpcy5uZXVyb254SW5zdGFuY2VUeXBlLFxuICAgICAgYnVja2V0OiB0aGlzLmJ1Y2tldCxcbiAgICAgIHMzUHJlZml4LFxuICAgICAgczNVcmk6IHRoaXMuYnVja2V0LnMzVXJsRm9yT2JqZWN0KHMzUHJlZml4KSxcbiAgICAgIHdlaWdodFNpemU6IHRoaXMud2VpZ2h0U2l6ZSxcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLmNvbXBpbGVkTW9kZWw7XG4gIH1cbn1cbiJdfQ==
|