UNPKG

aws-cdk-neuronx-patterns

Version:
133 lines 17.7 kB
"use strict"; var _a, _b, _c, _d; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApplicationLoadBalancedVllmNxDInferenceService = exports.VllmNxdInferenceTaskDefinition = exports.VllmNxdInferenceEcsImage = exports.VllmNxdInferenceEcsImageBase = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const ecs = require("aws-cdk-lib/aws-ecs"); const constructs_1 = require("constructs"); const aws_ecs_patterns_1 = require("../base/aws-ecs-patterns"); const neuronx_1 = require("../base/neuronx"); const vllm_engine_1 = require("../base/server-engine/vllm-engine"); /** * Base class for VllmNxdInferenceImage. */ class VllmNxdInferenceEcsImageBase { constructor(neuronxImage) { this.neuronSdkVersion = neuronxImage.neuronSdkVersion; } } exports.VllmNxdInferenceEcsImageBase = VllmNxdInferenceEcsImageBase; _a = JSII_RTTI_SYMBOL_1; VllmNxdInferenceEcsImageBase[_a] = { fqn: "aws-cdk-neuronx-patterns.VllmNxdInferenceEcsImageBase", version: "0.3.0" }; /** * Inference ECS container image for vLLM on NxD Inference. * This image uses the official AWS Neuron Deep Learning Containers which come with vLLM pre-installed. * * @example new VllmNxdInferenceEcsImage(VllmInferenceNeuronxImage.LATEST) */ class VllmNxdInferenceEcsImage extends VllmNxdInferenceEcsImageBase { /** * Create a VllmNxdInferenceImage from a custom neuronx image. * This will build a container image using a Dockerfile that installs vLLM from source. * * @example * new VllmNxdInferenceEcsImage(VllmInferenceNeuronxImage.LATEST) */ constructor(vllmInferenceNeuronxImage) { vllmInferenceNeuronxImage ?? (vllmInferenceNeuronxImage = neuronx_1.VllmInferenceNeuronxImage.LATEST); super(vllmInferenceNeuronxImage); this.image = ecs.ContainerImage.fromRegistry(`${vllmInferenceNeuronxImage.imageName}:${vllmInferenceNeuronxImage.imageTag}`); } } exports.VllmNxdInferenceEcsImage = VllmNxdInferenceEcsImage; _b = JSII_RTTI_SYMBOL_1; VllmNxdInferenceEcsImage[_b] = { fqn: "aws-cdk-neuronx-patterns.VllmNxdInferenceEcsImage", version: "0.3.0" }; /** * Task definition for VllmNxdInference. */ class VllmNxdInferenceTaskDefinition extends aws_ecs_patterns_1.NeuronxTaskDefinition { constructor(scope, id, props) { const neuronxInstanceType = props.neuronxInstanceType ?? props.compiledModel.recommendedInstanceType; const tensorParallelSize = props.compiledModel.vllmArgs.tensorParallelSize ?? 1; super(scope, id, { ...props, neuronxInstanceType, tensorParallelSize, }); const image = props.image ?? new VllmNxdInferenceEcsImage(); const port = props.compiledModel.vllmArgs.port ?? 8000; const vllmCliArgs = vllm_engine_1.VllmEngineArgumentsParser.cli(props.compiledModel.vllmArgs); // Prepare environment variables const environment = { ...props.environment, VLLM_NEURON_FRAMEWORK: "neuronx-distributed-inference", NEURON_COMPILED_ARTIFACTS: "neuron-compiled-artifacts", NEURON_RT_NUM_CORES: tensorParallelSize.toString(), XLA_HANDLE_SPECIAL_SCALAR: "1", MODEL_NAME: props.compiledModel.modelName, }; this.addContainerWithDefault("vLLM", { image: image.image, portMappings: [ { containerPort: port, }, ], healthCheck: { command: [ "CMD-SHELL", `curl -f http://localhost:${port}/health || exit 1`, ], startPeriod: aws_cdk_lib_1.Duration.minutes(5), }, workingDirectory: `/opt/ml/model/${props.compiledModel.s3Prefix}`, entryPoint: ["vllm", "serve"], command: vllmCliArgs, environment, }); } } exports.VllmNxdInferenceTaskDefinition = VllmNxdInferenceTaskDefinition; _c = JSII_RTTI_SYMBOL_1; VllmNxdInferenceTaskDefinition[_c] = { fqn: "aws-cdk-neuronx-patterns.VllmNxdInferenceTaskDefinition", version: "0.3.0" }; /** * ApplicationLoadBalancedVllmNxDInferenceService is a wrapper of ApplicationLoadBalancedNeuronxServiceBase. * It provides a simple way to deploy vLLM on NxD Inference. * @example * const compiler = new VllmNxdInferenceCompiler(this, "Compiler", { * vpc, * bucket, * model: Model.fromHuggingFace("example/example-7b-chat"), * }); * const compiledModel = compiler.compile(); * const taskDefinition = new VllmNxdInferenceTaskDefinition( * this, * "TaskDefinition", * { * vpc, * compiledModel, * }, * ); * new ApplicationLoadBalancedVllmNxDInferenceService(this, "Service", { * taskDefinition, * }); */ class ApplicationLoadBalancedVllmNxDInferenceService extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); const resource = new aws_ecs_patterns_1.ApplicationLoadBalancedNeuronxService(this, "Resource", props); resource.targetGroup.configureHealthCheck({ path: "/health", }); this.loadBalancer = resource.loadBalancer; this.listener = resource.listener; this.targetGroup = resource.targetGroup; this.service = resource.service; this.taskDefinition = resource.taskDefinition; } } exports.ApplicationLoadBalancedVllmNxDInferenceService = ApplicationLoadBalancedVllmNxDInferenceService; _d = JSII_RTTI_SYMBOL_1; ApplicationLoadBalancedVllmNxDInferenceService[_d] = { fqn: "aws-cdk-neuronx-patterns.ApplicationLoadBalancedVllmNxDInferenceService", version: "0.3.0" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmxsbS1ueGQtaW5mZXJlbmNlLWVjcy1wYXR0ZXJucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92bGxtLW54ZC1pbmZlcmVuY2UvdmxsbS1ueGQtaW5mZXJlbmNlLWVjcy1wYXR0ZXJucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQUF1QztBQUN2QywyQ0FBMkM7QUFNM0MsMkNBQXVDO0FBQ3ZDLCtEQUtrQztBQUNsQyw2Q0FHeUI7QUFFekIsbUVBQThFO0FBTzlFOztHQUVHO0FBQ0gsTUFBc0IsNEJBQTRCO0lBU2hELFlBQVksWUFBd0M7UUFDbEQsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQztJQUN4RCxDQUFDOztBQVhILG9FQVlDOzs7QUFFRDs7Ozs7R0FLRztBQUNILE1BQWEsd0JBQXlCLFNBQVEsNEJBQTRCO0lBR3hFOzs7Ozs7T0FNRztJQUNILFlBQVkseUJBQXNEO1FBQ2hFLHlCQUF5QixLQUF6Qix5QkFBeUIsR0FBSyxtQ0FBeUIsQ0FBQyxNQUFNLEVBQUM7UUFDL0QsS0FBSyxDQUFDLHlCQUF5QixDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDLEtBQUssR0FBRyxHQUFHLENBQUMsY0FBYyxDQUFDLFlBQVksQ0FDMUMsR0FBRyx5QkFBeUIsQ0FBQyxTQUFTLElBQUkseUJBQXlCLENBQUMsUUFBUSxFQUFFLENBQy9FLENBQUM7SUFDSixDQUFDOztBQWhCSCw0REFpQkM7OztBQTBCRDs7R0FFRztBQUNILE1BQWEsOEJBQStCLFNBQVEsd0NBQXFCO0lBQ3ZFLFlBQ0UsS0FBZ0IsRUFDaEIsRUFBVSxFQUNWLEtBQTBDO1FBRTFDLE1BQU0sbUJBQW1CLEdBQ3ZCLEtBQUssQ0FBQyxtQkFBbUIsSUFBSSxLQUFLLENBQUMsYUFBYSxDQUFDLHVCQUF1QixDQUFDO1FBQzNFLE1BQU0sa0JBQWtCLEdBQ3RCLEtBQUssQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLGtCQUFrQixJQUFJLENBQUMsQ0FBQztRQUN2RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLEdBQUcsS0FBSztZQUNSLG1CQUFtQjtZQUNuQixrQkFBa0I7U0FDbkIsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssSUFBSSxJQUFJLHdCQUF3QixFQUFFLENBQUM7UUFDNUQsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQztRQUN2RCxNQUFNLFdBQVcsR0FBRyx1Q0FBeUIsQ0FBQyxHQUFHLENBQy9DLEtBQUssQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUM3QixDQUFDO1FBQ0YsZ0NBQWdDO1FBQ2hDLE1BQU0sV0FBVyxHQUEyQjtZQUMxQyxHQUFHLEtBQUssQ0FBQyxXQUFXO1lBQ3BCLHFCQUFxQixFQUFFLCtCQUErQjtZQUN0RCx5QkFBeUIsRUFBRSwyQkFBMkI7WUFDdEQsbUJBQW1CLEVBQUUsa0JBQWtCLENBQUMsUUFBUSxFQUFFO1lBQ2xELHlCQUF5QixFQUFFLEdBQUc7WUFDOUIsVUFBVSxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUMsU0FBUztTQUMxQyxDQUFDO1FBRUYsSUFBSSxDQUFDLHVCQUF1QixDQUFDLE1BQU0sRUFBRTtZQUNuQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUs7WUFDbEIsWUFBWSxFQUFFO2dCQUNaO29CQUNFLGFBQWEsRUFBRSxJQUFJO2lCQUNwQjthQUNGO1lBQ0QsV0FBVyxFQUFFO2dCQUNYLE9BQU8sRUFBRTtvQkFDUCxXQUFXO29CQUNYLDRCQUE0QixJQUFJLG1CQUFtQjtpQkFDcEQ7Z0JBQ0QsV0FBVyxFQUFFLHNCQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQzthQUNqQztZQUNELGdCQUFnQixFQUFFLGlCQUFpQixLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRTtZQUNqRSxVQUFVLEVBQUUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDO1lBQzdCLE9BQU8sRUFBRSxXQUFXO1lBQ3BCLFdBQVc7U0FDWixDQUFDLENBQUM7SUFDTCxDQUFDOztBQWpESCx3RUFrREM7OztBQU9EOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFhLDhDQUErQyxTQUFRLHNCQUFTO0lBTTNFLFlBQ0UsS0FBZ0IsRUFDaEIsRUFBVSxFQUNWLEtBQTBEO1FBRTFELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDakIsTUFBTSxRQUFRLEdBQUcsSUFBSSx3REFBcUMsQ0FDeEQsSUFBSSxFQUNKLFVBQVUsRUFDVixLQUFLLENBQ04sQ0FBQztRQUNGLFFBQVEsQ0FBQyxXQUFXLENBQUMsb0JBQW9CLENBQUM7WUFDeEMsSUFBSSxFQUFFLFNBQVM7U0FDaEIsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLFlBQVksR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDO1FBQzFDLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQztRQUNsQyxJQUFJLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQyxXQUFXLENBQUM7UUFDeEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDO1FBQ2hDLElBQUksQ0FBQyxjQUFjLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQztJQUNoRCxDQUFDOztBQXpCSCx3R0EwQkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEdXJhdGlvbiB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0ICogYXMgZWNzIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQge1xuICBBcHBsaWNhdGlvbkxpc3RlbmVyLFxuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcixcbiAgQXBwbGljYXRpb25UYXJnZXRHcm91cCxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lbGFzdGljbG9hZGJhbGFuY2luZ3YyXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHtcbiAgQXBwbGljYXRpb25Mb2FkQmFsYW5jZWROZXVyb254U2VydmljZSxcbiAgQXBwbGljYXRpb25Mb2FkQmFsYW5jZWROZXVyb254U2VydmljZVByb3BzLFxuICBOZXVyb254VGFza0RlZmluaXRpb24sXG4gIE5ldXJvbnhUYXNrRGVmaW5pdGlvblByb3BzQmFzZSxcbn0gZnJvbSBcIi4uL2Jhc2UvYXdzLWVjcy1wYXR0ZXJuc1wiO1xuaW1wb3J0IHtcbiAgSVZsbG1JbmZlcmVuY2VOZXVyb254SW1hZ2UsXG4gIFZsbG1JbmZlcmVuY2VOZXVyb254SW1hZ2UsXG59IGZyb20gXCIuLi9iYXNlL25ldXJvbnhcIjtcbmltcG9ydCB7IElOZXVyb254Q29udGFpbmVySW1hZ2UgfSBmcm9tIFwiLi4vYmFzZS9uZXVyb254LWNvbXBpbGVyXCI7XG5pbXBvcnQgeyBWbGxtRW5naW5lQXJndW1lbnRzUGFyc2VyIH0gZnJvbSBcIi4uL2Jhc2Uvc2VydmVyLWVuZ2luZS92bGxtLWVuZ2luZVwiO1xuaW1wb3J0IHsgVmxsbU54ZEluZmVyZW5jZUNvbXBpbGVkTW9kZWwgfSBmcm9tIFwiLi92bGxtLW54ZC1pbmZlcmVuY2UtY29tcGlsZXJcIjtcblxuZXhwb3J0IGludGVyZmFjZSBWbGxtTnhkSW5mZXJlbmNlSW1hZ2VPcHRpb25zIHtcbiAgcmVhZG9ubHkgdmxsbUdpdEJyYW5jaD86IHN0cmluZztcbiAgcmVhZG9ubHkgdmxsbUdpdENvbW1pdEhhc2g/OiBzdHJpbmc7XG59XG4vKipcbiAqIEJhc2UgY2xhc3MgZm9yIFZsbG1OeGRJbmZlcmVuY2VJbWFnZS5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFZsbG1OeGRJbmZlcmVuY2VFY3NJbWFnZUJhc2UgaW1wbGVtZW50cyBJTmV1cm9ueENvbnRhaW5lckltYWdlIHtcbiAgLyoqXG4gICAqIFRoZSBjb250YWluZXIgaW1hZ2UuXG4gICAqL1xuICBhYnN0cmFjdCByZWFkb25seSBpbWFnZTogZWNzLkNvbnRhaW5lckltYWdlO1xuICAvKipcbiAgICogVGhlIG5ldXJvbnggU0RLIHZlcnNpb24uXG4gICAqL1xuICByZWFkb25seSBuZXVyb25TZGtWZXJzaW9uOiBzdHJpbmc7XG4gIGNvbnN0cnVjdG9yKG5ldXJvbnhJbWFnZTogSVZsbG1JbmZlcmVuY2VOZXVyb254SW1hZ2UpIHtcbiAgICB0aGlzLm5ldXJvblNka1ZlcnNpb24gPSBuZXVyb254SW1hZ2UubmV1cm9uU2RrVmVyc2lvbjtcbiAgfVxufVxuXG4vKipcbiAqIEluZmVyZW5jZSBFQ1MgY29udGFpbmVyIGltYWdlIGZvciB2TExNIG9uIE54RCBJbmZlcmVuY2UuXG4gKiBUaGlzIGltYWdlIHVzZXMgdGhlIG9mZmljaWFsIEFXUyBOZXVyb24gRGVlcCBMZWFybmluZyBDb250YWluZXJzIHdoaWNoIGNvbWUgd2l0aCB2TExNIHByZS1pbnN0YWxsZWQuXG4gKlxuICogQGV4YW1wbGUgbmV3IFZsbG1OeGRJbmZlcmVuY2VFY3NJbWFnZShWbGxtSW5mZXJlbmNlTmV1cm9ueEltYWdlLkxBVEVTVClcbiAqL1xuZXhwb3J0IGNsYXNzIFZsbG1OeGRJbmZlcmVuY2VFY3NJbWFnZSBleHRlbmRzIFZsbG1OeGRJbmZlcmVuY2VFY3NJbWFnZUJhc2Uge1xuICByZWFkb25seSBpbWFnZTogZWNzLkNvbnRhaW5lckltYWdlO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBWbGxtTnhkSW5mZXJlbmNlSW1hZ2UgZnJvbSBhIGN1c3RvbSBuZXVyb254IGltYWdlLlxuICAgKiBUaGlzIHdpbGwgYnVpbGQgYSBjb250YWluZXIgaW1hZ2UgdXNpbmcgYSBEb2NrZXJmaWxlIHRoYXQgaW5zdGFsbHMgdkxMTSBmcm9tIHNvdXJjZS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogbmV3IFZsbG1OeGRJbmZlcmVuY2VFY3NJbWFnZShWbGxtSW5mZXJlbmNlTmV1cm9ueEltYWdlLkxBVEVTVClcbiAgICovXG4gIGNvbnN0cnVjdG9yKHZsbG1JbmZlcmVuY2VOZXVyb254SW1hZ2U/OiBJVmxsbUluZmVyZW5jZU5ldXJvbnhJbWFnZSkge1xuICAgIHZsbG1JbmZlcmVuY2VOZXVyb254SW1hZ2UgPz89IFZsbG1JbmZlcmVuY2VOZXVyb254SW1hZ2UuTEFURVNUO1xuICAgIHN1cGVyKHZsbG1JbmZlcmVuY2VOZXVyb254SW1hZ2UpO1xuICAgIHRoaXMuaW1hZ2UgPSBlY3MuQ29udGFpbmVySW1hZ2UuZnJvbVJlZ2lzdHJ5KFxuICAgICAgYCR7dmxsbUluZmVyZW5jZU5ldXJvbnhJbWFnZS5pbWFnZU5hbWV9OiR7dmxsbUluZmVyZW5jZU5ldXJvbnhJbWFnZS5pbWFnZVRhZ31gLFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBUYXNrIGRlZmluaXRpb24gZm9yIFZsbG1OeGRJbmZlcmVuY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmxsbU54ZEluZmVyZW5jZVRhc2tEZWZpbml0aW9uUHJvcHMgZXh0ZW5kcyBOZXVyb254VGFza0RlZmluaXRpb25Qcm9wc0Jhc2Uge1xuICAvKipcbiAgICogVGhlIG1vZGVsIHRvIGJlIGNvbXBpbGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgY29tcGlsZWRNb2RlbDogVmxsbU54ZEluZmVyZW5jZUNvbXBpbGVkTW9kZWw7XG4gIC8qKlxuICAgKiBUaGUgaW1hZ2UgdG8gYmUgdXNlZCBmb3IgdGhlIGNvbnRhaW5lci5cbiAgICogQGRlZmF1bHQgLSBsYXRlc3QgVmxsbU54ZEluZmVyZW5jZUltYWdlXG4gICAqL1xuICByZWFkb25seSBpbWFnZT86IFZsbG1OeGRJbmZlcmVuY2VFY3NJbWFnZUJhc2U7XG4gIC8qKlxuICAgKiBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHRvIHBhc3MgdG8gdGhlIGNvbnRhaW5lci5cbiAgICogVGhpcyBpcyBvbmx5IGFwcGxpY2FibGUgd2hlbiB1c2luZyBjb250YWluZXIgcnVudGltZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXG4gICAqL1xuICByZWFkb25seSBlbnZpcm9ubWVudD86IHtcbiAgICBba2V5OiBzdHJpbmddOiBzdHJpbmc7XG4gIH07XG59XG5cbi8qKlxuICogVGFzayBkZWZpbml0aW9uIGZvciBWbGxtTnhkSW5mZXJlbmNlLlxuICovXG5leHBvcnQgY2xhc3MgVmxsbU54ZEluZmVyZW5jZVRhc2tEZWZpbml0aW9uIGV4dGVuZHMgTmV1cm9ueFRhc2tEZWZpbml0aW9uIHtcbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBWbGxtTnhkSW5mZXJlbmNlVGFza0RlZmluaXRpb25Qcm9wcyxcbiAgKSB7XG4gICAgY29uc3QgbmV1cm9ueEluc3RhbmNlVHlwZSA9XG4gICAgICBwcm9wcy5uZXVyb254SW5zdGFuY2VUeXBlID8/IHByb3BzLmNvbXBpbGVkTW9kZWwucmVjb21tZW5kZWRJbnN0YW5jZVR5cGU7XG4gICAgY29uc3QgdGVuc29yUGFyYWxsZWxTaXplID1cbiAgICAgIHByb3BzLmNvbXBpbGVkTW9kZWwudmxsbUFyZ3MudGVuc29yUGFyYWxsZWxTaXplID8/IDE7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICAuLi5wcm9wcyxcbiAgICAgIG5ldXJvbnhJbnN0YW5jZVR5cGUsXG4gICAgICB0ZW5zb3JQYXJhbGxlbFNpemUsXG4gICAgfSk7XG4gICAgY29uc3QgaW1hZ2UgPSBwcm9wcy5pbWFnZSA/PyBuZXcgVmxsbU54ZEluZmVyZW5jZUVjc0ltYWdlKCk7XG4gICAgY29uc3QgcG9ydCA9IHByb3BzLmNvbXBpbGVkTW9kZWwudmxsbUFyZ3MucG9ydCA/PyA4MDAwO1xuICAgIGNvbnN0IHZsbG1DbGlBcmdzID0gVmxsbUVuZ2luZUFyZ3VtZW50c1BhcnNlci5jbGkoXG4gICAgICBwcm9wcy5jb21waWxlZE1vZGVsLnZsbG1BcmdzLFxuICAgICk7XG4gICAgLy8gUHJlcGFyZSBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAgICBjb25zdCBlbnZpcm9ubWVudDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgIC4uLnByb3BzLmVudmlyb25tZW50LFxuICAgICAgVkxMTV9ORVVST05fRlJBTUVXT1JLOiBcIm5ldXJvbngtZGlzdHJpYnV0ZWQtaW5mZXJlbmNlXCIsXG4gICAgICBORVVST05fQ09NUElMRURfQVJUSUZBQ1RTOiBcIm5ldXJvbi1jb21waWxlZC1hcnRpZmFjdHNcIixcbiAgICAgIE5FVVJPTl9SVF9OVU1fQ09SRVM6IHRlbnNvclBhcmFsbGVsU2l6ZS50b1N0cmluZygpLFxuICAgICAgWExBX0hBTkRMRV9TUEVDSUFMX1NDQUxBUjogXCIxXCIsXG4gICAgICBNT0RFTF9OQU1FOiBwcm9wcy5jb21waWxlZE1vZGVsLm1vZGVsTmFtZSxcbiAgICB9O1xuXG4gICAgdGhpcy5hZGRDb250YWluZXJXaXRoRGVmYXVsdChcInZMTE1cIiwge1xuICAgICAgaW1hZ2U6IGltYWdlLmltYWdlLFxuICAgICAgcG9ydE1hcHBpbmdzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBjb250YWluZXJQb3J0OiBwb3J0LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIGhlYWx0aENoZWNrOiB7XG4gICAgICAgIGNvbW1hbmQ6IFtcbiAgICAgICAgICBcIkNNRC1TSEVMTFwiLFxuICAgICAgICAgIGBjdXJsIC1mIGh0dHA6Ly9sb2NhbGhvc3Q6JHtwb3J0fS9oZWFsdGggfHwgZXhpdCAxYCxcbiAgICAgICAgXSxcbiAgICAgICAgc3RhcnRQZXJpb2Q6IER1cmF0aW9uLm1pbnV0ZXMoNSksXG4gICAgICB9LFxuICAgICAgd29ya2luZ0RpcmVjdG9yeTogYC9vcHQvbWwvbW9kZWwvJHtwcm9wcy5jb21waWxlZE1vZGVsLnMzUHJlZml4fWAsXG4gICAgICBlbnRyeVBvaW50OiBbXCJ2bGxtXCIsIFwic2VydmVcIl0sXG4gICAgICBjb21tYW5kOiB2bGxtQ2xpQXJncyxcbiAgICAgIGVudmlyb25tZW50LFxuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogUHJvcHMgZm9yIEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VkVmxsbU54REluZmVyZW5jZVNlcnZpY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRWbGxtTnhESW5mZXJlbmNlU2VydmljZVByb3BzIGV4dGVuZHMgQXBwbGljYXRpb25Mb2FkQmFsYW5jZWROZXVyb254U2VydmljZVByb3BzIHt9XG5cbi8qKlxuICogQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRWbGxtTnhESW5mZXJlbmNlU2VydmljZSBpcyBhIHdyYXBwZXIgb2YgQXBwbGljYXRpb25Mb2FkQmFsYW5jZWROZXVyb254U2VydmljZUJhc2UuXG4gKiBJdCBwcm92aWRlcyBhIHNpbXBsZSB3YXkgdG8gZGVwbG95IHZMTE0gb24gTnhEIEluZmVyZW5jZS5cbiAqIEBleGFtcGxlXG4gKiBjb25zdCBjb21waWxlciA9IG5ldyBWbGxtTnhkSW5mZXJlbmNlQ29tcGlsZXIodGhpcywgXCJDb21waWxlclwiLCB7XG4gKiAgIHZwYyxcbiAqICAgYnVja2V0LFxuICogICBtb2RlbDogTW9kZWwuZnJvbUh1Z2dpbmdGYWNlKFwiZXhhbXBsZS9leGFtcGxlLTdiLWNoYXRcIiksXG4gKiB9KTtcbiAqIGNvbnN0IGNvbXBpbGVkTW9kZWwgPSBjb21waWxlci5jb21waWxlKCk7XG4gKiBjb25zdCB0YXNrRGVmaW5pdGlvbiA9IG5ldyBWbGxtTnhkSW5mZXJlbmNlVGFza0RlZmluaXRpb24oXG4gKiAgIHRoaXMsXG4gKiAgIFwiVGFza0RlZmluaXRpb25cIixcbiAqICAge1xuICogICAgIHZwYyxcbiAqICAgICBjb21waWxlZE1vZGVsLFxuICogICB9LFxuICogKTtcbiAqIG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZFZsbG1OeERJbmZlcmVuY2VTZXJ2aWNlKHRoaXMsIFwiU2VydmljZVwiLCB7XG4gKiAgIHRhc2tEZWZpbml0aW9uLFxuICogfSk7XG4gKi9cbmV4cG9ydCBjbGFzcyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZFZsbG1OeERJbmZlcmVuY2VTZXJ2aWNlIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgcmVhZG9ubHkgbG9hZEJhbGFuY2VyOiBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcjtcbiAgcmVhZG9ubHkgbGlzdGVuZXI6IEFwcGxpY2F0aW9uTGlzdGVuZXI7XG4gIHJlYWRvbmx5IHRhcmdldEdyb3VwOiBBcHBsaWNhdGlvblRhcmdldEdyb3VwO1xuICByZWFkb25seSBzZXJ2aWNlOiBlY3MuRWMyU2VydmljZTtcbiAgcmVhZG9ubHkgdGFza0RlZmluaXRpb246IGVjcy5FYzJUYXNrRGVmaW5pdGlvbjtcbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZFZsbG1OeERJbmZlcmVuY2VTZXJ2aWNlUHJvcHMsXG4gICkge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgY29uc3QgcmVzb3VyY2UgPSBuZXcgQXBwbGljYXRpb25Mb2FkQmFsYW5jZWROZXVyb254U2VydmljZShcbiAgICAgIHRoaXMsXG4gICAgICBcIlJlc291cmNlXCIsXG4gICAgICBwcm9wcyxcbiAgICApO1xuICAgIHJlc291cmNlLnRhcmdldEdyb3VwLmNvbmZpZ3VyZUhlYWx0aENoZWNrKHtcbiAgICAgIHBhdGg6IFwiL2hlYWx0aFwiLFxuICAgIH0pO1xuICAgIHRoaXMubG9hZEJhbGFuY2VyID0gcmVzb3VyY2UubG9hZEJhbGFuY2VyO1xuICAgIHRoaXMubGlzdGVuZXIgPSByZXNvdXJjZS5saXN0ZW5lcjtcbiAgICB0aGlzLnRhcmdldEdyb3VwID0gcmVzb3VyY2UudGFyZ2V0R3JvdXA7XG4gICAgdGhpcy5zZXJ2aWNlID0gcmVzb3VyY2Uuc2VydmljZTtcbiAgICB0aGlzLnRhc2tEZWZpbml0aW9uID0gcmVzb3VyY2UudGFza0RlZmluaXRpb247XG4gIH1cbn1cbiJdfQ==