aws-cdk-neuronx-patterns
Version:
> [!WARNING] > This library is experimental module.
186 lines • 37.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SageMakerInferenceToolkitTnxSageMakerRealtimeInferenceEndpoint = exports.SageMakerInferenceToolkitTnxSageMakerInferenceModelData = void 0;
const deploy_time_build_1 = require("@cdklabs/deploy-time-build");
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 fromNeuronxNativeCompiler(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);
let image;
if (props.image) {
image = props.image;
}
else {
const build = new deploy_time_build_1.ContainerImageBuild(this, "InferenceImageBuild", {
directory: (0, path_1.join)(__dirname, "../../scripts/inference/sagemaker-inference-toolkit-tnx"),
});
image = sagemaker.ContainerImage.fromEcrRepository(build.repository, build.imageTag);
}
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FnZW1ha2VyLWluZmVyZW5jZS10b29sa2l0LXRueC1zYWdlbWFrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2FnZW1ha2VyLWluZmVyZW5jZS10b29sa2l0LXRueC9zYWdlbWFrZXItaW5mZXJlbmNlLXRvb2xraXQtdG54LXNhZ2VtYWtlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxrRUFBaUU7QUFDakUsMERBQTBEO0FBQzFELDZDQUFvRDtBQUdwRCxxRUFJdUM7QUFFdkMsMkNBQW9EO0FBQ3BELCtCQUE0QjtBQUM1Qiw2Q0FXeUI7QUF3Q3pCOztHQUVHO0FBQ0gsTUFBYSx1REFBdUQ7SUFDbEUsTUFBTSxDQUFDLFVBQVUsQ0FDZixNQUFlLEVBQ2YsTUFBYyxFQUNkLE9BQW1DO1FBRW5DLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxjQUFjLEVBQUUsVUFBVSxJQUFJLElBQUksQ0FBQztRQUM5RCxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsY0FBYyxFQUFFLFVBQVUsQ0FBQztRQUN0RCxNQUFNLFFBQVEsR0FBRyxrQkFBUSxDQUFDLFlBQVksQ0FBQztRQUN2QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsY0FBYyxFQUFFLFNBQVMsSUFBSSxDQUFDLENBQUM7UUFDekQsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDLE1BQU07WUFDcEMsQ0FBQyxDQUFDLElBQUEsNkJBQW1CLEVBQ2pCLE9BQU8sQ0FBQyxNQUFNLENBQUMsa0JBQWtCLEVBQ2pDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUNyQixzQkFBWSxDQUFDLFlBQVksRUFDekIsVUFBVSxFQUNWLFNBQVMsQ0FDVjtZQUNILENBQUMsQ0FBQyxJQUFBLDRDQUFrQyxFQUNoQyxPQUFPLENBQUMsVUFBVSxFQUNsQixVQUFVLEVBQ1YsU0FBUyxDQUNWLENBQUM7UUFDTixNQUFNLG9CQUFvQixHQUFHO1lBQzNCLDZCQUFtQixDQUFDLFlBQVk7WUFD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RyxRQUFRLENBQUM7SUFDM0IsQ0FBQztJQUNELFdBQVcsQ0FBQyxPQUFtQjtRQUM3QixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFTyw0QkFBNEIsQ0FBQyxRQUFnQjtRQUNuRCxNQUFNLGFBQWEsR0FBRztZQUNwQiw2QkFBbUIsQ0FBQyxZQUFZO1lBQ2hDLDZCQUFtQixDQUFDLGFBQWE7WUFDakMsNkJBQW1CLENBQUMsYUFBYTtZQUNqQyw2QkFBbUIsQ0FBQyxhQUFhO1NBQ2xDLENBQUM7UUFDRixLQUFLLE1BQU0sWUFBWSxJQUFJLGFBQWEsRUFBRSxDQUFDO1lBQ3pDLElBQ0UsWUFBWSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxJQUFJLFFBQVEsQ0FBQyxFQUNwRSxDQUFDO2dCQUNELE9BQU8sWUFBWSxDQUFDO1lBQ3RCLENBQUM7UUFDSCxDQUFDO1FBQ0QsTUFBTSxJQUFJLEtBQUssQ0FDYix3RUFBd0UsQ0FDekUsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQTFKRCx3SUEwSkM7QUFFRCxTQUFTLDhCQUE4QixDQUFDLFVBQWdCO0lBQ3RELE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFLENBQUM7SUFDOUMsT0FBTyxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzNELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb250YWluZXJJbWFnZUJ1aWxkIH0gZnJvbSBcIkBjZGtsYWJzL2RlcGxveS10aW1lLWJ1aWxkXCI7XG5pbXBvcnQgKiBhcyBzYWdlbWFrZXIgZnJvbSBcIkBhd3MtY2RrL2F3cy1zYWdlbWFrZXItYWxwaGFcIjtcbmltcG9ydCB7IER1cmF0aW9uLCBTaXplLCBUb2tlbiB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgR3JhbnQsIElHcmFudGFibGUgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWlhbVwiO1xuaW1wb3J0IHsgSUJ1Y2tldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtczNcIjtcbmltcG9ydCB7XG4gIEJ1Y2tldERlcGxveW1lbnQsXG4gIElTb3VyY2UsXG4gIFNvdXJjZSxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zMy1kZXBsb3ltZW50XCI7XG5pbXBvcnQgeyBDZm5FbmRwb2ludENvbmZpZywgQ2ZuTW9kZWwgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNhZ2VtYWtlclwiO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBJRGVwZW5kYWJsZSB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7XG4gIGNhbGNNZW1vcnlGb290cHJpbnQsXG4gIGNhbGNUZW5zb3JQYXJhbGxlbCxcbiAgRGF0YVR5cGVCaXRzLFxuICBJTmV1cm9ueEluc3RhbmNlVHlwZSxcbiAgaW5mZXJNZW1vcnlGb290cHJpbnRGcm9tUGFyYW1ldGVycyxcbiAgTW9kZWxDb25maWcsXG4gIE5ldXJvbnhJbnN0YW5jZVR5cGUsXG4gIE9wdExldmVsLFxuICBQYXJhbWV0ZXJzLFxuICBRdWFudER0eXBlLFxufSBmcm9tIFwiLi4vYmFzZS9uZXVyb254XCI7XG5pbXBvcnQge1xuICBTYWdlTWFrZXJJbmZlcmVuY2VUb29sa2l0VG54Q29tcGlsZU9wdGlvbnMsXG4gIFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhDb21waWxlcixcbn0gZnJvbSBcIi4vc2FnZW1ha2VyLWluZmVyZW5jZS10b29sa2l0LXRueC1jb21waWxlclwiO1xuXG4vKipcbiAqIFByZWNvbXBpbGVkIG1vZGVsIG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGlsZWRNb2RlbE9wdGlvbnMge1xuICAvKipcbiAgICogTmV1cm9ueCBjb21waWxlIG9wdGlvbnMuXG4gICAqIEBkZWZhdWx0IC0gRWFjaCBwcm9wZXJ0aWVzIGFyZSBzZXQgZGVmYXVsdC5cbiAgICovXG4gIHJlYWRvbmx5IGNvbXBpbGVPcHRpb25zPzogU2FnZU1ha2VySW5mZXJlbmNlVG9vbGtpdFRueENvbXBpbGVPcHRpb25zO1xuICAvKipcbiAgICogQ29kZSB1c2VkIGZvciBpbmZlcmVuY2VcbiAgICogQGRlZmF1bHQgLSB1c2luZyB0aGUgcHJlZGVmaW5lZCBjb2RlXG4gICAqL1xuICByZWFkb25seSBjb2RlPzogSVNvdXJjZTtcbiAgLyoqXG4gICAqIE1vZGVsIElEIG9yIHNhdmVkIHBhdGhcbiAgICogQGRlZmF1bHQgXCIuL21vZGVsXCJcbiAgICovXG4gIHJlYWRvbmx5IG1vZGVsSWRPclBhdGg/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgcGF0aCB3aGVyZSBjb21waWxlZCBhcnRpZmFjdHMgKGkuZS4geHh4Lm5lZmYpIGFyZSBzdG9yZWRcbiAgICogQGRlZmF1bHQgXCIuL2NvbXBpbGVkXCJcbiAgICovXG4gIHJlYWRvbmx5IGNvbXBpbGVkQXJ0aWZhY3RQYXRoPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJ1Y2tldENvbXBpbGVkTW9kZWxPcHRpb25zIGV4dGVuZHMgQ29tcGlsZWRNb2RlbE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzIG9mIG1vZGVsLlxuICAgKi9cbiAgcmVhZG9ubHkgcGFyYW1ldGVyczogUGFyYW1ldGVycztcbiAgcmVhZG9ubHkgY29uZmlnPzogTW9kZWxDb25maWc7XG59XG5cbi8qKlxuICogQGRlcHJlY2F0ZWRcbiAqL1xuZXhwb3J0IGNsYXNzIFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhTYWdlTWFrZXJJbmZlcmVuY2VNb2RlbERhdGEge1xuICBzdGF0aWMgZnJvbUJ1Y2tldChcbiAgICBidWNrZXQ6IElCdWNrZXQsXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgb3B0aW9uczogQnVja2V0Q29tcGlsZWRNb2RlbE9wdGlvbnMsXG4gICkge1xuICAgIGNvbnN0IG5Qb3NpdGlvbnMgPSBvcHRpb25zLmNvbXBpbGVPcHRpb25zPy5uUG9zaXRpb25zID8/IDQwOTY7XG4gICAgY29uc3QgcXVhbnREdHlwZSA9IG9wdGlvbnMuY29tcGlsZU9wdGlvbnM/LnF1YW50RHR5cGU7XG4gICAgY29uc3Qgb3B0TGV2ZWwgPSBPcHRMZXZlbC5CRVNUX0JBTEFOQ0U7XG4gICAgY29uc3QgYmF0Y2hTaXplID0gb3B0aW9ucy5jb21waWxlT3B0aW9ucz8uYmF0Y2hTaXplID8/IDE7XG4gICAgY29uc3QgbWVtb3J5Rm9vdHByaW50ID0gb3B0aW9ucy5jb25maWdcbiAgICAgID8gY2FsY01lbW9yeUZvb3RwcmludChcbiAgICAgICAgICBvcHRpb25zLmNvbmZpZy5lbWJlZGRpbmdEaW1lbnNpb24sXG4gICAgICAgICAgb3B0aW9ucy5jb25maWcubGF5ZXJzLFxuICAgICAgICAgIERhdGFUeXBlQml0cy5CRjE2X09SX0ZQMTYsXG4gICAgICAgICAgblBvc2l0aW9ucyxcbiAgICAgICAgICBiYXRjaFNpemUsXG4gICAgICAgIClcbiAgICAgIDogaW5mZXJNZW1vcnlGb290cHJpbnRGcm9tUGFyYW1ldGVycyhcbiAgICAgICAgICBvcHRpb25zLnBhcmFtZXRlcnMsXG4gICAgICAgICAgblBvc2l0aW9ucyxcbiAgICAgICAgICBiYXRjaFNpemUsXG4gICAgICAgICk7XG4gICAgY29uc3QgbmV1cm9ueEluc3RhbmNlVHlwZXMgPSBbXG4gICAgICBOZXVyb254SW5zdGFuY2VUeXBlLklORjJfOFhMQVJHRSxcbiAgICAgIE5ldXJvbnhJbnN0YW5jZVR5cGUuSU5GMl8yNFhMQVJHRSxcbiAgICAgIE5ldXJvbnhJbnN0YW5jZVR5cGUuSU5GMl80OFhMQVJHRSxcbiAgICBdO1xuICAgIGNvbnN0IGF2YWlsYWJsZUluc3RhbmNlUGF0dGVybnMgPSBuZXVyb254SW5zdGFuY2VUeXBlc1xuICAgICAgLmZsYXRNYXAoKG5ldXJvbnhJbnN0YW5jZVR5cGUpID0+XG4gICAgICAgIGNhbGNUZW5zb3JQYXJhbGxlbChcbiAgICAgICAgICBuZXVyb254SW5zdGFuY2VUeXBlLFxuICAgICAgICAgIG1lbW9yeUZvb3RwcmludCxcbiAgICAgICAgICBvcHRpb25zLmNvbmZpZz8uYXR0ZW50aW9uSGVhZHMsXG4gICAgICAgICkubWFwKCh2KSA9PiAoe1xuICAgICAgICAgIG5ldXJvbnhJbnN0YW5jZVR5cGUsXG4gICAgICAgICAgLi4udixcbiAgICAgICAgfSkpLFxuICAgICAgKVxuICAgICAgLmZpbHRlcihcbiAgICAgICAgKHBhdHRlcm4pID0+XG4gICAgICAgICAgIW9wdGlvbnMuY29tcGlsZU9wdGlvbnM/LnRwRGVncmVlIHx8XG4gICAgICAgICAgcGF0dGVybi50cCA9PT0gb3B0aW9ucy5jb21waWxlT3B0aW9ucy50cERlZ3JlZSxcbiAgICAgICk7XG4gICAgaWYgKGF2YWlsYWJsZUluc3RhbmNlUGF0dGVybnMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBObyBhdmFpbGFibGUgaW5zdGFuY2UgdHlwZS4gWW91IGNhbiB1c2UgdHBEZWdyZWUgYXJlICR7YXZhaWxhYmxlSW5zdGFuY2VQYXR0ZXJucy5tYXAoKHApID0+IHAudHApLmpvaW4oXCIsIFwiKX0uYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IHRwRGVncmVlID1cbiAgICAgIG9wdGlvbnMuY29tcGlsZU9wdGlvbnM/LnRwRGVncmVlID8/IGF2YWlsYWJsZUluc3RhbmNlUGF0dGVybnNbMF0udHA7XG4gICAgcmV0dXJuIG5ldyBTYWdlTWFrZXJJbmZlcmVuY2VUb29sa2l0VG54U2FnZU1ha2VySW5mZXJlbmNlTW9kZWxEYXRhKHtcbiAgICAgIGJ1Y2tldCxcbiAgICAgIGNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeDogcHJlZml4LFxuICAgICAgblBvc2l0aW9ucyxcbiAgICAgIHF1YW50RHR5cGUsXG4gICAgICBvcHRMZXZlbCxcbiAgICAgIHRwRGVncmVlLFxuICAgICAgY29kZTogb3B0aW9ucy5jb2RlLFxuICAgICAgbW9kZWxJZE9yUGF0aDogb3B0aW9ucy5tb2RlbElkT3JQYXRoLFxuICAgICAgcGFyYW1ldGVyczogb3B0aW9ucy5wYXJhbWV0ZXJzLFxuICAgIH0pO1xuICB9XG4gIHN0YXRpYyBmcm9tTmV1cm9ueE5hdGl2ZUNvbXBpbGVyKFxuICAgIGNvbXBpbGVyOiBTYWdlTWFrZXJJbmZlcmVuY2VUb29sa2l0VG54Q29tcGlsZXIsXG4gICAgY29kZT86IElTb3VyY2UsXG4gICkge1xuICAgIGNvbnN0IGNvbXBpbGVkTW9kZWwgPSBjb21waWxlci5jb21waWxlKCk7XG4gICAgcmV0dXJuIG5ldyBTYWdlTWFrZXJJbmZlcmVuY2VUb29sa2l0VG54U2FnZU1ha2VySW5mZXJlbmNlTW9kZWxEYXRhKHtcbiAgICAgIC4uLmNvbXBpbGVkTW9kZWwsXG4gICAgICBvcHRMZXZlbDogY29tcGlsZWRNb2RlbC5vcHRMZXZlbCA/PyBPcHRMZXZlbC5CRVNUX0JBTEFOQ0UsXG4gICAgICBjb21waWxlZEFydGlmYWN0UzNQcmVmaXg6IGNvbXBpbGVkTW9kZWwuczNQcmVmaXgsXG4gICAgICBwYXJhbWV0ZXJzOiBjb21waWxlci5tb2RlbC5vcHRpb25zLnBhcmFtZXRlcnMsXG4gICAgICBjb2RlLFxuICAgICAgZGVwZW5kYWJsZXM6IFtjb21waWxlci5ub2RlLmRlZmF1bHRDaGlsZCFdLFxuICAgIH0pO1xuICB9XG4gIHJlYWRvbmx5IGJ1Y2tldDogSUJ1Y2tldDtcbiAgcmVhZG9ubHkgY29tcGlsZWRBcnRpZmFjdFMzUHJlZml4OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvZGU6IElTb3VyY2U7XG4gIHJlYWRvbmx5IHRwRGVncmVlOiBudW1iZXI7XG4gIHJlYWRvbmx5IHF1YW50RHR5cGU/OiBRdWFudER0eXBlO1xuICByZWFkb25seSBuUG9zaXRpb25zOiBudW1iZXI7XG4gIHJlYWRvbmx5IG9wdExldmVsOiBPcHRMZXZlbDtcbiAgcmVhZG9ubHkgbW9kZWxJZE9yUGF0aD86IHN0cmluZztcbiAgcmVhZG9ubHkgY29tcGlsZWRBcnRpZmFjdFBhdGg/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBhcmFtZXRlcnM6IFBhcmFtZXRlcnM7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVwZW5kYWJsZXM6IElEZXBlbmRhYmxlW107XG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcihvcHRpb25zOiB7XG4gICAgcmVhZG9ubHkgYnVja2V0OiBJQnVja2V0O1xuICAgIHJlYWRvbmx5IGNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeDogc3RyaW5nO1xuICAgIHJlYWRvbmx5IHRwRGVncmVlOiBudW1iZXI7XG4gICAgcmVhZG9ubHkgcXVhbnREdHlwZT86IFF1YW50RHR5cGU7XG4gICAgcmVhZG9ubHkgblBvc2l0aW9uczogbnVtYmVyO1xuICAgIHJlYWRvbmx5IG9wdExldmVsOiBPcHRMZXZlbDtcbiAgICByZWFkb25seSBjb2RlPzogSVNvdXJjZTtcbiAgICByZWFkb25seSBtb2RlbElkT3JQYXRoPzogc3RyaW5nO1xuICAgIHJlYWRvbmx5IGNvbXBpbGVkQXJ0aWZhY3RQYXRoPzogc3RyaW5nO1xuICAgIHJlYWRvbmx5IHBhcmFtZXRlcnM6IFBhcmFtZXRlcnM7XG4gICAgcmVhZG9ubHkgZGVwZW5kYWJsZXM/OiBJRGVwZW5kYWJsZVtdO1xuICB9KSB7XG4gICAgdGhpcy5idWNrZXQgPSBvcHRpb25zLmJ1Y2tldDtcbiAgICB0aGlzLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeCA9IG9wdGlvbnMuY29tcGlsZWRBcnRpZmFjdFMzUHJlZml4O1xuICAgIHRoaXMuY29kZSA9XG4gICAgICBvcHRpb25zLmNvZGUgPz9cbiAgICAgIFNvdXJjZS5hc3NldChcbiAgICAgICAgam9pbihcbiAgICAgICAgICBfX2Rpcm5hbWUsXG4gICAgICAgICAgXCIuLi8uLi9zY3JpcHRzL2luZmVyZW5jZS9zYWdlbWFrZXItaW5mZXJlbmNlLXRvb2xraXQtdG54L2NvZGVcIixcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgdGhpcy50cERlZ3JlZSA9IG9wdGlvbnMudHBEZWdyZWU7XG4gICAgdGhpcy5xdWFudER0eXBlID0gb3B0aW9ucy5xdWFudER0eXBlO1xuICAgIHRoaXMublBvc2l0aW9ucyA9IG9wdGlvbnMublBvc2l0aW9ucztcbiAgICB0aGlzLm9wdExldmVsID0gb3B0aW9ucy5vcHRMZXZlbDtcbiAgICB0aGlzLm1vZGVsSWRPclBhdGggPSBvcHRpb25zLm1vZGVsSWRPclBhdGg7XG4gICAgdGhpcy5jb21waWxlZEFydGlmYWN0UGF0aCA9IG9wdGlvbnMuY29tcGlsZWRBcnRpZmFjdFBhdGg7XG4gICAgdGhpcy5wYXJhbWV0ZXJzID0gb3B0aW9ucy5wYXJhbWV0ZXJzO1xuICAgIHRoaXMuZGVwZW5kYWJsZXMgPSBvcHRpb25zLmRlcGVuZGFibGVzID8/IFtdO1xuICB9XG5cbiAgYmluZChzY29wZTogQ29uc3RydWN0LCBtb2RlbDogc2FnZW1ha2VyLklNb2RlbCkge1xuICAgIGNvbnN0IGRlcGxveSA9IG5ldyBCdWNrZXREZXBsb3ltZW50KHNjb3BlLCBcIkNvZGVEZXBsb3ltZW50XCIsIHtcbiAgICAgIGRlc3RpbmF0aW9uQnVja2V0OiB0aGlzLmJ1Y2tldCxcbiAgICAgIHNvdXJjZXM6IFt0aGlzLmNvZGVdLFxuICAgICAgZGVzdGluYXRpb25LZXlQcmVmaXg6IGpvaW4odGhpcy5jb21waWxlZEFydGlmYWN0UzNQcmVmaXgsIFwiY29kZVwiKSxcbiAgICB9KTtcbiAgICBkZXBsb3kubm9kZS5hZGREZXBlbmRlbmN5KC4uLnRoaXMuZGVwZW5kYWJsZXMpO1xuICAgIG1vZGVsLm5vZGUuYWRkRGVwZW5kZW5jeShkZXBsb3kpO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2FnZU1ha2VySW5mZXJlbmNlVG9vbGtpdFRueFNhZ2VNYWtlclJlYWx0aW1lSW5mZXJlbmNlRW5kcG9pbnRQcm9wcyB7XG4gIC8qKlxuICAgKiBNb2RlbCBkYXRhIGZvciBTYWdlTWFrZXIgaW5mZXJlbmNlLlxuICAgKiBUaGUgbW9kZWwgZGF0YSByZXF1aXJlcyBhdCBsZWFzdCBjb21waWxlZCBhcnRpZmFjdHMuXG4gICAqL1xuICByZWFkb25seSBtb2RlbERhdGE6IFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhTYWdlTWFrZXJJbmZlcmVuY2VNb2RlbERhdGE7XG4gIC8qKlxuICAgKiBBbiBpbWFnZSBvZiB0aGUgY29udGFpbmVyIHdoZXJlIHRoZSBpbmZlcmVuY2Ugam9iIGlzIGV4ZWN1dGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2U/OiBzYWdlbWFrZXIuQ29udGFpbmVySW1hZ2U7XG4gIC8qKlxuICAgKiBBIG1hcCBvZiBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gcGFzcyBpbnRvIHRoZSBjb250YWluZXIuXG4gICAqIEBkZWZhdWx0IC0gT25seSB0aGUgcHJlZGVmaW5lZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgcmVxdWlyZWQgdG8gdXNlIE5ldXJvbnggaGF2ZSBiZWVuIHNldC5cbiAgICovXG4gIHJlYWRvbmx5IGVudmlyb25tZW50PzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcbiAgLyoqXG4gICAqIFRoZSBpbnN0YW5jZSB0eXBlIG9mIGNvbXBpbGUgd29ya2VyIGluc3RhbmNlLlxuICAgKiBAZGVmYXVsdCAtIEl0IGlzIGRldGVybWluZWQgYXV0b21hdGljYWxseSBhY2NvcmRpbmcgdG8gdGhlIG51bWJlciBvZiBtb2RlbCBwYXJhbWV0ZXJzIGFuZCBjb21waWxhdGlvbiBvcHRpb25zLlxuICAgKi9cbiAgcmVhZG9ubHkgaW5zdGFuY2VUeXBlPzogSU5ldXJvbnhJbnN0YW5jZVR5cGU7XG4gIC8qKlxuICAgKiBUaGUgc2l6ZSwgb2YgdGhlIE1MIHN0b3JhZ2Ugdm9sdW1lIGF0dGFjaGVkIHRvIGluZGl2aWR1YWwgaW5mZXJlbmNlIGluc3RhbmNlIGFzc29jaWF0ZWQgd2l0aCB0aGUgcHJvZHVjdGlvbiB2YXJpYW50LlxuICAgKiBDdXJyZW50bHkgb25seSBBbWF6b24gRUJTIGdwMiBzdG9yYWdlIHZvbHVtZXMgYXJlIHN1cHBvcnRlZC5cbiAgICogQHNlZSBodHRwczovL2F3cy5hbWF6b24uY29tL2pwL3JlbGVhc2Vub3Rlcy9ob3N0LWluc3RhbmNlLXN0b3JhZ2Utdm9sdW1lcy10YWJsZVxuICAgKiBAZGVmYXVsdCAtIDMgR0IgcGVyIGJpbGxpb24gcGFyYW1ldGVyIChNYXggNTEyIEdCKVxuICAgKi9cbiAgcmVhZG9ubHkgdm9sdW1lU2l6ZT86IFNpemU7XG4gIC8qKlxuICAgKiBUaGUgdGltZW91dCB2YWx1ZSwgdG8gZG93bmxvYWQgYW5kIGV4dHJhY3QgdGhlIG1vZGVsIHRoYXQgeW91IHdhbnQgdG8gaG9zdCBmcm9tIEFtYXpvbiBTM1xuICAgKiB0byB0aGUgaW5kaXZpZHVhbCBpbmZlcmVuY2UgaW5zdGFuY2UgYXNzb2NpYXRlZCB3aXRoIHRoaXMgcHJvZHVjdGlvbiB2YXJpYW50LlxuICAgKiBAZGVmYXVsdCAtIDYwIHNlY29uZHMsIHdoZW4gYHZvbHVtZVNpemVgIGxhcmdlciB0aGFuIDMwR0IgdGhlbiAxR0IgeCAxNSBzZWNvbmRzIChtYXggNjAgbWludXRlcylcbiAgICovXG4gIHJlYWRvbmx5IG1vZGVsRGF0YURvd25sb2FkVGltZW91dD86IER1cmF0aW9uO1xuICAvKipcbiAgICogVGhlIHRpbWVvdXQgdmFsdWUsIGZvciB5b3VyIGluZmVyZW5jZSBjb250YWluZXIgdG8gcGFzcyBoZWFsdGggY2hlY2sgYnkgU2FnZU1ha2VyIEhvc3RpbmcuXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL3NhZ2VtYWtlci9sYXRlc3QvZGcveW91ci1hbGdvcml0aG1zLWluZmVyZW5jZS1jb2RlLmh0bWwjeW91ci1hbGdvcml0aG1zLWluZmVyZW5jZS1hbGdvLXBpbmctcmVxdWVzdHNcbiAgICogQGRlZmF1bHQgLSA2MCBzZWNvbmRzLCB3aGVuIHNldCB0aGUgYG1vZGVsRGF0YURvd25sb2FkVGltZW91dGAgdGhlbiB1c2Ugc2FtZSB2YWx1ZSAobWF4IDYwIG1pbnV0ZXMpXG4gICAqL1xuICByZWFkb25seSBjb250YWluZXJTdGFydHVwSGVhbHRoQ2hlY2tUaW1lb3V0PzogRHVyYXRpb247XG59XG5cbi8qKlxuICogQGRlcHJlY2F0ZWRcbiAqL1xuZXhwb3J0IGNsYXNzIFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhTYWdlTWFrZXJSZWFsdGltZUluZmVyZW5jZUVuZHBvaW50IGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhlIGVuZHBvaW50LlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSBlbmRwb2ludEFybjogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGVuZHBvaW50LlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSBlbmRwb2ludE5hbWU6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBlbmRwb2ludDogc2FnZW1ha2VyLkVuZHBvaW50O1xuICBjb25zdHJ1Y3RvcihcbiAgICBzY29wZTogQ29uc3RydWN0LFxuICAgIGlkOiBzdHJpbmcsXG4gICAgcHJvcHM6IFNhZ2VNYWtlckluZmVyZW5jZVRvb2xraXRUbnhTYWdlTWFrZXJSZWFsdGltZUluZmVyZW5jZUVuZHBvaW50UHJvcHMsXG4gICkge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgbGV0IGltYWdlOiBzYWdlbWFrZXIuQ29udGFpbmVySW1hZ2U7XG4gICAgaWYgKHByb3BzLmltYWdlKSB7XG4gICAgICBpbWFnZSA9IHByb3BzLmltYWdlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBidWlsZCA9IG5ldyBDb250YWluZXJJbWFnZUJ1aWxkKHRoaXMsIFwiSW5mZXJlbmNlSW1hZ2VCdWlsZFwiLCB7XG4gICAgICAgIGRpcmVjdG9yeTogam9pbihcbiAgICAgICAgICBfX2Rpcm5hbWUsXG4gICAgICAgICAgXCIuLi8uLi9zY3JpcHRzL2luZmVyZW5jZS9zYWdlbWFrZXItaW5mZXJlbmNlLXRvb2xraXQtdG54XCIsXG4gICAgICAgICksXG4gICAgICB9KTtcbiAgICAgIGltYWdlID0gc2FnZW1ha2VyLkNvbnRhaW5lckltYWdlLmZyb21FY3JSZXBvc2l0b3J5KFxuICAgICAgICBidWlsZC5yZXBvc2l0b3J5LFxuICAgICAgICBidWlsZC5pbWFnZVRhZyxcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGluc3RhbmNlVHlwZSA9XG4gICAgICBwcm9wcy5pbnN0YW5jZVR5cGUgPz9cbiAgICAgIHRoaXMuc2VsZWN0SW5zdGFuY2VUeXBlQnlUcERlZ3JlZShwcm9wcy5tb2RlbERhdGEudHBEZWdyZWUpO1xuICAgIGNvbnN0IG1vZGVsID0gbmV3IHNhZ2VtYWtlci5Nb2RlbCh0aGlzLCBcIk1vZGVsXCIsIHtcbiAgICAgIGNvbnRhaW5lcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGltYWdlLFxuICAgICAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgICAgICBORVVST05fUlRfTlVNX0NPUkVTOiBwcm9wcy5tb2RlbERhdGEudHBEZWdyZWUudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIFRTX0RFRkFVTFRfUkVTUE9OU0VfVElNRU9VVDogKDYwICogNjApLnRvU3RyaW5nKCksXG4gICAgICAgICAgICBUU19ERUZBVUxUX1dPUktFUlNfUEVSX01PREVMOiBNYXRoLmZsb29yKFxuICAgICAgICAgICAgICBpbnN0YW5jZVR5cGUuYWNjZWxlcmF0b3JDaGlwcy5uZXVyb254Q29yZXMgL1xuICAgICAgICAgICAgICAgIHByb3BzLm1vZGVsRGF0YS50cERlZ3JlZSxcbiAgICAgICAgICAgICkudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIE1PREVMOiBwcm9wcy5tb2RlbERhdGEubW9kZWxJZE9yUGF0aCA/PyBcIi4vbW9kZWxcIixcbiAgICAgICAgICAgIENPTVBJTEVEX0FSVElGQUNUOlxuICAgICAgICAgICAgICBwcm9wcy5tb2RlbERhdGEuY29tcGlsZWRBcnRpZmFjdFBhdGggPz8gXCIuL2NvbXBpbGVkXCIsXG4gICAgICAgICAgICBUUF9ERUdSRUU6IHByb3BzLm1vZGVsRGF0YS50cERlZ3JlZS50b1N0cmluZygpLFxuICAgICAgICAgICAgTl9QT1NJVElPTlM6IHByb3BzLm1vZGVsRGF0YS5uUG9zaXRpb25zLnRvU3RyaW5nKCksXG4gICAgICAgICAgICBPUFRfTEVWRUw6IHByb3BzLm1vZGVsRGF0YS5vcHRMZXZlbC50b1N0cmluZygpLFxuICAgICAgICAgICAgUVVBTlRfRFRZUEU6IHByb3BzLm1vZGVsRGF0YS5xdWFudER0eXBlPy50b1N0cmluZygpID8/IFwiXCIsXG4gICAgICAgICAgICAuLi5wcm9wcy5lbnZpcm9ubWVudCxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBjb25zdCBjZm5Nb2RlbCA9IG1vZGVsLm5vZGUuZmluZENoaWxkKFwiTW9kZWxcIikgYXMgQ2ZuTW9kZWw7XG4gICAgY2ZuTW9kZWwuYWRkUHJvcGVydHlPdmVycmlkZShcbiAgICAgIFwiUHJpbWFyeUNvbnRhaW5lci5Nb2RlbERhdGFTb3VyY2UuUzNEYXRhU291cmNlLlMzVXJpXCIsXG4gICAgICBwcm9wcy5tb2RlbERhdGEuYnVja2V0LnMzVXJsRm9yT2JqZWN0KFxuICAgICAgICBUb2tlbi5pc1VucmVzb2x2ZWQocHJvcHMubW9kZWxEYXRhLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeCkgfHxcbiAgICAgICAgICBwcm9wcy5tb2RlbERhdGEuY29tcGlsZWRBcnRpZmFjdFMzUHJlZml4LmVuZHNXaXRoKFwiL1wiKVxuICAgICAgICAgID8gcHJvcHMubW9kZWxEYXRhLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeFxuICAgICAgICAgIDogYCR7cHJvcHMubW9kZWxEYXRhLmNvbXBpbGVkQXJ0aWZhY3RTM1ByZWZpeH0vYCxcbiAgICAgICksXG4gICAgKTtcbiAgICBjZm5Nb2RlbC5hZGRQcm9wZXJ0eU92ZXJyaWRlKFxuICAgICAgXCJQcmltYXJ5Q29udGFpbmVyLk1vZGVsRGF0YVNvdXJjZS5TM0RhdGFTb3VyY2UuUzNEYXRhVHlwZUJpdHNcIixcbiAgICAgIFwiUzNQcmVmaXhcIixcbiAgICApO1xuICAgIGNmbk1vZGVsLmFkZFByb3BlcnR5T3ZlcnJpZGUoXG4gICAgICBcIlByaW1hcnlDb250YWluZXIuTW9kZWxEYXRhU291cmNlLlMzRGF0YVNvdXJjZS5Db21wcmVzc2lvblR5cGVcIixcbiAgICAgIFwiTm9uZVwiLFxuICAgICk7XG4gICAgcHJvcHMubW9kZWxEYXRhLmJ1Y2tldC5ncmFudFJlYWQobW9kZWwpO1xuICAgIHByb3BzLm1vZGVsRGF0YS5iaW5kKHRoaXMsIG1vZGVsKTtcbiAgICBjb25zdCBlbmRwb2ludENvbmZpZyA9IG5ldyBzYWdlbWFrZXIuRW5kcG9pbnRDb25maWcoXG4gICAgICB0aGlzLFxuICAgICAgXCJFbmRwb2ludENvbmZpZ1wiLFxuICAgICAge1xuICAgICAgICBpbnN0YW5jZVByb2R1Y3Rpb25WYXJpYW50czogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIG1vZGVsLFxuICAgICAgICAgICAgdmFyaWFudE5hbWU6IFwiUHJpbWFyeVZhcmlhbnRcIixcbiAgICAgICAgICAgIGluc3RhbmNlVHlwZTogc2FnZW1ha2VyLkluc3RhbmNlVHlwZS5vZihcbiAgICAgICAgICAgICAgYG1sLiR7aW5zdGFuY2VUeXBlLnRvU3RyaW5nKCl9YCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgKTtcbiAgICBjb25zdCBjZm5FbmRwb2ludENvbmZpZyA9IGVuZHBvaW50Q29uZmlnLm5vZGUuZmluZENoaWxkKFxuICAgICAgXCJFbmRwb2ludENvbmZpZ1wiLFxuICAgICkgYXMgQ2ZuRW5kcG9pbnRDb25maWc7XG4gICAgY29uc3Qgdm9sdW1lU2l6ZSA9XG4gICAgICBwcm9wcy52b2x1bWVTaXplID8/XG4gICAgICBTaXplLmdpYmlieXRlcyhcbiAgICAgICAgTWF0aC5jZWlsKFxuICAgICAgICAgIHByb3BzLm1vZGVsRGF0YS5wYXJhbWV0ZXJzLnRvQmlsbGlvbigpICogMyA+IDUxMlxuICAgICAgICAgICAgPyA1MTJcbiAgICAgICAgICAgIDogcHJvcHMubW9kZWxEYXRhLnBhcmFtZXRlcnMudG9CaWxsaW9uKCkgKiAzLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICBjZm5FbmRwb2ludENvbmZpZy5hZGRQcm9wZXJ0eU92ZXJyaWRlKFxuICAgICAgXCJQcm9kdWN0aW9uVmFyaWFudHMuMC5Wb2x1bWVTaXplSW5HQlwiLFxuICAgICAgaW5zdGFuY2VUeXBlLnRvU3RyaW5nKCkuc3RhcnRzV2l0aChcIm1sLnRybjFcIilcbiAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgOiB2b2x1bWVTaXplLnRvR2liaWJ5dGVzKCksXG4gICAgKTtcbiAgICBjb25zdCBtb2RlbERhdGFEb3dubG9hZFRpbWVvdXQgPVxuICAgICAgcHJvcHMubW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0ID8/XG4gICAgICBpbmZlcmVuY2VNb2RlbERhdGFEb3dubG9hZFRpbWUodm9sdW1lU2l6ZSk7XG4gICAgY2ZuRW5kcG9pbnRDb25maWcuYWRkUHJvcGVydHlPdmVycmlkZShcbiAgICAgIFwiUHJvZHVjdGlvblZhcmlhbnRzLjAuTW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0SW5TZWNvbmRzXCIsXG4gICAgICBtb2RlbERhdGFEb3dubG9hZFRpbWVvdXQudG9TZWNvbmRzKCksXG4gICAgKTtcbiAgICBjZm5FbmRwb2ludENvbmZpZy5hZGRQcm9wZXJ0eU92ZXJyaWRlKFxuICAgICAgXCJQcm9kdWN0aW9uVmFyaWFudHMuMC5Db250YWluZXJTdGFydHVwSGVhbHRoQ2hlY2tUaW1lb3V0SW5TZWNvbmRzXCIsXG4gICAgICAoXG4gICAgICAgIHByb3BzLmNvbnRhaW5lclN0YXJ0dXBIZWFsdGhDaGVja1RpbWVvdXQgPz8gbW9kZWxEYXRhRG93bmxvYWRUaW1lb3V0XG4gICAgICApLnRvU2Vjb25kcygpLFxuICAgICk7XG4gICAgY29uc3QgZW5kcG9pbnQgPSBuZXcgc2FnZW1ha2VyLkVuZHBvaW50KHRoaXMsIFwiRW5kcG9pbnRcIiwge1xuICAgICAgZW5kcG9pbnRDb25maWcsXG4gICAgfSk7XG4gICAgdGhpcy5lbmRwb2ludEFybiA9IGVuZHBvaW50LmVuZHBvaW50QXJuO1xuICAgIHRoaXMuZW5kcG9pbnROYW1lID0gZW5kcG9pbnQuZW5kcG9pbnROYW1lO1xuICAgIHRoaXMuZW5kcG9pbnQgPSBlbmRwb2ludDtcbiAgfVxuICBncmFudEludm9rZShncmFudGVlOiBJR3JhbnRhYmxlKTogR3JhbnQge1xuICAgIHJldHVybiB0aGlzLmVuZHBvaW50LmdyYW50SW52b2tlKGdyYW50ZWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZWxlY3RJbnN0YW5jZVR5cGVCeVRwRGVncmVlKHRwRGVncmVlOiBudW1iZXIpIHtcbiAgICBjb25zdCBpbnN0YW5jZVR5cGVzID0gW1xuICAgICAgTmV1cm9ueEluc3RhbmNlVHlwZS5JTkYyXzhYTEFSR0UsXG4gICAgICBOZXVyb254SW5zdGFuY2VUeXBlLklORjJfMjRYTEFSR0UsXG4gICAgICBOZXVyb254SW5zdGFuY2VUeXBlLklORjJfNDhYTEFSR0UsXG4gICAgICBOZXVyb254SW5zdGFuY2VUeXBlLlRSTjFfMzJYTEFSR0UsXG4gICAgXTtcbiAgICBmb3IgKGNvbnN0IGluc3RhbmNlVHlwZSBvZiBpbnN0YW5jZVR5cGVzKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGluc3RhbmNlVHlwZS5zdXBwb3J0ZWRUZW5zb3JQYXJhbGxlbGlzbS5maW5kKCh0cCkgPT4gdHAgPj0gdHBEZWdyZWUpXG4gICAgICApIHtcbiAgICAgICAgcmV0dXJuIGluc3RhbmNlVHlwZTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgXCJUaGlzIG1vZGVsIGlzIHRvbyBsYXJnZSwgSSBjYW4gbm90IHN1cHBvcnQgdGhpcyBtb2RlbCBjdXJyZW50IHZlcnNpb24uXCIsXG4gICAgKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBpbmZlcmVuY2VNb2RlbERhdGFEb3dubG9hZFRpbWUodm9sdW1lU2l6ZTogU2l6ZSkge1xuICBjb25zdCBzZWNvbmRzID0gdm9sdW1lU2l6ZS50b0dpYmlieXRlcygpICogMTU7XG4gIHJldHVybiBEdXJhdGlvbi5zZWNvbmRzKHNlY29uZHMgPCAzNjAwID8gc2Vjb25kcyA6IDM2MDApO1xufVxuIl19