/** * @license * Copyright 2018 Google LLC * * Use of this source code is governed by an MIT-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT. * ============================================================================= */ /** * TensorFlow.js Layers: Convolutional Layers */ import * as tfc from '@tensorflow/tfjs-core'; import { serialization, tidy } from '@tensorflow/tfjs-core'; import { getActivation, serializeActivation } from '../activations'; import { imageDataFormat } from '../backend/common'; import * as K from '../backend/tfjs_backend'; import { checkDataFormat, checkInterpolationFormat, checkPaddingMode } from '../common'; import { getConstraint, serializeConstraint } from '../constraints'; import { InputSpec, Layer } from '../engine/topology'; import { NotImplementedError, ValueError } from '../errors'; import { getInitializer, serializeInitializer } from '../initializers'; import { getRegularizer, serializeRegularizer } from '../regularizers'; import { convOutputLength, deconvLength, normalizeArray } from '../utils/conv_utils'; import * as generic_utils from '../utils/generic_utils'; import { getExactlyOneShape, getExactlyOneTensor } from '../utils/types_utils'; /** * Transpose and cast the input before the conv2d. * @param x Input image tensor. * @param dataFormat */ export function preprocessConv2DInput(x, dataFormat) { // TODO(cais): Cast type to float32 if not. return tidy(() => { checkDataFormat(dataFormat); if (dataFormat === 'channelsFirst') { return tfc.transpose(x, [0, 2, 3, 1]); // NCHW -> NHWC. } else { return x; } }); } /** * Transpose and cast the input before the conv3d. * @param x Input image tensor. * @param dataFormat */ export function preprocessConv3DInput(x, dataFormat) { return tidy(() => { checkDataFormat(dataFormat); if (dataFormat === 'channelsFirst') { return tfc.transpose(x, [0, 2, 3, 4, 1]); // NCDHW -> NDHWC. } else { return x; } }); } /** * 1D-convolution with bias added. * * Porting Note: This function does not exist in the Python Keras backend. * It is exactly the same as `conv2d`, except the added `bias`. * * @param x Input tensor, rank-3, of shape `[batchSize, width, inChannels]`. * @param kernel Kernel, rank-3, of shape `[filterWidth, inDepth, outDepth]`. * @param bias Bias, rank-3, of shape `[outDepth]`. * @param strides * @param padding Padding mode. * @param dataFormat Data format. * @param dilationRate * @returns The result of the 1D convolution. * @throws ValueError, if `x`, `kernel` or `bias` is not of the correct rank. */ export function conv1dWithBias(x, kernel, bias, strides = 1, padding = 'valid', dataFormat, dilationRate = 1) { return tidy(() => { if (dataFormat == null) { dataFormat = imageDataFormat(); } checkDataFormat(dataFormat); // Check the ranks of x, kernel and bias. if (x.shape.length !== 3) { throw new ValueError(`The input of a conv1dWithBias operation should be 3, but is ` + `${x.shape.length} instead.`); } if (kernel.shape.length !== 3) { throw new ValueError(`The kernel for a conv1dWithBias operation should be 3, but is ` + `${kernel.shape.length} instead`); } if (bias != null && bias.shape.length !== 1) { throw new ValueError(`The bias for a conv1dWithBias operation should be 1, but is ` + `${kernel.shape.length} instead`); } // TODO(cais): Support CAUSAL padding mode. if (dataFormat === 'channelsFirst') { x = tfc.transpose(x, [0, 2, 1]); // NCW -> NWC. } if (padding === 'causal') { throw new NotImplementedError('The support for CAUSAL padding mode in conv1dWithBias is not ' + 'implemented yet.'); } let y = tfc.conv1d(x, kernel, strides, padding === 'same' ? 'same' : 'valid', 'NWC', dilationRate); if (bias != null) { y = K.biasAdd(y, bias); } return y; }); } /** * 1D-convolution. * * @param x Input tensor, rank-3, of shape `[batchSize, width, inChannels]`. * @param kernel Kernel, rank-3, of shape `[filterWidth, inDepth, outDepth]`.s * @param strides * @param padding Padding mode. * @param dataFormat Data format. * @param dilationRate * @returns The result of the 1D convolution. * @throws ValueError, if `x`, `kernel` or `bias` is not of the correct rank. */ export function conv1d(x, kernel, strides = 1, padding = 'valid', dataFormat, dilationRate = 1) { return tidy(() => { checkDataFormat(dataFormat); return conv1dWithBias(x, kernel, null, strides, padding, dataFormat, dilationRate); }); } /** * 2D Convolution * @param x * @param kernel kernel of the convolution. * @param strides strides array. * @param padding padding mode. Default to 'valid'. * @param dataFormat data format. Defaults to 'channelsLast'. * @param dilationRate dilation rate array. * @returns Result of the 2D pooling. */ export function conv2d(x, kernel, strides = [1, 1], padding = 'valid', dataFormat, dilationRate) { return tidy(() => { checkDataFormat(dataFormat); return conv2dWithBiasActivation(x, kernel, null, strides, padding, dataFormat, dilationRate); }); } /** * 2D Convolution with an added bias and optional activation. * Note: This function does not exist in the Python Keras Backend. This function * is exactly the same as `conv2d`, except the added `bias`. */ export function conv2dWithBiasActivation(x, kernel, bias, strides = [1, 1], padding = 'valid', dataFormat, dilationRate, activation = null) { return tidy(() => { if (dataFormat == null) { dataFormat = imageDataFormat(); } checkDataFormat(dataFormat); if (x.rank !== 3 && x.rank !== 4) { throw new ValueError(`conv2dWithBiasActivation expects input to be of rank 3 or 4, ` + `but received ${x.rank}.`); } if (kernel.rank !== 3 && kernel.rank !== 4) { throw new ValueError(`conv2dWithBiasActivation expects kernel to be of rank 3 or 4, ` + `but received ${x.rank}.`); } let y = preprocessConv2DInput(x, dataFormat); if (padding === 'causal') { throw new NotImplementedError('The support for CAUSAL padding mode in conv1dWithBias is not ' + 'implemented yet.'); } y = tfc.fused.conv2d({ x: y, filter: kernel, strides: strides, pad: padding === 'same' ? 'same' : 'valid', dilations: dilationRate, dataFormat: 'NHWC', bias, activation }); if (dataFormat === 'channelsFirst') { y = tfc.transpose(y, [0, 3, 1, 2]); } return y; }); } /** * 3D Convolution. * @param x * @param kernel kernel of the convolution. * @param strides strides array. * @param padding padding mode. Default to 'valid'. * @param dataFormat data format. Defaults to 'channelsLast'. * @param dilationRate dilation rate array. * @returns Result of the 3D convolution. */ export function conv3d(x, kernel, strides = [1, 1, 1], padding = 'valid', dataFormat, dilationRate) { return tidy(() => { checkDataFormat(dataFormat); return conv3dWithBias(x, kernel, null, strides, padding, dataFormat, dilationRate); }); } /** * 3D Convolution with an added bias. * Note: This function does not exist in the Python Keras Backend. This function * is exactly the same as `conv3d`, except the added `bias`. */ export function conv3dWithBias(x, kernel, bias, strides = [1, 1, 1], padding = 'valid', dataFormat, dilationRate) { return tidy(() => { if (dataFormat == null) { dataFormat = imageDataFormat(); } checkDataFormat(dataFormat); if (x.rank !== 4 && x.rank !== 5) { throw new ValueError(`conv3dWithBias expects input to be of rank 4 or 5, but received ` + `${x.rank}.`); } if (kernel.rank !== 4 && kernel.rank !== 5) { throw new ValueError(`conv3dWithBias expects kernel to be of rank 4 or 5, but received ` + `${x.rank}.`); } let y = preprocessConv3DInput(x, dataFormat); if (padding === 'causal') { throw new NotImplementedError('The support for CAUSAL padding mode in conv3dWithBias is not ' + 'implemented yet.'); } y = tfc.conv3d(y, kernel, strides, padding === 'same' ? 'same' : 'valid', 'NDHWC', dilationRate); if (bias != null) { y = K.biasAdd(y, bias); } if (dataFormat === 'channelsFirst') { y = tfc.transpose(y, [0, 4, 1, 2, 3]); } return y; }); } /** * Abstract convolution layer. */ export class BaseConv extends Layer { constructor(rank, args) { super(args); this.bias = null; this.DEFAULT_KERNEL_INITIALIZER = 'glorotNormal'; this.DEFAULT_BIAS_INITIALIZER = 'zeros'; BaseConv.verifyArgs(args); this.rank = rank; generic_utils.assertPositiveInteger(this.rank, 'rank'); if (this.rank !== 1 && this.rank !== 2 && this.rank !== 3) { throw new NotImplementedError(`Convolution layer for rank other than 1, 2, or 3 (${this.rank}) is ` + `not implemented yet.`); } this.kernelSize = normalizeArray(args.kernelSize, rank, 'kernelSize'); this.strides = normalizeArray(args.strides == null ? 1 : args.strides, rank, 'strides'); this.padding = args.padding == null ? 'valid' : args.padding; checkPaddingMode(this.padding); this.dataFormat = args.dataFormat == null ? 'channelsLast' : args.dataFormat; checkDataFormat(this.dataFormat); this.activation = getActivation(args.activation); this.useBias = args.useBias == null ? true : args.useBias; this.biasInitializer = getInitializer(args.biasInitializer || this.DEFAULT_BIAS_INITIALIZER); this.biasConstraint = getConstraint(args.biasConstraint); this.biasRegularizer = getRegularizer(args.biasRegularizer); this.activityRegularizer = getRegularizer(args.activityRegularizer); this.dilationRate = normalizeArray(args.dilationRate == null ? 1 : args.dilationRate, rank, 'dilationRate'); if (this.rank === 1 && (Array.isArray(this.dilationRate) && this.dilationRate.length !== 1)) { throw new ValueError(`dilationRate must be a number or an array of a single number ` + `for 1D convolution, but received ` + `${JSON.stringify(this.dilationRate)}`); } else if (this.rank === 2) { if (typeof this.dilationRate === 'number') { this.dilationRate = [this.dilationRate, this.dilationRate]; } else if (this.dilationRate.length !== 2) { throw new ValueError(`dilationRate must be a number or array of two numbers for 2D ` + `convolution, but received ${JSON.stringify(this.dilationRate)}`); } } else if (this.rank === 3) { if (typeof this.dilationRate === 'number') { this.dilationRate = [this.dilationRate, this.dilationRate, this.dilationRate]; } else if (this.dilationRate.length !== 3) { throw new ValueError(`dilationRate must be a number or array of three numbers for 3D ` + `convolution, but received ${JSON.stringify(this.dilationRate)}`); } } } static verifyArgs(args) { // Check config.kernelSize type and shape. generic_utils.assert('kernelSize' in args, `required key 'kernelSize' not in config`); if (typeof args.kernelSize !== 'number' && !generic_utils.checkArrayTypeAndLength(args.kernelSize, 'number', 1, 3)) { throw new ValueError(`BaseConv expects config.kernelSize to be number or number[] with ` + `length 1, 2, or 3, but received ${JSON.stringify(args.kernelSize)}.`); } } getConfig() { const config = { kernelSize: this.kernelSize, strides: this.strides, padding: this.padding, dataFormat: this.dataFormat, dilationRate: this.dilationRate, activation: serializeActivation(this.activation), useBias: this.useBias, biasInitializer: serializeInitializer(this.biasInitializer), biasRegularizer: serializeRegularizer(this.biasRegularizer), activityRegularizer: serializeRegularizer(this.activityRegularizer), biasConstraint: serializeConstraint(this.biasConstraint) }; const baseConfig = super.getConfig(); Object.assign(config, baseConfig); return config; } } /** * Abstract nD convolution layer. Ancestor of convolution layers which reduce * across channels, i.e., Conv1D and Conv2D, but not DepthwiseConv2D. */ export class Conv extends BaseConv { constructor(rank, args) { super(rank, args); this.kernel = null; Conv.verifyArgs(args); this.filters = args.filters; generic_utils.assertPositiveInteger(this.filters, 'filters'); this.kernelInitializer = getInitializer(args.kernelInitializer || this.DEFAULT_KERNEL_INITIALIZER); this.kernelConstraint = getConstraint(args.kernelConstraint); this.kernelRegularizer = getRegularizer(args.kernelRegularizer); } build(inputShape) { inputShape = getExactlyOneShape(inputShape); const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1; if (inputShape[channelAxis] == null) { throw new ValueError(`The channel dimension of the input should be defined. ` + `Found ${inputShape[channelAxis]}`); } const inputDim = inputShape[channelAxis]; const kernelShape = this.kernelSize.concat([inputDim, this.filters]); this.kernel = this.addWeight('kernel', kernelShape, null, this.kernelInitializer, this.kernelRegularizer, true, this.kernelConstraint); if (this.useBias) { this.bias = this.addWeight('bias', [this.filters], null, this.biasInitializer, this.biasRegularizer, true, this.biasConstraint); } this.inputSpec = [{ ndim: this.rank + 2, axes: { [channelAxis]: inputDim } }]; this.built = true; } call(inputs, kwargs) { return tidy(() => { inputs = getExactlyOneTensor(inputs); let outputs; const biasValue = this.bias == null ? null : this.bias.read(); const fusedActivationName = generic_utils.mapActivationToFusedKernel(this.activation.getClassName()); if (fusedActivationName != null && this.rank === 2) { outputs = conv2dWithBiasActivation(inputs, this.kernel.read(), biasValue, this.strides, this.padding, this.dataFormat, this.dilationRate, fusedActivationName); } else { if (this.rank === 1) { outputs = conv1dWithBias(inputs, this.kernel.read(), biasValue, this.strides[0], this.padding, this.dataFormat, this.dilationRate[0]); } else if (this.rank === 2) { // TODO(cais): Move up to constructor. outputs = conv2dWithBiasActivation(inputs, this.kernel.read(), biasValue, this.strides, this.padding, this.dataFormat, this.dilationRate); } else if (this.rank === 3) { outputs = conv3dWithBias(inputs, this.kernel.read(), biasValue, this.strides, this.padding, this.dataFormat, this.dilationRate); } else { throw new NotImplementedError('convolutions greater than 3D are not implemented yet.'); } if (this.activation != null) { outputs = this.activation.apply(outputs); } } return outputs; }); } computeOutputShape(inputShape) { inputShape = getExactlyOneShape(inputShape); const newSpace = []; const space = (this.dataFormat === 'channelsLast') ? inputShape.slice(1, inputShape.length - 1) : inputShape.slice(2); for (let i = 0; i < space.length; ++i) { const newDim = convOutputLength(space[i], this.kernelSize[i], this.padding, this.strides[i], typeof this.dilationRate === 'number' ? this.dilationRate : this.dilationRate[i]); newSpace.push(newDim); } let outputShape = [inputShape[0]]; if (this.dataFormat === 'channelsLast') { outputShape = outputShape.concat(newSpace); outputShape.push(this.filters); } else { outputShape.push(this.filters); outputShape = outputShape.concat(newSpace); } return outputShape; } getConfig() { const config = { filters: this.filters, kernelInitializer: serializeInitializer(this.kernelInitializer), kernelRegularizer: serializeRegularizer(this.kernelRegularizer), kernelConstraint: serializeConstraint(this.kernelConstraint) }; const baseConfig = super.getConfig(); Object.assign(config, baseConfig); return config; } static verifyArgs(args) { // Check config.filters type, shape, and value. if (!('filters' in args) || typeof args.filters !== 'number' || args.filters < 1) { throw new ValueError(`Convolution layer expected config.filters to be a 'number' > 0 ` + `but got ${JSON.stringify(args.filters)}`); } } } class Conv2D extends Conv { constructor(args) { super(2, args); Conv2D.verifyArgs(args); } getConfig() { const config = super.getConfig(); delete config['rank']; return config; } static verifyArgs(args) { // config.kernelSize must be a number or array of numbers. if ((typeof args.kernelSize !== 'number') && !generic_utils.checkArrayTypeAndLength(args.kernelSize, 'number', 1, 2)) { throw new ValueError(`Conv2D expects config.kernelSize to be number or number[] with ` + `length 1 or 2, but received ${JSON.stringify(args.kernelSize)}.`); } } } /** @nocollapse */ Conv2D.className = 'Conv2D'; export { Conv2D }; serialization.registerClass(Conv2D); class Conv3D extends Conv { constructor(args) { super(3, args); Conv3D.verifyArgs(args); } getConfig() { const config = super.getConfig(); delete config['rank']; return config; } static verifyArgs(args) { // config.kernelSize must be a number or array of numbers. if (typeof args.kernelSize !== 'number') { if (!(Array.isArray(args.kernelSize) && (args.kernelSize.length === 1 || args.kernelSize.length === 3))) { throw new ValueError(`Conv3D expects config.kernelSize to be number or` + ` [number, number, number], but received ${JSON.stringify(args.kernelSize)}.`); } } } } /** @nocollapse */ Conv3D.className = 'Conv3D'; export { Conv3D }; serialization.registerClass(Conv3D); class Conv2DTranspose extends Conv2D { constructor(args) { super(args); this.inputSpec = [new InputSpec({ ndim: 4 })]; if (this.padding !== 'same' && this.padding !== 'valid') { throw new ValueError(`Conv2DTranspose currently supports only padding modes 'same' ` + `and 'valid', but received padding mode ${this.padding}`); } } build(inputShape) { inputShape = getExactlyOneShape(inputShape); if (inputShape.length !== 4) { throw new ValueError('Input should have rank 4; Received input shape: ' + JSON.stringify(inputShape)); } const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1; if (inputShape[channelAxis] == null) { throw new ValueError('The channel dimension of the inputs should be defined. ' + 'Found `None`.'); } const inputDim = inputShape[channelAxis]; const kernelShape = this.kernelSize.concat([this.filters, inputDim]); this.kernel = this.addWeight('kernel', kernelShape, 'float32', this.kernelInitializer, this.kernelRegularizer, true, this.kernelConstraint); if (this.useBias) { this.bias = this.addWeight('bias', [this.filters], 'float32', this.biasInitializer, this.biasRegularizer, true, this.biasConstraint); } // Set input spec. this.inputSpec = [new InputSpec({ ndim: 4, axes: { [channelAxis]: inputDim } })]; this.built = true; } call(inputs, kwargs) { return tfc.tidy(() => { let input = getExactlyOneTensor(inputs); if (input.shape.length !== 4) { throw new ValueError(`Conv2DTranspose.call() expects input tensor to be rank-4, but ` + `received a tensor of rank-${input.shape.length}`); } const inputShape = input.shape; const batchSize = inputShape[0]; let hAxis; let wAxis; if (this.dataFormat === 'channelsFirst') { hAxis = 2; wAxis = 3; } else { hAxis = 1; wAxis = 2; } const height = inputShape[hAxis]; const width = inputShape[wAxis]; const kernelH = this.kernelSize[0]; const kernelW = this.kernelSize[1]; const strideH = this.strides[0]; const strideW = this.strides[1]; // Infer the dynamic output shape. const outHeight = deconvLength(height, strideH, kernelH, this.padding); const outWidth = deconvLength(width, strideW, kernelW, this.padding); // Porting Note: We don't branch based on `this.dataFormat` here, // because // the tjfs-core function `conv2dTranspose` called below always // assumes channelsLast. const outputShape = [batchSize, outHeight, outWidth, this.filters]; if (this.dataFormat !== 'channelsLast') { input = tfc.transpose(input, [0, 2, 3, 1]); } let outputs = tfc.conv2dTranspose(input, this.kernel.read(), outputShape, this.strides, this.padding); if (this.dataFormat !== 'channelsLast') { outputs = tfc.transpose(outputs, [0, 3, 1, 2]); } if (this.bias != null) { outputs = K.biasAdd(outputs, this.bias.read(), this.dataFormat); } if (this.activation != null) { outputs = this.activation.apply(outputs); } return outputs; }); } computeOutputShape(inputShape) { inputShape = getExactlyOneShape(inputShape); const outputShape = inputShape.slice(); let channelAxis; let heightAxis; let widthAxis; if (this.dataFormat === 'channelsFirst') { channelAxis = 1; heightAxis = 2; widthAxis = 3; } else { channelAxis = 3; heightAxis = 1; widthAxis = 2; } const kernelH = this.kernelSize[0]; const kernelW = this.kernelSize[1]; const strideH = this.strides[0]; const strideW = this.strides[1]; outputShape[channelAxis] = this.filters; outputShape[heightAxis] = deconvLength(outputShape[heightAxis], strideH, kernelH, this.padding); outputShape[widthAxis] = deconvLength(outputShape[widthAxis], strideW, kernelW, this.padding); return outputShape; } getConfig() { const config = super.getConfig(); delete config['dilationRate']; return config; } } /** @nocollapse */ Conv2DTranspose.className = 'Conv2DTranspose'; export { Conv2DTranspose }; serialization.registerClass(Conv2DTranspose); class Conv3DTranspose extends Conv3D { constructor(args) { super(args); this.inputSpec = [new InputSpec({ ndim: 5 })]; if (this.padding !== 'same' && this.padding !== 'valid') { throw new ValueError(`Conv3DTranspose currently supports only padding modes 'same' ` + `and 'valid', but received padding mode ${this.padding}`); } } build(inputShape) { inputShape = getExactlyOneShape(inputShape); if (inputShape.length !== 5) { throw new ValueError('Input should have rank 5; Received input shape: ' + JSON.stringify(inputShape)); } const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1; if (inputShape[channelAxis] == null) { throw new ValueError('The channel dimension of the inputs should be defined. ' + 'Found `None`.'); } const inputDim = inputShape[channelAxis]; const kernelShape = this.kernelSize.concat([this.filters, inputDim]); this.kernel = this.addWeight('kernel', kernelShape, 'float32', this.kernelInitializer, this.kernelRegularizer, true, this.kernelConstraint); if (this.useBias) { this.bias = this.addWeight('bias', [this.filters], 'float32', this.biasInitializer, this.biasRegularizer, true, this.biasConstraint); } // Set input spec. this.inputSpec = [new InputSpec({ ndim: 5, axes: { [channelAxis]: inputDim } })]; this.built = true; } call(inputs, kwargs) { return tfc.tidy(() => { let input = getExactlyOneTensor(inputs); if (input.shape.length !== 5) { throw new ValueError(`Conv3DTranspose.call() expects input tensor to be rank-4, but ` + `received a tensor of rank-${input.shape.length}`); } const inputShape = input.shape; const batchSize = inputShape[0]; let hAxis; let wAxis; let dAxis; if (this.dataFormat === 'channelsFirst') { dAxis = 2; hAxis = 3; wAxis = 4; } else { dAxis = 1; hAxis = 2; wAxis = 3; } const depth = inputShape[dAxis]; const height = inputShape[hAxis]; const width = inputShape[wAxis]; const kernelD = this.kernelSize[0]; const kernelH = this.kernelSize[1]; const kernelW = this.kernelSize[2]; const strideD = this.strides[0]; const strideH = this.strides[1]; const strideW = this.strides[2]; // Infer the dynamic output shape. const outDepth = deconvLength(depth, strideD, kernelD, this.padding); const outHeight = deconvLength(height, strideH, kernelH, this.padding); const outWidth = deconvLength(width, strideW, kernelW, this.padding); // Same as `conv2dTranspose`. We always assumes channelsLast. const outputShape = [batchSize, outDepth, outHeight, outWidth, this.filters]; if (this.dataFormat !== 'channelsLast') { input = tfc.transpose(input, [0, 2, 3, 4, 1]); } let outputs = tfc.conv3dTranspose(input, this.kernel.read(), outputShape, this.strides, this.padding); if (this.dataFormat !== 'channelsLast') { outputs = tfc.transpose(outputs, [0, 4, 1, 2, 3]); } if (this.bias !== null) { outputs = K.biasAdd(outputs, this.bias.read(), this.dataFormat); } if (this.activation !== null) { outputs = this.activation.apply(outputs); } return outputs; }); } computeOutputShape(inputShape) { inputShape = getExactlyOneShape(inputShape); const outputShape = inputShape.slice(); let channelAxis; let depthAxis; let heightAxis; let widthAxis; if (this.dataFormat === 'channelsFirst') { channelAxis = 1; depthAxis = 2; heightAxis = 3; widthAxis = 4; } else { channelAxis = 4; depthAxis = 1; heightAxis = 2; widthAxis = 3; } const kernelD = this.kernelSize[0]; const kernelH = this.kernelSize[1]; const kernelW = this.kernelSize[2]; const strideD = this.strides[0]; const strideH = this.strides[1]; const strideW = this.strides[2]; outputShape[channelAxis] = this.filters; outputShape[depthAxis] = deconvLength(outputShape[depthAxis], strideD, kernelD, this.padding); outputShape[heightAxis] = deconvLength(outputShape[heightAxis], strideH, kernelH, this.padding); outputShape[widthAxis] = deconvLength(outputShape[widthAxis], strideW, kernelW, this.padding); return outputShape; } getConfig() { const config = super.getConfig(); delete config['dilationRate']; return config; } } /** @nocollapse */ Conv3DTranspose.className = 'Conv3DTranspose'; export { Conv3DTranspose }; serialization.registerClass(Conv3DTranspose); class SeparableConv extends Conv { constructor(rank, config) { super(rank, config); this.DEFAULT_DEPTHWISE_INITIALIZER = 'glorotUniform'; this.DEFAULT_POINTWISE_INITIALIZER = 'glorotUniform'; this.depthwiseKernel = null; this.pointwiseKernel = null; if (config.filters == null) { throw new ValueError('The `filters` configuration field is required by SeparableConv, ' + 'but is unspecified.'); } if (config.kernelInitializer != null || config.kernelRegularizer != null || config.kernelConstraint != null) { throw new ValueError('Fields kernelInitializer, kernelRegularizer and kernelConstraint ' + 'are invalid for SeparableConv2D. Use depthwiseInitializer, ' + 'depthwiseRegularizer, depthwiseConstraint, pointwiseInitializer, ' + 'pointwiseRegularizer and pointwiseConstraint instead.'); } if (config.padding != null && config.padding !== 'same' && config.padding !== 'valid') { throw new ValueError(`SeparableConv${this.rank}D supports only padding modes: ` + `'same' and 'valid', but received ${JSON.stringify(config.padding)}`); } this.depthMultiplier = config.depthMultiplier == null ? 1 : config.depthMultiplier; this.depthwiseInitializer = getInitializer(config.depthwiseInitializer || this.DEFAULT_DEPTHWISE_INITIALIZER); this.depthwiseRegularizer = getRegularizer(config.depthwiseRegularizer); this.depthwiseConstraint = getConstraint(config.depthwiseConstraint); this.pointwiseInitializer = getInitializer(config.depthwiseInitializer || this.DEFAULT_POINTWISE_INITIALIZER); this.pointwiseRegularizer = getRegularizer(config.pointwiseRegularizer); this.pointwiseConstraint = getConstraint(config.pointwiseConstraint); } build(inputShape) { inputShape = getExactlyOneShape(inputShape); if (inputShape.length < this.rank + 2) { throw new ValueError(`Inputs to SeparableConv${this.rank}D should have rank ` + `${this.rank + 2}, but received input shape: ` + `${JSON.stringify(inputShape)}`); } const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1; if (inputShape[channelAxis] == null || inputShape[channelAxis] < 0) { throw new ValueError(`The channel dimension of the inputs should be defined, ` + `but found ${JSON.stringify(inputShape[channelAxis])}`); } const inputDim = inputShape[channelAxis]; const depthwiseKernelShape = this.kernelSize.concat([inputDim, this.depthMultiplier]); const pointwiseKernelShape = []; for (let i = 0; i < this.rank; ++i) { pointwiseKernelShape.push(1); } pointwiseKernelShape.push(inputDim * this.depthMultiplier, this.filters); const trainable = true; this.depthwiseKernel = this.addWeight('depthwise_kernel', depthwiseKernelShape, 'float32', this.depthwiseInitializer, this.depthwiseRegularizer, trainable, this.depthwiseConstraint); this.pointwiseKernel = this.addWeight('pointwise_kernel', pointwiseKernelShape, 'float32', this.pointwiseInitializer, this.pointwiseRegularizer, trainable, this.pointwiseConstraint); if (this.useBias) { this.bias = this.addWeight('bias', [this.filters], 'float32', this.biasInitializer, this.biasRegularizer, trainable, this.biasConstraint); } else { this.bias = null; } this.inputSpec = [new InputSpec({ ndim: this.rank + 2, axes: { [channelAxis]: inputDim } })]; this.built = true; } call(inputs, kwargs) { return tidy(() => { inputs = getExactlyOneTensor(inputs); let output; if (this.rank === 1) { throw new NotImplementedError('1D separable convolution is not implemented yet.'); } else if (this.rank === 2) { if (this.dataFormat === 'channelsFirst') { inputs = tfc.transpose(inputs, [0, 2, 3, 1]); // NCHW -> NHWC. } output = tfc.separableConv2d(inputs, this.depthwiseKernel.read(), this.pointwiseKernel.read(), this.strides, this.padding, this.dilationRate, 'NHWC'); } if (this.useBias) { output = K.biasAdd(output, this.bias.read(), this.dataFormat); } if (this.activation != null) { output = this.activation.apply(output); } if (this.dataFormat === 'channelsFirst') { output = tfc.transpose(output, [0, 3, 1, 2]); // NHWC -> NCHW. } return output; }); } getConfig() { const config = super.getConfig(); delete config['rank']; delete config['kernelInitializer']; delete config['kernelRegularizer']; delete config['kernelConstraint']; config['depthwiseInitializer'] = serializeInitializer(this.depthwiseInitializer); config['pointwiseInitializer'] = serializeInitializer(this.pointwiseInitializer); config['depthwiseRegularizer'] = serializeRegularizer(this.depthwiseRegularizer); config['pointwiseRegularizer'] = serializeRegularizer(this.pointwiseRegularizer); config['depthwiseConstraint'] = serializeConstraint(this.depthwiseConstraint); config['pointwiseConstraint'] = serializeConstraint(this.pointwiseConstraint); return config; } } /** @nocollapse */ SeparableConv.className = 'SeparableConv'; export { SeparableConv }; class SeparableConv2D extends SeparableConv { constructor(args) { super(2, args); } } /** @nocollapse */ SeparableConv2D.className = 'SeparableConv2D'; export { SeparableConv2D }; serialization.registerClass(SeparableConv2D); class Conv1D extends Conv { constructor(args) { super(1, args); Conv1D.verifyArgs(args); this.inputSpec = [{ ndim: 3 }]; } getConfig() { const config = super.getConfig(); delete config['rank']; delete config['dataFormat']; return config; } static verifyArgs(args) { // config.kernelSize must be a number or array of numbers. if (typeof args.kernelSize !== 'number' && !generic_utils.checkArrayTypeAndLength(args.kernelSize, 'number', 1, 1)) { throw new ValueError(`Conv1D expects config.kernelSize to be number or number[] with ` + `length 1, but received ${JSON.stringify(args.kernelSize)}.`); } } } /** @nocollapse */ Conv1D.className = 'Conv1D'; export { Conv1D }; serialization.registerClass(Conv1D); class Cropping2D extends Layer { constructor(args) { super(args); if (typeof args.cropping === 'number') { this.cropping = [[args.cropping, args.cropping], [args.cropping, args.cropping]]; } else if (typeof args.cropping[0] === 'number') { this.cropping = [ [args.cropping[0], args.cropping[0]], [args.cropping[1], args.cropping[1]] ]; } else { this.cropping = args.cropping; } this.dataFormat = args.dataFormat === undefined ? 'channelsLast' : args.dataFormat; this.inputSpec = [{ ndim: 4 }]; } computeOutputShape(inputShape) { if (this.dataFormat === 'channelsFirst') { return [ inputShape[0], inputShape[1], inputShape[2] - this.cropping[0][0] - this.cropping[0][1], inputShape[3] - this.cropping[1][0] - this.cropping[1][1] ]; } else { return [ inputShape[0], inputShape[1] - this.cropping[0][0] - this.cropping[0][1], inputShape[2] - this.cropping[1][0] - this.cropping[1][1], inputShape[3] ]; } } call(inputs, kwargs) { return tidy(() => { inputs = getExactlyOneTensor(inputs); if (this.dataFormat === 'channelsLast') { const hSliced = K.sliceAlongAxis(inputs, this.cropping[0][0], inputs.shape[1] - this.cropping[0][0] - this.cropping[0][1], 2); return K.sliceAlongAxis(hSliced, this.cropping[1][0], inputs.shape[2] - this.cropping[1][1] - this.cropping[1][0], 3); } else { const hSliced = K.sliceAlongAxis(inputs, this.cropping[0][0], inputs.shape[2] - this.cropping[0][0] - this.cropping[0][1], 3); return K.sliceAlongAxis(hSliced, this.cropping[1][0], inputs.shape[3] - this.cropping[1][1] - this.cropping[1][0], 4); } }); } getConfig() { const config = { cropping: this.cropping, dataFormat: this.dataFormat }; const baseConfig = super.getConfig(); Object.assign(config, baseConfig); return config; } } /** @nocollapse */ Cropping2D.className = 'Cropping2D'; export { Cropping2D }; serialization.registerClass(Cropping2D); class UpSampling2D extends Layer { constructor(args) { super(args); this.DEFAULT_SIZE = [2, 2]; this.inputSpec = [{ ndim: 4 }]; this.size = args.size == null ? this.DEFAULT_SIZE : args.size; this.dataFormat = args.dataFormat == null ? 'channelsLast' : args.dataFormat; checkDataFormat(this.dataFormat); this.interpolation = args.interpolation == null ? 'nearest' : args.interpolation; checkInterpolationFormat(this.interpolation); } computeOutputShape(inputShape) { if (this.dataFormat === 'channelsFirst') { const height = inputShape[2] == null ? null : this.size[0] * inputShape[2]; const width = inputShape[3] == null ? null : this.size[1] * inputShape[3]; return [inputShape[0], inputShape[1], height, width]; } else { const height = inputShape[1] == null ? null : this.size[0] * inputShape[1]; const width = inputShape[2] == null ? null : this.size[1] * inputShape[2]; return [inputShape[0], height, width, inputShape[3]]; } } call(inputs, kwargs) { return tfc.tidy(() => { let input = getExactlyOneTensor(inputs); const inputShape = input.shape; if (this.dataFormat === 'channelsFirst') { input = tfc.transpose(input, [0, 2, 3, 1]); const height = this.size[0] * inputShape[2]; const width = this.size[1] * inputShape[3]; const resized = this.interpolation === 'nearest' ? tfc.image.resizeNearestNeighbor(input, [height, width]) : tfc.image.resizeBilinear(input, [height, width]); return tfc.transpose(resized, [0, 3, 1, 2]); } else { const height = this.size[0] * inputShape[1]; const width = this.size[1] * inputShape[2]; return this.interpolation === 'nearest' ? tfc.image.resizeNearestNeighbor(input, [height, width]) : tfc.image.resizeBilinear(input, [height, width]); } }); } getConfig() { const config = { size: this.size, dataFormat: this.dataFormat, interpolation: this.interpolation }; const baseConfig = super.getConfig(); Object.assign(config, baseConfig); return config; } } /** @nocollapse */ UpSampling2D.className = 'UpSampling2D'; export { UpSampling2D }; serialization.registerClass(UpSampling2D); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udm9sdXRpb25hbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9sYXllcnMvY29udm9sdXRpb25hbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVIOztHQUVHO0FBRUgsT0FBTyxLQUFLLEdBQUcsTUFBTSx1QkFBdUIsQ0FBQztBQUM3QyxPQUFPLEVBQVEsYUFBYSxFQUE0RCxJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUUzSCxPQUFPLEVBQWEsYUFBYSxFQUFFLG1CQUFtQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUUsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBQ2xELE9BQU8sS0FBSyxDQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDN0MsT0FBTyxFQUFDLGVBQWUsRUFBRSx3QkFBd0IsRUFBRSxnQkFBZ0IsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUN0RixPQUFPLEVBQW1DLGFBQWEsRUFBRSxtQkFBbUIsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3BHLE9BQU8sRUFBQyxTQUFTLEVBQUUsS0FBSyxFQUFZLE1BQU0sb0JBQW9CLENBQUM7QUFDL0QsT0FBTyxFQUFDLG1CQUFtQixFQUFFLFVBQVUsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUMxRCxPQUFPLEVBQUMsY0FBYyxFQUFzQyxvQkFBb0IsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBR3pHLE9BQU8sRUFBQyxjQUFjLEVBQXNDLG9CQUFvQixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFFekcsT0FBTyxFQUFDLGdCQUFnQixFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUNuRixPQUFPLEtBQUssYUFBYSxNQUFNLHdCQUF3QixDQUFDO0FBQ3hELE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBQyxNQUFNLHNCQUFzQixD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TyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQzVCLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO2FBQ3JFO2lCQUFNO2dCQUNMLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQyxjQUFjLENBQzVCLE1BQU0sRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUMzQixNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDcEUsT0FBTyxDQUFDLENBQUMsY0FBYyxDQUNuQixPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFDNUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7YUFDckU7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFUSxTQUFTO1FBQ2hCLE1BQU0sTUFBTSxHQUFHLEVBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUMsQ0FBQztRQUN0RSxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUM7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LEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUN6RCxHQUFHLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQzthQUN0RDtRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVRLFNBQVM7UUFDaEIsTUFBTSxNQUFNLEdBQUc7WUFDWCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7WUFDZixVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVU7WUFDM0IsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO1NBQ3BDLENBQUM7UUFDRixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDckMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDbEMsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQzs7QUFsRUQsa0JBQWtCO0FBQ1gsc0JBQVMsR0FBRyxjQUFjLEFBQWpCLENBQWtCO1NBRnZCLFlBQVk7QUFxRXpCLGFBQWEsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxOCBHb29nbGUgTExDXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlXG4gKiBsaWNlbnNlIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgb3IgYXRcbiAqIGh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlULlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG4vKipcbiAqIFRlbnNvckZsb3cuanMgTGF5ZXJzOiBDb252b2x1dGlvbmFsIExheWVyc1xuICovXG5cbmltcG9ydCAqIGFzIHRmYyBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHtmdXNlZCwgc2VyaWFsaXphdGlvbiwgVGVuc29yLCBUZW5zb3IxRCwgVGVuc29yMkQsIFRlbnNvcjNELCBUZW5zb3I0RCwgVGVuc29yNUQsIHRpZHl9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCB7QWN0aXZhdGlvbiwgZ2V0QWN0aXZhdGlvbiwgc2VyaWFsaXplQWN0aXZhdGlvbn0gZnJvbSAnLi4vYWN0aXZhdGlvbnMnO1xuaW1wb3J0IHtpbWFnZURhdGFGb3JtYXR9IGZyb20gJy4uL2JhY2tlbmQvY29tbW9uJztcbmltcG9ydCAqIGFzIEsgZnJvbSAnLi4vYmFja2VuZC90ZmpzX2JhY2tlbmQnO1xuaW1wb3J0IHtjaGVja0RhdGFGb3JtYXQsIGNoZWNrSW50ZXJwb2xhdGlvbkZvcm1hdCwgY2hlY2tQYWRkaW5nTW9kZX0gZnJvbSAnLi4vY29tbW9uJztcbmltcG9ydCB7Q29uc3RyYWludCwgQ29uc3RyYWludElkZW50aWZpZXIsIGdldENvbnN0cmFpbnQsIHNlcmlhbGl6ZUNvbnN0cmFpbnR9IGZyb20gJy4uL2NvbnN0cmFpbnRzJztcbmltcG9ydCB7SW5wdXRTcGVjLCBMYXllciwgTGF5ZXJBcmdzfSBmcm9tICcuLi9lbmdpbmUvdG9wb2xvZ3knO1xuaW1wb3J0IHtOb3RJbXBsZW1lbnRlZEVycm9yLCBWYWx1ZUVycm9yfSBmcm9tICcuLi9lcnJvcnMnO1xuaW1wb3J0IHtnZXRJbml0aWFsaXplciwgSW5pdGlhbGl6ZXIsIEluaXRpYWxpemVySWRlbnRpZmllciwgc2VyaWFsaXplSW5pdGlhbGl6ZXJ9IGZyb20gJy4uL2luaXRpYWxpemVycyc7XG5pbXBvcnQge0FjdGl2YXRpb25JZGVudGlmaWVyfSBmcm9tICcuLi9rZXJhc19mb3JtYXQvYWN0aXZhdGlvbl9jb25maWcnO1xuaW1wb3J0IHtEYXRhRm9ybWF0LCBJbnRlcnBvbGF0aW9uRm9ybWF0LCBQYWRkaW5nTW9kZSwgU2hhcGV9IGZyb20gJy4uL2tlcmFzX2Zvcm1hdC9jb21tb24nO1xuaW1wb3J0IHtnZXRSZWd1bGFyaXplciwgUmVndWxhcml6ZXIsIFJlZ3VsYXJpemVySWRlbnRpZmllciwgc2VyaWFsaXplUmVndWxhcml6ZXJ9IGZyb20gJy4uL3JlZ3VsYXJpemVycyc7XG5pbXBvcnQge0t3YXJnc30gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHtjb252T3V0cHV0TGVuZ3RoLCBkZWNvbnZMZW5ndGgsIG5vcm1hbGl6ZUFycmF5fSBmcm9tICcuLi91dGlscy9jb252X3V0aWxzJztcbmltcG9ydCAqIGFzIGdlbmVyaWNfdXRpbHMgZnJvbSAnLi4vdXRpbHMvZ2VuZXJpY191dGlscyc7XG5pbXBvcnQge2dldEV4YWN0bHlPbmVTaGFwZSwgZ2V0RXhhY3RseU9uZVRlbnNvcn0gZnJvbSAnLi4vdXRpbHMvdHlwZXNfdXRpbHMnO1xuaW1wb3J0IHtMYXllclZhcmlhYmxlfSBmcm9tICcuLi92YXJpYWJsZXMnO1xuXG4vKipcbiAqIFRyYW5zcG9zZSBhbmQgY2FzdCB0aGUgaW5wdXQgYmVmb3JlIHRoZSBjb252MmQuXG4gKiBAcGFyYW0geCBJbnB1dCBpbWFnZSB0ZW5zb3IuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdFxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlcHJvY2Vzc0NvbnYyRElucHV0KFxuICAgIHg6IFRlbnNvciwgZGF0YUZvcm1hdDogRGF0YUZvcm1hdCk6IFRlbnNvciB7XG4gIC8vIFRPRE8oY2Fpcyk6IENhc3QgdHlwZSB0byBmbG9hdDMyIGlmIG5vdC5cbiAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICByZXR1cm4gdGZjLnRyYW5zcG9zZSh4LCBbMCwgMiwgMywgMV0pOyAgLy8gTkNIVyAtPiBOSFdDLlxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4geDtcbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIFRyYW5zcG9zZSBhbmQgY2FzdCB0aGUgaW5wdXQgYmVmb3JlIHRoZSBjb252M2QuXG4gKiBAcGFyYW0geCBJbnB1dCBpbWFnZSB0ZW5zb3IuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdFxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlcHJvY2Vzc0NvbnYzRElucHV0KFxuICAgIHg6IFRlbnNvciwgZGF0YUZvcm1hdDogRGF0YUZvcm1hdCk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjaGVja0RhdGFGb3JtYXQoZGF0YUZvcm1hdCk7XG4gICAgaWYgKGRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgcmV0dXJuIHRmYy50cmFuc3Bvc2UoeCwgWzAsIDIsIDMsIDQsIDFdKTsgIC8vIE5DREhXIC0+IE5ESFdDLlxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4geDtcbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIDFELWNvbnZvbHV0aW9uIHdpdGggYmlhcyBhZGRlZC5cbiAqXG4gKiBQb3J0aW5nIE5vdGU6IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgZXhpc3QgaW4gdGhlIFB5dGhvbiBLZXJhcyBiYWNrZW5kLlxuICogICBJdCBpcyBleGFjdGx5IHRoZSBzYW1lIGFzIGBjb252MmRgLCBleGNlcHQgdGhlIGFkZGVkIGBiaWFzYC5cbiAqXG4gKiBAcGFyYW0geCBJbnB1dCB0ZW5zb3IsIHJhbmstMywgb2Ygc2hhcGUgYFtiYXRjaFNpemUsIHdpZHRoLCBpbkNoYW5uZWxzXWAuXG4gKiBAcGFyYW0ga2VybmVsIEtlcm5lbCwgcmFuay0zLCBvZiBzaGFwZSBgW2ZpbHRlcldpZHRoLCBpbkRlcHRoLCBvdXREZXB0aF1gLlxuICogQHBhcmFtIGJpYXMgQmlhcywgcmFuay0zLCBvZiBzaGFwZSBgW291dERlcHRoXWAuXG4gKiBAcGFyYW0gc3RyaWRlc1xuICogQHBhcmFtIHBhZGRpbmcgUGFkZGluZyBtb2RlLlxuICogQHBhcmFtIGRhdGFGb3JtYXQgRGF0YSBmb3JtYXQuXG4gKiBAcGFyYW0gZGlsYXRpb25SYXRlXG4gKiBAcmV0dXJucyBUaGUgcmVzdWx0IG9mIHRoZSAxRCBjb252b2x1dGlvbi5cbiAqIEB0aHJvd3MgVmFsdWVFcnJvciwgaWYgYHhgLCBga2VybmVsYCBvciBgYmlhc2AgaXMgbm90IG9mIHRoZSBjb3JyZWN0IHJhbmsuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252MWRXaXRoQmlhcyhcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBiaWFzOiBUZW5zb3IsIHN0cmlkZXMgPSAxLCBwYWRkaW5nID0gJ3ZhbGlkJyxcbiAgICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdCwgZGlsYXRpb25SYXRlID0gMSk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PSBudWxsKSB7XG4gICAgICBkYXRhRm9ybWF0ID0gaW1hZ2VEYXRhRm9ybWF0KCk7XG4gICAgfVxuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICAvLyBDaGVjayB0aGUgcmFua3Mgb2YgeCwga2VybmVsIGFuZCBiaWFzLlxuICAgIGlmICh4LnNoYXBlLmxlbmd0aCAhPT0gMykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFRoZSBpbnB1dCBvZiBhIGNvbnYxZFdpdGhCaWFzIG9wZXJhdGlvbiBzaG91bGQgYmUgMywgYnV0IGlzIGAgK1xuICAgICAgICAgIGAke3guc2hhcGUubGVuZ3RofSBpbnN0ZWFkLmApO1xuICAgIH1cbiAgICBpZiAoa2VybmVsLnNoYXBlLmxlbmd0aCAhPT0gMykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFRoZSBrZXJuZWwgZm9yIGEgY29udjFkV2l0aEJpYXMgb3BlcmF0aW9uIHNob3VsZCBiZSAzLCBidXQgaXMgYCArXG4gICAgICAgICAgYCR7a2VybmVsLnNoYXBlLmxlbmd0aH0gaW5zdGVhZGApO1xuICAgIH1cbiAgICBpZiAoYmlhcyAhPSBudWxsICYmIGJpYXMuc2hhcGUubGVuZ3RoICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgVGhlIGJpYXMgZm9yIGEgY29udjFkV2l0aEJpYXMgb3BlcmF0aW9uIHNob3VsZCBiZSAxLCBidXQgaXMgYCArXG4gICAgICAgICAgYCR7a2VybmVsLnNoYXBlLmxlbmd0aH0gaW5zdGVhZGApO1xuICAgIH1cbiAgICAvLyBUT0RPKGNhaXMpOiBTdXBwb3J0IENBVVNBTCBwYWRkaW5nIG1vZGUuXG4gICAgaWYgKGRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgeCA9IHRmYy50cmFuc3Bvc2UoeCwgWzAsIDIsIDFdKTsgIC8vIE5DVyAtPiBOV0MuXG4gICAgfVxuICAgIGlmIChwYWRkaW5nID09PSAnY2F1c2FsJykge1xuICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgJ1RoZSBzdXBwb3J0IGZvciBDQVVTQUwgcGFkZGluZyBtb2RlIGluIGNvbnYxZFdpdGhCaWFzIGlzIG5vdCAnICtcbiAgICAgICAgICAnaW1wbGVtZW50ZWQgeWV0LicpO1xuICAgIH1cbiAgICBsZXQgeTogVGVuc29yID0gdGZjLmNvbnYxZChcbiAgICAgICAgeCBhcyBUZW5zb3IyRCB8IFRlbnNvcjNELCBrZXJuZWwgYXMgVGVuc29yM0QsIHN0cmlkZXMsXG4gICAgICAgIHBhZGRpbmcgPT09ICdzYW1lJyA/ICdzYW1lJyA6ICd2YWxpZCcsICdOV0MnLCBkaWxhdGlvblJhdGUpO1xuICAgIGlmIChiaWFzICE9IG51bGwpIHtcbiAgICAgIHkgPSBLLmJpYXNBZGQoeSwgYmlhcyk7XG4gICAgfVxuICAgIHJldHVybiB5O1xuICB9KTtcbn1cblxuLyoqXG4gKiAxRC1jb252b2x1dGlvbi5cbiAqXG4gKiBAcGFyYW0geCBJbnB1dCB0ZW5zb3IsIHJhbmstMywgb2Ygc2hhcGUgYFtiYXRjaFNpemUsIHdpZHRoLCBpbkNoYW5uZWxzXWAuXG4gKiBAcGFyYW0ga2VybmVsIEtlcm5lbCwgcmFuay0zLCBvZiBzaGFwZSBgW2ZpbHRlcldpZHRoLCBpbkRlcHRoLCBvdXREZXB0aF1gLnNcbiAqIEBwYXJhbSBzdHJpZGVzXG4gKiBAcGFyYW0gcGFkZGluZyBQYWRkaW5nIG1vZGUuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdCBEYXRhIGZvcm1hdC5cbiAqIEBwYXJhbSBkaWxhdGlvblJhdGVcbiAqIEByZXR1cm5zIFRoZSByZXN1bHQgb2YgdGhlIDFEIGNvbnZvbHV0aW9uLlxuICogQHRocm93cyBWYWx1ZUVycm9yLCBpZiBgeGAsIGBrZXJuZWxgIG9yIGBiaWFzYCBpcyBub3Qgb2YgdGhlIGNvcnJlY3QgcmFuay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnYxZChcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBzdHJpZGVzID0gMSwgcGFkZGluZyA9ICd2YWxpZCcsXG4gICAgZGF0YUZvcm1hdD86IERhdGFGb3JtYXQsIGRpbGF0aW9uUmF0ZSA9IDEpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgY2hlY2tEYXRhRm9ybWF0KGRhdGFGb3JtYXQpO1xuICAgIHJldHVybiBjb252MWRXaXRoQmlhcyhcbiAgICAgICAgeCwga2VybmVsLCBudWxsLCBzdHJpZGVzLCBwYWRkaW5nLCBkYXRhRm9ybWF0LCBkaWxhdGlvblJhdGUpO1xuICB9KTtcbn1cblxuLyoqXG4gKiAyRCBDb252b2x1dGlvblxuICogQHBhcmFtIHhcbiAqIEBwYXJhbSBrZXJuZWwga2VybmVsIG9mIHRoZSBjb252b2x1dGlvbi5cbiAqIEBwYXJhbSBzdHJpZGVzIHN0cmlkZXMgYXJyYXkuXG4gKiBAcGFyYW0gcGFkZGluZyBwYWRkaW5nIG1vZGUuIERlZmF1bHQgdG8gJ3ZhbGlkJy5cbiAqIEBwYXJhbSBkYXRhRm9ybWF0IGRhdGEgZm9ybWF0LiBEZWZhdWx0cyB0byAnY2hhbm5lbHNMYXN0Jy5cbiAqIEBwYXJhbSBkaWxhdGlvblJhdGUgZGlsYXRpb24gcmF0ZSBhcnJheS5cbiAqIEByZXR1cm5zIFJlc3VsdCBvZiB0aGUgMkQgcG9vbGluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnYyZChcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBzdHJpZGVzID0gWzEsIDFdLCBwYWRkaW5nID0gJ3ZhbGlkJyxcbiAgICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdCwgZGlsYXRpb25SYXRlPzogW251bWJlciwgbnVtYmVyXSk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjaGVja0RhdGFGb3JtYXQoZGF0YUZvcm1hdCk7XG4gICAgcmV0dXJuIGNvbnYyZFdpdGhCaWFzQWN0aXZhdGlvbihcbiAgICAgICAgeCwga2VybmVsLCBudWxsLCBzdHJpZGVzLCBwYWRkaW5nLCBkYXRhRm9ybWF0LCBkaWxhdGlvblJhdGUpO1xuICB9KTtcbn1cblxuLyoqXG4gKiAyRCBDb252b2x1dGlvbiB3aXRoIGFuIGFkZGVkIGJpYXMgYW5kIG9wdGlvbmFsIGFjdGl2YXRpb24uXG4gKiBOb3RlOiBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IGV4aXN0IGluIHRoZSBQeXRob24gS2VyYXMgQmFja2VuZC4gVGhpcyBmdW5jdGlvblxuICogaXMgZXhhY3RseSB0aGUgc2FtZSBhcyBgY29udjJkYCwgZXhjZXB0IHRoZSBhZGRlZCBgYmlhc2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252MmRXaXRoQmlhc0FjdGl2YXRpb24oXG4gICAgeDogVGVuc29yLCBrZXJuZWw6IFRlbnNvciwgYmlhczogVGVuc29yLCBzdHJpZGVzID0gWzEsIDFdLFxuICAgIHBhZGRpbmcgPSAndmFsaWQnLCBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdCwgZGlsYXRpb25SYXRlPzogW251bWJlciwgbnVtYmVyXSxcbiAgICBhY3RpdmF0aW9uOiBmdXNlZC5BY3RpdmF0aW9uID0gbnVsbCk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PSBudWxsKSB7XG4gICAgICBkYXRhRm9ybWF0ID0gaW1hZ2VEYXRhRm9ybWF0KCk7XG4gICAgfVxuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICBpZiAoeC5yYW5rICE9PSAzICYmIHgucmFuayAhPT0gNCkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYGNvbnYyZFdpdGhCaWFzQWN0aXZhdGlvbiBleHBlY3RzIGlucHV0IHRvIGJlIG9mIHJhbmsgMyBvciA0LCBgICtcbiAgICAgICAgICBgYnV0IHJlY2VpdmVkICR7eC5yYW5rfS5gKTtcbiAgICB9XG4gICAgaWYgKGtlcm5lbC5yYW5rICE9PSAzICYmIGtlcm5lbC5yYW5rICE9PSA0KSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgY29udjJkV2l0aEJpYXNBY3RpdmF0aW9uIGV4cGVjdHMga2VybmVsIHRvIGJlIG9mIHJhbmsgMyBvciA0LCBgICtcbiAgICAgICAgICBgYnV0IHJlY2VpdmVkICR7eC5yYW5rfS5gKTtcbiAgICB9XG4gICAgbGV0IHkgPSBwcmVwcm9jZXNzQ29udjJESW5wdXQoeCwgZGF0YUZvcm1hdCk7XG4gICAgaWYgKHBhZGRpbmcgPT09ICdjYXVzYWwnKSB7XG4gICAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcihcbiAgICAgICAgICAnVGhlIHN1cHBvcnQgZm9yIENBVVNBTCBwYWRkaW5nIG1vZGUgaW4gY29udjFkV2l0aEJpYXMgaXMgbm90ICcgK1xuICAgICAgICAgICdpbXBsZW1lbnRlZCB5ZXQuJyk7XG4gICAgfVxuICAgIHkgPSB0ZmMuZnVzZWQuY29udjJkKHtcbiAgICAgIHg6IHkgYXMgVGVuc29yM0QgfCBUZW5zb3I0RCxcbiAgICAgIGZpbHRlcjoga2VybmVsIGFzIFRlbnNvcjRELFxuICAgICAgc3RyaWRlczogc3RyaWRlcyBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgcGFkOiBwYWRkaW5nID09PSAnc2FtZScgPyAnc2FtZScgOiAndmFsaWQnLFxuICAgICAgZGlsYXRpb25zOiBkaWxhdGlvblJhdGUsXG4gICAgICBkYXRhRm9ybWF0OiAnTkhXQycsXG4gICAgICBiaWFzLFxuICAgICAgYWN0aXZhdGlvblxuICAgIH0pO1xuICAgIGlmIChkYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIHkgPSB0ZmMudHJhbnNwb3NlKHksIFswLCAzLCAxLCAyXSk7XG4gICAgfVxuICAgIHJldHVybiB5O1xuICB9KTtcbn1cblxuLyoqXG4gKiAzRCBDb252b2x1dGlvbi5cbiAqIEBwYXJhbSB4XG4gKiBAcGFyYW0ga2VybmVsIGtlcm5lbCBvZiB0aGUgY29udm9sdXRpb24uXG4gKiBAcGFyYW0gc3RyaWRlcyBzdHJpZGVzIGFycmF5LlxuICogQHBhcmFtIHBhZGRpbmcgcGFkZGluZyBtb2RlLiBEZWZhdWx0IHRvICd2YWxpZCcuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdCBkYXRhIGZvcm1hdC4gRGVmYXVsdHMgdG8gJ2NoYW5uZWxzTGFzdCcuXG4gKiBAcGFyYW0gZGlsYXRpb25SYXRlIGRpbGF0aW9uIHJhdGUgYXJyYXkuXG4gKiBAcmV0dXJucyBSZXN1bHQgb2YgdGhlIDNEIGNvbnZvbHV0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udjNkKFxuICAgIHg6IFRlbnNvciwga2VybmVsOiBUZW5zb3IsIHN0cmlkZXMgPSBbMSwgMSwgMV0sIHBhZGRpbmcgPSAndmFsaWQnLFxuICAgIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0LCBkaWxhdGlvblJhdGU/OiBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0pOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgY2hlY2tEYXRhRm9ybWF0KGRhdGFGb3JtYXQpO1xuICAgIHJldHVybiBjb252M2RXaXRoQmlhcyhcbiAgICAgICAgeCwga2VybmVsLCBudWxsLCBzdHJpZGVzLCBwYWRkaW5nLCBkYXRhRm9ybWF0LCBkaWxhdGlvblJhdGUpO1xuICB9KTtcbn1cblxuLyoqXG4gKiAzRCBDb252b2x1dGlvbiB3aXRoIGFuIGFkZGVkIGJpYXMuXG4gKiBOb3RlOiBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IGV4aXN0IGluIHRoZSBQeXRob24gS2VyYXMgQmFja2VuZC4gVGhpcyBmdW5jdGlvblxuICogaXMgZXhhY3RseSB0aGUgc2FtZSBhcyBgY29udjNkYCwgZXhjZXB0IHRoZSBhZGRlZCBgYmlhc2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252M2RXaXRoQmlhcyhcbiAgICB4OiBUZW5zb3IsIGtlcm5lbDogVGVuc29yLCBiaWFzOiBUZW5zb3IsIHN0cmlkZXMgPSBbMSwgMSwgMV0sXG4gICAgcGFkZGluZyA9ICd2YWxpZCcsIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0LFxuICAgIGRpbGF0aW9uUmF0ZT86IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSk6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBpZiAoZGF0YUZvcm1hdCA9PSBudWxsKSB7XG4gICAgICBkYXRhRm9ybWF0ID0gaW1hZ2VEYXRhRm9ybWF0KCk7XG4gICAgfVxuICAgIGNoZWNrRGF0YUZvcm1hdChkYXRhRm9ybWF0KTtcbiAgICBpZiAoeC5yYW5rICE9PSA0ICYmIHgucmFuayAhPT0gNSkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYGNvbnYzZFdpdGhCaWFzIGV4cGVjdHMgaW5wdXQgdG8gYmUgb2YgcmFuayA0IG9yIDUsIGJ1dCByZWNlaXZlZCBgICtcbiAgICAgICAgICBgJHt4LnJhbmt9LmApO1xuICAgIH1cbiAgICBpZiAoa2VybmVsLnJhbmsgIT09IDQgJiYga2VybmVsLnJhbmsgIT09IDUpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBjb252M2RXaXRoQmlhcyBleHBlY3RzIGtlcm5lbCB0byBiZSBvZiByYW5rIDQgb3IgNSwgYnV0IHJlY2VpdmVkIGAgK1xuICAgICAgICAgIGAke3gucmFua30uYCk7XG4gICAgfVxuICAgIGxldCB5ID0gcHJlcHJvY2Vzc0NvbnYzRElucHV0KHgsIGRhdGFGb3JtYXQpO1xuICAgIGlmIChwYWRkaW5nID09PSAnY2F1c2FsJykge1xuICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgJ1RoZSBzdXBwb3J0IGZvciBDQVVTQUwgcGFkZGluZyBtb2RlIGluIGNvbnYzZFdpdGhCaWFzIGlzIG5vdCAnICtcbiAgICAgICAgICAnaW1wbGVtZW50ZWQgeWV0LicpO1xuICAgIH1cbiAgICB5ID0gdGZjLmNvbnYzZChcbiAgICAgICAgeSBhcyBUZW5zb3I0RCB8IHRmYy5UZW5zb3I8dGZjLlJhbmsuUjU+LFxuICAgICAgICBrZXJuZWwgYXMgdGZjLlRlbnNvcjx0ZmMuUmFuay5SNT4sIHN0cmlkZXMgYXMgW251bWJlciwgbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICBwYWRkaW5nID09PSAnc2FtZScgPyAnc2FtZScgOiAndmFsaWQnLCAnTkRIV0MnLCBkaWxhdGlvblJhdGUpO1xuICAgIGlmIChiaWFzICE9IG51bGwpIHtcbiAgICAgIHkgPSBLLmJpYXNBZGQoeSwgYmlhcyBhcyBUZW5zb3IxRCk7XG4gICAgfVxuICAgIGlmIChkYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIHkgPSB0ZmMudHJhbnNwb3NlKHksIFswLCA0LCAxLCAyLCAzXSk7XG4gICAgfVxuICAgIHJldHVybiB5O1xuICB9KTtcbn1cblxuLyoqXG4gKiBCYXNlIExheWVyQ29uZmlnIGZvciBkZXB0aHdpc2UgYW5kIG5vbi1kZXB0aHdpc2UgY29udm9sdXRpb25hbCBsYXllcnMuXG4gKi9cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBCYXNlQ29udkxheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBUaGUgZGltZW5zaW9ucyBvZiB0aGUgY29udm9sdXRpb24gd2luZG93LiBJZiBrZXJuZWxTaXplIGlzIGEgbnVtYmVyLCB0aGVcbiAgICogY29udm9sdXRpb25hbCB3aW5kb3cgd2lsbCBiZSBzcXVhcmUuXG4gICAqL1xuICBrZXJuZWxTaXplOiBudW1iZXJ8bnVtYmVyW107XG5cbiAgLyoqXG4gICAqIFRoZSBzdHJpZGVzIG9mIHRoZSBjb252b2x1dGlvbiBpbiBlYWNoIGRpbWVuc2lvbi4gSWYgc3RyaWRlcyBpcyBhIG51bWJlcixcbiAgICogc3RyaWRlcyBpbiBib3RoIGRpbWVuc2lvbnMgYXJlIGVxdWFsLlxuICAgKlxuICAgKiBTcGVjaWZ5aW5nIGFueSBzdHJpZGUgdmFsdWUgIT0gMSBpcyBpbmNvbXBhdGlibGUgd2l0aCBzcGVjaWZ5aW5nIGFueVxuICAgKiBgZGlsYXRpb25SYXRlYCB2YWx1ZSAhPSAxLlxuICAgKi9cbiAgc3RyaWRlcz86IG51bWJlcnxudW1iZXJbXTtcblxuICAvKipcbiAgICogUGFkZGluZyBtb2RlLlxuICAgKi9cbiAgcGFkZGluZz86IFBhZGRpbmdNb2RlO1xuXG4gIC8qKlxuICAgKiBGb3JtYXQgb2YgdGhlIGRhdGEsIHdoaWNoIGRldGVybWluZXMgdGhlIG9yZGVyaW5nIG9mIHRoZSBkaW1lbnNpb25zIGluXG4gICAqIHRoZSBpbnB1dHMuXG4gICAqXG4gICAqIGBjaGFubmVsc19sYXN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZVxuICAgKiAgIGAoYmF0Y2gsIC4uLiwgY2hhbm5lbHMpYFxuICAgKlxuICAgKiAgYGNoYW5uZWxzX2ZpcnN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZSBgKGJhdGNoLCBjaGFubmVscyxcbiAgICogLi4uKWAuXG4gICAqXG4gICAqIERlZmF1bHRzIHRvIGBjaGFubmVsc19sYXN0YC5cbiAgICovXG4gIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0O1xuXG4gIC8qKlxuICAgKiBUaGUgZGlsYXRpb24gcmF0ZSB0byB1c2UgZm9yIHRoZSBkaWxhdGVkIGNvbnZvbHV0aW9uIGluIGVhY2ggZGltZW5zaW9uLlxuICAgKiBTaG91bGQgYmUgYW4gaW50ZWdlciBvciBhcnJheSBvZiB0d28gb3IgdGhyZWUgaW50ZWdlcnMuXG4gICAqXG4gICAqIEN1cnJlbnRseSwgc3BlY2lmeWluZyBhbnkgYGRpbGF0aW9uUmF0ZWAgdmFsdWUgIT0gMSBpcyBpbmNvbXBhdGlibGUgd2l0aFxuICAgKiBzcGVjaWZ5aW5nIGFueSBgc3RyaWRlc2AgdmFsdWUgIT0gMS5cbiAgICovXG4gIGRpbGF0aW9uUmF0ZT86IG51bWJlcnxbbnVtYmVyXXxbbnVtYmVyLCBudW1iZXJdfFtudW1iZXIsIG51bWJlciwgbnVtYmVyXTtcblxuICAvKipcbiAgICogQWN0aXZhdGlvbiBmdW5jdGlvbiBvZiB0aGUgbGF5ZXIuXG4gICAqXG4gICAqIElmIHlvdSBkb24ndCBzcGVjaWZ5IHRoZSBhY3RpdmF0aW9uLCBub25lIGlzIGFwcGxpZWQuXG4gICAqL1xuICBhY3RpdmF0aW9uPzogQWN0aXZhdGlvbklkZW50aWZpZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGxheWVyIHVzZXMgYSBiaWFzIHZlY3Rvci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgKi9cbiAgdXNlQmlhcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVyIGZvciB0aGUgY29udm9sdXRpb25hbCBrZXJuZWwgd2VpZ2h0cyBtYXRyaXguXG4gICAqL1xuICBrZXJuZWxJbml0aWFsaXplcj86IEluaXRpYWxpemVySWRlbnRpZmllcnxJbml0aWFsaXplcjtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXIgZm9yIHRoZSBiaWFzIHZlY3Rvci5cbiAgICovXG4gIGJpYXNJbml0aWFsaXplcj86IEluaXRpYWxpemVySWRlbnRpZmllcnxJbml0aWFsaXplcjtcblxuICAvKipcbiAgICogQ29uc3RyYWludCBmb3IgdGhlIGNvbnZvbHV0aW9uYWwga2VybmVsIHdlaWdodHMuXG4gICAqL1xuICBrZXJuZWxDb25zdHJhaW50PzogQ29uc3RyYWludElkZW50aWZpZXJ8Q29uc3RyYWludDtcblxuICAvKipcbiAgICogQ29uc3RyYWludCBmb3IgdGhlIGJpYXMgdmVjdG9yLlxuICAgKi9cbiAgYmlhc0NvbnN0cmFpbnQ/OiBDb25zdHJhaW50SWRlbnRpZmllcnxDb25zdHJhaW50O1xuXG4gIC8qKlxuICAgKiBSZWd1bGFyaXplciBmdW5jdGlvbiBhcHBsaWVkIHRvIHRoZSBrZXJuZWwgd2VpZ2h0cyBtYXRyaXguXG4gICAqL1xuICBrZXJuZWxSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVySWRlbnRpZmllcnxSZWd1bGFyaXplcjtcblxuICAvKipcbiAgICogUmVndWxhcml6ZXIgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgYmlhcyB2ZWN0b3IuXG4gICAqL1xuICBiaWFzUmVndWxhcml6ZXI/OiBSZWd1bGFyaXplcklkZW50aWZpZXJ8UmVndWxhcml6ZXI7XG5cbiAgLyoqXG4gICAqIFJlZ3VsYXJpemVyIGZ1bmN0aW9uIGFwcGxpZWQgdG8gdGhlIGFjdGl2YXRpb24uXG4gICAqL1xuICBhY3Rpdml0eVJlZ3VsYXJpemVyPzogUmVndWxhcml6ZXJJZGVudGlmaWVyfFJlZ3VsYXJpemVyO1xufVxuXG4vKipcbiAqIExheWVyQ29uZmlnIGZvciBub24tZGVwdGh3aXNlIGNvbnZvbHV0aW9uYWwgbGF5ZXJzLlxuICogQXBwbGllcyB0byBub24tZGVwdGh3aXNlIGNvbnZvbHV0aW9uIG9mIGFsbCByYW5rcyAoZS5nLCBDb252MUQsIENvbnYyRCxcbiAqIENvbnYzRCkuXG4gKi9cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBDb252TGF5ZXJBcmdzIGV4dGVuZHMgQmFzZUNvbnZMYXllckFyZ3Mge1xuICAvKipcbiAgICogVGhlIGRpbWVuc2lvbmFsaXR5IG9mIHRoZSBvdXRwdXQgc3BhY2UgKGkuZS4gdGhlIG51bWJlciBvZiBmaWx0ZXJzIGluIHRoZVxuICAgKiBjb252b2x1dGlvbikuXG4gICAqL1xuICBmaWx0ZXJzOiBudW1iZXI7XG59XG5cbi8qKlxuICogQWJzdHJhY3QgY29udm9sdXRpb24gbGF5ZXIuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlQ29udiBleHRlbmRzIExheWVyIHtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHJhbms6IG51bWJlcjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGtlcm5lbFNpemU6IG51bWJlcltdO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc3RyaWRlczogbnVtYmVyW107XG4gIHByb3RlY3RlZCByZWFkb25seSBwYWRkaW5nOiBQYWRkaW5nTW9kZTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRhdGFGb3JtYXQ6IERhdGFGb3JtYXQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBhY3RpdmF0aW9uOiBBY3RpdmF0aW9uO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdXNlQmlhczogYm9vbGVhbjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRpbGF0aW9uUmF0ZTogbnVtYmVyW107XG5cbiAgLy8gQmlhcy1yZWxhdGVkIG1lbWJlcnMgYXJlIGhlcmUgYmVjYXVzZSBhbGwgY29udm9sdXRpb24gc3ViY2xhc3NlcyB1c2UgdGhlXG4gIC8vIHNhbWUgY29uZmlndXJhdGlvbiBwYXJtZXRlcnMgdG8gY29udHJvbCBiaWFzLiAgS2VybmVsLXJlbGF0ZWQgbWVtYmVyc1xuICAvLyBhcmUgaW4gc3ViY2xhc3MgYENvbnZgIGJlY2F1c2Ugc29tZSBzdWJjbGFzc2VzIHVzZSBkaWZmZXJlbnQgcGFyYW1ldGVycyB0b1xuICAvLyBjb250cm9sIGtlcm5lbCBwcm9wZXJ0aWVzLCBmb3IgaW5zdGFuY2UsIGBEZXB0aHdpc2VDb252MkRgIHVzZXNcbiAgLy8gYGRlcHRod2lzZUluaXRpYWxpemVyYCBpbnN0ZWFkIG9mIGBrZXJuZWxJbml0aWFsaXplcmAuXG4gIHByb3RlY3RlZCByZWFkb25seSBiaWFzSW5pdGlhbGl6ZXI/OiBJbml0aWFsaXplcjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGJpYXNDb25zdHJhaW50PzogQ29uc3RyYWludDtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGJpYXNSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVyO1xuXG4gIHByb3RlY3RlZCBiaWFzOiBMYXllclZhcmlhYmxlID0gbnVsbDtcblxuICByZWFkb25seSBERUZBVUxUX0tFUk5FTF9JTklUSUFMSVpFUjogSW5pdGlhbGl6ZXJJZGVudGlmaWVyID0gJ2dsb3JvdE5vcm1hbCc7XG4gIHJlYWRvbmx5IERFRkFVTFRfQklBU19JTklUSUFMSVpFUjogSW5pdGlhbGl6ZXJJZGVudGlmaWVyID0gJ3plcm9zJztcblxuICBjb25zdHJ1Y3RvcihyYW5rOiBudW1iZXIsIGFyZ3M6IEJhc2VDb252TGF5ZXJBcmdzKSB7XG4gICAgc3VwZXIoYXJncyBhcyBMYXllckFyZ3MpO1xuICAgIEJhc2VDb252LnZlcmlmeUFyZ3MoYXJncyk7XG4gICAgdGhpcy5yYW5rID0gcmFuaztcbiAgICBnZW5lcmljX3V0aWxzLmFzc2VydFBvc2l0aXZlSW50ZWdlcih0aGlzLnJhbmssICdyYW5rJyk7XG4gICAgaWYgKHRoaXMucmFuayAhPT0gMSAmJiB0aGlzLnJhbmsgIT09IDIgJiYgdGhpcy5yYW5rICE9PSAzKSB7XG4gICAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcihcbiAgICAgICAgICBgQ29udm9sdXRpb24gbGF5ZXIgZm9yIHJhbmsgb3RoZXIgdGhhbiAxLCAyLCBvciAzICgke1xuICAgICAgICAgICAgICB0aGlzLnJhbmt9KSBpcyBgICtcbiAgICAgICAgICBgbm90IGltcGxlbWVudGVkIHlldC5gKTtcbiAgICB9XG4gICAgdGhpcy5rZXJuZWxTaXplID0gbm9ybWFsaXplQXJyYXkoYXJncy5rZXJuZWxTaXplLCByYW5rLCAna2VybmVsU2l6ZScpO1xuICAgIHRoaXMuc3RyaWRlcyA9IG5vcm1hbGl6ZUFycmF5KFxuICAgICAgICBhcmdzLnN0cmlkZXMgPT0gbnVsbCA/IDEgOiBhcmdzLnN0cmlkZXMsIHJhbmssICdzdHJpZGVzJyk7XG4gICAgdGhpcy5wYWRkaW5nID0gYXJncy5wYWRkaW5nID09IG51bGwgPyAndmFsaWQnIDogYXJncy5wYWRkaW5nO1xuICAgIGNoZWNrUGFkZGluZ01vZGUodGhpcy5wYWRkaW5nKTtcbiAgICB0aGlzLmRhdGFGb3JtYXQgPVxuICAgICAgICBhcmdzLmRhdGFGb3JtYXQgPT0gbnVsbCA/ICdjaGFubmVsc0xhc3QnIDogYXJncy5kYXRhRm9ybWF0O1xuICAgIGNoZWNrRGF0YUZvcm1hdCh0aGlzLmRhdGFGb3JtYXQpO1xuICAgIHRoaXMuYWN0aXZhdGlvbiA9IGdldEFjdGl2YXRpb24oYXJncy5hY3RpdmF0aW9uKTtcbiAgICB0aGlzLnVzZUJpYXMgPSBhcmdzLnVzZUJpYXMgPT0gbnVsbCA/IHRydWUgOiBhcmdzLnVzZUJpYXM7XG4gICAgdGhpcy5iaWFzSW5pdGlhbGl6ZXIgPVxuICAgICAgICBnZXRJbml0aWFsaXplcihhcmdzLmJpYXNJbml0aWFsaXplciB8fCB0aGlzLkRFRkFVTFRfQklBU19JTklUSUFMSVpFUik7XG4gICAgdGhpcy5iaWFzQ29uc3RyYWludCA9IGdldENvbnN0cmFpbnQoYXJncy5iaWFzQ29uc3RyYWludCk7XG4gICAgdGhpcy5iaWFzUmVndWxhcml6ZXIgPSBnZXRSZWd1bGFyaXplcihhcmdzLmJpYXNSZWd1bGFyaXplcik7XG4gICAgdGhpcy5hY3Rpdml0eVJlZ3VsYXJpemVyID0gZ2V0UmVndWxhcml6ZXIoYXJncy5hY3Rpdml0eVJlZ3VsYXJpemVyKTtcbiAgICB0aGlzLmRpbGF0aW9uUmF0ZSA9IG5vcm1hbGl6ZUFycmF5KFxuICAgICAgICBhcmdzLmRpbGF0aW9uUmF0ZSA9PSBudWxsID8gMSA6IGFyZ3MuZGlsYXRpb25SYXRlLCByYW5rLFxuICAgICAgICAnZGlsYXRpb25SYXRlJyk7XG4gICAgaWYgKHRoaXMucmFuayA9PT0gMSAmJlxuICAgICAgICAoQXJyYXkuaXNBcnJheSh0aGlzLmRpbGF0aW9uUmF0ZSkgJiYgdGhpcy5kaWxhdGlvblJhdGUubGVuZ3RoICE9PSAxKSkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYGRpbGF0aW9uUmF0ZSBtdXN0IGJlIGEgbnVtYmVyIG9yIGFuIGFycmF5IG9mIGEgc2luZ2xlIG51bWJlciBgICtcbiAgICAgICAgICBgZm9yIDFEIGNvbnZvbHV0aW9uLCBidXQgcmVjZWl2ZWQgYCArXG4gICAgICAgICAgYCR7SlNPTi5zdHJpbmdpZnkodGhpcy5kaWxhdGlvblJhdGUpfWApO1xuICAgIH0gZWxzZSBpZiAodGhpcy5yYW5rID09PSAyKSB7XG4gICAgICBpZiAodHlwZW9mIHRoaXMuZGlsYXRpb25SYXRlID09PSAnbnVtYmVyJykge1xuICAgICAgICB0aGlzLmRpbGF0aW9uUmF0ZSA9IFt0aGlzLmRpbGF0aW9uUmF0ZSwgdGhpcy5kaWxhdGlvblJhdGVdO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLmRpbGF0aW9uUmF0ZS5sZW5ndGggIT09IDIpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgICBgZGlsYXRpb25SYXRlIG11c3QgYmUgYSBudW1iZXIgb3IgYXJyYXkgb2YgdHdvIG51bWJlcnMgZm9yIDJEIGAgK1xuICAgICAgICAgICAgYGNvbnZvbHV0aW9uLCBidXQgcmVjZWl2ZWQgJHtKU09OLnN0cmluZ2lmeSh0aGlzLmRpbGF0aW9uUmF0ZSl9YCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0aGlzLnJhbmsgPT09IDMpIHtcbiAgICAgIGlmICh0eXBlb2YgdGhpcy5kaWxhdGlvblJhdGUgPT09ICdudW1iZXInKSB7XG4gICAgICAgIHRoaXMuZGlsYXRpb25SYXRlID1cbiAgICAgICAgICAgIFt0aGlzLmRpbGF0aW9uUmF0ZSwgdGhpcy5kaWxhdGlvblJhdGUsIHRoaXMuZGlsYXRpb25SYXRlXTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5kaWxhdGlvblJhdGUubGVuZ3RoICE9PSAzKSB7XG4gICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgYGRpbGF0aW9uUmF0ZSBtdXN0IGJlIGEgbnVtYmVyIG9yIGFycmF5IG9mIHRocmVlIG51bWJlcnMgZm9yIDNEIGAgK1xuICAgICAgICAgICAgYGNvbnZvbHV0aW9uLCBidXQgcmVjZWl2ZWQgJHtKU09OLnN0cmluZ2lmeSh0aGlzLmRpbGF0aW9uUmF0ZSl9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyB2ZXJpZnlBcmdzKGFyZ3M6IEJhc2VDb252TGF5ZXJBcmdzKSB7XG4gICAgLy8gQ2hlY2sgY29uZmlnLmtlcm5lbFNpemUgdHlwZSBhbmQgc2hhcGUuXG4gICAgZ2VuZXJpY191dGlscy5hc3NlcnQoXG4gICAgICAgICdrZXJuZWxTaXplJyBpbiBhcmdzLCBgcmVxdWlyZWQga2V5ICdrZXJuZWxTaXplJyBub3QgaW4gY29uZmlnYCk7XG4gICAgaWYgKHR5cGVvZiBhcmdzLmtlcm5lbFNpemUgIT09ICdudW1iZXInICYmXG4gICAgICAgICFnZW5lcmljX3V0aWxzLmNoZWNrQXJyYXlUeXBlQW5kTGVuZ3RoKFxuICAgICAgICAgICAgYXJncy5rZXJuZWxTaXplLCAnbnVtYmVyJywgMSwgMykpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBCYXNlQ29udiBleHBlY3RzIGNvbmZpZy5rZXJuZWxTaXplIHRvIGJlIG51bWJlciBvciBudW1iZXJbXSB3aXRoIGAgK1xuICAgICAgICAgIGBsZW5ndGggMSwgMiwgb3IgMywgYnV0IHJlY2VpdmVkICR7XG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGdldENvbmZpZygpOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIGNvbnN0IGNvbmZpZzogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0ID0ge1xuICAgICAga2VybmVsU2l6ZTogdGhpcy5rZXJuZWxTaXplLFxuICAgICAgc3RyaWRlczogdGhpcy5zdHJpZGVzLFxuICAgICAgcGFkZGluZzogdGhpcy5wYWRkaW5nLFxuICAgICAgZGF0YUZvcm1hdDogdGhpcy5kYXRhRm9ybWF0LFxuICAgICAgZGlsYXRpb25SYXRlOiB0aGlzLmRpbGF0aW9uUmF0ZSxcbiAgICAgIGFjdGl2YXRpb246IHNlcmlhbGl6ZUFjdGl2YXRpb24odGhpcy5hY3RpdmF0aW9uKSxcbiAgICAgIHVzZUJpYXM6IHRoaXMudXNlQmlhcyxcbiAgICAgIGJpYXNJbml0aWFsaXplcjogc2VyaWFsaXplSW5pdGlhbGl6ZXIodGhpcy5iaWFzSW5pdGlhbGl6ZXIpLFxuICAgICAgYmlhc1JlZ3VsYXJpemVyOiBzZXJpYWxpemVSZWd1bGFyaXplcih0aGlzLmJpYXNSZWd1bGFyaXplciksXG4gICAgICBhY3Rpdml0eVJlZ3VsYXJpemVyOiBzZXJpYWxpemVSZWd1bGFyaXplcih0aGlzLmFjdGl2aXR5UmVndWxhcml6ZXIpLFxuICAgICAgYmlhc0NvbnN0cmFpbnQ6IHNlcmlhbGl6ZUNvbnN0cmFpbnQodGhpcy5iaWFzQ29uc3RyYWludClcbiAgICB9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuXG4vKipcbiAqIEFic3RyYWN0IG5EIGNvbnZvbHV0aW9uIGxheWVyLiAgQW5jZXN0b3Igb2YgY29udm9sdXRpb24gbGF5ZXJzIHdoaWNoIHJlZHVjZVxuICogYWNyb3NzIGNoYW5uZWxzLCBpLmUuLCBDb252MUQgYW5kIENvbnYyRCwgYnV0IG5vdCBEZXB0aHdpc2VDb252MkQuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBDb252IGV4dGVuZHMgQmFzZUNvbnYge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZmlsdGVyczogbnVtYmVyO1xuXG4gIHByb3RlY3RlZCBrZXJuZWw6IExheWVyVmFyaWFibGUgPSBudWxsO1xuXG4gIC8vIEJpYXMtcmVsYXRlZCBwcm9wZXJ0aWVzIGFyZSBzdG9yZWQgaW4gdGhlIHN1cGVyY2xhc3MgYEJhc2VDb252YCBiZWNhdXNlIGFsbFxuICAvLyBjb252b2x1dGlvbiBzdWJjbGFzc2VzIHVzZSB0aGUgc2FtZSBjb25maWd1cmF0aW9uIHBhcmFtZXRlcnMgdG8gY29udHJvbFxuICAvLyBiaWFzLiBLZXJuZWwtcmVsYXRlZCBwcm9wZXJ0aWVzIGFyZSBkZWZpbmVkIGhlcmUgcmF0aGVyIHRoYW4gaW4gdGhlXG4gIC8vIHN1cGVyY2xhc3MgYmVjYXVzZSBzb21lIGNvbnZvbHV0aW9uIHN1YmNsYXNzZXMgdXNlIGRpZmZlcmVudCBuYW1lcyBhbmRcbiAgLy8gY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzIGZvciB0aGVpciBpbnRlcm5hbCBrZXJuZWwgc3RhdGUuXG4gIHByb3RlY3RlZCByZWFkb25seSBrZXJuZWxJbml0aWFsaXplcj86IEluaXRpYWxpemVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkga2VybmVsQ29uc3RyYWludD86IENvbnN0cmFpbnQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBrZXJuZWxSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVyO1xuXG4gIGNvbnN0cnVjdG9yKHJhbms6IG51bWJlciwgYXJnczogQ29udkxheWVyQXJncykge1xuICAgIHN1cGVyKHJhbmssIGFyZ3MgYXMgQmFzZUNvbnZMYXllckFyZ3MpO1xuICAgIENvbnYudmVyaWZ5QXJncyhhcmdzKTtcbiAgICB0aGlzLmZpbHRlcnMgPSBhcmdzLmZpbHRlcnM7XG4gICAgZ2VuZXJpY191dGlscy5hc3NlcnRQb3NpdGl2ZUludGVnZXIodGhpcy5maWx0ZXJzLCAnZmlsdGVycycpO1xuICAgIHRoaXMua2VybmVsSW5pdGlhbGl6ZXIgPSBnZXRJbml0aWFsaXplcihcbiAgICAgICAgYXJncy5rZXJuZWxJbml0aWFsaXplciB8fCB0aGlzLkRFRkFVTFRfS0VSTkVMX0lOSVRJQUxJWkVSKTtcbiAgICB0aGlzLmtlcm5lbENvbnN0cmFpbnQgPSBnZXRDb25zdHJhaW50KGFyZ3Mua2VybmVsQ29uc3RyYWludCk7XG4gICAgdGhpcy5rZXJuZWxSZWd1bGFyaXplciA9IGdldFJlZ3VsYXJpemVyKGFyZ3Mua2VybmVsUmVndWxhcml6ZXIpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYnVpbGQoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IHZvaWQge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPVxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiBpbnB1dFNoYXBlLmxlbmd0aCAtIDE7XG4gICAgaWYgKGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBUaGUgY2hhbm5lbCBkaW1lbnNpb24gb2YgdGhlIGlucHV0IHNob3VsZCBiZSBkZWZpbmVkLiBgICtcbiAgICAgICAgICBgRm91bmQgJHtpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXX1gKTtcbiAgICB9XG4gICAgY29uc3QgaW5wdXREaW0gPSBpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXTtcblxuICAgIGNvbnN0IGtlcm5lbFNoYXBlID0gdGhpcy5rZXJuZWxTaXplLmNvbmNhdChbaW5wdXREaW0sIHRoaXMuZmlsdGVyc10pO1xuXG4gICAgdGhpcy5rZXJuZWwgPSB0aGlzLmFkZFdlaWdodChcbiAgICAgICAgJ2tlcm5lbCcsIGtlcm5lbFNoYXBlLCBudWxsLCB0aGlzLmtlcm5lbEluaXRpYWxpemVyLFxuICAgICAgICB0aGlzLmtlcm5lbFJlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmtlcm5lbENvbnN0cmFpbnQpO1xuICAgIGlmICh0aGlzLnVzZUJpYXMpIHtcbiAgICAgIHRoaXMuYmlhcyA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAgICdiaWFzJywgW3RoaXMuZmlsdGVyc10sIG51bGwsIHRoaXMuYmlhc0luaXRpYWxpemVyLFxuICAgICAgICAgIHRoaXMuYmlhc1JlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmJpYXNDb25zdHJhaW50KTtcbiAgICB9XG5cbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogdGhpcy5yYW5rICsgMiwgYXhlczoge1tjaGFubmVsQXhpc106IGlucHV0RGltfX1dO1xuICAgIHRoaXMuYnVpbHQgPSB0cnVlO1xuICB9XG5cbiAgb3ZlcnJpZGUgY2FsbChpbnB1dHM6IFRlbnNvcnxUZW5zb3JbXSwga3dhcmdzOiBLd2FyZ3MpOiBUZW5zb3J8VGVuc29yW10ge1xuICAgIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICAgIGlucHV0cyA9IGdldEV4YWN0bHlPbmVUZW5zb3IoaW5wdXRzKTtcbiAgICAgIGxldCBvdXRwdXRzOiBUZW5zb3I7XG4gICAgICBjb25zdCBiaWFzVmFsdWUgPSB0aGlzLmJpYXMgPT0gbnVsbCA/IG51bGwgOiB0aGlzLmJpYXMucmVhZCgpO1xuICAgICAgY29uc3QgZnVzZWRBY3RpdmF0aW9uTmFtZSA9IGdlbmVyaWNfdXRpbHMubWFwQWN0aXZhdGlvblRvRnVzZWRLZXJuZWwoXG4gICAgICAgICAgdGhpcy5hY3RpdmF0aW9uLmdldENsYXNzTmFtZSgpKTtcblxuICAgICAgaWYgKGZ1c2VkQWN0aXZhdGlvbk5hbWUgIT0gbnVsbCAmJiB0aGlzLnJhbmsgPT09IDIpIHtcbiAgICAgICAgb3V0cHV0cyA9IGNvbnYyZFdpdGhCaWFzQWN0aXZhdGlvbihcbiAgICAgICAgICAgIGlucHV0cywgdGhpcy5rZXJuZWwucmVhZCgpLCBiaWFzVmFsdWUsIHRoaXMuc3RyaWRlcywgdGhpcy5wYWRkaW5nLFxuICAgICAgICAgICAgdGhpcy5kYXRhRm9ybWF0LCB0aGlzLmRpbGF0aW9uUmF0ZSBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICAgICAgZnVzZWRBY3RpdmF0aW9uTmFtZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAodGhpcy5yYW5rID09PSAxKSB7XG4gICAgICAgICAgb3V0cHV0cyA9IGNvbnYxZFdpdGhCaWFzKFxuICAgICAgICAgICAgICBpbnB1dHMsIHRoaXMua2VybmVsLnJlYWQoKSwgYmlhc1ZhbHVlLCB0aGlzLnN0cmlkZXNbMF0sXG4gICAgICAgICAgICAgIHRoaXMucGFkZGluZywgdGhpcy5kYXRhRm9ybWF0LCB0aGlzLmRpbGF0aW9uUmF0ZVswXSk7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5yYW5rID09PSAyKSB7XG4gICAgICAgICAgLy8gVE9ETyhjYWlzKTogTW92ZSB1cCB0byBjb25zdHJ1Y3Rvci5cbiAgICAgICAgICBvdXRwdXRzID0gY29udjJkV2l0aEJpYXNBY3RpdmF0aW9uKFxuICAgICAgICAgICAgICBpbnB1dHMsIHRoaXMua2VybmVsLnJlYWQoKSwgYmlhc1ZhbHVlLCB0aGlzLnN0cmlkZXMsIHRoaXMucGFkZGluZyxcbiAgICAgICAgICAgICAgdGhpcy5kYXRhRm9ybWF0LCB0aGlzLmRpbGF0aW9uUmF0ZSBhcyBbbnVtYmVyLCBudW1iZXJdKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnJhbmsgPT09IDMpIHtcbiAgICAgICAgICBvdXRwdXRzID0gY29udjNkV2l0aEJpYXMoXG4gICAgICAgICAgICAgIGlucHV0cywgdGhpcy5rZXJuZWwucmVhZCgpLCBiaWFzVmFsdWUsIHRoaXMuc3RyaWRlcywgdGhpcy5wYWRkaW5nLFxuICAgICAgICAgICAgICB0aGlzLmRhdGFGb3JtYXQsIHRoaXMuZGlsYXRpb25SYXRlIGFzIFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgICAgICdjb252b2x1dGlvbnMgZ3JlYXRlciB0aGFuIDNEIGFyZSBub3QgaW1wbGVtZW50ZWQgeWV0LicpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgICAgb3V0cHV0cyA9IHRoaXMuYWN0aXZhdGlvbi5hcHBseShvdXRwdXRzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gb3V0cHV0cztcbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogU2hhcGV8U2hhcGVbXSB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBjb25zdCBuZXdTcGFjZTogbnVtYmVyW10gPSBbXTtcbiAgICBjb25zdCBzcGFjZSA9ICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0xhc3QnKSA/XG4gICAgICAgIGlucHV0U2hhcGUuc2xpY2UoMSwgaW5wdXRTaGFwZS5sZW5ndGggLSAxKSA6XG4gICAgICAgIGlucHV0U2hhcGUuc2xpY2UoMik7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzcGFjZS5sZW5ndGg7ICsraSkge1xuICAgICAgY29uc3QgbmV3RGltID0gY29udk91dHB1dExlbmd0aChcbiAgICAgICAgICBzcGFjZVtpXSwgdGhpcy5rZXJuZWxTaXplW2ldLCB0aGlzLnBhZGRpbmcsIHRoaXMuc3RyaWRlc1tpXSxcbiAgICAgICAgICB0eXBlb2YgdGhpcy5kaWxhdGlvblJhdGUgPT09ICdudW1iZXInID8gdGhpcy5kaWxhdGlvblJhdGUgOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRpbGF0aW9uUmF0ZVtpXSk7XG4gICAgICBuZXdTcGFjZS5wdXNoKG5ld0RpbSk7XG4gICAgfVxuXG4gICAgbGV0IG91dHB1dFNoYXBlID0gW2lucHV0U2hhcGVbMF1dO1xuICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0xhc3QnKSB7XG4gICAgICBvdXRwdXRTaGFwZSA9IG91dHB1dFNoYXBlLmNvbmNhdChuZXdTcGFjZSk7XG4gICAgICBvdXRwdXRTaGFwZS5wdXNoKHRoaXMuZmlsdGVycyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG91dHB1dFNoYXBlLnB1c2godGhpcy5maWx0ZXJzKTtcbiAgICAgIG91dHB1dFNoYXBlID0gb3V0cHV0U2hhcGUuY29uY2F0KG5ld1NwYWNlKTtcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0ge1xuICAgICAgZmlsdGVyczogdGhpcy5maWx0ZXJzLFxuICAgICAga2VybmVsSW5pdGlhbGl6ZXI6IHNlcmlhbGl6ZUluaXRpYWxpemVyKHRoaXMua2VybmVsSW5pdGlhbGl6ZXIpLFxuICAgICAga2VybmVsUmVndWxhcml6ZXI6IHNlcmlhbGl6ZVJlZ3VsYXJpemVyKHRoaXMua2VybmVsUmVndWxhcml6ZXIpLFxuICAgICAga2VybmVsQ29uc3RyYWludDogc2VyaWFsaXplQ29uc3RyYWludCh0aGlzLmtlcm5lbENvbnN0cmFpbnQpXG4gICAgfTtcbiAgICBjb25zdCBiYXNlQ29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgT2JqZWN0LmFzc2lnbihjb25maWcsIGJhc2VDb25maWcpO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIG92ZXJyaWRlIHZlcmlmeUFyZ3MoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIC8vIENoZWNrIGNvbmZpZy5maWx0ZXJzIHR5cGUsIHNoYXBlLCBhbmQgdmFsdWUuXG4gICAgaWYgKCEoJ2ZpbHRlcnMnIGluIGFyZ3MpIHx8IHR5cGVvZiBhcmdzLmZpbHRlcnMgIT09ICdudW1iZXInIHx8XG4gICAgICAgIGFyZ3MuZmlsdGVycyA8IDEpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBDb252b2x1dGlvbiBsYXllciBleHBlY3RlZCBjb25maWcuZmlsdGVycyB0byBiZSBhICdudW1iZXInID4gMCBgICtcbiAgICAgICAgICBgYnV0IGdvdCAke0pTT04uc3RyaW5naWZ5KGFyZ3MuZmlsdGVycyl9YCk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBDb252MkQgZXh0ZW5kcyBDb252IHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBjbGFzc05hbWUgPSAnQ29udjJEJztcbiAgY29uc3RydWN0b3IoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIHN1cGVyKDIsIGFyZ3MpO1xuICAgIENvbnYyRC52ZXJpZnlBcmdzKGFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIG92ZXJyaWRlIHZlcmlmeUFyZ3MoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIC8vIGNvbmZpZy5rZXJuZWxTaXplIG11c3QgYmUgYSBudW1iZXIgb3IgYXJyYXkgb2YgbnVtYmVycy5cbiAgICBpZiAoKHR5cGVvZiBhcmdzLmtlcm5lbFNpemUgIT09ICdudW1iZXInKSAmJlxuICAgICAgICAhZ2VuZXJpY191dGlscy5jaGVja0FycmF5VHlwZUFuZExlbmd0aChcbiAgICAgICAgICAgIGFyZ3Mua2VybmVsU2l6ZSwgJ251bWJlcicsIDEsIDIpKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgQ29udjJEIGV4cGVjdHMgY29uZmlnLmtlcm5lbFNpemUgdG8gYmUgbnVtYmVyIG9yIG51bWJlcltdIHdpdGggYCArXG4gICAgICAgICAgYGxlbmd0aCAxIG9yIDIsIGJ1dCByZWNlaXZlZCAke0pTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgIH1cbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYyRCk7XG5cbmV4cG9ydCBjbGFzcyBDb252M0QgZXh0ZW5kcyBDb252IHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBjbGFzc05hbWUgPSAnQ29udjNEJztcbiAgY29uc3RydWN0b3IoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIHN1cGVyKDMsIGFyZ3MpO1xuICAgIENvbnYzRC52ZXJpZnlBcmdzKGFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIG92ZXJyaWRlIHZlcmlmeUFyZ3MoYXJnczogQ29udkxheWVyQXJncykge1xuICAgIC8vIGNvbmZpZy5rZXJuZWxTaXplIG11c3QgYmUgYSBudW1iZXIgb3IgYXJyYXkgb2YgbnVtYmVycy5cbiAgICBpZiAodHlwZW9mIGFyZ3Mua2VybmVsU2l6ZSAhPT0gJ251bWJlcicpIHtcbiAgICAgIGlmICghKEFycmF5LmlzQXJyYXkoYXJncy5rZXJuZWxTaXplKSAmJlxuICAgICAgICAgICAgKGFyZ3Mua2VybmVsU2l6ZS5sZW5ndGggPT09IDEgfHwgYXJncy5rZXJuZWxTaXplLmxlbmd0aCA9PT0gMykpKSB7XG4gICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgYENvbnYzRCBleHBlY3RzIGNvbmZpZy5rZXJuZWxTaXplIHRvIGJlIG51bWJlciBvcmAgK1xuICAgICAgICAgICAgYCBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0sIGJ1dCByZWNlaXZlZCAke1xuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYzRCk7XG5cbmV4cG9ydCBjbGFzcyBDb252MkRUcmFuc3Bvc2UgZXh0ZW5kcyBDb252MkQge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIG92ZXJyaWRlIGNsYXNzTmFtZSA9ICdDb252MkRUcmFuc3Bvc2UnO1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFtuZXcgSW5wdXRTcGVjKHtuZGltOiA0fSldO1xuXG4gICAgaWYgKHRoaXMucGFkZGluZyAhPT0gJ3NhbWUnICYmIHRoaXMucGFkZGluZyAhPT0gJ3ZhbGlkJykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYENvbnYyRFRyYW5zcG9zZSBjdXJyZW50bHkgc3VwcG9ydHMgb25seSBwYWRkaW5nIG1vZGVzICdzYW1lJyBgICtcbiAgICAgICAgICBgYW5kICd2YWxpZCcsIGJ1dCByZWNlaXZlZCBwYWRkaW5nIG1vZGUgJHt0aGlzLnBhZGRpbmd9YCk7XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgYnVpbGQoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IHZvaWQge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG5cbiAgICBpZiAoaW5wdXRTaGFwZS5sZW5ndGggIT09IDQpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdJbnB1dCBzaG91bGQgaGF2ZSByYW5rIDQ7IFJlY2VpdmVkIGlucHV0IHNoYXBlOiAnICtcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShpbnB1dFNoYXBlKSk7XG4gICAgfVxuXG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPVxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiBpbnB1dFNoYXBlLmxlbmd0aCAtIDE7XG4gICAgaWYgKGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdUaGUgY2hhbm5lbCBkaW1lbnNpb24gb2YgdGhlIGlucHV0cyBzaG91bGQgYmUgZGVmaW5lZC4gJyArXG4gICAgICAgICAgJ0ZvdW5kIGBOb25lYC4nKTtcbiAgICB9XG4gICAgY29uc3QgaW5wdXREaW0gPSBpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXTtcbiAgICBjb25zdCBrZXJuZWxTaGFwZSA9IHRoaXMua2VybmVsU2l6ZS5jb25jYXQoW3RoaXMuZmlsdGVycywgaW5wdXREaW1dKTtcblxuICAgIHRoaXMua2VybmVsID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICdrZXJuZWwnLCBrZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLCB0aGlzLmtlcm5lbEluaXRpYWxpemVyLFxuICAgICAgICB0aGlzLmtlcm5lbFJlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmtlcm5lbENvbnN0cmFpbnQpO1xuICAgIGlmICh0aGlzLnVzZUJpYXMpIHtcbiAgICAgIHRoaXMuYmlhcyA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAgICdiaWFzJywgW3RoaXMuZmlsdGVyc10sICdmbG9hdDMyJywgdGhpcy5iaWFzSW5pdGlhbGl6ZXIsXG4gICAgICAgICAgdGhpcy5iaWFzUmVndWxhcml6ZXIsIHRydWUsIHRoaXMuYmlhc0NvbnN0cmFpbnQpO1xuICAgIH1cblxuICAgIC8vIFNldCBpbnB1dCBzcGVjLlxuICAgIHRoaXMuaW5wdXRTcGVjID1cbiAgICAgICAgW25ldyBJbnB1dFNwZWMoe25kaW06IDQsIGF4ZXM6IHtbY2hhbm5lbEF4aXNdOiBpbnB1dERpbX19KV07XG4gICAgdGhpcy5idWlsdCA9IHRydWU7XG4gIH1cblxuICBvdmVycmlkZSBjYWxsKGlucHV0czogVGVuc29yfFRlbnNvcltdLCBrd2FyZ3M6IEt3YXJncyk6IFRlbnNvcnxUZW5zb3JbXSB7XG4gICAgcmV0dXJuIHRmYy50aWR5KCgpID0+IHtcbiAgICAgIGxldCBpbnB1dCA9IGdldEV4YWN0bHlPbmVUZW5zb3IoaW5wdXRzKTtcbiAgICAgIGlmIChpbnB1dC5zaGFwZS5sZW5ndGggIT09IDQpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgICBgQ29udjJEVHJhbnNwb3NlLmNhbGwoKSBleHBlY3RzIGlucHV0IHRlbnNvciB0byBiZSByYW5rLTQsIGJ1dCBgICtcbiAgICAgICAgICAgIGByZWNlaXZlZCBhIHRlbnNvciBvZiByYW5rLSR7aW5wdXQuc2hhcGUubGVuZ3RofWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbnB1dFNoYXBlID0gaW5wdXQuc2hhcGU7XG4gICAgICBjb25zdCBiYXRjaFNpemUgPSBpbnB1dFNoYXBlWzBdO1xuXG4gICAgICBsZXQgaEF4aXM6IG51bWJlcjtcbiAgICAgIGxldCB3QXhpczogbnVtYmVyO1xuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICAgIGhBeGlzID0gMjtcbiAgICAgICAgd0F4aXMgPSAzO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaEF4aXMgPSAxO1xuICAgICAgICB3QXhpcyA9IDI7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhlaWdodCA9IGlucHV0U2hhcGVbaEF4aXNdO1xuICAgICAgY29uc3Qgd2lkdGggPSBpbnB1dFNoYXBlW3dBeGlzXTtcbiAgICAgIGNvbnN0IGtlcm5lbEggPSB0aGlzLmtlcm5lbFNpemVbMF07XG4gICAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzFdO1xuICAgICAgY29uc3Qgc3RyaWRlSCA9IHRoaXMuc3RyaWRlc1swXTtcbiAgICAgIGNvbnN0IHN0cmlkZVcgPSB0aGlzLnN0cmlkZXNbMV07XG5cbiAgICAgIC8vIEluZmVyIHRoZSBkeW5hbWljIG91dHB1dCBzaGFwZS5cbiAgICAgIGNvbnN0IG91dEhlaWdodCA9IGRlY29udkxlbmd0aChoZWlnaHQsIHN0cmlkZUgsIGtlcm5lbEgsIHRoaXMucGFkZGluZyk7XG4gICAgICBjb25zdCBvdXRXaWR0aCA9IGRlY29udkxlbmd0aCh3aWR0aCwgc3RyaWRlVywga2VybmVsVywgdGhpcy5wYWRkaW5nKTtcblxuICAgICAgLy8gUG9ydGluZyBOb3RlOiBXZSBkb24ndCBicmFuY2ggYmFzZWQgb24gYHRoaXMuZGF0YUZvcm1hdGAgaGVyZSxcbiAgICAgIC8vIGJlY2F1c2VcbiAgICAgIC8vICAgdGhlIHRqZnMtY29yZSBmdW5jdGlvbiBgY29udjJkVHJhbnNwb3NlYCBjYWxsZWQgYmVsb3cgYWx3YXlzXG4gICAgICAvLyAgIGFzc3VtZXMgY2hhbm5lbHNMYXN0LlxuICAgICAgY29uc3Qgb3V0cHV0U2hhcGU6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXJdID1cbiAgICAgICAgICBbYmF0Y2hTaXplLCBvdXRIZWlnaHQsIG91dFdpZHRoLCB0aGlzLmZpbHRlcnNdO1xuXG4gICAgICBpZiAodGhpcy5kYXRhRm9ybWF0ICE9PSAnY2hhbm5lbHNMYXN0Jykge1xuICAgICAgICBpbnB1dCA9IHRmYy50cmFuc3Bvc2UoaW5wdXQsIFswLCAyLCAzLCAxXSk7XG4gICAgICB9XG4gICAgICBsZXQgb3V0cHV0cyA9IHRmYy5jb252MmRUcmFuc3Bvc2UoXG4gICAgICAgICAgaW5wdXQgYXMgVGVuc29yNEQsIHRoaXMua2VybmVsLnJlYWQoKSBhcyBUZW5zb3I0RCwgb3V0cHV0U2hhcGUsXG4gICAgICAgICAgdGhpcy5zdHJpZGVzIGFzIFtudW1iZXIsIG51bWJlcl0sIHRoaXMucGFkZGluZyBhcyAnc2FtZScgfCAndmFsaWQnKTtcbiAgICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgIT09ICdjaGFubmVsc0xhc3QnKSB7XG4gICAgICAgIG91dHB1dHMgPSB0ZmMudHJhbnNwb3NlKG91dHB1dHMsIFswLCAzLCAxLCAyXSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmJpYXMgIT0gbnVsbCkge1xuICAgICAgICBvdXRwdXRzID1cbiAgICAgICAgICAgIEsuYmlhc0FkZChvdXRwdXRzLCB0aGlzLmJpYXMucmVhZCgpLCB0aGlzLmRhdGFGb3JtYXQpIGFzIFRlbnNvcjREO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgIG91dHB1dHMgPSB0aGlzLmFjdGl2YXRpb24uYXBwbHkob3V0cHV0cykgYXMgVGVuc29yNEQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3V0cHV0cztcbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogU2hhcGV8U2hhcGVbXSB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBjb25zdCBvdXRwdXRTaGFwZSA9IGlucHV0U2hhcGUuc2xpY2UoKTtcblxuICAgIGxldCBjaGFubmVsQXhpczogbnVtYmVyO1xuICAgIGxldCBoZWlnaHRBeGlzOiBudW1iZXI7XG4gICAgbGV0IHdpZHRoQXhpczogbnVtYmVyO1xuICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgY2hhbm5lbEF4aXMgPSAxO1xuICAgICAgaGVpZ2h0QXhpcyA9IDI7XG4gICAgICB3aWR0aEF4aXMgPSAzO1xuICAgIH0gZWxzZSB7XG4gICAgICBjaGFubmVsQXhpcyA9IDM7XG4gICAgICBoZWlnaHRBeGlzID0gMTtcbiAgICAgIHdpZHRoQXhpcyA9IDI7XG4gICAgfVxuXG4gICAgY29uc3Qga2VybmVsSCA9IHRoaXMua2VybmVsU2l6ZVswXTtcbiAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzFdO1xuICAgIGNvbnN0IHN0cmlkZUggPSB0aGlzLnN0cmlkZXNbMF07XG4gICAgY29uc3Qgc3RyaWRlVyA9IHRoaXMuc3RyaWRlc1sxXTtcblxuICAgIG91dHB1dFNoYXBlW2NoYW5uZWxBeGlzXSA9IHRoaXMuZmlsdGVycztcbiAgICBvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSA9XG4gICAgICAgIGRlY29udkxlbmd0aChvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSwgc3RyaWRlSCwga2VybmVsSCwgdGhpcy5wYWRkaW5nKTtcbiAgICBvdXRwdXRTaGFwZVt3aWR0aEF4aXNdID1cbiAgICAgICAgZGVjb252TGVuZ3RoKG91dHB1dFNoYXBlW3dpZHRoQXhpc10sIHN0cmlkZVcsIGtlcm5lbFcsIHRoaXMucGFkZGluZyk7XG4gICAgcmV0dXJuIG91dHB1dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1snZGlsYXRpb25SYXRlJ107XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYyRFRyYW5zcG9zZSk7XG5cbmV4cG9ydCBjbGFzcyBDb252M0RUcmFuc3Bvc2UgZXh0ZW5kcyBDb252M0Qge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIG92ZXJyaWRlIGNsYXNzTmFtZSA9ICdDb252M0RUcmFuc3Bvc2UnO1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFtuZXcgSW5wdXRTcGVjKHtuZGltOiA1fSldO1xuXG4gICAgaWYgKHRoaXMucGFkZGluZyAhPT0gJ3NhbWUnICYmIHRoaXMucGFkZGluZyAhPT0gJ3ZhbGlkJykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYENvbnYzRFRyYW5zcG9zZSBjdXJyZW50bHkgc3VwcG9ydHMgb25seSBwYWRkaW5nIG1vZGVzICdzYW1lJyBgICtcbiAgICAgICAgICBgYW5kICd2YWxpZCcsIGJ1dCByZWNlaXZlZCBwYWRkaW5nIG1vZGUgJHt0aGlzLnBhZGRpbmd9YCk7XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgYnVpbGQoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IHZvaWQge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG5cbiAgICBpZiAoaW5wdXRTaGFwZS5sZW5ndGggIT09IDUpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdJbnB1dCBzaG91bGQgaGF2ZSByYW5rIDU7IFJlY2VpdmVkIGlucHV0IHNoYXBlOiAnICtcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShpbnB1dFNoYXBlKSk7XG4gICAgfVxuXG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPVxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiBpbnB1dFNoYXBlLmxlbmd0aCAtIDE7XG4gICAgaWYgKGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdID09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICdUaGUgY2hhbm5lbCBkaW1lbnNpb24gb2YgdGhlIGlucHV0cyBzaG91bGQgYmUgZGVmaW5lZC4gJyArXG4gICAgICAgICAgJ0ZvdW5kIGBOb25lYC4nKTtcbiAgICB9XG4gICAgY29uc3QgaW5wdXREaW0gPSBpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXTtcbiAgICBjb25zdCBrZXJuZWxTaGFwZSA9IHRoaXMua2VybmVsU2l6ZS5jb25jYXQoW3RoaXMuZmlsdGVycywgaW5wdXREaW1dKTtcblxuICAgIHRoaXMua2VybmVsID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICdrZXJuZWwnLCBrZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLCB0aGlzLmtlcm5lbEluaXRpYWxpemVyLFxuICAgICAgICB0aGlzLmtlcm5lbFJlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmtlcm5lbENvbnN0cmFpbnQpO1xuICAgIGlmICh0aGlzLnVzZUJpYXMpIHtcbiAgICAgIHRoaXMuYmlhcyA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAgICdiaWFzJywgW3RoaXMuZmlsdGVyc10sICdmbG9hdDMyJywgdGhpcy5iaWFzSW5pdGlhbGl6ZXIsXG4gICAgICAgICAgdGhpcy5iaWFzUmVndWxhcml6ZXIsIHRydWUsIHRoaXMuYmlhc0NvbnN0cmFpbnQpO1xuICAgIH1cblxuICAgIC8vIFNldCBpbnB1dCBzcGVjLlxuICAgIHRoaXMuaW5wdXRTcGVjID1cbiAgICAgICAgW25ldyBJbnB1dFNwZWMoe25kaW06IDUsIGF4ZXM6IHtbY2hhbm5lbEF4aXNdOiBpbnB1dERpbX19KV07XG4gICAgdGhpcy5idWlsdCA9IHRydWU7XG4gIH1cblxuICBvdmVycmlkZSBjYWxsKGlucHV0czogVGVuc29yfFRlbnNvcltdLCBrd2FyZ3M6IEt3YXJncyk6IFRlbnNvcnxUZW5zb3JbXSB7XG4gICAgcmV0dXJuIHRmYy50aWR5PHRmYy5UZW5zb3I1RD4oKCkgPT4ge1xuICAgICAgbGV0IGlucHV0ID0gZ2V0RXhhY3RseU9uZVRlbnNvcihpbnB1dHMpO1xuICAgICAgaWYgKGlucHV0LnNoYXBlLmxlbmd0aCAhPT0gNSkge1xuICAgICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICAgIGBDb252M0RUcmFuc3Bvc2UuY2FsbCgpIGV4cGVjdHMgaW5wdXQgdGVuc29yIHRvIGJlIHJhbmstNCwgYnV0IGAgK1xuICAgICAgICAgICAgYHJlY2VpdmVkIGEgdGVuc29yIG9mIHJhbmstJHtpbnB1dC5zaGFwZS5sZW5ndGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGlucHV0U2hhcGUgPSBpbnB1dC5zaGFwZTtcbiAgICAgIGNvbnN0IGJhdGNoU2l6ZSA9IGlucHV0U2hhcGVbMF07XG5cbiAgICAgIGxldCBoQXhpczogbnVtYmVyO1xuICAgICAgbGV0IHdBeGlzOiBudW1iZXI7XG4gICAgICBsZXQgZEF4aXM6IG51bWJlcjtcblxuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICAgIGRBeGlzID0gMjtcbiAgICAgICAgaEF4aXMgPSAzO1xuICAgICAgICB3QXhpcyA9IDQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkQXhpcyA9IDE7XG4gICAgICAgIGhBeGlzID0gMjtcbiAgICAgICAgd0F4aXMgPSAzO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBkZXB0aCA9IGlucHV0U2hhcGVbZEF4aXNdO1xuICAgICAgY29uc3QgaGVpZ2h0ID0gaW5wdXRTaGFwZVtoQXhpc107XG4gICAgICBjb25zdCB3aWR0aCA9IGlucHV0U2hhcGVbd0F4aXNdO1xuICAgICAgY29uc3Qga2VybmVsRCA9IHRoaXMua2VybmVsU2l6ZVswXTtcbiAgICAgIGNvbnN0IGtlcm5lbEggPSB0aGlzLmtlcm5lbFNpemVbMV07XG4gICAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzJdO1xuICAgICAgY29uc3Qgc3RyaWRlRCA9IHRoaXMuc3RyaWRlc1swXTtcbiAgICAgIGNvbnN0IHN0cmlkZUggPSB0aGlzLnN0cmlkZXNbMV07XG4gICAgICBjb25zdCBzdHJpZGVXID0gdGhpcy5zdHJpZGVzWzJdO1xuXG4gICAgICAvLyBJbmZlciB0aGUgZHluYW1pYyBvdXRwdXQgc2hhcGUuXG4gICAgICBjb25zdCBvdXREZXB0aCA9IGRlY29udkxlbmd0aChkZXB0aCwgc3RyaWRlRCwga2VybmVsRCwgdGhpcy5wYWRkaW5nKTtcbiAgICAgIGNvbnN0IG91dEhlaWdodCA9IGRlY29udkxlbmd0aChoZWlnaHQsIHN0cmlkZUgsIGtlcm5lbEgsIHRoaXMucGFkZGluZyk7XG4gICAgICBjb25zdCBvdXRXaWR0aCA9IGRlY29udkxlbmd0aCh3aWR0aCwgc3RyaWRlVywga2VybmVsVywgdGhpcy5wYWRkaW5nKTtcblxuICAgICAgLy8gU2FtZSBhcyBgY29udjJkVHJhbnNwb3NlYC4gV2UgYWx3YXlzIGFzc3VtZXMgY2hhbm5lbHNMYXN0LlxuICAgICAgY29uc3Qgb3V0cHV0U2hhcGU6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXIsIG51bWJlcl0gPVxuICAgICAgICAgIFtiYXRjaFNpemUsIG91dERlcHRoLCBvdXRIZWlnaHQsIG91dFdpZHRoLCB0aGlzLmZpbHRlcnNdO1xuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCAhPT0gJ2NoYW5uZWxzTGFzdCcpIHtcbiAgICAgICAgaW5wdXQgPSB0ZmMudHJhbnNwb3NlKGlucHV0LCBbMCwgMiwgMywgNCwgMV0pO1xuICAgICAgfVxuICAgICAgbGV0IG91dHB1dHMgPSB0ZmMuY29udjNkVHJhbnNwb3NlKFxuICAgICAgICAgIGlucHV0IGFzIFRlbnNvcjVELCB0aGlzLmtlcm5lbC5yZWFkKCkgYXMgVGVuc29yNUQsIG91dHB1dFNoYXBlLFxuICAgICAgICAgIHRoaXMuc3RyaWRlcyBhcyBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0sXG4gICAgICAgICAgdGhpcy5wYWRkaW5nIGFzICdzYW1lJyB8ICd2YWxpZCcpO1xuICAgICAgaWYgKHRoaXMuZGF0YUZvcm1hdCAhPT0gJ2NoYW5uZWxzTGFzdCcpIHtcbiAgICAgICAgb3V0cHV0cyA9IHRmYy50cmFuc3Bvc2Uob3V0cHV0cywgWzAsIDQsIDEsIDIsIDNdKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuYmlhcyAhPT0gbnVsbCkge1xuICAgICAgICBvdXRwdXRzID1cbiAgICAgICAgICAgIEsuYmlhc0FkZChvdXRwdXRzLCB0aGlzLmJpYXMucmVhZCgpLCB0aGlzLmRhdGFGb3JtYXQpIGFzIFRlbnNvcjVEO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPT0gbnVsbCkge1xuICAgICAgICBvdXRwdXRzID0gdGhpcy5hY3RpdmF0aW9uLmFwcGx5KG91dHB1dHMpIGFzIFRlbnNvcjVEO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG91dHB1dHM7XG4gICAgfSk7XG4gIH1cblxuICBvdmVycmlkZSBjb21wdXRlT3V0cHV0U2hhcGUoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IFNoYXBlfFNoYXBlW10ge1xuICAgIGlucHV0U2hhcGUgPSBnZXRFeGFjdGx5T25lU2hhcGUoaW5wdXRTaGFwZSk7XG4gICAgY29uc3Qgb3V0cHV0U2hhcGUgPSBpbnB1dFNoYXBlLnNsaWNlKCk7XG5cbiAgICBsZXQgY2hhbm5lbEF4aXM6IG51bWJlcjtcbiAgICBsZXQgZGVwdGhBeGlzOiBudW1iZXI7XG4gICAgbGV0IGhlaWdodEF4aXM6IG51bWJlcjtcbiAgICBsZXQgd2lkdGhBeGlzOiBudW1iZXI7XG4gICAgaWYgKHRoaXMuZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnKSB7XG4gICAgICBjaGFubmVsQXhpcyA9IDE7XG4gICAgICBkZXB0aEF4aXMgPSAyO1xuICAgICAgaGVpZ2h0QXhpcyA9IDM7XG4gICAgICB3aWR0aEF4aXMgPSA0O1xuICAgIH0gZWxzZSB7XG4gICAgICBjaGFubmVsQXhpcyA9IDQ7XG4gICAgICBkZXB0aEF4aXMgPSAxO1xuICAgICAgaGVpZ2h0QXhpcyA9IDI7XG4gICAgICB3aWR0aEF4aXMgPSAzO1xuICAgIH1cblxuICAgIGNvbnN0IGtlcm5lbEQgPSB0aGlzLmtlcm5lbFNpemVbMF07XG4gICAgY29uc3Qga2VybmVsSCA9IHRoaXMua2VybmVsU2l6ZVsxXTtcbiAgICBjb25zdCBrZXJuZWxXID0gdGhpcy5rZXJuZWxTaXplWzJdO1xuICAgIGNvbnN0IHN0cmlkZUQgPSB0aGlzLnN0cmlkZXNbMF07XG4gICAgY29uc3Qgc3RyaWRlSCA9IHRoaXMuc3RyaWRlc1sxXTtcbiAgICBjb25zdCBzdHJpZGVXID0gdGhpcy5zdHJpZGVzWzJdO1xuXG4gICAgb3V0cHV0U2hhcGVbY2hhbm5lbEF4aXNdID0gdGhpcy5maWx0ZXJzO1xuICAgIG91dHB1dFNoYXBlW2RlcHRoQXhpc10gPVxuICAgICAgICBkZWNvbnZMZW5ndGgob3V0cHV0U2hhcGVbZGVwdGhBeGlzXSwgc3RyaWRlRCwga2VybmVsRCwgdGhpcy5wYWRkaW5nKTtcbiAgICBvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSA9XG4gICAgICAgIGRlY29udkxlbmd0aChvdXRwdXRTaGFwZVtoZWlnaHRBeGlzXSwgc3RyaWRlSCwga2VybmVsSCwgdGhpcy5wYWRkaW5nKTtcbiAgICBvdXRwdXRTaGFwZVt3aWR0aEF4aXNdID1cbiAgICAgICAgZGVjb252TGVuZ3RoKG91dHB1dFNoYXBlW3dpZHRoQXhpc10sIHN0cmlkZVcsIGtlcm5lbFcsIHRoaXMucGFkZGluZyk7XG4gICAgcmV0dXJuIG91dHB1dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1snZGlsYXRpb25SYXRlJ107XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYzRFRyYW5zcG9zZSk7XG5cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBTZXBhcmFibGVDb252TGF5ZXJBcmdzIGV4dGVuZHMgQ29udkxheWVyQXJncyB7XG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIGRlcHRod2lzZSBjb252b2x1dGlvbiBvdXRwdXQgY2hhbm5lbHMgZm9yIGVhY2ggaW5wdXRcbiAgICogY2hhbm5lbC5cbiAgICogVGhlIHRvdGFsIG51bWJlciBvZiBkZXB0aHdpc2UgY29udm9sdXRpb24gb3V0cHV0IGNoYW5uZWxzIHdpbGwgYmUgZXF1YWxcbiAgICogdG8gYGZpbHRlcnNJbiAqIGRlcHRoTXVsdGlwbGllcmAuIERlZmF1bHQ6IDEuXG4gICAqL1xuICBkZXB0aE11bHRpcGxpZXI/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVyIGZvciB0aGUgZGVwdGh3aXNlIGtlcm5lbCBtYXRyaXguXG4gICAqL1xuICBkZXB0aHdpc2VJbml0aWFsaXplcj86IEluaXRpYWxpemVySWRlbnRpZmllcnxJbml0aWFsaXplcjtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXIgZm9yIHRoZSBwb2ludHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICovXG4gIHBvaW50d2lzZUluaXRpYWxpemVyPzogSW5pdGlhbGl6ZXJJZGVudGlmaWVyfEluaXRpYWxpemVyO1xuXG4gIC8qKlxuICAgKiBSZWd1bGFyaXplciBmdW5jdGlvbiBhcHBsaWVkIHRvIHRoZSBkZXB0aHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICovXG4gIGRlcHRod2lzZVJlZ3VsYXJpemVyPzogUmVndWxhcml6ZXJJZGVudGlmaWVyfFJlZ3VsYXJpemVyO1xuXG4gIC8qKlxuICAgKiBSZWd1bGFyaXplciBmdW5jdGlvbiBhcHBsaWVkIHRvIHRoZSBwb2ludHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICovXG4gIHBvaW50d2lzZVJlZ3VsYXJpemVyPzogUmVndWxhcml6ZXJJZGVudGlmaWVyfFJlZ3VsYXJpemVyO1xuXG4gIC8qKlxuICAgKiBDb25zdHJhaW50IGZ1bmN0aW9uIGFwcGxpZWQgdG8gdGhlIGRlcHRod2lzZSBrZXJuZWwgbWF0cml4LlxuICAgKi9cbiAgZGVwdGh3aXNlQ29uc3RyYWludD86IENvbnN0cmFpbnRJZGVudGlmaWVyfENvbnN0cmFpbnQ7XG5cbiAgLyoqXG4gICAqIENvbnN0cmFpbnQgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgcG9pbnR3aXNlIGtlcm5lbCBtYXRyaXguXG4gICAqL1xuICBwb2ludHdpc2VDb25zdHJhaW50PzogQ29uc3RyYWludElkZW50aWZpZXJ8Q29uc3RyYWludDtcbn1cblxuZXhwb3J0IGNsYXNzIFNlcGFyYWJsZUNvbnYgZXh0ZW5kcyBDb252IHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBjbGFzc05hbWUgPSAnU2VwYXJhYmxlQ29udic7XG5cbiAgcmVhZG9ubHkgZGVwdGhNdWx0aXBsaWVyOiBudW1iZXI7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRlcHRod2lzZUluaXRpYWxpemVyPzogSW5pdGlhbGl6ZXI7XG4gIHByb3RlY3RlZCByZWFkb25seSBkZXB0aHdpc2VSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZGVwdGh3aXNlQ29uc3RyYWludD86IENvbnN0cmFpbnQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBwb2ludHdpc2VJbml0aWFsaXplcj86IEluaXRpYWxpemVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcG9pbnR3aXNlUmVndWxhcml6ZXI/OiBSZWd1bGFyaXplcjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHBvaW50d2lzZUNvbnN0cmFpbnQ/OiBDb25zdHJhaW50O1xuXG4gIHJlYWRvbmx5IERFRkFVTFRfREVQVEhXSVNFX0lOSVRJQUxJWkVSOiBJbml0aWFsaXplcklkZW50aWZpZXIgPVxuICAgICAgJ2dsb3JvdFVuaWZvcm0nO1xuICByZWFkb25seSBERUZBVUxUX1BPSU5UV0lTRV9JTklUSUFMSVpFUjogSW5pdGlhbGl6ZXJJZGVudGlmaWVyID1cbiAgICAgICdnbG9yb3RVbmlmb3JtJztcblxuICBwcm90ZWN0ZWQgZGVwdGh3aXNlS2VybmVsOiBMYXllclZhcmlhYmxlID0gbnVsbDtcbiAgcHJvdGVjdGVkIHBvaW50d2lzZUtlcm5lbDogTGF5ZXJWYXJpYWJsZSA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IocmFuazogbnVtYmVyLCBjb25maWc/OiBTZXBhcmFibGVDb252TGF5ZXJBcmdzKSB7XG4gICAgc3VwZXIocmFuaywgY29uZmlnKTtcblxuICAgIGlmIChjb25maWcuZmlsdGVycyA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICAnVGhlIGBmaWx0ZXJzYCBjb25maWd1cmF0aW9uIGZpZWxkIGlzIHJlcXVpcmVkIGJ5IFNlcGFyYWJsZUNvbnYsICcgK1xuICAgICAgICAgICdidXQgaXMgdW5zcGVjaWZpZWQuJyk7XG4gICAgfVxuICAgIGlmIChjb25maWcua2VybmVsSW5pdGlhbGl6ZXIgIT0gbnVsbCB8fCBjb25maWcua2VybmVsUmVndWxhcml6ZXIgIT0gbnVsbCB8fFxuICAgICAgICBjb25maWcua2VybmVsQ29uc3RyYWludCAhPSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICAnRmllbGRzIGtlcm5lbEluaXRpYWxpemVyLCBrZXJuZWxSZWd1bGFyaXplciBhbmQga2VybmVsQ29uc3RyYWludCAnICtcbiAgICAgICAgICAnYXJlIGludmFsaWQgZm9yIFNlcGFyYWJsZUNvbnYyRC4gVXNlIGRlcHRod2lzZUluaXRpYWxpemVyLCAnICtcbiAgICAgICAgICAnZGVwdGh3aXNlUmVndWxhcml6ZXIsIGRlcHRod2lzZUNvbnN0cmFpbnQsIHBvaW50d2lzZUluaXRpYWxpemVyLCAnICtcbiAgICAgICAgICAncG9pbnR3aXNlUmVndWxhcml6ZXIgYW5kIHBvaW50d2lzZUNvbnN0cmFpbnQgaW5zdGVhZC4nKTtcbiAgICB9XG4gICAgaWYgKGNvbmZpZy5wYWRkaW5nICE9IG51bGwgJiYgY29uZmlnLnBhZGRpbmcgIT09ICdzYW1lJyAmJlxuICAgICAgICBjb25maWcucGFkZGluZyAhPT0gJ3ZhbGlkJykge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFNlcGFyYWJsZUNvbnYke3RoaXMucmFua31EIHN1cHBvcnRzIG9ubHkgcGFkZGluZyBtb2RlczogYCArXG4gICAgICAgICAgYCdzYW1lJyBhbmQgJ3ZhbGlkJywgYnV0IHJlY2VpdmVkICR7SlNPTi5zdHJpbmdpZnkoY29uZmlnLnBhZGRpbmcpfWApO1xuICAgIH1cblxuICAgIHRoaXMuZGVwdGhNdWx0aXBsaWVyID1cbiAgICAgICAgY29uZmlnLmRlcHRoTXVsdGlwbGllciA9PSBudWxsID8gMSA6IGNvbmZpZy5kZXB0aE11bHRpcGxpZXI7XG4gICAgdGhpcy5kZXB0aHdpc2VJbml0aWFsaXplciA9IGdldEluaXRpYWxpemVyKFxuICAgICAgICBjb25maWcuZGVwdGh3aXNlSW5pdGlhbGl6ZXIgfHwgdGhpcy5ERUZBVUxUX0RFUFRIV0lTRV9JTklUSUFMSVpFUik7XG4gICAgdGhpcy5kZXB0aHdpc2VSZWd1bGFyaXplciA9IGdldFJlZ3VsYXJpemVyKGNvbmZpZy5kZXB0aHdpc2VSZWd1bGFyaXplcik7XG4gICAgdGhpcy5kZXB0aHdpc2VDb25zdHJhaW50ID0gZ2V0Q29uc3RyYWludChjb25maWcuZGVwdGh3aXNlQ29uc3RyYWludCk7XG4gICAgdGhpcy5wb2ludHdpc2VJbml0aWFsaXplciA9IGdldEluaXRpYWxpemVyKFxuICAgICAgICBjb25maWcuZGVwdGh3aXNlSW5pdGlhbGl6ZXIgfHwgdGhpcy5ERUZBVUxUX1BPSU5UV0lTRV9JTklUSUFMSVpFUik7XG4gICAgdGhpcy5wb2ludHdpc2VSZWd1bGFyaXplciA9IGdldFJlZ3VsYXJpemVyKGNvbmZpZy5wb2ludHdpc2VSZWd1bGFyaXplcik7XG4gICAgdGhpcy5wb2ludHdpc2VDb25zdHJhaW50ID0gZ2V0Q29uc3RyYWludChjb25maWcucG9pbnR3aXNlQ29uc3RyYWludCk7XG4gIH1cblxuICBvdmVycmlkZSBidWlsZChpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogdm9pZCB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBpZiAoaW5wdXRTaGFwZS5sZW5ndGggPCB0aGlzLnJhbmsgKyAyKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgSW5wdXRzIHRvIFNlcGFyYWJsZUNvbnYke3RoaXMucmFua31EIHNob3VsZCBoYXZlIHJhbmsgYCArXG4gICAgICAgICAgYCR7dGhpcy5yYW5rICsgMn0sIGJ1dCByZWNlaXZlZCBpbnB1dCBzaGFwZTogYCArXG4gICAgICAgICAgYCR7SlNPTi5zdHJpbmdpZnkoaW5wdXRTaGFwZSl9YCk7XG4gICAgfVxuICAgIGNvbnN0IGNoYW5uZWxBeGlzID1cbiAgICAgICAgdGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcgPyAxIDogaW5wdXRTaGFwZS5sZW5ndGggLSAxO1xuICAgIGlmIChpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXSA9PSBudWxsIHx8IGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFRoZSBjaGFubmVsIGRpbWVuc2lvbiBvZiB0aGUgaW5wdXRzIHNob3VsZCBiZSBkZWZpbmVkLCBgICtcbiAgICAgICAgICBgYnV0IGZvdW5kICR7SlNPTi5zdHJpbmdpZnkoaW5wdXRTaGFwZVtjaGFubmVsQXhpc10pfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGlucHV0RGltID0gaW5wdXRTaGFwZVtjaGFubmVsQXhpc107XG4gICAgY29uc3QgZGVwdGh3aXNlS2VybmVsU2hhcGUgPVxuICAgICAgICB0aGlzLmtlcm5lbFNpemUuY29uY2F0KFtpbnB1dERpbSwgdGhpcy5kZXB0aE11bHRpcGxpZXJdKTtcbiAgICBjb25zdCBwb2ludHdpc2VLZXJuZWxTaGFwZSA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5yYW5rOyArK2kpIHtcbiAgICAgIHBvaW50d2lzZUtlcm5lbFNoYXBlLnB1c2goMSk7XG4gICAgfVxuICAgIHBvaW50d2lzZUtlcm5lbFNoYXBlLnB1c2goaW5wdXREaW0gKiB0aGlzLmRlcHRoTXVsdGlwbGllciwgdGhpcy5maWx0ZXJzKTtcblxuICAgIGNvbnN0IHRyYWluYWJsZSA9IHRydWU7XG4gICAgdGhpcy5kZXB0aHdpc2VLZXJuZWwgPSB0aGlzLmFkZFdlaWdodChcbiAgICAgICAgJ2RlcHRod2lzZV9rZXJuZWwnLCBkZXB0aHdpc2VLZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLFxuICAgICAgICB0aGlzLmRlcHRod2lzZUluaXRpYWxpemVyLCB0aGlzLmRlcHRod2lzZVJlZ3VsYXJpemVyLCB0cmFpbmFibGUsXG4gICAgICAgIHRoaXMuZGVwdGh3aXNlQ29uc3RyYWludCk7XG4gICAgdGhpcy5wb2ludHdpc2VLZXJuZWwgPSB0aGlzLmFkZFdlaWdodChcbiAgICAgICAgJ3BvaW50d2lzZV9rZXJuZWwnLCBwb2ludHdpc2VLZXJuZWxTaGFwZSwgJ2Zsb2F0MzInLFxuICAgICAgICB0aGlzLnBvaW50d2lzZUluaXRpYWxpemVyLCB0aGlzLnBvaW50d2lzZVJlZ3VsYXJpemVyLCB0cmFpbmFibGUsXG4gICAgICAgIHRoaXMucG9pbnR3aXNlQ29uc3RyYWludCk7XG4gICAgaWYgKHRoaXMudXNlQmlhcykge1xuICAgICAgdGhpcy5iaWFzID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICAgJ2JpYXMnLCBbdGhpcy5maWx0ZXJzXSwgJ2Zsb2F0MzInLCB0aGlzLmJpYXNJbml0aWFsaXplcixcbiAgICAgICAgICB0aGlzLmJpYXNSZWd1bGFyaXplciwgdHJhaW5hYmxlLCB0aGlzLmJpYXNDb25zdHJhaW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5iaWFzID0gbnVsbDtcbiAgICB9XG5cbiAgICB0aGlzLmlucHV0U3BlYyA9XG4gICAgICAgIFtuZXcgSW5wdXRTcGVjKHtuZGltOiB0aGlzLnJhbmsgKyAyLCBheGVzOiB7W2NoYW5uZWxBeGlzXTogaW5wdXREaW19fSldO1xuICAgIHRoaXMuYnVpbHQgPSB0cnVlO1xuICB9XG5cbiAgb3ZlcnJpZGUgY2FsbChpbnB1dHM6IFRlbnNvcnxUZW5zb3JbXSwga3dhcmdzOiBLd2FyZ3MpOiBUZW5zb3J8VGVuc29yW10ge1xuICAgIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICAgIGlucHV0cyA9IGdldEV4YWN0bHlPbmVUZW5zb3IoaW5wdXRzKTtcblxuICAgICAgbGV0IG91dHB1dDogVGVuc29yO1xuICAgICAgaWYgKHRoaXMucmFuayA9PT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcihcbiAgICAgICAgICAgICcxRCBzZXBhcmFibGUgY29udm9sdXRpb24gaXMgbm90IGltcGxlbWVudGVkIHlldC4nKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5yYW5rID09PSAyKSB7XG4gICAgICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgICAgIGlucHV0cyA9IHRmYy50cmFuc3Bvc2UoaW5wdXRzLCBbMCwgMiwgMywgMV0pOyAgLy8gTkNIVyAtPiBOSFdDLlxuICAgICAgICB9XG5cbiAgICAgICAgb3V0cHV0ID0gdGZjLnNlcGFyYWJsZUNvbnYyZChcbiAgICAgICAgICAgIGlucHV0cyBhcyBUZW5zb3I0RCwgdGhpcy5kZXB0aHdpc2VLZXJuZWwucmVhZCgpIGFzIFRlbnNvcjRELFxuICAgICAgICAgICAgdGhpcy5wb2ludHdpc2VLZXJuZWwucmVhZCgpIGFzIFRlbnNvcjRELFxuICAgICAgICAgICAgdGhpcy5zdHJpZGVzIGFzIFtudW1iZXIsIG51bWJlcl0sIHRoaXMucGFkZGluZyBhcyAnc2FtZScgfCAndmFsaWQnLFxuICAgICAgICAgICAgdGhpcy5kaWxhdGlvblJhdGUgYXMgW251bWJlciwgbnVtYmVyXSwgJ05IV0MnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMudXNlQmlhcykge1xuICAgICAgICBvdXRwdXQgPSBLLmJpYXNBZGQob3V0cHV0LCB0aGlzLmJpYXMucmVhZCgpLCB0aGlzLmRhdGFGb3JtYXQpO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgIG91dHB1dCA9IHRoaXMuYWN0aXZhdGlvbi5hcHBseShvdXRwdXQpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgICAgb3V0cHV0ID0gdGZjLnRyYW5zcG9zZShvdXRwdXQsIFswLCAzLCAxLCAyXSk7ICAvLyBOSFdDIC0+IE5DSFcuXG4gICAgICB9XG4gICAgICByZXR1cm4gb3V0cHV0O1xuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIGRlbGV0ZSBjb25maWdbJ2tlcm5lbEluaXRpYWxpemVyJ107XG4gICAgZGVsZXRlIGNvbmZpZ1sna2VybmVsUmVndWxhcml6ZXInXTtcbiAgICBkZWxldGUgY29uZmlnWydrZXJuZWxDb25zdHJhaW50J107XG4gICAgY29uZmlnWydkZXB0aHdpc2VJbml0aWFsaXplciddID1cbiAgICAgICAgc2VyaWFsaXplSW5pdGlhbGl6ZXIodGhpcy5kZXB0aHdpc2VJbml0aWFsaXplcik7XG4gICAgY29uZmlnWydwb2ludHdpc2VJbml0aWFsaXplciddID1cbiAgICAgICAgc2VyaWFsaXplSW5pdGlhbGl6ZXIodGhpcy5wb2ludHdpc2VJbml0aWFsaXplcik7XG4gICAgY29uZmlnWydkZXB0aHdpc2VSZWd1bGFyaXplciddID1cbiAgICAgICAgc2VyaWFsaXplUmVndWxhcml6ZXIodGhpcy5kZXB0aHdpc2VSZWd1bGFyaXplcik7XG4gICAgY29uZmlnWydwb2ludHdpc2VSZWd1bGFyaXplciddID1cbiAgICAgICAgc2VyaWFsaXplUmVndWxhcml6ZXIodGhpcy5wb2ludHdpc2VSZWd1bGFyaXplcik7XG4gICAgY29uZmlnWydkZXB0aHdpc2VDb25zdHJhaW50J10gPVxuICAgICAgICBzZXJpYWxpemVDb25zdHJhaW50KHRoaXMuZGVwdGh3aXNlQ29uc3RyYWludCk7XG4gICAgY29uZmlnWydwb2ludHdpc2VDb25zdHJhaW50J10gPVxuICAgICAgICBzZXJpYWxpemVDb25zdHJhaW50KHRoaXMucG9pbnR3aXNlQ29uc3RyYWludCk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgU2VwYXJhYmxlQ29udjJEIGV4dGVuZHMgU2VwYXJhYmxlQ29udiB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgb3ZlcnJpZGUgY2xhc3NOYW1lID0gJ1NlcGFyYWJsZUNvbnYyRCc7XG4gIGNvbnN0cnVjdG9yKGFyZ3M/OiBTZXBhcmFibGVDb252TGF5ZXJBcmdzKSB7XG4gICAgc3VwZXIoMiwgYXJncyk7XG4gIH1cbn1cbnNlcmlhbGl6YXRpb24ucmVnaXN0ZXJDbGFzcyhTZXBhcmFibGVDb252MkQpO1xuXG5leHBvcnQgY2xhc3MgQ29udjFEIGV4dGVuZHMgQ29udiB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgY2xhc3NOYW1lID0gJ0NvbnYxRCc7XG4gIGNvbnN0cnVjdG9yKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICBzdXBlcigxLCBhcmdzKTtcbiAgICBDb252MUQudmVyaWZ5QXJncyhhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogM31dO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgZGVsZXRlIGNvbmZpZ1sncmFuayddO1xuICAgIGRlbGV0ZSBjb25maWdbJ2RhdGFGb3JtYXQnXTtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBvdmVycmlkZSB2ZXJpZnlBcmdzKGFyZ3M6IENvbnZMYXllckFyZ3MpIHtcbiAgICAvLyBjb25maWcua2VybmVsU2l6ZSBtdXN0IGJlIGEgbnVtYmVyIG9yIGFycmF5IG9mIG51bWJlcnMuXG4gICAgaWYgKHR5cGVvZiBhcmdzLmtlcm5lbFNpemUgIT09ICdudW1iZXInICYmXG4gICAgICAgICFnZW5lcmljX3V0aWxzLmNoZWNrQXJyYXlUeXBlQW5kTGVuZ3RoKFxuICAgICAgICAgICAgYXJncy5rZXJuZWxTaXplLCAnbnVtYmVyJywgMSwgMSkpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBDb252MUQgZXhwZWN0cyBjb25maWcua2VybmVsU2l6ZSB0byBiZSBudW1iZXIgb3IgbnVtYmVyW10gd2l0aCBgICtcbiAgICAgICAgICBgbGVuZ3RoIDEsIGJ1dCByZWNlaXZlZCAke0pTT04uc3RyaW5naWZ5KGFyZ3Mua2VybmVsU2l6ZSl9LmApO1xuICAgIH1cbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnYxRCk7XG5cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBDcm9wcGluZzJETGF5ZXJBcmdzIGV4dGVuZHMgTGF5ZXJBcmdzIHtcbiAgLyoqXG4gICAqIERpbWVuc2lvbiBvZiB0aGUgY3JvcHBpbmcgYWxvbmcgdGhlIHdpZHRoIGFuZCB0aGUgaGVpZ2h0LlxuICAgKiAtIElmIGludGVnZXI6IHRoZSBzYW1lIHN5bW1ldHJpYyBjcm9wcGluZ1xuICAgKiAgaXMgYXBwbGllZCB0byB3aWR0aCBhbmQgaGVpZ2h0LlxuICAgKiAtIElmIGxpc3Qgb2YgMiBpbnRlZ2VyczpcbiAgICogICBpbnRlcnByZXRlZCBhcyB0d28gZGlmZmVyZW50XG4gICAqICAgc3ltbWV0cmljIGNyb3BwaW5nIHZhbHVlcyBmb3IgaGVpZ2h0IGFuZCB3aWR0aDpcbiAgICogICBgW3N5bW1ldHJpY19oZWlnaHRfY3JvcCwgc3ltbWV0cmljX3dpZHRoX2Nyb3BdYC5cbiAgICogLSBJZiBhIGxpc3Qgb2YgMiBsaXN0cyBvZiAyIGludGVnZXJzOlxuICAgKiAgIGludGVycHJldGVkIGFzXG4gICAqICAgYFtbdG9wX2Nyb3AsIGJvdHRvbV9jcm9wXSwgW2xlZnRfY3JvcCwgcmlnaHRfY3JvcF1dYFxuICAgKi9cbiAgY3JvcHBpbmc6IG51bWJlcnxbbnVtYmVyLCBudW1iZXJdfFtbbnVtYmVyLCBudW1iZXJdLCBbbnVtYmVyLCBudW1iZXJdXTtcblxuICAvKipcbiAgICogRm9ybWF0IG9mIHRoZSBkYXRhLCB3aGljaCBkZXRlcm1pbmVzIHRoZSBvcmRlcmluZyBvZiB0aGUgZGltZW5zaW9ucyBpblxuICAgKiB0aGUgaW5wdXRzLlxuICAgKlxuICAgKiBgY2hhbm5lbHNfbGFzdGAgY29ycmVzcG9uZHMgdG8gaW5wdXRzIHdpdGggc2hhcGVcbiAgICogICBgKGJhdGNoLCAuLi4sIGNoYW5uZWxzKWBcbiAgICpcbiAgICogYGNoYW5uZWxzX2ZpcnN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZVxuICAgKiAgIGAoYmF0Y2gsIGNoYW5uZWxzLCAuLi4pYFxuICAgKlxuICAgKiBEZWZhdWx0cyB0byBgY2hhbm5lbHNfbGFzdGAuXG4gICAqL1xuICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdDtcbn1cblxuZXhwb3J0IGNsYXNzIENyb3BwaW5nMkQgZXh0ZW5kcyBMYXllciB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgY2xhc3NOYW1lID0gJ0Nyb3BwaW5nMkQnO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY3JvcHBpbmc6IFtbbnVtYmVyLCBudW1iZXJdLCBbbnVtYmVyLCBudW1iZXJdXTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRhdGFGb3JtYXQ6IERhdGFGb3JtYXQ7XG5cbiAgY29uc3RydWN0b3IoYXJnczogQ3JvcHBpbmcyRExheWVyQXJncykge1xuICAgIHN1cGVyKGFyZ3MpO1xuICAgIGlmICh0eXBlb2YgYXJncy5jcm9wcGluZyA9PT0gJ251bWJlcicpIHtcbiAgICAgIHRoaXMuY3JvcHBpbmcgPVxuICAgICAgICAgIFtbYXJncy5jcm9wcGluZywgYXJncy5jcm9wcGluZ10sIFthcmdzLmNyb3BwaW5nLCBhcmdzLmNyb3BwaW5nXV07XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgYXJncy5jcm9wcGluZ1swXSA9PT0gJ251bWJlcicpIHtcbiAgICAgIHRoaXMuY3JvcHBpbmcgPSBbXG4gICAgICAgIFthcmdzLmNyb3BwaW5nWzBdLCBhcmdzLmNyb3BwaW5nWzBdXSxcbiAgICAgICAgW2FyZ3MuY3JvcHBpbmdbMV0gYXMgbnVtYmVyLCBhcmdzLmNyb3BwaW5nWzFdIGFzIG51bWJlcl1cbiAgICAgIF07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3JvcHBpbmcgPSBhcmdzLmNyb3BwaW5nIGFzIFtbbnVtYmVyLCBudW1iZXJdLCBbbnVtYmVyLCBudW1iZXJdXTtcbiAgICB9XG4gICAgdGhpcy5kYXRhRm9ybWF0ID1cbiAgICAgICAgYXJncy5kYXRhRm9ybWF0ID09PSB1bmRlZmluZWQgPyAnY2hhbm5lbHNMYXN0JyA6IGFyZ3MuZGF0YUZvcm1hdDtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogNH1dO1xuICB9XG5cbiAgb3ZlcnJpZGUgY29tcHV0ZU91dHB1dFNoYXBlKGlucHV0U2hhcGU6IFNoYXBlKTogU2hhcGUge1xuICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0Jykge1xuICAgICAgcmV0dXJuIFtcbiAgICAgICAgaW5wdXRTaGFwZVswXSwgaW5wdXRTaGFwZVsxXSxcbiAgICAgICAgaW5wdXRTaGFwZVsyXSAtIHRoaXMuY3JvcHBpbmdbMF1bMF0gLSB0aGlzLmNyb3BwaW5nWzBdWzFdLFxuICAgICAgICBpbnB1dFNoYXBlWzNdIC0gdGhpcy5jcm9wcGluZ1sxXVswXSAtIHRoaXMuY3JvcHBpbmdbMV1bMV1cbiAgICAgIF07XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBbXG4gICAgICAgIGlucHV0U2hhcGVbMF0sXG4gICAgICAgIGlucHV0U2hhcGVbMV0gLSB0aGlzLmNyb3BwaW5nWzBdWzBdIC0gdGhpcy5jcm9wcGluZ1swXVsxXSxcbiAgICAgICAgaW5wdXRTaGFwZVsyXSAtIHRoaXMuY3JvcHBpbmdbMV1bMF0gLSB0aGlzLmNyb3BwaW5nWzFdWzFdLCBpbnB1dFNoYXBlWzNdXG4gICAgICBdO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgICBpbnB1dHMgPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG5cbiAgICAgIGlmICh0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0xhc3QnKSB7XG4gICAgICAgIGNvbnN0IGhTbGljZWQgPSBLLnNsaWNlQWxvbmdBeGlzKFxuICAgICAgICAgICAgaW5wdXRzLCB0aGlzLmNyb3BwaW5nWzBdWzBdLFxuICAgICAgICAgICAgaW5wdXRzLnNoYXBlWzFdIC0gdGhpcy5jcm9wcGluZ1swXVswXSAtIHRoaXMuY3JvcHBpbmdbMF1bMV0sIDIpO1xuICAgICAgICByZXR1cm4gSy5zbGljZUFsb25nQXhpcyhcbiAgICAgICAgICAgIGhTbGljZWQsIHRoaXMuY3JvcHBpbmdbMV1bMF0sXG4gICAgICAgICAgICBpbnB1dHMuc2hhcGVbMl0gLSB0aGlzLmNyb3BwaW5nWzFdWzFdIC0gdGhpcy5jcm9wcGluZ1sxXVswXSwgMyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBoU2xpY2VkID0gSy5zbGljZUFsb25nQXhpcyhcbiAgICAgICAgICAgIGlucHV0cywgdGhpcy5jcm9wcGluZ1swXVswXSxcbiAgICAgICAgICAgIGlucHV0cy5zaGFwZVsyXSAtIHRoaXMuY3JvcHBpbmdbMF1bMF0gLSB0aGlzLmNyb3BwaW5nWzBdWzFdLCAzKTtcbiAgICAgICAgcmV0dXJuIEsuc2xpY2VBbG9uZ0F4aXMoXG4gICAgICAgICAgICBoU2xpY2VkLCB0aGlzLmNyb3BwaW5nWzFdWzBdLFxuICAgICAgICAgICAgaW5wdXRzLnNoYXBlWzNdIC0gdGhpcy5jcm9wcGluZ1sxXVsxXSAtIHRoaXMuY3JvcHBpbmdbMV1bMF0sIDQpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0ge2Nyb3BwaW5nOiB0aGlzLmNyb3BwaW5nLCBkYXRhRm9ybWF0OiB0aGlzLmRhdGFGb3JtYXR9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENyb3BwaW5nMkQpO1xuXG5leHBvcnQgZGVjbGFyZSBpbnRlcmZhY2UgVXBTYW1wbGluZzJETGF5ZXJBcmdzIGV4dGVuZHMgTGF5ZXJBcmdzIHtcbiAgLyoqXG4gICAqIFRoZSB1cHNhbXBsaW5nIGZhY3RvcnMgZm9yIHJvd3MgYW5kIGNvbHVtbnMuXG4gICAqXG4gICAqIERlZmF1bHRzIHRvIGBbMiwgMl1gLlxuICAgKi9cbiAgc2l6ZT86IG51bWJlcltdO1xuICAvKipcbiAgICogRm9ybWF0IG9mIHRoZSBkYXRhLCB3aGljaCBkZXRlcm1pbmVzIHRoZSBvcmRlcmluZyBvZiB0aGUgZGltZW5zaW9ucyBpblxuICAgKiB0aGUgaW5wdXRzLlxuICAgKlxuICAgKiBgXCJjaGFubmVsc0xhc3RcImAgY29ycmVzcG9uZHMgdG8gaW5wdXRzIHdpdGggc2hhcGVcbiAgICogICBgW2JhdGNoLCAuLi4sIGNoYW5uZWxzXWBcbiAgICpcbiAgICogIGBcImNoYW5uZWxzRmlyc3RcImAgY29ycmVzcG9uZHMgdG8gaW5wdXRzIHdpdGggc2hhcGUgYFtiYXRjaCwgY2hhbm5lbHMsXG4gICAqIC4uLl1gLlxuICAgKlxuICAgKiBEZWZhdWx0cyB0byBgXCJjaGFubmVsc0xhc3RcImAuXG4gICAqL1xuICBkYXRhRm9ybWF0PzogRGF0YUZvcm1hdDtcbiAgLyoqXG4gICAqIFRoZSBpbnRlcnBvbGF0aW9uIG1lY2hhbmlzbSwgb25lIG9mIGBcIm5lYXJlc3RcImAgb3IgYFwiYmlsaW5lYXJcImAsIGRlZmF1bHRcbiAgICogdG8gYFwibmVhcmVzdFwiYC5cbiAgICovXG4gIGludGVycG9sYXRpb24/OiBJbnRlcnBvbGF0aW9uRm9ybWF0O1xufVxuXG5leHBvcnQgY2xhc3MgVXBTYW1wbGluZzJEIGV4dGVuZHMgTGF5ZXIge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIGNsYXNzTmFtZSA9ICdVcFNhbXBsaW5nMkQnO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgREVGQVVMVF9TSVpFID0gWzIsIDJdO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2l6ZTogbnVtYmVyW107XG4gIHByb3RlY3RlZCByZWFkb25seSBkYXRhRm9ybWF0OiBEYXRhRm9ybWF0O1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgaW50ZXJwb2xhdGlvbjogSW50ZXJwb2xhdGlvbkZvcm1hdDtcblxuICBjb25zdHJ1Y3RvcihhcmdzOiBVcFNhbXBsaW5nMkRMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzKTtcbiAgICB0aGlzLmlucHV0U3BlYyA9IFt7bmRpbTogNH1dO1xuICAgIHRoaXMuc2l6ZSA9IGFyZ3Muc2l6ZSA9PSBudWxsID8gdGhpcy5ERUZBVUxUX1NJWkUgOiBhcmdzLnNpemU7XG4gICAgdGhpcy5kYXRhRm9ybWF0ID1cbiAgICAgICAgYXJncy5kYXRhRm9ybWF0ID09IG51bGwgPyAnY2hhbm5lbHNMYXN0JyA6IGFyZ3MuZGF0YUZvcm1hdDtcbiAgICBjaGVja0RhdGFGb3JtYXQodGhpcy5kYXRhRm9ybWF0KTtcbiAgICB0aGlzLmludGVycG9sYXRpb24gPVxuICAgICAgICBhcmdzLmludGVycG9sYXRpb24gPT0gbnVsbCA/ICduZWFyZXN0JyA6IGFyZ3MuaW50ZXJwb2xhdGlvbjtcbiAgICBjaGVja0ludGVycG9sYXRpb25Gb3JtYXQodGhpcy5pbnRlcnBvbGF0aW9uKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZSk6IFNoYXBlIHtcbiAgICBpZiAodGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIGNvbnN0IGhlaWdodCA9XG4gICAgICAgICAgaW5wdXRTaGFwZVsyXSA9PSBudWxsID8gbnVsbCA6IHRoaXMuc2l6ZVswXSAqIGlucHV0U2hhcGVbMl07XG4gICAgICBjb25zdCB3aWR0aCA9IGlucHV0U2hhcGVbM10gPT0gbnVsbCA/IG51bGwgOiB0aGlzLnNpemVbMV0gKiBpbnB1dFNoYXBlWzNdO1xuICAgICAgcmV0dXJuIFtpbnB1dFNoYXBlWzBdLCBpbnB1dFNoYXBlWzFdLCBoZWlnaHQsIHdpZHRoXTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgaGVpZ2h0ID1cbiAgICAgICAgICBpbnB1dFNoYXBlWzFdID09IG51bGwgPyBudWxsIDogdGhpcy5zaXplWzBdICogaW5wdXRTaGFwZVsxXTtcbiAgICAgIGNvbnN0IHdpZHRoID0gaW5wdXRTaGFwZVsyXSA9PSBudWxsID8gbnVsbCA6IHRoaXMuc2l6ZVsxXSAqIGlucHV0U2hhcGVbMl07XG4gICAgICByZXR1cm4gW2lucHV0U2hhcGVbMF0sIGhlaWdodCwgd2lkdGgsIGlucHV0U2hhcGVbM11dO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICByZXR1cm4gdGZjLnRpZHkoKCkgPT4ge1xuICAgICAgbGV0IGlucHV0ID0gZ2V0RXhhY3RseU9uZVRlbnNvcihpbnB1dHMpIGFzIFRlbnNvcjREO1xuICAgICAgY29uc3QgaW5wdXRTaGFwZSA9IGlucHV0LnNoYXBlO1xuXG4gICAgICBpZiAodGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgICAgaW5wdXQgPSB0ZmMudHJhbnNwb3NlKGlucHV0LCBbMCwgMiwgMywgMV0pO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSB0aGlzLnNpemVbMF0gKiBpbnB1dFNoYXBlWzJdO1xuICAgICAgICBjb25zdCB3aWR0aCA9IHRoaXMuc2l6ZVsxXSAqIGlucHV0U2hhcGVbM107XG5cbiAgICAgICAgY29uc3QgcmVzaXplZCA9IHRoaXMuaW50ZXJwb2xhdGlvbiA9PT0gJ25lYXJlc3QnID9cbiAgICAgICAgICAgIHRmYy5pbWFnZS5yZXNpemVOZWFyZXN0TmVpZ2hib3IoaW5wdXQsIFtoZWlnaHQsIHdpZHRoXSkgOlxuICAgICAgICAgICAgdGZjLmltYWdlLnJlc2l6ZUJpbGluZWFyKGlucHV0LCBbaGVpZ2h0LCB3aWR0aF0pO1xuICAgICAgICByZXR1cm4gdGZjLnRyYW5zcG9zZShyZXNpemVkLCBbMCwgMywgMSwgMl0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgaGVpZ2h0ID0gdGhpcy5zaXplWzBdICogaW5wdXRTaGFwZVsxXTtcbiAgICAgICAgY29uc3Qgd2lkdGggPSB0aGlzLnNpemVbMV0gKiBpbnB1dFNoYXBlWzJdO1xuICAgICAgICByZXR1cm4gdGhpcy5pbnRlcnBvbGF0aW9uID09PSAnbmVhcmVzdCcgP1xuICAgICAgICAgICAgdGZjLmltYWdlLnJlc2l6ZU5lYXJlc3ROZWlnaGJvcihpbnB1dCwgW2hlaWdodCwgd2lkdGhdKSA6XG4gICAgICAgICAgICB0ZmMuaW1hZ2UucmVzaXplQmlsaW5lYXIoaW5wdXQsIFtoZWlnaHQsIHdpZHRoXSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBvdmVycmlkZSBnZXRDb25maWcoKTogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0IHtcbiAgICBjb25zdCBjb25maWcgPSB7XG4gICAgICAgIHNpemU6IHRoaXMuc2l6ZSxcbiAgICAgICAgZGF0YUZvcm1hdDogdGhpcy5kYXRhRm9ybWF0LFxuICAgICAgICBpbnRlcnBvbGF0aW9uOiB0aGlzLmludGVycG9sYXRpb25cbiAgICB9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKFVwU2FtcGxpbmcyRCk7XG4iXX0=