aws-cdk-neuronx-patterns
Version:
> [!WARNING] > This library is experimental module.
177 lines • 36.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SageMakerInferenceToolkitTnxSageMakerRealtimeInferenceEndpoint = exports.SageMakerInferenceToolkitTnxSageMakerInferenceModelData = void 0;
const sagemaker = require("@aws-cdk/aws-sagemaker-alpha");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_s3_deployment_1 = require("aws-cdk-lib/aws-s3-deployment");
const constructs_1 = require("constructs");
const path_1 = require("path");
const neuronx_1 = require("../base/neuronx");
/**
* @deprecated
*/
class SageMakerInferenceToolkitTnxSageMakerInferenceModelData {
static fromBucket(bucket, prefix, options) {
const nPositions = options.compileOptions?.nPositions ?? 4096;
const quantDtype = options.compileOptions?.quantDtype;
const optLevel = neuronx_1.OptLevel.BEST_BALANCE;
const batchSize = options.compileOptions?.batchSize ?? 1;
const memoryFootprint = options.config
? (0, neuronx_1.calcMemoryFootprint)(options.config.embeddingDimension, options.config.layers, neuronx_1.DataTypeBits.BF16_OR_FP16, nPositions, batchSize)
: (0, neuronx_1.inferMemoryFootprintFromParameters)(options.parameters, nPositions, batchSize);
const neuronxInstanceTypes = [
neuronx_1.NeuronxInstanceType.INF2_8XLARGE,
neuronx_1.NeuronxInstanceType.INF2_24XLARGE,
neuronx_1.NeuronxInstanceType.INF2_48XLARGE,
];
const availableInstancePatterns = neuronxInstanceTypes
.flatMap((neuronxInstanceType) => (0, neuronx_1.calcTensorParallel)(neuronxInstanceType, memoryFootprint, options.config?.attentionHeads).map((v) => ({
neuronxInstanceType,
...v,
})))
.filter((pattern) => !options.compileOptions?.tpDegree ||
pattern.tp === options.compileOptions.tpDegree);
if (availableInstancePatterns.length === 0) {
throw new Error(`No available instance type. You can use tpDegree are ${availableInstancePatterns.map((p) => p.tp).join(", ")}.`);
}
const tpDegree = options.compileOptions?.tpDegree ?? availableInstancePatterns[0].tp;
return new SageMakerInferenceToolkitTnxSageMakerInferenceModelData({
bucket,
compiledArtifactS3Prefix: prefix,
nPositions,
quantDtype,
optLevel,
tpDegree,
code: options.code,
modelIdOrPath: options.modelIdOrPath,
parameters: options.parameters,
});
}
static fromNeuronxCompiler(compiler, code) {
const compiledModel = compiler.compile();
return new SageMakerInferenceToolkitTnxSageMakerInferenceModelData({
...compiledModel,
optLevel: compiledModel.optLevel ?? neuronx_1.OptLevel.BEST_BALANCE,
compiledArtifactS3Prefix: compiledModel.s3Prefix,
parameters: compiler.model.options.parameters,
code,
dependables: [compiler.node.defaultChild],
});
}
constructor(options) {
this.bucket = options.bucket;
this.compiledArtifactS3Prefix = options.compiledArtifactS3Prefix;
this.code =
options.code ??
aws_s3_deployment_1.Source.asset((0, path_1.join)(__dirname, "../../scripts/inference/sagemaker-inference-toolkit-tnx/code"));
this.tpDegree = options.tpDegree;
this.quantDtype = options.quantDtype;
this.nPositions = options.nPositions;
this.optLevel = options.optLevel;
this.modelIdOrPath = options.modelIdOrPath;
this.compiledArtifactPath = options.compiledArtifactPath;
this.parameters = options.parameters;
this.dependables = options.dependables ?? [];
}
bind(scope, model) {
const deploy = new aws_s3_deployment_1.BucketDeployment(scope, "CodeDeployment", {
destinationBucket: this.bucket,
sources: [this.code],
destinationKeyPrefix: (0, path_1.join)(this.compiledArtifactS3Prefix, "code"),
});
deploy.node.addDependency(...this.dependables);
model.node.addDependency(deploy);
}
}
exports.SageMakerInferenceToolkitTnxSageMakerInferenceModelData = SageMakerInferenceToolkitTnxSageMakerInferenceModelData;
/**
* @deprecated
*/
class SageMakerInferenceToolkitTnxSageMakerRealtimeInferenceEndpoint extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
const image = props.image ??
sagemaker.ContainerImage.fromAsset((0, path_1.join)(__dirname, "../../scripts/inference/sagemaker-inference-toolkit-tnx"));
const instanceType = props.instanceType ??
this.selectInstanceTypeByTpDegree(props.modelData.tpDegree);
const model = new sagemaker.Model(this, "Model", {
containers: [
{
image,
environment: {
NEURON_RT_NUM_CORES: props.modelData.tpDegree.toString(),
TS_DEFAULT_RESPONSE_TIMEOUT: (60 * 60).toString(),
TS_DEFAULT_WORKERS_PER_MODEL: Math.floor(instanceType.acceleratorChips.neuronxCores /
props.modelData.tpDegree).toString(),
MODEL: props.modelData.modelIdOrPath ?? "./model",
COMPILED_ARTIFACT: props.modelData.compiledArtifactPath ?? "./compiled",
TP_DEGREE: props.modelData.tpDegree.toString(),
N_POSITIONS: props.modelData.nPositions.toString(),
OPT_LEVEL: props.modelData.optLevel.toString(),
QUANT_DTYPE: props.modelData.quantDtype?.toString() ?? "",
...props.environment,
},
},
],
});
const cfnModel = model.node.findChild("Model");
cfnModel.addPropertyOverride("PrimaryContainer.ModelDataSource.S3DataSource.S3Uri", props.modelData.bucket.s3UrlForObject(aws_cdk_lib_1.Token.isUnresolved(props.modelData.compiledArtifactS3Prefix) ||
props.modelData.compiledArtifactS3Prefix.endsWith("/")
? props.modelData.compiledArtifactS3Prefix
: `${props.modelData.compiledArtifactS3Prefix}/`));
cfnModel.addPropertyOverride("PrimaryContainer.ModelDataSource.S3DataSource.S3DataTypeBits", "S3Prefix");
cfnModel.addPropertyOverride("PrimaryContainer.ModelDataSource.S3DataSource.CompressionType", "None");
props.modelData.bucket.grantRead(model);
props.modelData.bind(this, model);
const endpointConfig = new sagemaker.EndpointConfig(this, "EndpointConfig", {
instanceProductionVariants: [
{
model,
variantName: "PrimaryVariant",
instanceType: sagemaker.InstanceType.of(`ml.${instanceType.toString()}`),
},
],
});
const cfnEndpointConfig = endpointConfig.node.findChild("EndpointConfig");
const volumeSize = props.volumeSize ??
aws_cdk_lib_1.Size.gibibytes(Math.ceil(props.modelData.parameters.toBillion() * 3 > 512
? 512
: props.modelData.parameters.toBillion() * 3));
cfnEndpointConfig.addPropertyOverride("ProductionVariants.0.VolumeSizeInGB", instanceType.toString().startsWith("ml.trn1")
? undefined
: volumeSize.toGibibytes());
const modelDataDownloadTimeout = props.modelDataDownloadTimeout ??
inferenceModelDataDownloadTime(volumeSize);
cfnEndpointConfig.addPropertyOverride("ProductionVariants.0.ModelDataDownloadTimeoutInSeconds", modelDataDownloadTimeout.toSeconds());
cfnEndpointConfig.addPropertyOverride("ProductionVariants.0.ContainerStartupHealthCheckTimeoutInSeconds", (props.containerStartupHealthCheckTimeout ?? modelDataDownloadTimeout).toSeconds());
const endpoint = new sagemaker.Endpoint(this, "Endpoint", {
endpointConfig,
});
this.endpointArn = endpoint.endpointArn;
this.endpointName = endpoint.endpointName;
this.endpoint = endpoint;
}
grantInvoke(grantee) {
return this.endpoint.grantInvoke(grantee);
}
selectInstanceTypeByTpDegree(tpDegree) {
const instanceTypes = [
neuronx_1.NeuronxInstanceType.INF2_8XLARGE,
neuronx_1.NeuronxInstanceType.INF2_24XLARGE,
neuronx_1.NeuronxInstanceType.INF2_48XLARGE,
neuronx_1.NeuronxInstanceType.TRN1_32XLARGE,
];
for (const instanceType of instanceTypes) {
if (instanceType.supportedTensorParallelism.find((tp) => tp >= tpDegree)) {
return instanceType;
}
}
throw new Error("This model is too large, I can not support this model current version.");
}
}
exports.SageMakerInferenceToolkitTnxSageMakerRealtimeInferenceEndpoint = SageMakerInferenceToolkitTnxSageMakerRealtimeInferenceEndpoint;
function inferenceModelDataDownloadTime(volumeSize) {
const seconds = volumeSize.toGibibytes() * 15;
return aws_cdk_lib_1.Duration.seconds(seconds < 3600 ? seconds : 3600);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FnZW1ha2VyLWluZmVyZW5jZS10b29sa2l0LXRueC1zYWdlbWFrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2FnZW1ha2VyLWluZmVyZW5jZS10b29sa2l0LXRueC9zYWdlbWFrZXItaW5mZXJlbmNlLXRvb2xraXQtdG54LXNhZ2VtYWtlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwwREFBMEQ7QUFDMUQsNkNBQW9EO0FBR3BELHFFQUl1QztBQUV2QywyQ0FBb0Q7QUFDcEQsK0JBQTRCO0FBQzVCLDZDQVd5QjtBQXdDekI7O0dBRUc7QUFDSCxNQUFhLHVEQUF1RDtJQUNsRSxNQUFNLENBQUMsVUFBVSxDQUNmLE1BQWUsRUFDZixNQUFjLEVBQ2QsT0FBbUM7UUFFbkMsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLGNBQWMsRUFBRSxVQUFVLElBQUksSUFBSSxDQUFDO1FBQzlELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxjQUFjLEVBQUUsVUFBVSxDQUFDO1FBQ3RELE1BQU0sUUFBUSxHQUFHLGtCQUFRLENBQUMsWUFBWSxDQUFDO1FBQ3ZDLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxjQUFjLEVBQUUsU0FBUyxJQUFJLENBQUMsQ0FBQztRQUN6RCxNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUMsTUFBTTtZQUNwQyxDQUFDLENBQUMsSUFBQSw2QkFBbUIsRUFDakIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsRUFDakMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQ3JCLHNCQUFZLENBQUMsWUFBWSxFQUN6QixVQUFVLEVBQ1YsU0FBUyxDQUNWO1lBQ0gsQ0FBQyxDQUFDLElBQUEsNENBQWtDLEVBQ2hDLE9BQU8sQ0FBQyxVQUFVLEVBQ2xCLFVBQVUsRUFDVixTQUFTLENBQ1YsQ0FBQztRQUNOLE1BQU0sb0JBQW9CLEdBQUc7WUFDM0IsNkJBQW1CLENBQUMsWUFBWTtZQUNoQyw2QkFBbUIsQ0FB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LGFBQWE7U0FDbEMsQ0FBQztRQUNGLEtBQUssTUFBTSxZQUFZLElBQUksYUFBYSxFQUFFLENBQUM7WUFDekMsSUFDRSxZQUFZLENBQUMsMEJBQTBCLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLElBQUksUUFBUSxDQUFDLEVBQ3BFLENBQUM7Z0JBQ0QsT0FBTyxZQUFZLENBQUM7WUFDdEIsQ0FBQztRQUNILENBQUM7UUFDRCxNQUFNLElBQUksS0FBSyxDQUNiLHdFQUF3RSxDQUN6RSxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBbkpELHdJQW1KQztBQUVELFNBQVMsOEJBQThCLENBQUMsVUFBZ0I7SUFDdEQsTUFBTSxPQUFPLEdBQUcsVUFBVSxDQUFDLFdBQVcsRUFBRSxHQUFHLEVBQUUsQ0FBQztJQUM5QyxPQUFPLHNCQUFRLENBQUMsT0FBTyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDM0QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHNhZ2VtYWtlciBmcm9tIFwiQGF3cy1jZGsvYXdzLXNhZ2VtYWtlci1hbHBoYVwiO1xuaW1wb3J0IHsgRHVyYXRpb24sIFNpemUsIFRva2VuIH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgeyBHcmFudCwgSUdyYW50YWJsZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQgeyBJQnVja2V0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zM1wiO1xuaW1wb3J0IHtcbiAgQnVja2V0RGVwbG95bWVudCxcbiAgSVNvdXJjZSxcbiAgU291cmNlLFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXMzLWRlcGxveW1lbnRcIjtcbmltcG9ydCB7IENmbkVuZHBvaW50Q29uZmlnLCBDZm5Nb2RlbCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtc2FnZW1ha2VyXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QsIElEZXBlbmRhYmxlIH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHtcbiAgY2FsY01lbW9yeUZvb3RwcmludCxcbiAgY2FsY1RlbnNvclBhcmFsbGVsLFxuICBEYXRhVHlwZUJpdHMsXG4gIElOZXVyb254SW5zdGFuY2VUeXBlLFxuICBpbmZlck1lbW9yeUZvb3RwcmludEZyb21QYXJhbWV0ZXJzLFxuICBNb2RlbENvbmZpZyxcbiAgTmV1cm9ueEluc3RhbmNlVHlwZSxcbiAgT3B0TGV2ZWwsXG4gIFBhcmFtZXRlcnMsXG4gIFF1YW50RHR5cGUsXG59IGZyb20gXCIuLi9iYXNlL25ldXJvbnhcIjtcbmltcG9ydCB7XG4gIFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhDb21waWxlT3B0aW9ucyxcbiAgU2FnZU1ha2VySW5mZXJlbmNlVG9vbGtpdFRueENvbXBpbGVyLFxufSBmcm9tIFwiLi9zYWdlbWFrZXItaW5mZXJlbmNlLXRvb2xraXQtdG54LWNvbXBpbGVyXCI7XG5cbi8qKlxuICogUHJlY29tcGlsZWQgbW9kZWwgb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb21waWxlZE1vZGVsT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBOZXVyb254IGNvbXBpbGUgb3B0aW9ucy5cbiAgICogQGRlZmF1bHQgLSBFYWNoIHByb3BlcnRpZXMgYXJlIHNldCBkZWZhdWx0LlxuICAgKi9cbiAgcmVhZG9ubHkgY29tcGlsZU9wdGlvbnM/OiBTYWdlTWFrZXJJbmZlcmVuY2VUb29sa2l0VG54Q29tcGlsZU9wdGlvbnM7XG4gIC8qKlxuICAgKiBDb2RlIHVzZWQgZm9yIGluZmVyZW5jZVxuICAgKiBAZGVmYXVsdCAtIHVzaW5nIHRoZSBwcmVkZWZpbmVkIGNvZGVcbiAgICovXG4gIHJlYWRvbmx5IGNvZGU/OiBJU291cmNlO1xuICAvKipcbiAgICogTW9kZWwgSUQgb3Igc2F2ZWQgcGF0aFxuICAgKiBAZGVmYXVsdCBcIi4vbW9kZWxcIlxuICAgKi9cbiAgcmVhZG9ubHkgbW9kZWxJZE9yUGF0aD86IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBwYXRoIHdoZXJlIGNvbXBpbGVkIGFydGlmYWN0cyAoaS5lLiB4eHgubmVmZikgYXJlIHN0b3JlZFxuICAgKiBAZGVmYXVsdCBcIi4vY29tcGlsZWRcIlxuICAgKi9cbiAgcmVhZG9ubHkgY29tcGlsZWRBcnRpZmFjdFBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQnVja2V0Q29tcGlsZWRNb2RlbE9wdGlvbnMgZXh0ZW5kcyBDb21waWxlZE1vZGVsT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIHBhcmFtZXRlcnMgb2YgbW9kZWwuXG4gICAqL1xuICByZWFkb25seSBwYXJhbWV0ZXJzOiBQYXJhbWV0ZXJzO1xuICByZWFkb25seSBjb25maWc/OiBNb2RlbENvbmZpZztcbn1cblxuLyoqXG4gKiBAZGVwcmVjYXRlZFxuICovXG5leHBvcnQgY2xhc3MgU2FnZU1ha2VySW5mZXJlbmNlVG9vbGtpdFRueFNhZ2VNYWtlckluZmVyZW5jZU1vZGVsRGF0YSB7XG4gIHN0YXRpYyBmcm9tQnVja2V0KFxuICAgIGJ1Y2tldDogSUJ1Y2tldCxcbiAgICBwcmVmaXg6IHN0cmluZyxcbiAgICBvcHRpb25zOiBCdWNrZXRDb21waWxlZE1vZGVsT3B0aW9ucyxcbiAgKSB7XG4gICAgY29uc3QgblBvc2l0aW9ucyA9IG9wdGlvbnMuY29tcGlsZU9wdGlvbnM/Lm5Qb3NpdGlvbnMgPz8gNDA5NjtcbiAgICBjb25zdCBxdWFudER0eXBlID0gb3B0aW9ucy5jb21waWxlT3B0aW9ucz8ucXVhbnREdHlwZTtcbiAgICBjb25zdCBvcHRMZXZlbCA9IE9wdExldmVsLkJFU1RfQkFMQU5DRTtcbiAgICBjb25zdCBiYXRjaFNpemUgPSBvcHRpb25zLmNvbXBpbGVPcHRpb25zPy5iYXRjaFNpemUgPz8gMTtcbiAgICBjb25zdCBtZW1vcnlGb290cHJpbnQgPSBvcHRpb25zLmNvbmZpZ1xuICAgICAgPyBjYWxjTWVtb3J5Rm9vdHByaW50KFxuICAgICAgICAgIG9wdGlvbnMuY29uZmlnLmVtYmVkZGluZ0RpbWVuc2lvbixcbiAgICAgICAgICBvcHRpb25zLmNvbmZpZy5sYXllcnMsXG4gICAgICAgICAgRGF0YVR5cGVCaXRzLkJGMTZfT1JfRlAxNixcbiAgICAgICAgICBuUG9zaXRpb25zLFxuICAgICAgICAgIGJhdGNoU2l6ZSxcbiAgICAgICAgKVxuICAgICAgOiBpbmZlck1lbW9yeUZvb3RwcmludEZyb21QYXJhbWV0ZXJzKFxuICAgICAgICAgIG9wdGlvbnMucGFyYW1ldGVycyxcbiAgICAgICAgICBuUG9zaXRpb25zLFxuICAgICAgICAgIGJhdGNoU2l6ZSxcbiAgICAgICAgKTtcbiAgICBjb25zdCBuZXVyb254SW5zdGFuY2VUeXBlcyA9IFtcbiAgICAgIE5ldXJvbnhJbnN0YW5jZVR5cGUuSU5GMl84WExBUkdFLFxuICAgICAgTmV1cm9ueEluc3RhbmNlVHlwZS5JTkYyXzI0WExBUkdFLFxuICAgICAgTmV1cm9ueEluc3RhbmNlVHlwZS5JTkYyXzQ4WExBUkdFLFxuICAgIF07XG4gICAgY29uc3QgYXZhaWxhYmxlSW5zdGFuY2VQYXR0ZXJucyA9IG5ldXJvbnhJbnN0YW5jZVR5cGVzXG4gICAgICAuZmxhdE1hcCgobmV1cm9ueEluc3RhbmNlVHlwZSkgPT5cbiAgICAgICAgY2FsY1RlbnNvclBhcmFsbGVsKFxuICAgICAgICAgIG5ldXJvbnhJbnN0YW5jZVR5cGUsXG4gICAgICAgICAgbWVtb3J5Rm9vdHByaW50LFxuICAgICAgICAgIG9wdGlvbnMuY29uZmlnPy5hdHRlbnRpb25IZWFkcyxcbiAgICAgICAgKS5tYXAoKHYpID0+ICh7XG4gICAgICAgICAgbmV1cm9ueEluc3RhbmNlVHlwZSxcbiAgICAgICAgICAuLi52LFxuICAgICAgICB9KSksXG4gICAgICApXG4gICAgICAuZmlsdGVyKFxuICAgICAgICAocGF0dGVybikgPT5cbiAgICAgICAgICAhb3B0aW9ucy5jb21waWxlT3B0aW9ucz8udHBEZWdyZWUgfHxcbiAgICAgICAgICBwYXR0ZXJuLnRwID09PSBvcHRpb25zLmNvbXBpbGVPcHRpb25zLnRwRGVncmVlLFxuICAgICAgKTtcbiAgICBpZiAoYXZhaWxhYmxlSW5zdGFuY2VQYXR0ZXJucy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYE5vIGF2YWlsYWJsZSBpbnN0YW5jZSB0eXBlLiBZb3UgY2FuIHVzZSB0cERlZ3JlZSBhcmUgJHthdmFpbGFibGVJbnN0YW5jZVBhdHRlcm5zLm1hcCgocCkgPT4gcC50cCkuam9pbihcIiwgXCIpfS5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgdHBEZWdyZWUgPVxuICAgICAgb3B0aW9ucy5jb21waWxlT3B0aW9ucz8udHBEZWdyZWUgPz8gYXZhaWxhYmxlSW5zdGFuY2VQYXR0ZXJuc1swXS50cDtcbiAgICByZXR1cm4gbmV3IFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhTYWdlTWFrZXJJbmZlcmVuY2VNb2RlbERhdGEoe1xuICAgICAgYnVja2V0LFxuICAgICAgY29tcGlsZWRBcnRpZmFjdFMzUHJlZml4OiBwcmVmaXgsXG4gICAgICBuUG9zaXRpb25zLFxuICAgICAgcXVhbnREdHlwZSxcbiAgICAgIG9wdExldmVsLFxuICAgICAgdHBEZWdyZWUsXG4gICAgICBjb2RlOiBvcHRpb25zLmNvZGUsXG4gICAgICBtb2RlbElkT3JQYXRoOiBvcHRpb25zLm1vZGVsSWRPclBhdGgsXG4gICAgICBwYXJhbWV0ZXJzOiBvcHRpb25zLnBhcmFtZXRlcnMsXG4gICAgfSk7XG4gIH1cbiAgc3RhdGljIGZyb21OZXVyb254Q29tcGlsZXIoXG4gICAgY29tcGlsZXI6IFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhDb21waWxlcixcbiAgICBjb2RlPzogSVNvdXJjZSxcbiAgKSB7XG4gICAgY29uc3QgY29tcGlsZWRNb2RlbCA9IGNvbXBpbGVyLmNvbXBpbGUoKTtcbiAgICByZXR1cm4gbmV3IFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhTYWdlTWFrZXJJbmZlcmVuY2VNb2RlbERhdGEoe1xuICAgICAgLi4uY29tcGlsZWRNb2RlbCxcbiAgICAgIG9wdExldmVsOiBjb21waWxlZE1vZGVsLm9wdExldmVsID8/IE9wdExldmVsLkJFU1RfQkFMQU5DRSxcbiAgICAgIGNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeDogY29tcGlsZWRNb2RlbC5zM1ByZWZpeCxcbiAgICAgIHBhcmFtZXRlcnM6IGNvbXBpbGVyLm1vZGVsLm9wdGlvbnMucGFyYW1ldGVycyxcbiAgICAgIGNvZGUsXG4gICAgICBkZXBlbmRhYmxlczogW2NvbXBpbGVyLm5vZGUuZGVmYXVsdENoaWxkIV0sXG4gICAgfSk7XG4gIH1cbiAgcmVhZG9ubHkgYnVja2V0OiBJQnVja2V0O1xuICByZWFkb25seSBjb21waWxlZEFydGlmYWN0UzNQcmVmaXg6IHN0cmluZztcbiAgcmVhZG9ubHkgY29kZTogSVNvdXJjZTtcbiAgcmVhZG9ubHkgdHBEZWdyZWU6IG51bWJlcjtcbiAgcmVhZG9ubHkgcXVhbnREdHlwZT86IFF1YW50RHR5cGU7XG4gIHJlYWRvbmx5IG5Qb3NpdGlvbnM6IG51bWJlcjtcbiAgcmVhZG9ubHkgb3B0TGV2ZWw6IE9wdExldmVsO1xuICByZWFkb25seSBtb2RlbElkT3JQYXRoPzogc3RyaW5nO1xuICByZWFkb25seSBjb21waWxlZEFydGlmYWN0UGF0aD86IHN0cmluZztcbiAgcmVhZG9ubHkgcGFyYW1ldGVyczogUGFyYW1ldGVycztcbiAgcHJpdmF0ZSByZWFkb25seSBkZXBlbmRhYmxlczogSURlcGVuZGFibGVbXTtcblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKG9wdGlvbnM6IHtcbiAgICByZWFkb25seSBidWNrZXQ6IElCdWNrZXQ7XG4gICAgcmVhZG9ubHkgY29tcGlsZWRBcnRpZmFjdFMzUHJlZml4OiBzdHJpbmc7XG4gICAgcmVhZG9ubHkgdHBEZWdyZWU6IG51bWJlcjtcbiAgICByZWFkb25seSBxdWFudER0eXBlPzogUXVhbnREdHlwZTtcbiAgICByZWFkb25seSBuUG9zaXRpb25zOiBudW1iZXI7XG4gICAgcmVhZG9ubHkgb3B0TGV2ZWw6IE9wdExldmVsO1xuICAgIHJlYWRvbmx5IGNvZGU/OiBJU291cmNlO1xuICAgIHJlYWRvbmx5IG1vZGVsSWRPclBhdGg/OiBzdHJpbmc7XG4gICAgcmVhZG9ubHkgY29tcGlsZWRBcnRpZmFjdFBhdGg/OiBzdHJpbmc7XG4gICAgcmVhZG9ubHkgcGFyYW1ldGVyczogUGFyYW1ldGVycztcbiAgICByZWFkb25seSBkZXBlbmRhYmxlcz86IElEZXBlbmRhYmxlW107XG4gIH0pIHtcbiAgICB0aGlzLmJ1Y2tldCA9IG9wdGlvbnMuYnVja2V0O1xuICAgIHRoaXMuY29tcGlsZWRBcnRpZmFjdFMzUHJlZml4ID0gb3B0aW9ucy5jb21waWxlZEFydGlmYWN0UzNQcmVmaXg7XG4gICAgdGhpcy5jb2RlID1cbiAgICAgIG9wdGlvbnMuY29kZSA/P1xuICAgICAgU291cmNlLmFzc2V0KFxuICAgICAgICBqb2luKFxuICAgICAgICAgIF9fZGlybmFtZSxcbiAgICAgICAgICBcIi4uLy4uL3NjcmlwdHMvaW5mZXJlbmNlL3NhZ2VtYWtlci1pbmZlcmVuY2UtdG9vbGtpdC10bngvY29kZVwiLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICB0aGlzLnRwRGVncmVlID0gb3B0aW9ucy50cERlZ3JlZTtcbiAgICB0aGlzLnF1YW50RHR5cGUgPSBvcHRpb25zLnF1YW50RHR5cGU7XG4gICAgdGhpcy5uUG9zaXRpb25zID0gb3B0aW9ucy5uUG9zaXRpb25zO1xuICAgIHRoaXMub3B0TGV2ZWwgPSBvcHRpb25zLm9wdExldmVsO1xuICAgIHRoaXMubW9kZWxJZE9yUGF0aCA9IG9wdGlvbnMubW9kZWxJZE9yUGF0aDtcbiAgICB0aGlzLmNvbXBpbGVkQXJ0aWZhY3RQYXRoID0gb3B0aW9ucy5jb21waWxlZEFydGlmYWN0UGF0aDtcbiAgICB0aGlzLnBhcmFtZXRlcnMgPSBvcHRpb25zLnBhcmFtZXRlcnM7XG4gICAgdGhpcy5kZXBlbmRhYmxlcyA9IG9wdGlvbnMuZGVwZW5kYWJsZXMgPz8gW107XG4gIH1cblxuICBiaW5kKHNjb3BlOiBDb25zdHJ1Y3QsIG1vZGVsOiBzYWdlbWFrZXIuSU1vZGVsKSB7XG4gICAgY29uc3QgZGVwbG95ID0gbmV3IEJ1Y2tldERlcGxveW1lbnQoc2NvcGUsIFwiQ29kZURlcGxveW1lbnRcIiwge1xuICAgICAgZGVzdGluYXRpb25CdWNrZXQ6IHRoaXMuYnVja2V0LFxuICAgICAgc291cmNlczogW3RoaXMuY29kZV0sXG4gICAgICBkZXN0aW5hdGlvbktleVByZWZpeDogam9pbih0aGlzLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeCwgXCJjb2RlXCIpLFxuICAgIH0pO1xuICAgIGRlcGxveS5ub2RlLmFkZERlcGVuZGVuY3koLi4udGhpcy5kZXBlbmRhYmxlcyk7XG4gICAgbW9kZWwubm9kZS5hZGREZXBlbmRlbmN5KGRlcGxveSk7XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBTYWdlTWFrZXJJbmZlcmVuY2VUb29sa2l0VG54U2FnZU1ha2VyUmVhbHRpbWVJbmZlcmVuY2VFbmRwb2ludFByb3BzIHtcbiAgLyoqXG4gICAqIE1vZGVsIGRhdGEgZm9yIFNhZ2VNYWtlciBpbmZlcmVuY2UuXG4gICAqIFRoZSBtb2RlbCBkYXRhIHJlcXVpcmVzIGF0IGxlYXN0IGNvbXBpbGVkIGFydGlmYWN0cy5cbiAgICovXG4gIHJlYWRvbmx5IG1vZGVsRGF0YTogU2FnZU1ha2VySW5mZXJlbmNlVG9vbGtpdFRueFNhZ2VNYWtlckluZmVyZW5jZU1vZGVsRGF0YTtcbiAgLyoqXG4gICAqIEFuIGltYWdlIG9mIHRoZSBjb250YWluZXIgd2hlcmUgdGhlIGluZmVyZW5jZSBqb2IgaXMgZXhlY3V0ZWQuXG4gICAqL1xuICByZWFkb25seSBpbWFnZT86IHNhZ2VtYWtlci5Db250YWluZXJJbWFnZTtcbiAgLyoqXG4gICAqIEEgbWFwIG9mIGVudmlyb25tZW50IHZhcmlhYmxlcyB0byBwYXNzIGludG8gdGhlIGNvbnRhaW5lci5cbiAgICogQGRlZmF1bHQgLSBPbmx5IHRoZSBwcmVkZWZpbmVkIGVudmlyb25tZW50IHZhcmlhYmxlcyByZXF1aXJlZCB0byB1c2UgTmV1cm9ueCBoYXZlIGJlZW4gc2V0LlxuICAgKi9cbiAgcmVhZG9ubHkgZW52aXJvbm1lbnQ/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xuICAvKipcbiAgICogVGhlIGluc3RhbmNlIHR5cGUgb2YgY29tcGlsZSB3b3JrZXIgaW5zdGFuY2UuXG4gICAqIEBkZWZhdWx0IC0gSXQgaXMgZGV0ZXJtaW5lZCBhdXRvbWF0aWNhbGx5IGFjY29yZGluZyB0byB0aGUgbnVtYmVyIG9mIG1vZGVsIHBhcmFtZXRlcnMgYW5kIGNvbXBpbGF0aW9uIG9wdGlvbnMuXG4gICAqL1xuICByZWFkb25seSBpbnN0YW5jZVR5cGU/OiBJTmV1cm9ueEluc3RhbmNlVHlwZTtcbiAgLyoqXG4gICAqIFRoZSBzaXplLCBvZiB0aGUgTUwgc3RvcmFnZSB2b2x1bWUgYXR0YWNoZWQgdG8gaW5kaXZpZHVhbCBpbmZlcmVuY2UgaW5zdGFuY2UgYXNzb2NpYXRlZCB3aXRoIHRoZSBwcm9kdWN0aW9uIHZhcmlhbnQuXG4gICAqIEN1cnJlbnRseSBvbmx5IEFtYXpvbiBFQlMgZ3AyIHN0b3JhZ2Ugdm9sdW1lcyBhcmUgc3VwcG9ydGVkLlxuICAgKiBAc2VlIGh0dHBzOi8vYXdzLmFtYXpvbi5jb20vanAvcmVsZWFzZW5vdGVzL2hvc3QtaW5zdGFuY2Utc3RvcmFnZS12b2x1bWVzLXRhYmxlXG4gICAqIEBkZWZhdWx0IC0gMyBHQiBwZXIgYmlsbGlvbiBwYXJhbWV0ZXIgKE1heCA1MTIgR0IpXG4gICAqL1xuICByZWFkb25seSB2b2x1bWVTaXplPzogU2l6ZTtcbiAgLyoqXG4gICAqIFRoZSB0aW1lb3V0IHZhbHVlLCB0byBkb3dubG9hZCBhbmQgZXh0cmFjdCB0aGUgbW9kZWwgdGhhdCB5b3Ugd2FudCB0byBob3N0IGZyb20gQW1hem9uIFMzXG4gICAqIHRvIHRoZSBpbmRpdmlkdWFsIGluZmVyZW5jZSBpbnN0YW5jZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBwcm9kdWN0aW9uIHZhcmlhbnQuXG4gICAqIEBkZWZhdWx0IC0gNjAgc2Vjb25kcywgd2hlbiBgdm9sdW1lU2l6ZWAgbGFyZ2VyIHRoYW4gMzBHQiB0aGVuIDFHQiB4IDE1IHNlY29uZHMgKG1heCA2MCBtaW51dGVzKVxuICAgKi9cbiAgcmVhZG9ubHkgbW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0PzogRHVyYXRpb247XG4gIC8qKlxuICAgKiBUaGUgdGltZW91dCB2YWx1ZSwgZm9yIHlvdXIgaW5mZXJlbmNlIGNvbnRhaW5lciB0byBwYXNzIGhlYWx0aCBjaGVjayBieSBTYWdlTWFrZXIgSG9zdGluZy5cbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vc2FnZW1ha2VyL2xhdGVzdC9kZy95b3VyLWFsZ29yaXRobXMtaW5mZXJlbmNlLWNvZGUuaHRtbCN5b3VyLWFsZ29yaXRobXMtaW5mZXJlbmNlLWFsZ28tcGluZy1yZXF1ZXN0c1xuICAgKiBAZGVmYXVsdCAtIDYwIHNlY29uZHMsIHdoZW4gc2V0IHRoZSBgbW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0YCB0aGVuIHVzZSBzYW1lIHZhbHVlIChtYXggNjAgbWludXRlcylcbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lclN0YXJ0dXBIZWFsdGhDaGVja1RpbWVvdXQ/OiBEdXJhdGlvbjtcbn1cblxuLyoqXG4gKiBAZGVwcmVjYXRlZFxuICovXG5leHBvcnQgY2xhc3MgU2FnZU1ha2VySW5mZXJlbmNlVG9vbGtpdFRueFNhZ2VNYWtlclJlYWx0aW1lSW5mZXJlbmNlRW5kcG9pbnQgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAvKipcbiAgICogVGhlIEFSTiBvZiB0aGUgZW5kcG9pbnQuXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHJlYWRvbmx5IGVuZHBvaW50QXJuOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgZW5kcG9pbnQuXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHJlYWRvbmx5IGVuZHBvaW50TmFtZTogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGVuZHBvaW50OiBzYWdlbWFrZXIuRW5kcG9pbnQ7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHNjb3BlOiBDb25zdHJ1Y3QsXG4gICAgaWQ6IHN0cmluZyxcbiAgICBwcm9wczogU2FnZU1ha2VySW5mZXJlbmNlVG9vbGtpdFRueFNhZ2VNYWtlclJlYWx0aW1lSW5mZXJlbmNlRW5kcG9pbnRQcm9wcyxcbiAgKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcbiAgICBjb25zdCBpbWFnZSA9XG4gICAgICBwcm9wcy5pbWFnZSA/P1xuICAgICAgc2FnZW1ha2VyLkNvbnRhaW5lckltYWdlLmZyb21Bc3NldChcbiAgICAgICAgam9pbihcbiAgICAgICAgICBfX2Rpcm5hbWUsXG4gICAgICAgICAgXCIuLi8uLi9zY3JpcHRzL2luZmVyZW5jZS9zYWdlbWFrZXItaW5mZXJlbmNlLXRvb2xraXQtdG54XCIsXG4gICAgICAgICksXG4gICAgICApO1xuICAgIGNvbnN0IGluc3RhbmNlVHlwZSA9XG4gICAgICBwcm9wcy5pbnN0YW5jZVR5cGUgPz9cbiAgICAgIHRoaXMuc2VsZWN0SW5zdGFuY2VUeXBlQnlUcERlZ3JlZShwcm9wcy5tb2RlbERhdGEudHBEZWdyZWUpO1xuICAgIGNvbnN0IG1vZGVsID0gbmV3IHNhZ2VtYWtlci5Nb2RlbCh0aGlzLCBcIk1vZGVsXCIsIHtcbiAgICAgIGNvbnRhaW5lcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGltYWdlLFxuICAgICAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgICAgICBORVVST05fUlRfTlVNX0NPUkVTOiBwcm9wcy5tb2RlbERhdGEudHBEZWdyZWUudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIFRTX0RFRkFVTFRfUkVTUE9OU0VfVElNRU9VVDogKDYwICogNjApLnRvU3RyaW5nKCksXG4gICAgICAgICAgICBUU19ERUZBVUxUX1dPUktFUlNfUEVSX01PREVMOiBNYXRoLmZsb29yKFxuICAgICAgICAgICAgICBpbnN0YW5jZVR5cGUuYWNjZWxlcmF0b3JDaGlwcy5uZXVyb254Q29yZXMgL1xuICAgICAgICAgICAgICAgIHByb3BzLm1vZGVsRGF0YS50cERlZ3JlZSxcbiAgICAgICAgICAgICkudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIE1PREVMOiBwcm9wcy5tb2RlbERhdGEubW9kZWxJZE9yUGF0aCA/PyBcIi4vbW9kZWxcIixcbiAgICAgICAgICAgIENPTVBJTEVEX0FSVElGQUNUOlxuICAgICAgICAgICAgICBwcm9wcy5tb2RlbERhdGEuY29tcGlsZWRBcnRpZmFjdFBhdGggPz8gXCIuL2NvbXBpbGVkXCIsXG4gICAgICAgICAgICBUUF9ERUdSRUU6IHByb3BzLm1vZGVsRGF0YS50cERlZ3JlZS50b1N0cmluZygpLFxuICAgICAgICAgICAgTl9QT1NJVElPTlM6IHByb3BzLm1vZGVsRGF0YS5uUG9zaXRpb25zLnRvU3RyaW5nKCksXG4gICAgICAgICAgICBPUFRfTEVWRUw6IHByb3BzLm1vZGVsRGF0YS5vcHRMZXZlbC50b1N0cmluZygpLFxuICAgICAgICAgICAgUVVBTlRfRFRZUEU6IHByb3BzLm1vZGVsRGF0YS5xdWFudER0eXBlPy50b1N0cmluZygpID8/IFwiXCIsXG4gICAgICAgICAgICAuLi5wcm9wcy5lbnZpcm9ubWVudCxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBjb25zdCBjZm5Nb2RlbCA9IG1vZGVsLm5vZGUuZmluZENoaWxkKFwiTW9kZWxcIikgYXMgQ2ZuTW9kZWw7XG4gICAgY2ZuTW9kZWwuYWRkUHJvcGVydHlPdmVycmlkZShcbiAgICAgIFwiUHJpbWFyeUNvbnRhaW5lci5Nb2RlbERhdGFTb3VyY2UuUzNEYXRhU291cmNlLlMzVXJpXCIsXG4gICAgICBwcm9wcy5tb2RlbERhdGEuYnVja2V0LnMzVXJsRm9yT2JqZWN0KFxuICAgICAgICBUb2tlbi5pc1VucmVzb2x2ZWQocHJvcHMubW9kZWxEYXRhLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeCkgfHxcbiAgICAgICAgICBwcm9wcy5tb2RlbERhdGEuY29tcGlsZWRBcnRpZmFjdFMzUHJlZml4LmVuZHNXaXRoKFwiL1wiKVxuICAgICAgICAgID8gcHJvcHMubW9kZWxEYXRhLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeFxuICAgICAgICAgIDogYCR7cHJvcHMubW9kZWxEYXRhLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeH0vYCxcbiAgICAgICksXG4gICAgKTtcbiAgICBjZm5Nb2RlbC5hZGRQcm9wZXJ0eU92ZXJyaWRlKFxuICAgICAgXCJQcmltYXJ5Q29udGFpbmVyLk1vZGVsRGF0YVNvdXJjZS5TM0RhdGFTb3VyY2UuUzNEYXRhVHlwZUJpdHNcIixcbiAgICAgIFwiUzNQcmVmaXhcIixcbiAgICApO1xuICAgIGNmbk1vZGVsLmFkZFByb3BlcnR5T3ZlcnJpZGUoXG4gICAgICBcIlByaW1hcnlDb250YWluZXIuTW9kZWxEYXRhU291cmNlLlMzRGF0YVNvdXJjZS5Db21wcmVzc2lvblR5cGVcIixcbiAgICAgIFwiTm9uZVwiLFxuICAgICk7XG4gICAgcHJvcHMubW9kZWxEYXRhLmJ1Y2tldC5ncmFudFJlYWQobW9kZWwpO1xuICAgIHByb3BzLm1vZGVsRGF0YS5iaW5kKHRoaXMsIG1vZGVsKTtcbiAgICBjb25zdCBlbmRwb2ludENvbmZpZyA9IG5ldyBzYWdlbWFrZXIuRW5kcG9pbnRDb25maWcoXG4gICAgICB0aGlzLFxuICAgICAgXCJFbmRwb2ludENvbmZpZ1wiLFxuICAgICAge1xuICAgICAgICBpbnN0YW5jZVByb2R1Y3Rpb25WYXJpYW50czogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIG1vZGVsLFxuICAgICAgICAgICAgdmFyaWFudE5hbWU6IFwiUHJpbWFyeVZhcmlhbnRcIixcbiAgICAgICAgICAgIGluc3RhbmNlVHlwZTogc2FnZW1ha2VyLkluc3RhbmNlVHlwZS5vZihcbiAgICAgICAgICAgICAgYG1sLiR7aW5zdGFuY2VUeXBlLnRvU3RyaW5nKCl9YCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgKTtcbiAgICBjb25zdCBjZm5FbmRwb2ludENvbmZpZyA9IGVuZHBvaW50Q29uZmlnLm5vZGUuZmluZENoaWxkKFxuICAgICAgXCJFbmRwb2ludENvbmZpZ1wiLFxuICAgICkgYXMgQ2ZuRW5kcG9pbnRDb25maWc7XG4gICAgY29uc3Qgdm9sdW1lU2l6ZSA9XG4gICAgICBwcm9wcy52b2x1bWVTaXplID8/XG4gICAgICBTaXplLmdpYmlieXRlcyhcbiAgICAgICAgTWF0aC5jZWlsKFxuICAgICAgICAgIHByb3BzLm1vZGVsRGF0YS5wYXJhbWV0ZXJzLnRvQmlsbGlvbigpICogMyA+IDUxMlxuICAgICAgICAgICAgPyA1MTJcbiAgICAgICAgICAgIDogcHJvcHMubW9kZWxEYXRhLnBhcmFtZXRlcnMudG9CaWxsaW9uKCkgKiAzLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICBjZm5FbmRwb2ludENvbmZpZy5hZGRQcm9wZXJ0eU92ZXJyaWRlKFxuICAgICAgXCJQcm9kdWN0aW9uVmFyaWFudHMuMC5Wb2x1bWVTaXplSW5HQlwiLFxuICAgICAgaW5zdGFuY2VUeXBlLnRvU3RyaW5nKCkuc3RhcnRzV2l0aChcIm1sLnRybjFcIilcbiAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgOiB2b2x1bWVTaXplLnRvR2liaWJ5dGVzKCksXG4gICAgKTtcbiAgICBjb25zdCBtb2RlbERhdGFEb3dubG9hZFRpbWVvdXQgPVxuICAgICAgcHJvcHMubW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0ID8/XG4gICAgICBpbmZlcmVuY2VNb2RlbERhdGFEb3dubG9hZFRpbWUodm9sdW1lU2l6ZSk7XG4gICAgY2ZuRW5kcG9pbnRDb25maWcuYWRkUHJvcGVydHlPdmVycmlkZShcbiAgICAgIFwiUHJvZHVjdGlvblZhcmlhbnRzLjAuTW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0SW5TZWNvbmRzXCIsXG4gICAgICBtb2RlbERhdGFEb3dubG9hZFRpbWVvdXQudG9TZWNvbmRzKCksXG4gICAgKTtcbiAgICBjZm5FbmRwb2ludENvbmZpZy5hZGRQcm9wZXJ0eU92ZXJyaWRlKFxuICAgICAgXCJQcm9kdWN0aW9uVmFyaWFudHMuMC5Db250YWluZXJTdGFydHVwSGVhbHRoQ2hlY2tUaW1lb3V0SW5TZWNvbmRzXCIsXG4gICAgICAoXG4gICAgICAgIHByb3BzLmNvbnRhaW5lclN0YXJ0dXBIZWFsdGhDaGVja1RpbWVvdXQgPz8gbW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0XG4gICAgICApLnRvU2Vjb25kcygpLFxuICAgICk7XG4gICAgY29uc3QgZW5kcG9pbnQgPSBuZXcgc2FnZW1ha2VyLkVuZHBvaW50KHRoaXMsIFwiRW5kcG9pbnRcIiwge1xuICAgICAgZW5kcG9pbnRDb25maWcsXG4gICAgfSk7XG4gICAgdGhpcy5lbmRwb2ludEFybiA9IGVuZHBvaW50LmVuZHBvaW50QXJuO1xuICAgIHRoaXMuZW5kcG9pbnROYW1lID0gZW5kcG9pbnQuZW5kcG9pbnROYW1lO1xuICAgIHRoaXMuZW5kcG9pbnQgPSBlbmRwb2ludDtcbiAgfVxuICBncmFudEludm9rZShncmFudGVlOiBJR3JhbnRhYmxlKTogR3JhbnQge1xuICAgIHJldHVybiB0aGlzLmVuZHBvaW50LmdyYW50SW52b2tlKGdyYW50ZWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZWxlY3RJbnN0YW5jZVR5cGVCeVRwRGVncmVlKHRwRGVncmVlOiBudW1iZXIpIHtcbiAgICBjb25zdCBpbnN0YW5jZVR5cGVzID0gW1xuICAgICAgTmV1cm9ueEluc3RhbmNlVHlwZS5JTkYyXzhYTEFSR0UsXG4gICAgICBOZXVyb254SW5zdGFuY2VUeXBlLklORjJfMjRYTEFSR0UsXG4gICAgICBOZXVyb254SW5zdGFuY2VUeXBlLklORjJfNDhYTEFSR0UsXG4gICAgICBOZXVyb254SW5zdGFuY2VUeXBlLlRSTjFfMzJYTEFSR0UsXG4gICAgXTtcbiAgICBmb3IgKGNvbnN0IGluc3RhbmNlVHlwZSBvZiBpbnN0YW5jZVR5cGVzKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGluc3RhbmNlVHlwZS5zdXBwb3J0ZWRUZW5zb3JQYXJhbGxlbGlzbS5maW5kKCh0cCkgPT4gdHAgPj0gdHBEZWdyZWUpXG4gICAgICApIHtcbiAgICAgICAgcmV0dXJuIGluc3RhbmNlVHlwZTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgXCJUaGlzIG1vZGVsIGlzIHRvbyBsYXJnZSwgSSBjYW4gbm90IHN1cHBvcnQgdGhpcyBtb2RlbCBjdXJyZW50IHZlcnNpb24uXCIsXG4gICAgKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBpbmZlcmVuY2VNb2RlbERhdGFEb3dubG9hZFRpbWUodm9sdW1lU2l6ZTogU2l6ZSkge1xuICBjb25zdCBzZWNvbmRzID0gdm9sdW1lU2l6ZS50b0dpYmlieXRlcygpICogMTU7XG4gIHJldHVybiBEdXJhdGlvbi5zZWNvbmRzKHNlY29uZHMgPCAzNjAwID8gc2Vjb25kcyA6IDM2MDApO1xufVxuIl19