UNPKG

aws-cdk-neuronx-patterns

Version:
166 lines 28.6 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.NeuronxCompiler = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const batch = require("aws-cdk-lib/aws-batch"); const ec2 = require("aws-cdk-lib/aws-ec2"); const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const custom_resources_1 = require("aws-cdk-lib/custom-resources"); const constructs_1 = require("constructs"); const path_1 = require("path"); const aws_batch_1 = require("../aws-batch"); const neuronx_1 = require("../neuronx"); /** * Neuronx compiler construct. * Compile the model to work with Inferentia2 and Trainium1 and upload it to an S3 bucket. */ class NeuronxCompiler extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); const weightSize = aws_cdk_lib_1.Size.gibibytes(props.model.options.parameters.toBillion() * 2.5); const volumeSize = props.volumeSize?.toGibibytes() ?? Math.ceil(weightSize.toGibibytes() + neuronx_1.PytorchTrainingNeuronxImage.size.toGibibytes() + neuronx_1.NeuronOptimizedMachineImage.size.toGibibytes()); const launchTemplate = new ec2.LaunchTemplate(this, "LaunchTemplate", { blockDevices: [ { deviceName: "/dev/xvda", volume: ec2.BlockDeviceVolume.ebs(volumeSize, { volumeType: ec2.EbsDeviceVolumeType.GP3, encrypted: true, }), }, ], }); const neuronxInstanceType = props.neuronxInstanceType ?? neuronx_1.NeuronxInstanceType.INF2_48XLARGE; const computeEnvironment = new aws_batch_1.NeuronxBatchComputeEnvironment(this, "ComputeEnvironment", { vpc: props.vpc, vpcSubnets: props.vpcSubnets, instanceTypes: [neuronxInstanceType.instanceType], useOptimalInstanceClasses: false, launchTemplate, spot: props.spot, }); aws_cdk_lib_1.Tags.of(computeEnvironment).add("Name", "neuronx-compile-worker"); this.jobQueue = new batch.JobQueue(this, "JobQueue", { computeEnvironments: [ { computeEnvironment, order: 1, }, ], jobStateTimeLimitActions: [ { state: batch.JobStateTimeLimitActionsState.RUNNABLE, reason: batch.JobStateTimeLimitActionsReason.JOB_RESOURCE_REQUIREMENT, maxTime: aws_cdk_lib_1.Duration.minutes(10), action: batch.JobStateTimeLimitActionsAction.CANCEL, }, ], }); props.model.bucket?.grantRead(computeEnvironment.instanceRole); props.bucket.grantReadWrite(computeEnvironment.instanceRole); this.jobDefinition = new aws_batch_1.NeuronxBatchEcsJobDefinition(this, "JobDefinition", { neuronxInstanceType, image: props.image.image, // The fllowing command was executed on inf2.8xlarge // sh-5.2$ free -b // total used free shared buff/cache available // Mem: 132265766912 866320384 130341785600 667648 1057660928 130529148928 // https://docs.aws.amazon.com/batch/latest/userguide/memory-management.html memory: aws_cdk_lib_1.Size.mebibytes(Math.ceil(neuronxInstanceType.memory.toMebibytes() * 0.95)), cpu: neuronxInstanceType.vCpu, environment: { NEURON_COMPILE_CACHE_URL: `${props.bucket.s3UrlForObject("neuron-compile-cache")}`, ...props.environment, }, command: props.command, secrets: props.secrets, }); const jobSubmitFunction = new aws_lambda_1.SingletonFunction(this, "JobSubmitFunction", { code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, "private/await-compile-job")), handler: "index.onEvent", runtime: aws_lambda_1.Runtime.NODEJS_LATEST, uuid: "1361f469-5c92-4c46-9e11-5d1dbf925bac", environment: { JOB_DEFINITION_ARN: this.jobDefinition.jobDefinitionArn, JOB_QUEUE_ARN: this.jobQueue.jobQueueArn, }, }); this.jobDefinition.grantSubmitJob(jobSubmitFunction, this.jobQueue); const jobMonitoringFunction = new aws_lambda_1.SingletonFunction(this, "JobMonitoringFunction", { code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, "private/await-compile-job")), handler: "index.isComplete", runtime: aws_lambda_1.Runtime.NODEJS_LATEST, uuid: "df16dba8-5f77-480c-a6ad-cfdf74c3de62", environment: { ARTIFACT_S3_PREFIX: props.artifactS3Prefix, }, }); aws_iam_1.Grant.addToPrincipal({ resourceArns: ["*"], grantee: jobMonitoringFunction, actions: ["batch:DescribeJobs"], }); const provider = new custom_resources_1.Provider(this, "CompileJobProvider", { onEventHandler: jobSubmitFunction, isCompleteHandler: jobMonitoringFunction, queryInterval: aws_cdk_lib_1.Duration.minutes(1), totalTimeout: aws_cdk_lib_1.Duration.hours(12), }); this.entrypoint = new aws_lambda_1.SingletonFunction(this, "JobEntrypointFunction", { code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, "private/await-compile-job")), handler: "index.entrypoint", environment: { PROVIDER_ARN: provider.serviceToken, }, timeout: aws_cdk_lib_1.Duration.minutes(15), runtime: aws_lambda_1.Runtime.NODEJS_LATEST, uuid: "f6e66997-5042-4df1-8781-bd68b3ac5313", }); aws_lambda_1.Function.fromFunctionArn(this, "ProviderFunction", provider.serviceToken).grantInvoke(this.entrypoint); this.model = props.model; this.bucket = props.bucket; this.artifactS3Prefix = props.artifactS3Prefix; this.weightSize = weightSize; this.neuronxInstanceType = neuronxInstanceType; } compile() { // when invoke multiple times if (this.compiledModel) { return this.compiledModel; } const waitConditionHandle = new aws_cdk_lib_1.CfnWaitConditionHandle(this, `WaitConditionHandle${this.artifactS3Prefix}`); const compileJob = new aws_cdk_lib_1.CustomResource(this, "NeuronxCompile", { serviceToken: this.entrypoint.functionArn, resourceType: "Custom::NeuronxCompile", properties: { waitConditionCallbackURL: waitConditionHandle.ref, }, }); const wait = new aws_cdk_lib_1.CfnWaitCondition(this, `WaitCondition${this.artifactS3Prefix}`, { count: 1, timeout: aws_cdk_lib_1.Duration.hours(12).toSeconds().toString(), handle: waitConditionHandle.ref, }); wait.node.addDependency(compileJob); const s3Prefix = aws_cdk_lib_1.Fn.select(3, aws_cdk_lib_1.Fn.split('"', wait.attrData.toString())); this.compiledModel = { modelName: this.model.modelName, compileTimeInstanceType: this.neuronxInstanceType, bucket: this.bucket, s3Prefix, s3Uri: this.bucket.s3UrlForObject(s3Prefix), weightSize: this.weightSize, }; return this.compiledModel; } } exports.NeuronxCompiler = NeuronxCompiler; _a = JSII_RTTI_SYMBOL_1; NeuronxCompiler[_a] = { fqn: "aws-cdk-neuronx-patterns.NeuronxCompiler", version: "0.0.23" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV1cm9ueC1jb21waWxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYXNlL25ldXJvbngtY29tcGlsZXIvbmV1cm9ueC1jb21waWxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQVFxQjtBQUNyQiwrQ0FBK0M7QUFDL0MsMkNBQTJDO0FBRTNDLGlEQUE0QztBQUM1Qyx1REFLZ0M7QUFFaEMsbUVBQXdEO0FBQ3hELDJDQUF1QztBQUN2QywrQkFBNEI7QUFDNUIsNENBR3NCO0FBQ3RCLHdDQU1vQjtBQW1HcEI7OztHQUdHO0FBQ0gsTUFBYSxlQUFnQixTQUFRLHNCQUFTO0lBVTVDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBMkI7UUFDbkUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixNQUFNLFVBQVUsR0FBRyxrQkFBSSxDQUFDLFNBQVMsQ0FDL0IsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxHQUFHLEdBQUcsQ0FDakQsQ0FBQztRQUNGLE1BQU0sVUFBVSxHQUNkLEtBQUssQ0FBQyxVQUFVLEVBQUUsV0FBVyxFQUFFO1lBQy9CLElBQUksQ0FBQyxJQUFJLENBQ1AsVUFBVSxDQUFDLFdBQVcsRUFBRTtnQkFDdEIscUNBQTJCLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRTtnQkFDOUMscUNBQTJCLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUNqRCxDQUFDO1FBQ0osTUFBTSxjQUFjLEdBQUcsSUFBSSxHQUFHLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUNwRSxZQUFZLEVBQUU7Z0JBQ1o7b0JBQ0UsVUFBVSxFQUFFLFdBQVc7b0JBQ3ZCLE1BQU0sRUFBRSxHQUFHLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRTt3QkFDNUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxt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QUMsQ0FBQztRQUNILE1BQU0sSUFBSSxHQUFHLElBQUksOEJBQWdCLENBQy9CLElBQUksRUFDSixnQkFBZ0IsSUFBSSxDQUFDLGdCQUFnQixFQUFFLEVBQ3ZDO1lBQ0UsS0FBSyxFQUFFLENBQUM7WUFDUixPQUFPLEVBQUUsc0JBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxFQUFFO1lBQ2xELE1BQU0sRUFBRSxtQkFBbUIsQ0FBQyxHQUFHO1NBQ2hDLENBQ0YsQ0FBQztRQUNGLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sUUFBUSxHQUFHLGdCQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxnQkFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFdkUsSUFBSSxDQUFDLGFBQWEsR0FBRztZQUNuQixTQUFTLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTO1lBQy9CLHVCQUF1QixFQUFFLElBQUksQ0FBQyxtQkFBbUI7WUFDakQsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ25CLFFBQVE7WUFDUixLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDO1lBQzNDLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVTtTQUM1QixDQUFDO1FBQ0YsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDO0lBQzVCLENBQUM7O0FBMUxILDBDQTJMQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENmbldhaXRDb25kaXRpb24sXG4gIENmbldhaXRDb25kaXRpb25IYW5kbGUsXG4gIEN1c3RvbVJlc291cmNlLFxuICBEdXJhdGlvbixcbiAgRm4sXG4gIFNpemUsXG4gIFRhZ3MsXG59IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0ICogYXMgYmF0Y2ggZnJvbSBcImF3cy1jZGstbGliL2F3cy1iYXRjaFwiO1xuaW1wb3J0ICogYXMgZWMyIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWMyXCI7XG5pbXBvcnQgeyBDb250YWluZXJJbWFnZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQgeyBHcmFudCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQge1xuICBDb2RlLFxuICBGdW5jdGlvbixcbiAgUnVudGltZSxcbiAgU2luZ2xldG9uRnVuY3Rpb24sXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCI7XG5pbXBvcnQgeyBJQnVja2V0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zM1wiO1xuaW1wb3J0IHsgUHJvdmlkZXIgfSBmcm9tIFwiYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHtcbiAgTmV1cm9ueEJhdGNoQ29tcHV0ZUVudmlyb25tZW50LFxuICBOZXVyb254QmF0Y2hFY3NKb2JEZWZpbml0aW9uLFxufSBmcm9tIFwiLi4vYXdzLWJhdGNoXCI7XG5pbXBvcnQge1xuICBJTmV1cm9ueEluc3RhbmNlVHlwZSxcbiAgTW9kZWwsXG4gIE5ldXJvbk9wdGltaXplZE1hY2hpbmVJbWFnZSxcbiAgTmV1cm9ueEluc3RhbmNlVHlwZSxcbiAgUHl0b3JjaFRyYWluaW5nTmV1cm9ueEltYWdlLFxufSBmcm9tIFwiLi4vbmV1cm9ueFwiO1xuXG4vKipcbiAqIENvbXBpbGUgcnVudGltZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJTmV1cm9ueENvbnRhaW5lckltYWdlIHtcbiAgLyoqXG4gICAqIEFuIGltYWdlIG9mIHRoZSBjb250YWluZXIgd2hlcmUgdGhlIGNvbXBpbGUgam9iIGlzIGV4ZWN1dGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2U6IENvbnRhaW5lckltYWdlO1xuICAvKipcbiAgICogTmV1cm9ueCB2ZXJzaW9uIGluY2x1ZGVkIGluIGNvbnRhaW5lciBpbWFnZS5cbiAgICovXG4gIHJlYWRvbmx5IHNka1ZlcnNpb246IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wcyBvZiBOZXVyb254Q29tcGlsZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTmV1cm9ueENvbXBpbGVyUHJvcHMge1xuICAvKipcbiAgICogVlBDIGluIHdoaWNoIHRoaXMgd2lsbCBsYXVuY2ggY29tcGlsZSB3b3JrZXIgaW5zdGFuY2UuXG4gICAqL1xuICByZWFkb25seSB2cGM6IGVjMi5JVnBjO1xuICAvKipcbiAgICogVGhlIGJ1Y2tldCB0byB1cGxvYWQgY29tcGlsZWQgYXJ0aWZhY3RzLlxuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0OiBJQnVja2V0O1xuICAvKipcbiAgICogU2VjcmV0cyB0byBwYXNzIHRvIHRoZSBjb250YWluZXIuXG4gICAqL1xuICByZWFkb25seSBzZWNyZXRzPzogeyBba2V5OiBzdHJpbmddOiBiYXRjaC5TZWNyZXQgfTtcbiAgLyoqXG4gICAqIFMzIFByZWZpeCB0aGF0IGNvbXBpbGVkIGFydGlmYWN0IHVwbG9hZGVkLlxuICAgKiBUaGlzIHByb3BlcnR5IGlzIG5vdCBkZXBlbmRzIG9uIGNvbXBpbGUgam9iIGZpbmlzaC5cbiAgICovXG4gIHJlYWRvbmx5IGFydGlmYWN0UzNQcmVmaXg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBpbnN0YW5jZSB0eXBlIG9mIGNvbXBpbGUgd29ya2VyIGluc3RhbmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgbmV1cm9ueEluc3RhbmNlVHlwZTogSU5ldXJvbnhJbnN0YW5jZVR5cGU7XG4gIC8qKlxuICAgKiBUaGUgbW9kZWwgdG8gYmUgY29tcGlsZWQuXG4gICAqL1xuICByZWFkb25seSBtb2RlbDogTW9kZWw7XG4gIC8qKlxuICAgKiBBbiBpbWFnZSBvZiB0aGUgY29udGFpbmVyIHdoZXJlIHRoZSBjb21waWxlIGpvYiBpcyBleGVjdXRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGltYWdlOiBJTmV1cm9ueENvbnRhaW5lckltYWdlO1xuICByZWFkb25seSBjb21tYW5kPzogc3RyaW5nW107XG4gIC8qKlxuICAgKiBUaGUgcm9vdCB2b2x1bWUgb2Ygd29ya2VyIGluc3RhbmNlLlxuICAgKiBAZGVmYXVsdCAtIE4gYmlsaW9uIHBhcmFtZXRlcnMgKiA1R2lCIEVCU1xuICAgKi9cbiAgcmVhZG9ubHkgdm9sdW1lU2l6ZT86IFNpemU7XG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCB0byB1c2Ugc3BvdCBpbnN0YW5jZXMuIFNwb3QgaW5zdGFuY2VzIGFyZSBsZXNzIGV4cGVuc2l2ZSBFQzIgaW5zdGFuY2VzIHRoYXQgY2FuIGJlIHJlY2xhaW1lZCBieSBFQzIgYXQgYW55IHRpbWU7IHlvdXIgam9iIHdpbGwgYmUgZ2l2ZW4gdHdvIG1pbnV0ZXMgb2Ygbm90aWNlIGJlZm9yZSByZWNsYW1hdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHNwb3Q/OiBib29sZWFuO1xuICAvKipcbiAgICogVGhlIFZQQyBTdWJuZXRzIHRoaXMgQ29tcHV0ZSBFbnZpcm9ubWVudCB3aWxsIGxhdW5jaCBpbnN0YW5jZXMgaW4uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbmV3IHN1Ym5ldHMgd2lsbCBiZSBjcmVhdGVkXG4gICAqL1xuICByZWFkb25seSB2cGNTdWJuZXRzPzogZWMyLlN1Ym5ldFNlbGVjdGlvbjtcbiAgLyoqXG4gICAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gcGFzcyB0byB0aGUgY29udGFpbmVyLlxuICAgKiBUaGlzIGlzIG9ubHkgYXBwbGljYWJsZSB3aGVuIHVzaW5nIGNvbnRhaW5lciBydW50aW1lLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAgICovXG4gIHJlYWRvbmx5IGVudmlyb25tZW50Pzoge1xuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZztcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOZXVyb254Q29tcGlsZWRNb2RlbCB7XG4gIHJlYWRvbmx5IGNvbXBpbGVUaW1lSW5zdGFuY2VUeXBlOiBJTmV1cm9ueEluc3RhbmNlVHlwZTtcbiAgLyoqXG4gICAqIFRoZSBidWNrZXQgdG8gdXBsb2FkIGNvbXBpbGVkIGFydGlmYWN0cy5cbiAgICovXG4gIHJlYWRvbmx5IGJ1Y2tldDogSUJ1Y2tldDtcbiAgLyoqXG4gICAqIFMzIFVSTCB0aGF0IGNvbXBpbGVkIGFydGlmYWN0IHVwbG9hZGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgczNVcmk6IHN0cmluZztcbiAgLyoqXG4gICAqIFMzIHByZWZpeCB0aGF0IGNvbXBpbGVkIGFydGlmYWN0IHVwbG9hZGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgczNQcmVmaXg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBtb2RlbCBuYW1lLlxuICAgKi9cbiAgcmVhZG9ubHkgbW9kZWxOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHdlaWdodFNpemU6IFNpemU7XG59XG5cbi8qKlxuICogTmV1cm9ueCBjb21waWxlciBjb25zdHJ1Y3QuXG4gKiBDb21waWxlIHRoZSBtb2RlbCB0byB3b3JrIHdpdGggSW5mZXJlbnRpYTIgYW5kIFRyYWluaXVtMSBhbmQgdXBsb2FkIGl0IHRvIGFuIFMzIGJ1Y2tldC5cbiAqL1xuZXhwb3J0IGNsYXNzIE5ldXJvbnhDb21waWxlciBleHRlbmRzIENvbnN0cnVjdCB7XG4gIHByaXZhdGUgY29tcGlsZWRNb2RlbD86IE5ldXJvbnhDb21waWxlZE1vZGVsO1xuICBwcml2YXRlIHJlYWRvbmx5IGVudHJ5cG9pbnQ6IFNpbmdsZXRvbkZ1bmN0aW9uO1xuICBwcml2YXRlIHJlYWRvbmx5IGpvYkRlZmluaXRpb246IE5ldXJvbnhCYXRjaEVjc0pvYkRlZmluaXRpb247XG4gIHByaXZhdGUgcmVhZG9ubHkgam9iUXVldWU6IGJhdGNoLkpvYlF1ZXVlO1xuICBwcml2YXRlIHJlYWRvbmx5IGFydGlmYWN0UzNQcmVmaXg6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSB3ZWlnaHRTaXplOiBTaXplO1xuICBwcml2YXRlIHJlYWRvbmx5IG5ldXJvbnhJbnN0YW5jZVR5cGU6IElOZXVyb254SW5zdGFuY2VUeXBlO1xuICBwcml2YXRlIHJlYWRvbmx5IG1vZGVsOiBNb2RlbDtcbiAgcHJpdmF0ZSByZWFkb25seSBidWNrZXQ6IElCdWNrZXQ7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOZXVyb254Q29tcGlsZXJQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgY29uc3Qgd2VpZ2h0U2l6ZSA9IFNpemUuZ2liaWJ5dGVzKFxuICAgICAgcHJvcHMubW9kZWwub3B0aW9ucy5wYXJhbWV0ZXJzLnRvQmlsbGlvbigpICogMi41LFxuICAgICk7XG4gICAgY29uc3Qgdm9sdW1lU2l6ZSA9XG4gICAgICBwcm9wcy52b2x1bWVTaXplPy50b0dpYmlieXRlcygpID8/XG4gICAgICBNYXRoLmNlaWwoXG4gICAgICAgIHdlaWdodFNpemUudG9HaWJpYnl0ZXMoKSArXG4gICAgICAgICAgUHl0b3JjaFRyYWluaW5nTmV1cm9ueEltYWdlLnNpemUudG9HaWJpYnl0ZXMoKSArXG4gICAgICAgICAgTmV1cm9uT3B0aW1pemVkTWFjaGluZUltYWdlLnNpemUudG9HaWJpYnl0ZXMoKSxcbiAgICAgICk7XG4gICAgY29uc3QgbGF1bmNoVGVtcGxhdGUgPSBuZXcgZWMyLkxhdW5jaFRlbXBsYXRlKHRoaXMsIFwiTGF1bmNoVGVtcGxhdGVcIiwge1xuICAgICAgYmxvY2tEZXZpY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBkZXZpY2VOYW1lOiBcIi9kZXYveHZkYVwiLFxuICAgICAgICAgIHZvbHVtZTogZWMyLkJsb2NrRGV2aWNlVm9sdW1lLmVicyh2b2x1bWVTaXplLCB7XG4gICAgICAgICAgICB2b2x1bWVUeXBlOiBlYzIuRWJzRGV2aWNlVm9sdW1lVHlwZS5HUDMsXG4gICAgICAgICAgICBlbmNyeXB0ZWQ6IHRydWUsXG4gICAgICAgICAgfSksXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuXG4gICAgY29uc3QgbmV1cm9ueEluc3RhbmNlVHlwZSA9XG4gICAgICBwcm9wcy5uZXVyb254SW5zdGFuY2VUeXBlID8/IE5ldXJvbnhJbnN0YW5jZVR5cGUuSU5GMl80OFhMQVJHRTtcbiAgICBjb25zdCBjb21wdXRlRW52aXJvbm1lbnQgPSBuZXcgTmV1cm9ueEJhdGNoQ29tcHV0ZUVudmlyb25tZW50KFxuICAgICAgdGhpcyxcbiAgICAgIFwiQ29tcHV0ZUVudmlyb25tZW50XCIsXG4gICAgICB7XG4gICAgICAgIHZwYzogcHJvcHMudnBjLFxuICAgICAgICB2cGNTdWJuZXRzOiBwcm9wcy52cGNTdWJuZXRzLFxuICAgICAgICBpbnN0YW5jZVR5cGVzOiBbbmV1cm9ueEluc3RhbmNlVHlwZS5pbnN0YW5jZVR5cGVdLFxuICAgICAgICB1c2VPcHRpbWFsSW5zdGFuY2VDbGFzc2VzOiBmYWxzZSxcbiAgICAgICAgbGF1bmNoVGVtcGxhdGUsXG4gICAgICAgIHNwb3Q6IHByb3BzLnNwb3QsXG4gICAgICB9LFxuICAgICk7XG5cbiAgICBUYWdzLm9mKGNvbXB1dGVFbnZpcm9ubWVudCkuYWRkKFwiTmFtZVwiLCBcIm5ldXJvbngtY29tcGlsZS13b3JrZXJcIik7XG4gICAgdGhpcy5qb2JRdWV1ZSA9IG5ldyBiYXRjaC5Kb2JRdWV1ZSh0aGlzLCBcIkpvYlF1ZXVlXCIsIHtcbiAgICAgIGNvbXB1dGVFbnZpcm9ubWVudHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGNvbXB1dGVFbnZpcm9ubWVudCxcbiAgICAgICAgICBvcmRlcjogMSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBqb2JTdGF0ZVRpbWVMaW1pdEFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHN0YXRlOiBiYXRjaC5Kb2JTdGF0ZVRpbWVMaW1pdEFjdGlvbnNTdGF0ZS5SVU5OQUJMRSxcbiAgICAgICAgICByZWFzb246IGJhdGNoLkpvYlN0YXRlVGltZUxpbWl0QWN0aW9uc1JlYXNvbi5KT0JfUkVTT1VSQ0VfUkVRVUlSRU1FTlQsXG4gICAgICAgICAgbWF4VGltZTogRHVyYXRpb24ubWludXRlcygxMCksXG4gICAgICAgICAgYWN0aW9uOiBiYXRjaC5Kb2JTdGF0ZVRpbWVMaW1pdEFjdGlvbnNBY3Rpb24uQ0FOQ0VMLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBwcm9wcy5tb2RlbC5idWNrZXQ/LmdyYW50UmVhZChjb21wdXRlRW52aXJvbm1lbnQuaW5zdGFuY2VSb2xlKTtcbiAgICBwcm9wcy5idWNrZXQuZ3JhbnRSZWFkV3JpdGUoY29tcHV0ZUVudmlyb25tZW50Lmluc3RhbmNlUm9sZSk7XG4gICAgdGhpcy5qb2JEZWZpbml0aW9uID0gbmV3IE5ldXJvbnhCYXRjaEVjc0pvYkRlZmluaXRpb24oXG4gICAgICB0aGlzLFxuICAgICAgXCJKb2JEZWZpbml0aW9uXCIsXG4gICAgICB7XG4gICAgICAgIG5ldXJvbnhJbnN0YW5jZVR5cGUsXG4gICAgICAgIGltYWdlOiBwcm9wcy5pbWFnZS5pbWFnZSxcbiAgICAgICAgLy8gVGhlIGZsbG93aW5nIGNvbW1hbmQgd2FzIGV4ZWN1dGVkIG9uIGluZjIuOHhsYXJnZVxuICAgICAgICAvLyBzaC01LjIkIGZyZWUgLWJcbiAgICAgICAgLy8gXHRcdFx0dG90YWxcdFx0XHRcdFx0dXNlZFx0XHRcdGZyZWVcdFx0XHRcdFx0c2hhcmVkXHRidWZmL2NhY2hlXHRhdmFpbGFibGVcbiAgICAgICAgLy8gTWVtOlx0MTMyMjY1NzY2OTEyXHQ4NjYzMjAzODRcdDEzMDM0MTc4NTYwMFx0NjY3NjQ4XHQxMDU3NjYwOTI4XHQxMzA1MjkxNDg5MjhcbiAgICAgICAgLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2JhdGNoL2xhdGVzdC91c2VyZ3VpZGUvbWVtb3J5LW1hbmFnZW1lbnQuaHRtbFxuICAgICAgICBtZW1vcnk6IFNpemUubWViaWJ5dGVzKFxuICAgICAgICAgIE1hdGguY2VpbChuZXVyb254SW5zdGFuY2VUeXBlLm1lbW9yeS50b01lYmlieXRlcygpICogMC45NSksXG4gICAgICAgICksXG4gICAgICAgIGNwdTogbmV1cm9ueEluc3RhbmNlVHlwZS52Q3B1LFxuICAgICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICAgIE5FVVJPTl9DT01QSUxFX0NBQ0hFX1VSTDogYCR7cHJvcHMuYnVja2V0LnMzVXJsRm9yT2JqZWN0KFwibmV1cm9uLWNvbXBpbGUtY2FjaGVcIil9YCxcbiAgICAgICAgICAuLi5wcm9wcy5lbnZpcm9ubWVudCxcbiAgICAgICAgfSxcbiAgICAgICAgY29tbWFuZDogcHJvcHMuY29tbWFuZCxcbiAgICAgICAgc2VjcmV0czogcHJvcHMuc2VjcmV0cyxcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIGNvbnN0IGpvYlN1Ym1pdEZ1bmN0aW9uID0gbmV3IFNpbmdsZXRvbkZ1bmN0aW9uKHRoaXMsIFwiSm9iU3VibWl0RnVuY3Rpb25cIiwge1xuICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQoam9pbihfX2Rpcm5hbWUsIFwicHJpdmF0ZS9hd2FpdC1jb21waWxlLWpvYlwiKSksXG4gICAgICBoYW5kbGVyOiBcImluZGV4Lm9uRXZlbnRcIixcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTX0xBVEVTVCxcbiAgICAgIHV1aWQ6IFwiMTM2MWY0NjktNWM5Mi00YzQ2LTllMTEtNWQxZGJmOTI1YmFjXCIsXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBKT0JfREVGSU5JVElPTl9BUk46IHRoaXMuam9iRGVmaW5pdGlvbi5qb2JEZWZpbml0aW9uQXJuLFxuICAgICAgICBKT0JfUVVFVUVfQVJOOiB0aGlzLmpvYlF1ZXVlLmpvYlF1ZXVlQXJuLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICB0aGlzLmpvYkRlZmluaXRpb24uZ3JhbnRTdWJtaXRKb2Ioam9iU3VibWl0RnVuY3Rpb24sIHRoaXMuam9iUXVldWUpO1xuICAgIGNvbnN0IGpvYk1vbml0b3JpbmdGdW5jdGlvbiA9IG5ldyBTaW5nbGV0b25GdW5jdGlvbihcbiAgICAgIHRoaXMsXG4gICAgICBcIkpvYk1vbml0b3JpbmdGdW5jdGlvblwiLFxuICAgICAge1xuICAgICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldChqb2luKF9fZGlybmFtZSwgXCJwcml2YXRlL2F3YWl0LWNvbXBpbGUtam9iXCIpKSxcbiAgICAgICAgaGFuZGxlcjogXCJpbmRleC5pc0NvbXBsZXRlXCIsXG4gICAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTX0xBVEVTVCxcbiAgICAgICAgdXVpZDogXCJkZjE2ZGJhOC01Zjc3LTQ4MGMtYTZhZC1jZmRmNzRjM2RlNjJcIixcbiAgICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgICBBUlRJRkFDVF9TM19QUkVGSVg6IHByb3BzLmFydGlmYWN0UzNQcmVmaXgsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICk7XG4gICAgR3JhbnQuYWRkVG9QcmluY2lwYWwoe1xuICAgICAgcmVzb3VyY2VBcm5zOiBbXCIqXCJdLFxuICAgICAgZ3JhbnRlZTogam9iTW9uaXRvcmluZ0Z1bmN0aW9uLFxuICAgICAgYWN0aW9uczogW1wiYmF0Y2g6RGVzY3JpYmVKb2JzXCJdLFxuICAgIH0pO1xuICAgIGNvbnN0IHByb3ZpZGVyID0gbmV3IFByb3ZpZGVyKHRoaXMsIFwiQ29tcGlsZUpvYlByb3ZpZGVyXCIsIHtcbiAgICAgIG9uRXZlbnRIYW5kbGVyOiBqb2JTdWJtaXRGdW5jdGlvbixcbiAgICAgIGlzQ29tcGxldGVIYW5kbGVyOiBqb2JNb25pdG9yaW5nRnVuY3Rpb24sXG4gICAgICBxdWVyeUludGVydmFsOiBEdXJhdGlvbi5taW51dGVzKDEpLFxuICAgICAgdG90YWxUaW1lb3V0OiBEdXJhdGlvbi5ob3VycygxMiksXG4gICAgfSk7XG4gICAgdGhpcy5lbnRyeXBvaW50ID0gbmV3IFNpbmdsZXRvbkZ1bmN0aW9uKHRoaXMsIFwiSm9iRW50cnlwb2ludEZ1bmN0aW9uXCIsIHtcbiAgICAgIGNvZGU6IENvZGUuZnJvbUFzc2V0KGpvaW4oX19kaXJuYW1lLCBcInByaXZhdGUvYXdhaXQtY29tcGlsZS1qb2JcIikpLFxuICAgICAgaGFuZGxlcjogXCJpbmRleC5lbnRyeXBvaW50XCIsXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBQUk9WSURFUl9BUk46IHByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgIH0sXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5taW51dGVzKDE1KSxcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTX0xBVEVTVCxcbiAgICAgIHV1aWQ6IFwiZjZlNjY5OTctNTA0Mi00ZGYxLTg3ODEtYmQ2OGIzYWM1MzEzXCIsXG4gICAgfSk7XG4gICAgRnVuY3Rpb24uZnJvbUZ1bmN0aW9uQXJuKFxuICAgICAgdGhpcyxcbiAgICAgIFwiUHJvdmlkZXJGdW5jdGlvblwiLFxuICAgICAgcHJvdmlkZXIuc2VydmljZVRva2VuLFxuICAgICkuZ3JhbnRJbnZva2UodGhpcy5lbnRyeXBvaW50KTtcblxuICAgIHRoaXMubW9kZWwgPSBwcm9wcy5tb2RlbDtcbiAgICB0aGlzLmJ1Y2tldCA9IHByb3BzLmJ1Y2tldDtcbiAgICB0aGlzLmFydGlmYWN0UzNQcmVmaXggPSBwcm9wcy5hcnRpZmFjdFMzUHJlZml4O1xuICAgIHRoaXMud2VpZ2h0U2l6ZSA9IHdlaWdodFNpemU7XG4gICAgdGhpcy5uZXVyb254SW5zdGFuY2VUeXBlID0gbmV1cm9ueEluc3RhbmNlVHlwZTtcbiAgfVxuICBjb21waWxlKCkge1xuICAgIC8vIHdoZW4gaW52b2tlIG11bHRpcGxlIHRpbWVzXG4gICAgaWYgKHRoaXMuY29tcGlsZWRNb2RlbCkge1xuICAgICAgcmV0dXJuIHRoaXMuY29tcGlsZWRNb2RlbDtcbiAgICB9XG4gICAgY29uc3Qgd2FpdENvbmRpdGlvbkhhbmRsZSA9IG5ldyBDZm5XYWl0Q29uZGl0aW9uSGFuZGxlKFxuICAgICAgdGhpcyxcbiAgICAgIGBXYWl0Q29uZGl0aW9uSGFuZGxlJHt0aGlzLmFydGlmYWN0UzNQcmVmaXh9YCxcbiAgICApO1xuICAgIGNvbnN0IGNvbXBpbGVKb2IgPSBuZXcgQ3VzdG9tUmVzb3VyY2UodGhpcywgXCJOZXVyb254Q29tcGlsZVwiLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IHRoaXMuZW50cnlwb2ludC5mdW5jdGlvbkFybixcbiAgICAgIHJlc291cmNlVHlwZTogXCJDdXN0b206Ok5ldXJvbnhDb21waWxlXCIsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIHdhaXRDb25kaXRpb25DYWxsYmFja1VSTDogd2FpdENvbmRpdGlvbkhhbmRsZS5yZWYsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGNvbnN0IHdhaXQgPSBuZXcgQ2ZuV2FpdENvbmRpdGlvbihcbiAgICAgIHRoaXMsXG4gICAgICBgV2FpdENvbmRpdGlvbiR7dGhpcy5hcnRpZmFjdFMzUHJlZml4fWAsXG4gICAgICB7XG4gICAgICAgIGNvdW50OiAxLFxuICAgICAgICB0aW1lb3V0OiBEdXJhdGlvbi5ob3VycygxMikudG9TZWNvbmRzKCkudG9TdHJpbmcoKSxcbiAgICAgICAgaGFuZGxlOiB3YWl0Q29uZGl0aW9uSGFuZGxlLnJlZixcbiAgICAgIH0sXG4gICAgKTtcbiAgICB3YWl0Lm5vZGUuYWRkRGVwZW5kZW5jeShjb21waWxlSm9iKTtcbiAgICBjb25zdCBzM1ByZWZpeCA9IEZuLnNlbGVjdCgzLCBGbi5zcGxpdCgnXCInLCB3YWl0LmF0dHJEYXRhLnRvU3RyaW5nKCkpKTtcblxuICAgIHRoaXMuY29tcGlsZWRNb2RlbCA9IHtcbiAgICAgIG1vZGVsTmFtZTogdGhpcy5tb2RlbC5tb2RlbE5hbWUsXG4gICAgICBjb21waWxlVGltZUluc3RhbmNlVHlwZTogdGhpcy5uZXVyb254SW5zdGFuY2VUeXBlLFxuICAgICAgYnVja2V0OiB0aGlzLmJ1Y2tldCxcbiAgICAgIHMzUHJlZml4LFxuICAgICAgczNVcmk6IHRoaXMuYnVja2V0LnMzVXJsRm9yT2JqZWN0KHMzUHJlZml4KSxcbiAgICAgIHdlaWdodFNpemU6IHRoaXMud2VpZ2h0U2l6ZSxcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLmNvbXBpbGVkTW9kZWw7XG4gIH1cbn1cbiJdfQ==