UNPKG

lib-sketch-tool

Version:

## Installing with npm $ npm install --save lib-sketch-tool

525 lines 70.2 kB
import * as tslib_1 from "tslib";
import { Injectable } from '@angular/core';
import { fabric } from 'fabric';
import { AvailableGeometricShape } from './../constants/available-geometric-shapes';
import { SHAPE_DATA } from './../constants/shape-data';
let CanvasManagerService = class CanvasManagerService {
    constructor() {
        this.canvasId = 'canvas';
        this.mousePosition = { x: 0, y: 0 };
        this.left = 0;
    }
    get canvasObjects() {
        return this.canvas.getObjects();
    }
    get canvasBackgroundImage() {
        return this.canvas.backgroundImage;
    }
    get activeObject() {
        return this.canvas.getActiveObject();
    }
    get activeGroup() {
        return this.canvas.getActiveObjects();
    }
    get divCanvasContainer() {
        let collection = document.getElementsByClassName('div-canvas-container');
        return collection[collection.length - 1];
    }
    createCanvas(canvasId) {
        this.canvasId = canvasId;
        this.canvas = new fabric.Canvas(this.canvasId);
    }
    emptyCanvas() {
        if (this.canvas) {
            this.canvas.dispose();
        }
        this.canvas = new fabric.Canvas(this.canvasId);
        this.canvas.clear();
        this.canvas.remove(this.canvas.getObjects());
    }
    loadNewImage(backgroundImageURL) {
        this.emptyCanvas();
        if (backgroundImageURL) {
            this.setBackgroundFromURL(backgroundImageURL);
        }
    }
    renderCanvas() {
        this.markSelectedObjectsDirty();
        this.canvas.renderAll();
    }
    addGeometricShape(strokeColor, fillColor, shape) {
        switch (shape) {
            case AvailableGeometricShape.Rectangle:
                this.addRectangle(strokeColor, fillColor);
                break;
            case AvailableGeometricShape.Circle:
                this.addCircle(strokeColor, fillColor);
                break;
            case AvailableGeometricShape.Triangle:
                this.addTriangle(strokeColor, fillColor);
                break;
            case AvailableGeometricShape.Line:
                this.addHorizontalLine(strokeColor, fillColor);
                break;
            case AvailableGeometricShape.Cross:
                this.addCross(strokeColor, fillColor);
                break;
        }
    }
    addRectangle(strokeColor, fillColor) {
        this.canvas.add(new fabric.Rect({
            width: SHAPE_DATA.width,
            height: SHAPE_DATA.height,
            left: SHAPE_DATA.left,
            top: SHAPE_DATA.top,
            fill: fillColor,
            stroke: strokeColor,
            strokeWidth: SHAPE_DATA.stroke,
            cornerSize: SHAPE_DATA.cornerSize
        }));
    }
    addCircle(strokeColor, fillColor) {
        this.canvas.add(new fabric.Circle({
            left: SHAPE_DATA.left,
            top: SHAPE_DATA.top,
            radius: SHAPE_DATA.radius,
            stroke: strokeColor,
            strokeWidth: SHAPE_DATA.stroke,
            fill: fillColor,
            cornerSize: SHAPE_DATA.cornerSize
        }));
    }
    addTriangle(strokeColor, fillColor) {
        this.canvas.add(new fabric.Triangle({
            width: SHAPE_DATA.width,
            height: SHAPE_DATA.height,
            left: SHAPE_DATA.left,
            top: SHAPE_DATA.top,
            fill: fillColor,
            stroke: strokeColor,
            strokeWidth: SHAPE_DATA.stroke,
            cornerSize: SHAPE_DATA.cornerSize
        }));
    }
    addHorizontalLine(strokeColor, fillColor) {
        this.canvas.add(this.createHorizontalLine(strokeColor));
    }
    createHorizontalLine(strokeColor) {
        const line = new fabric.Line([100, 150, 200, 150], {
            left: 50,
            top: 100,
            stroke: strokeColor,
            strokeWidth: 5,
            cornerSize: SHAPE_DATA.cornerSize
        });
        line.setControlsVisibility({
            bl: false,
            br: false,
            tl: false,
            tr: false,
            mt: false,
            mb: false
        });
        return line;
    }
    createVerticalLine(strokeColor) {
        const line = new fabric.Line([150, 100, 150, 200], {
            left: 100,
            top: 50,
            stroke: strokeColor,
            strokeWidth: 5,
            cornerSize: SHAPE_DATA.cornerSize
        });
        line.setControlsVisibility({
            bl: false,
            br: false,
            tl: false,
            tr: false,
            ml: false,
            mr: false
        });
        return line;
    }
    addCross(strokeColor, fillColor) {
        const horizontalLine = this.createHorizontalLine(strokeColor);
        const verticalLine = this.createVerticalLine(strokeColor);
        this.canvas.add(horizontalLine);
        this.canvas.add(verticalLine);
    }
    toggleFreeDrawing() {
        this.canvas.isDrawingMode = !this.canvas.isDrawingMode;
    }
    setFreeDrawingBrushColor(color) {
        this.canvas.freeDrawingBrush.color = color;
        this.setFreeDrawingBrushWidthFromZoom(this.canvas.getZoom());
    }
    setFreeDrawingBrushWidthFromZoom(zoom) {
        this.canvas.freeDrawingBrush.width = SHAPE_DATA.freeDrawingBrushWidth * (1 / zoom);
    }
    addText(color, inputText) {
        const text = new fabric.IText('text', {
            fontFamily: 'arial black',
            fontStyle: 'bold',
            left: SHAPE_DATA.left,
            top: SHAPE_DATA.top,
            cornerSize: SHAPE_DATA.cornerSize
        });
        text.setColor(color);
        this.canvas.add(text);
    }
    addImage(imageURL) {
        return new Promise((resolve, reject) => {
            const canvas = this.canvas;
            const image = new Image();
            image.onload = function (img) {
                const fabricImage = new fabric.Image(image, {
                    angle: 0,
                    width: image.width,
                    height: image.height,
                    left: SHAPE_DATA.left,
                    top: SHAPE_DATA.top,
                    scaleX: 1,
                    scaleY: 1,
                    cornerSize: SHAPE_DATA.cornerSize
                });
                canvas.add(fabricImage);
                resolve();
            };
            image.src = imageURL;
        });
    }
    setBackgroundFromURL(backgroundImageURL) {
        const container = this.divCanvasContainer;
        this.setCanvasSize(container.clientWidth, container.clientHeight);
        return new Promise((resolve, reject) => {
            if (backgroundImageURL == null) {
                return reject();
            }
            const image = new Image();
            image.onload = () => {
                const f_img = new fabric.Image(image, {});
                const scaleData = this.computeScaleFactor(f_img, this.canvas);
                this.canvas.setBackgroundImage(f_img, this.canvas.renderAll.bind(this.canvas), {
                    scaleX: scaleData.scaleFactor,
                    scaleY: scaleData.scaleFactor
                });
                this.setCanvasSize(f_img.width * scaleData.scaleFactor, f_img.height * scaleData.scaleFactor);
                this.canvas.renderAll();
                resolve();
            };
            image.src = backgroundImageURL;
        });
    }
    computeScaleFactor(f_img, canvas) {
        const container = this.divCanvasContainer;
        const canvasAspect = container.clientWidth / container.clientHeight;
        const imgAspect = f_img.width / f_img.height;
        let left, top, scaleFactor;
        if (canvasAspect <= imgAspect) {
            scaleFactor = container.clientWidth / f_img.width;
            left = 0;
            top = -(f_img.height * scaleFactor - container.clientHeight) / 2;
        }
        else {
            scaleFactor = container.clientHeight / f_img.height;
            top = 0;
            left = -(f_img.width * scaleFactor - container.clientWidth) / 2;
        }
        this.left = left;
        return { scaleFactor: scaleFactor, left: left, top: top };
    }
    onOrientationChange() {
        this.mousePosition = { x: this.canvas.getWidth, y: this.canvas.getHeight };
        this.cropImage();
    }
    changeSelectedObjectsFillColor(color) {
        const activeObjects = this.canvas.getActiveObjects();
        if (activeObjects) {
            for (const object of activeObjects) {
                object.setColor(color);
                this.canvas.renderAll();
            }
        }
    }
    changeSelectedObjectsStrokeColor(color) {
        const activeObjects = this.canvas.getActiveObjects();
        if (activeObjects) {
            for (const object of activeObjects) {
                if (object.type === 'i-text') {
                    object.setColor(color);
                }
                else {
                    object.stroke = color;
                    object.set('dirty', true);
                }
            }
            this.canvas.renderAll();
        }
    }
    deleteSelectedObjects() {
        const activeObjects = this.canvas.getActiveObjects();
        if (activeObjects) {
            for (const object of activeObjects) {
                this.canvas.remove(object);
            }
            this.canvas.discardActiveObject();
            this.canvas.renderAll();
        }
    }
    bringSelectedObjectsToFront() {
        const activeObjects = this.canvas.getActiveObjects();
        if (activeObjects) {
            for (const object of activeObjects) {
                this.canvas.bringToFront(object);
            }
        }
    }
    sendSelectedObjectsToBack() {
        const activeObjects = this.canvas.getActiveObjects();
        if (activeObjects) {
            for (const object of activeObjects) {
                this.canvas.sendToBack(object);
            }
        }
    }
    jsonFromCanvas() {
        return this.canvas.toJSON(['width', 'height']);
    }
    loadfromJson(json) {
        const container = this.divCanvasContainer;
        this.setCanvasSize(container.clientWidth, container.clientHeight);
        return new Promise((resolve, reject) => {
            this.adjustCanvas(json);
            this.canvas.loadFromJSON(json, this.canvas.renderAll.bind(this.canvas));
            this.canvas.renderAll();
            resolve();
        });
    }
    adjustCanvas(json) {
        const backgroundImage = json['backgroundImage'];
        const container = this.divCanvasContainer;
        const width = json['width'];
        const height = json['height'];
        const canvasWidth = container.clientWidth;
        const canvasHeight = container.clientHeight;
        const canvasAspect = canvasWidth / canvasHeight;
        const imgAspect = width / height;
        let scaleFactor, left;
        if (canvasAspect <= imgAspect) {
            scaleFactor = canvasWidth / width;
            left = 0;
        }
        else {
            scaleFactor = canvasHeight / height;
            left = -(width * scaleFactor - container.clientWidth) / 2;
        }
        this.left = left;
        backgroundImage['scaleX'] *= scaleFactor;
        backgroundImage['scaleY'] *= scaleFactor;
        this.setCanvasSize(width * scaleFactor, height * scaleFactor);
        const objects = json['objects'];
        for (let i = 0; i < objects.length; i++) {
            objects[i]['left'] *= scaleFactor;
            objects[i]['top'] *= scaleFactor;
            objects[i]['scaleX'] *= scaleFactor;
            objects[i]['scaleY'] *= scaleFactor;
        }
    }
    exportImageAsDataURL() {
        return this.canvas.toDataURL('image/png');
    }
    selectItem(itemNumber) {
        this.canvas.setActiveObject(this.canvas.item(itemNumber));
    }
    getIndexOf(activeObject) {
        return this.canvas.getObjects().indexOf(activeObject);
    }
    markSelectedObjectsDirty() {
        const activeObjects = this.canvas.getActiveObjects();
        if (activeObjects) {
            for (const object of activeObjects) {
                object.set('dirty', true);
            }
        }
    }
    addSelectionRectangle() {
        this.cropRectangle = new fabric.Rect({
            fill: 'transparent',
            originX: 'left',
            originY: 'top',
            stroke: '#ccc',
            strokeDashArray: [2, 2],
            opacity: 1,
            width: 0,
            height: 0
        });
        this.cropRectangle.visible = false;
        this.canvas.add(this.cropRectangle);
    }
    ajustCropRectangleFromMouse(event) {
        const x = Math.min(event.offsetX, this.mousePosition.x), y = Math.min(event.offsetY, this.mousePosition.y), w = Math.abs(event.offsetX - this.mousePosition.x), h = Math.abs(event.offsetY - this.mousePosition.y);
        if (!w || !h) {
            return false;
        }
        this.cropRectangle
            .set('top', y)
            .set('left', x)
            .set('width', w)
            .set('height', h);
        this.canvas.renderAll();
        return true;
    }
    startSelectingCropRectangleFromMouse(event) {
        this.cropRectangle.left = event.offsetX;
        this.cropRectangle.top = event.offsetY;
        this.cropRectangle.setCoords();
        this.mousePosition = { x: event.offsetX, y: event.offsetY };
        this.cropRectangle.visible = true;
        this.canvas.bringToFront(this.cropRectangle);
    }
    cropImage() {
        const left = this.cropRectangle.left;
        const top = this.cropRectangle.top;
        const width = this.cropRectangle.width;
        const height = this.cropRectangle.height;
        const container = this.divCanvasContainer;
        const canvasWidth = container.clientWidth;
        const canvasHeight = container.clientHeight;
        const canvasAspect = canvasWidth / canvasHeight;
        const imgAspect = width / height;
        let scaleFactor;
        if (canvasAspect <= imgAspect) {
            scaleFactor = canvasWidth / width;
        }
        else {
            scaleFactor = canvasHeight / height;
        }
        this.setCanvasSize(width * scaleFactor, height * scaleFactor);
        this.canvas.backgroundImage.scaleX *= scaleFactor;
        this.canvas.backgroundImage.scaleY *= scaleFactor;
        this.canvas.backgroundImage.left -= left;
        this.canvas.backgroundImage.left *= scaleFactor;
        this.canvas.backgroundImage.top -= top - scaleFactor;
        this.canvas.backgroundImage.top *= scaleFactor;
        this.moveAllObjectsInCanvas(-1 * left, -1 * top, scaleFactor);
        this.enableSlection();
        this.cropRectangle.visible = false;
        this.canvas.remove(this.cropRectangle);
        this.canvas.renderAll();
    }
    enableSlection() {
        this.canvas.selectable = true;
        this.canvas.selection = true;
    }
    ajustCropRectangle(event) {
        const touch = event.touches[0];
        const rect = event.target.getBoundingClientRect();
        const x = Math.min(touch.clientX - rect.left, this.mousePosition.x), y = Math.min(touch.clientY - rect.top, this.mousePosition.y), w = Math.abs(touch.clientX - rect.left - this.mousePosition.x), h = Math.abs(touch.clientY - rect.top - this.mousePosition.y);
        if (!w || !h) {
            return false;
        }
        this.cropRectangle
            .set('left', x)
            .set('top', y)
            .set('width', w)
            .set('height', h);
        this.canvas.renderAll();
        return true;
    }
    startSelectingCropRectangle(event) {
        const touch = event.touches[0];
        const rect = event.target.getBoundingClientRect();
        this.cropRectangle.left = touch.clientX - rect.left;
        this.cropRectangle.top = touch.clientY - rect.top;
        this.cropRectangle.setCoords();
        this.mousePosition = { x: touch.clientX - rect.left, y: touch.clientY - rect.top };
        this.canvas.renderAll();
        this.cropRectangle.visible = true;
        this.canvas.bringToFront(this.cropRectangle);
    }
    disableSelection() {
        this.canvas.selection = false;
    }
    moveAllObjectsInCanvas(x, y, scaleFactor) {
        const objects = this.canvas.getObjects();
        for (const obj of objects) {
            obj.left += x;
            obj.left *= scaleFactor;
            obj.scaleX *= scaleFactor;
            obj.top += y;
            obj.scaleY *= scaleFactor;
            obj.top *= scaleFactor;
            obj.setCoords();
        }
    }
    groupSelectedObjects() {
        const activeObjects = this.canvas.getActiveObjects();
        if (activeObjects) {
            const objects = [];
            for (const object of activeObjects) {
                objects.push(object);
            }
            this.deleteSelectedObjects();
            const group = new fabric.Group(objects);
            this.canvas.add(group);
            group.setCoords();
            this.canvas.setActiveObject(group);
            this.canvas.renderAll();
        }
    }
    setLastPanPosition(event) {
        this.lastPanPosition = new fabric.Point(event.touches[0].clientX, event.touches[0].clientY);
    }
    panCanvas(event) {
        const delta = new fabric.Point(event.touches[0].clientX - this.lastPanPosition.x, event.touches[0].clientY - this.lastPanPosition.y);
        this.canvas.relativePan(delta);
        this.preventPanOutsideCanvas();
        this.canvas.renderAll();
        this.setLastPanPosition(event);
    }
    preventPanOutsideCanvas() {
        const canvasViewPort = this.canvas.viewportTransform;
        const bottomEndPoint = this.canvas.height * (canvasViewPort[0] - 1);
        if (canvasViewPort[5] >= 0 || -bottomEndPoint > canvasViewPort[5]) {
            canvasViewPort[5] = (canvasViewPort[5] >= 0) ? 0 : -bottomEndPoint;
        }
        const rightEndPoint = this.canvas.width * (canvasViewPort[0] - 1);
        if (canvasViewPort[4] >= 0 || -rightEndPoint > canvasViewPort[4]) {
            canvasViewPort[4] = (canvasViewPort[4] >= 0) ? 0 : -rightEndPoint;
        }
    }
    zoom(event) {
        if (Math.abs(event.overallVelocity) > 0.005) {
            const point = new fabric.Point(event.center.x, event.center.y);
            let zoom = this.canvas.getZoom();
            zoom = zoom + (event.scale - zoom) / 20;
            if (zoom < 1) {
                zoom = 1;
                this.canvas.zoomToPoint(new fabric.Point(0, 0), zoom);
                this.canvas.absolutePan(new fabric.Point(0, 0));
            }
            else {
                if (zoom > 10) {
                    zoom = 10;
                }
                this.canvas.zoomToPoint(point, zoom);
            }
            this.setFreeDrawingBrushWidthFromZoom(zoom);
            this.canvas.renderAll();
        }
    }
    setCanvasSize(width, height) {
        this.canvas.setWidth(width);
        this.canvas.setHeight(height);
    }
    resetZoom() {
        this.canvas.zoomToPoint(new fabric.Point(0, 0), 1);
        this.canvas.absolutePan(new fabric.Point(0, 0));
    }
};
CanvasManagerService = tslib_1.__decorate([
    Injectable(),
    tslib_1.__metadata("design:paramtypes", [])
], CanvasManagerService);
export { CanvasManagerService };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FudmFzLW1hbmFnZXIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL2xpYi1za2V0Y2gtdG9vbC8iLCJzb3VyY2VzIjpbImFwcC9saWItc2tldGNoLXRvb2wvc2VydmljZXMvY2FudmFzLW1hbmFnZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRWhDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQ3BGLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQWN2RCxJQUFhLG9CQUFvQixHQUFqQyxNQUFhLG9CQUFvQjtJQVMvQjtRQUZRLGFBQVEsR0FBSSxRQUFRLENBQUM7UUFHM0IsSUFBSSxDQUFDLGFBQWEsR0FBRyxFQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQ2hCLENBQUM7SUFFRCxJQUFJLGFBQWE7UUFDZixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVELElBQUkscUJBQXFCO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUM7SUFDckMsQ0FBQztJQUVELElBQUksWUFBWTtRQUNkLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUN2QyxDQUFDO0lBRUQsSUFBSSxXQUFXO1FBQ2IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLGdCQUFnQixFQUFFLENBQUM7SUFDeEMsQ0FBQztJQUVELElBQUksa0JBQWtCO1FBQ3BCLElBQUksVUFBVSxHQUFHLFFBQVEsQ0FBQyxzQkFBc0IsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1FB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LElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUM7UUFFckQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDcEUsSUFBSSxjQUFjLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUMvRCxjQUFjLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUM7U0FDdEU7UUFFRCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNsRSxJQUFJLGNBQWMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQzlELGNBQWMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQztTQUNyRTtJQUNILENBQUM7SUFFTSxJQUFJLENBQUMsS0FBSztRQUNmLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLEdBQUcsS0FBSyxFQUFFO1lBQzNDLE1BQU0sS0FBSyxHQUFHLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRS9ELElBQUksSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDakMsSUFBSSxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBR3hDLElBQUksSUFBSSxHQUFHLENBQUMsRUFBRTtnQkFDWixJQUFJLEdBQUcsQ0FBQyxDQUFDO2dCQUNULElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQ3RELElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUNqRDtpQkFBTTtnQkFDTCxJQUFJLElBQUksR0FBRyxFQUFFLEVBQUU7b0JBQ2IsSUFBSSxHQUFHLEVBQUUsQ0FBQztpQkFDWDtnQkFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7YUFDdEM7WUFFRCxJQUFJLENBQUMsZ0NBQWdDLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDNUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztTQUN6QjtJQUNILENBQUM7SUFFTyxhQUFhLENBQUMsS0FBYSxFQUFFLE1BQWM7UUFDakQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVNLFNBQVM7UUFDZCxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRCxDQUFDO0NBQ0YsQ0FBQTtBQXpwQlksb0JBQW9CO0lBRGhDLFVBQVUsRUFBRTs7R0FDQSxvQkFBb0IsQ0F5cEJoQztTQXpwQlksb0JBQW9CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgZmFicmljIH0gZnJvbSAnZmFicmljJztcblxuaW1wb3J0IHsgQXZhaWxhYmxlR2VvbWV0cmljU2hhcGUgfSBmcm9tICcuLy4uL2NvbnN0YW50cy9hdmFpbGFibGUtZ2VvbWV0cmljLXNoYXBlcyc7XG5pbXBvcnQgeyBTSEFQRV9EQVRBIH0gZnJvbSAnLi8uLi9jb25zdGFudHMvc2hhcGUtZGF0YSc7XG5cbmludGVyZmFjZSBTY2FsZURhdGEge1xuICBzY2FsZUZhY3RvcjogbnVtYmVyO1xuICBsZWZ0OiBudW1iZXI7XG4gIHRvcDogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgUG9zaXRpb24ge1xuICB4OiBudW1iZXI7XG4gIHk6IG51bWJlcjtcbn1cblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIENhbnZhc01hbmFnZXJTZXJ2aWNlIHtcbiAgcHVibGljIGNhbnZhcztcbiAgcHVibGljIGxlZnQ7XG5cbiAgcHJpdmF0ZSBjcm9wUmVjdGFuZ2xlOiBmYWJyaWMuUmVjdDtcbiAgcHJpdmF0ZSBtb3VzZVBvc2l0aW9uOiBQb3NpdGlvbjtcbiAgcHJpdmF0ZSBsYXN0UGFuUG9zaXRpb246IGZhYnJpYy5Qb2ludDtcbiAgcHJpdmF0ZSBjYW52YXNJZCA9ICAnY2FudmFzJztcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLm1vdXNlUG9zaXRpb24gPSB7eDogMCwgeTogMH07XG4gICAgdGhpcy5sZWZ0ID0gMDtcbiAgfVxuXG4gIGdldCBjYW52YXNPYmplY3RzKCkge1xuICAgIHJldHVybiB0aGlzLmNhbnZhcy5nZXRPYmplY3RzKCk7XG4gIH1cblxuICBnZXQgY2FudmFzQmFja2dyb3VuZEltYWdlKCkge1xuICAgIHJldHVybiB0aGlzLmNhbnZhcy5iYWNrZ3JvdW5kSW1hZ2U7XG4gIH1cblxuICBnZXQgYWN0aXZlT2JqZWN0KCkge1xuICAgIHJldHVybiB0aGlzLmNhbnZhcy5nZXRBY3RpdmVPYmplY3QoKTtcbiAgfVxuXG4gIGdldCBhY3RpdmVHcm91cCgpIHtcbiAgICByZXR1cm4gdGhpcy5jYW52YXMuZ2V0QWN0aXZlT2JqZWN0cygpO1xuICB9XG5cbiAgZ2V0IGRpdkNhbnZhc0NvbnRhaW5lcigpIHtcbiAgICBsZXQgY29sbGVjdGlvbiA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ2Rpdi1jYW52YXMtY29udGFpbmVyJyk7XG4gICAgcmV0dXJuIGNvbGxlY3Rpb25bY29sbGVjdGlvbi5sZW5ndGggLTFdO1xuICB9XG5cbiAgcHVibGljIGNyZWF0ZUNhbnZhcyhjYW52YXNJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jYW52YXNJZCA9IGNhbnZhc0lkO1xuICAgIHRoaXMuY2FudmFzID0gbmV3IGZhYnJpYy5DYW52YXModGhpcy5jYW52YXNJZCk7XG4gIH1cblxuICBwdWJsaWMgZW1wdHlDYW52YXMoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuY2FudmFzKSB7XG4gICAgICB0aGlzLmNhbnZhcy5kaXNwb3NlKCk7XG4gICAgfVxuICAgIHRoaXMuY2FudmFzID0gbmV3IGZhYnJpYy5DYW52YXModGhpcy5jYW52YXNJZCk7XG4gICAgdGhpcy5jYW52YXMuY2xlYXIoKTtcbiAgICB0aGlzLmNhbnZhcy5yZW1vdmUodGhpcy5jYW52YXMuZ2V0T2JqZWN0cygpKTtcbiAgfVxuXG4gIHB1YmxpYyBsb2FkTmV3SW1hZ2UoYmFja2dyb3VuZEltYWdlVVJMPzogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5lbXB0eUNhbnZhcygpO1xuICAgIGlmIChiYWNrZ3JvdW5kSW1hZ2VVUkwpIHtcbiAgICAgIHRoaXMuc2V0QmFja2dyb3VuZEZyb21VUkwoYmFja2dyb3VuZEltYWdlVVJMKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgcmVuZGVyQ2FudmFzKCk6IHZvaWQge1xuICAgIHRoaXMubWFya1NlbGVjdGVkT2JqZWN0c0RpcnR5KCk7XG4gICAgdGhpcy5jYW52YXMucmVuZGVyQWxsKCk7XG4gIH1cblxuICBwdWJsaWMgYWRkR2VvbWV0cmljU2hhcGUoc3Ryb2tlQ29sb3I6IHN0cmluZywgZmlsbENvbG9yOiBzdHJpbmcsIHNoYXBlOiBBdmFpbGFibGVHZW9tZXRyaWNTaGFwZSk6IHZvaWQge1xuICAgIHN3aXRjaCAoc2hhcGUpIHtcbiAgICAgIGNhc2UgQXZhaWxhYmxlR2VvbWV0cmljU2hhcGUuUmVjdGFuZ2xlOlxuICAgICAgICB0aGlzLmFkZFJlY3RhbmdsZShzdHJva2VDb2xvciwgZmlsbENvbG9yKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIEF2YWlsYWJsZUdlb21ldHJpY1NoYXBlLkNpcmNsZTpcbiAgICAgICAgdGhpcy5hZGRDaXJjbGUoc3Ryb2tlQ29sb3IsIGZpbGxDb2xvcik7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBBdmFpbGFibGVHZW9tZXRyaWNTaGFwZS5UcmlhbmdsZTpcbiAgICAgICAgdGhpcy5hZGRUcmlhbmdsZShzdHJva2VDb2xvciwgZmlsbENvbG9yKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIEF2YWlsYWJsZUdlb21ldHJpY1NoYXBlLkxpbmU6XG4gICAgICAgIHRoaXMuYWRkSG9yaXpvbnRhbExpbmUoc3Ryb2tlQ29sb3IsIGZpbGxDb2xvcik7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBBdmFpbGFibGVHZW9tZXRyaWNTaGFwZS5Dcm9zczpcbiAgICAgICAgdGhpcy5hZGRDcm9zcyhzdHJva2VDb2xvciwgZmlsbENvbG9yKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRSZWN0YW5nbGUoc3Ryb2tlQ29sb3I6IHN0cmluZywgZmlsbENvbG9yOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmNhbnZhcy5hZGQoXG4gICAgICBuZXcgZmFicmljLlJlY3Qoe1xuICAgICAgICB3aWR0aDogU0hBUEVfREFUQS53aWR0aCxcbiAgICAgICAgaGVpZ2h0OiBTSEFQRV9EQVRBLmhlaWdodCxcbiAgICAgICAgbGVmdDogU0hBUEVfREFUQS5sZWZ0LFxuICAgICAgICB0b3A6IFNIQVBFX0RBVEEudG9wLFxuICAgICAgICBmaWxsOiBmaWxsQ29sb3IsXG4gICAgICAgIHN0cm9rZTogc3Ryb2tlQ29sb3IsXG4gICAgICAgIHN0cm9rZVdpZHRoOiBTSEFQRV9EQVRBLnN0cm9rZSxcbiAgICAgICAgY29ybmVyU2l6ZTogU0hBUEVfREFUQS5jb3JuZXJTaXplXG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFkZENpcmNsZShzdHJva2VDb2xvcjogc3RyaW5nLCBmaWxsQ29sb3I6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuY2FudmFzLmFkZChcbiAgICAgIG5ldyBmYWJyaWMuQ2lyY2xlKHtcbiAgICAgICAgbGVmdDogU0hBUEVfREFUQS5sZWZ0LFxuICAgICAgICB0b3A6IFNIQVBFX0RBVEEudG9wLFxuICAgICAgICByYWRpdXM6IFNIQVBFX0RBVEEucmFkaXVzLFxuICAgICAgICBzdHJva2U6IHN0cm9rZUNvbG9yLFxuICAgICAgICBzdHJva2VXaWR0aDogU0hBUEVfREFUQS5zdHJva2UsXG4gICAgICAgIGZpbGw6IGZpbGxDb2xvcixcbiAgICAgICAgY29ybmVyU2l6ZTogU0hBUEVfREFUQS5jb3JuZXJTaXplXG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFkZFRyaWFuZ2xlKHN0cm9rZUNvbG9yOiBzdHJpbmcsIGZpbGxDb2xvcjogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jYW52YXMuYWRkKFxuICAgICAgbmV3IGZhYnJpYy5UcmlhbmdsZSh7XG4gICAgICAgIHdpZHRoOiBTSEFQRV9EQVRBLndpZHRoLFxuICAgICAgICBoZWlnaHQ6IFNIQVBFX0RBVEEuaGVpZ2h0LFxuICAgICAgICBsZWZ0OiBTSEFQRV9EQVRBLmxlZnQsXG4gICAgICAgIHRvcDogU0hBUEVfREFUQS50b3AsXG4gICAgICAgIGZpbGw6IGZpbGxDb2xvcixcbiAgICAgICAgc3Ryb2tlOiBzdHJva2VDb2xvcixcbiAgICAgICAgc3Ryb2tlV2lkdGg6IFNIQVBFX0RBVEEuc3Ryb2tlLFxuICAgICAgICBjb3JuZXJTaXplOiBTSEFQRV9EQVRBLmNvcm5lclNpemVcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkSG9yaXpvbnRhbExpbmUoc3Ryb2tlQ29sb3I6IHN0cmluZywgZmlsbENvbG9yOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmNhbnZhcy5hZGQodGhpcy5jcmVhdGVIb3Jpem9udGFsTGluZShzdHJva2VDb2xvcikpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVIb3Jpem9udGFsTGluZShzdHJva2VDb2xvcjogc3RyaW5nKTogZmFicmljLkxpbmUge1xuICAgIGNvbnN0IGxpbmUgPSBuZXcgZmFicmljLkxpbmUoWzEwMCwgMTUwLCAyMDAsIDE1MF0sIHtcbiAgICAgIGxlZnQ6IDUwLFxuICAgICAgdG9wOiAxMDAsXG4gICAgICBzdHJva2U6IHN0cm9rZUNvbG9yLFxuICAgICAgc3Ryb2tlV2lkdGg6IDUsXG4gICAgICBjb3JuZXJTaXplOiBTSEFQRV9EQVRBLmNvcm5lclNpemVcbiAgICB9KTtcblxuICAgIGxpbmUuc2V0Q29udHJvbHNWaXNpYmlsaXR5KHtcbiAgICAgIGJsOiBmYWxzZSxcbiAgICAgIGJyOiBmYWxzZSxcbiAgICAgIHRsOiBmYWxzZSxcbiAgICAgIHRyOiBmYWxzZSxcbiAgICAgIG10OiBmYWxzZSxcbiAgICAgIG1iOiBmYWxzZVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxpbmU7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVZlcnRpY2FsTGluZShzdHJva2VDb2xvcjogc3RyaW5nKTogZmFicmljLkxpbmUge1xuICAgIGNvbnN0IGxpbmUgPSBuZXcgZmFicmljLkxpbmUoWzE1MCwgMTAwLCAxNTAsIDIwMF0sIHtcbiAgICAgIGxlZnQ6IDEwMCxcbiAgICAgIHRvcDogNTAsXG4gICAgICBzdHJva2U6IHN0cm9rZUNvbG9yLFxuICAgICAgc3Ryb2tlV2lkdGg6IDUsXG4gICAgICBjb3JuZXJTaXplOiBTSEFQRV9EQVRBLmNvcm5lclNpemVcbiAgICB9KTtcblxuICAgIGxpbmUuc2V0Q29udHJvbHNWaXNpYmlsaXR5KHtcbiAgICAgIGJsOiBmYWxzZSxcbiAgICAgIGJyOiBmYWxzZSxcbiAgICAgIHRsOiBmYWxzZSxcbiAgICAgIHRyOiBmYWxzZSxcbiAgICAgIG1sOiBmYWxzZSxcbiAgICAgIG1yOiBmYWxzZVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxpbmU7XG4gIH1cblxuICBwcml2YXRlIGFkZENyb3NzKHN0cm9rZUNvbG9yOiBzdHJpbmcsIGZpbGxDb2xvcjogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgaG9yaXpvbnRhbExpbmUgPSB0aGlzLmNyZWF0ZUhvcml6b250YWxMaW5lKHN0cm9rZUNvbG9yKTtcbiAgICBjb25zdCB2ZXJ0aWNhbExpbmUgPSB0aGlzLmNyZWF0ZVZlcnRpY2FsTGluZShzdHJva2VDb2xvcik7XG4gICAgdGhpcy5jYW52YXMuYWRkKGhvcml6b250YWxMaW5lKTtcbiAgICB0aGlzLmNhbnZhcy5hZGQodmVydGljYWxMaW5lKTtcbiAgfVxuXG4gIHB1YmxpYyB0b2dnbGVGcmVlRHJhd2luZygpOiB2b2lkIHtcbiAgICB0aGlzLmNhbnZhcy5pc0RyYXdpbmdNb2RlID0gIXRoaXMuY2FudmFzLmlzRHJhd2luZ01vZGU7XG4gIH1cblxuICBwdWJsaWMgc2V0RnJlZURyYXdpbmdCcnVzaENvbG9yKGNvbG9yOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmNhbnZhcy5mcmVlRHJhd2luZ0JydXNoLmNvbG9yID0gY29sb3I7XG4gICAgdGhpcy5zZXRGcmVlRHJhd2luZ0JydXNoV2lkdGhGcm9tWm9vbSh0aGlzLmNhbnZhcy5nZXRab29tKCkpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRGcmVlRHJhd2luZ0JydXNoV2lkdGhGcm9tWm9vbSh6b29tOiBudW1iZXIpIHtcbiAgICB0aGlzLmNhbnZhcy5mcmVlRHJhd2luZ0JydXNoLndpZHRoID0gU0hBUEVfREFUQS5mcmVlRHJhd2luZ0JydXNoV2lkdGggKiAoMSAvIHpvb20pO1xuICB9XG5cbiAgcHVibGljIGFkZFRleHQoY29sb3I6IHN0cmluZywgaW5wdXRUZXh0OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCB0ZXh0ID0gbmV3IGZhYnJpYy5JVGV4dCgndGV4dCcsIHtcbiAgICAgIGZvbnRGYW1pbHk6ICdhcmlhbCBibGFjaycsXG4gICAgICBmb250U3R5bGU6ICdib2xkJyxcbiAgICAgIGxlZnQ6IFNIQVBFX0RBVEEubGVmdCxcbiAgICAgIHRvcDogU0hBUEVfREFUQS50b3AsXG4gICAgICBjb3JuZXJTaXplOiBTSEFQRV9EQVRBLmNvcm5lclNpemVcbiAgICB9KTtcblxuICAgIHRleHQuc2V0Q29sb3IoY29sb3IpO1xuXG4gICAgdGhpcy5jYW52YXMuYWRkKHRleHQpO1xuICB9XG5cbiAgcHVibGljIGFkZEltYWdlKGltYWdlVVJMOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoXG4gICAgICAocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IHRoaXMuY2FudmFzO1xuXG4gICAgICAgIGNvbnN0IGltYWdlID0gbmV3IEltYWdlKCk7XG4gICAgICAgIGltYWdlLm9ubG9hZCA9IGZ1bmN0aW9uKGltZykge1xuICAgICAgICAgIGNvbnN0IGZhYnJpY0ltYWdlID0gbmV3IGZhYnJpYy5JbWFnZShpbWFnZSwge1xuICAgICAgICAgICAgYW5nbGU6IDAsXG4gICAgICAgICAgICB3aWR0aDogaW1hZ2Uud2lkdGgsXG4gICAgICAgICAgICBoZWlnaHQ6IGltYWdlLmhlaWdodCxcbiAgICAgICAgICAgIGxlZnQ6IFNIQVBFX0RBVEEubGVmdCxcbiAgICAgICAgICAgIHRvcDogU0hBUEVfREFUQS50b3AsXG4gICAgICAgICAgICBzY2FsZVg6IDEsXG4gICAgICAgICAgICBzY2FsZVk6IDEsXG4gICAgICAgICAgICBjb3JuZXJTaXplOiBTSEFQRV9EQVRBLmNvcm5lclNpemVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBjYW52YXMuYWRkKGZhYnJpY0ltYWdlKTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH07XG4gICAgICAgIGltYWdlLnNyYyA9IGltYWdlVVJMO1xuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBwdWJsaWMgc2V0QmFja2dyb3VuZEZyb21VUkwoYmFja2dyb3VuZEltYWdlVVJMOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb250YWluZXIgPSAgdGhpcy5kaXZDYW52YXNDb250YWluZXI7XG4gICAgdGhpcy5zZXRDYW52YXNTaXplKGNvbnRhaW5lci5jbGllbnRXaWR0aCwgY29udGFpbmVyLmNsaWVudEhlaWdodCk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoXG4gICAgICAocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICAgIGlmIChiYWNrZ3JvdW5kSW1hZ2VVUkwgPT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiByZWplY3QoKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBpbWFnZSA9IG5ldyBJbWFnZSgpO1xuICAgICAgICBpbWFnZS5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgZl9pbWcgPSBuZXcgZmFicmljLkltYWdlKGltYWdlLCB7fSk7XG5cbiAgICAgICAgICBjb25zdCBzY2FsZURhdGEgPSB0aGlzLmNvbXB1dGVTY2FsZUZhY3RvcihmX2ltZywgdGhpcy5jYW52YXMpO1xuXG4gICAgICAgICAgdGhpcy5jYW52YXMuc2V0QmFja2dyb3VuZEltYWdlKGZfaW1nLCB0aGlzLmNhbnZhcy5yZW5kZXJBbGwuYmluZCh0aGlzLmNhbnZhcyksIHtcbiAgICAgICAgICAgIHNjYWxlWDogc2NhbGVEYXRhLnNjYWxlRmFjdG9yLFxuICAgICAgICAgICAgc2NhbGVZOiBzY2FsZURhdGEuc2NhbGVGYWN0b3JcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIHRoaXMuc2V0Q2FudmFzU2l6ZShmX2ltZy53aWR0aCAqIHNjYWxlRGF0YS5zY2FsZUZhY3RvciwgZl9pbWcuaGVpZ2h0ICogc2NhbGVEYXRhLnNjYWxlRmFjdG9yKTtcblxuICAgICAgICAgIHRoaXMuY2FudmFzLnJlbmRlckFsbCgpO1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfTtcbiAgICAgICAgaW1hZ2Uuc3JjID0gYmFja2dyb3VuZEltYWdlVVJMO1xuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGNvbXB1dGVTY2FsZUZhY3RvcihmX2ltZzogZmFicmljLkltYWdlLCBjYW52YXM6IGZhYnJpYy5DYW52YXMpOiBTY2FsZURhdGEge1xuICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZGl2Q2FudmFzQ29udGFpbmVyO1xuXG4gICAgY29uc3QgY2FudmFzQXNwZWN0ID0gY29udGFpbmVyLmNsaWVudFdpZHRoIC8gY29udGFpbmVyLmNsaWVudEhlaWdodDtcbiAgICBjb25zdCBpbWdBc3BlY3QgPSBmX2ltZy53aWR0aCAvIGZfaW1nLmhlaWdodDtcbiAgICBsZXQgbGVmdCwgdG9wLCBzY2FsZUZhY3RvcjtcblxuICAgIGlmIChjYW52YXNBc3BlY3QgPD0gaW1nQXNwZWN0KSB7XG4gICAgICBzY2FsZUZhY3RvciA9IGNvbnRhaW5lci5jbGllbnRXaWR0aCAvIGZfaW1nLndpZHRoO1xuICAgICAgbGVmdCA9IDA7XG4gICAgICB0b3AgPSAtKGZfaW1nLmhlaWdodCAqIHNjYWxlRmFjdG9yIC0gY29udGFpbmVyLmNsaWVudEhlaWdodCkgLyAyO1xuICAgIH0gZWxzZSB7XG4gICAgICBzY2FsZUZhY3RvciA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQgLyBmX2ltZy5oZWlnaHQ7XG4gICAgICB0b3AgPSAwO1xuICAgICAgbGVmdCA9IC0oZl9pbWcud2lkdGggKiBzY2FsZUZhY3RvciAtIGNvbnRhaW5lci5jbGllbnRXaWR0aCkgLyAyO1xuICAgIH1cblxuICAgIHRoaXMubGVmdCA9IGxlZnQ7XG5cbiAgICByZXR1cm4geyBzY2FsZUZhY3Rvcjogc2NhbGVGYWN0b3IsIGxlZnQ6IGxlZnQsIHRvcDogdG9wIH07XG4gIH1cblxuICBwdWJsaWMgb25PcmllbnRhdGlvbkNoYW5nZSgpIHtcbiAgICB0aGlzLm1vdXNlUG9zaXRpb24gPSB7eDogdGhpcy5jYW52YXMuZ2V0V2lkdGgsIHk6IHRoaXMuY2FudmFzLmdldEhlaWdodCB9O1xuICAgIHRoaXMuY3JvcEltYWdlKCk7XG4gIH1cblxuICBwdWJsaWMgY2hhbmdlU2VsZWN0ZWRPYmplY3RzRmlsbENvbG9yKGNvbG9yOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBhY3RpdmVPYmplY3RzID0gdGhpcy5jYW52YXMuZ2V0QWN0aXZlT2JqZWN0cygpO1xuXG4gICAgaWYgKGFjdGl2ZU9iamVjdHMpIHtcbiAgICAgIGZvciAoY29uc3Qgb2JqZWN0IG9mIGFjdGl2ZU9iamVjdHMpIHtcbiAgICAgICAgb2JqZWN0LnNldENvbG9yKGNvbG9yKTtcbiAgICAgICAgdGhpcy5jYW52YXMucmVuZGVyQWxsKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGNoYW5nZVNlbGVjdGVkT2JqZWN0c1N0cm9rZUNvbG9yKGNvbG9yOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBhY3RpdmVPYmplY3RzID0gdGhpcy5jYW52YXMuZ2V0QWN0aXZlT2JqZWN0cygpO1xuXG4gICAgaWYgKGFjdGl2ZU9iamVjdHMpIHtcbiAgICAgIGZvciAoY29uc3Qgb2JqZWN0IG9mIGFjdGl2ZU9iamVjdHMpIHtcbiAgICAgICAgaWYgKG9iamVjdC50eXBlID09PSAnaS10ZXh0Jykge1xuICAgICAgICAgIG9iamVjdC5zZXRDb2xvcihjb2xvcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgb2JqZWN0LnN0cm9rZSA9IGNvbG9yO1xuICAgICAgICAgIG9iamVjdC5zZXQoJ2RpcnR5JywgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRoaXMuY2FudmFzLnJlbmRlckFsbCgpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBkZWxldGVTZWxlY3RlZE9iamVjdHMoKTogdm9pZCB7XG4gICAgY29uc3QgYWN0aXZlT2JqZWN0cyA9IHRoaXMuY2FudmFzLmdldEFjdGl2ZU9iamVjdHMoKTtcblxuICAgIGlmIChhY3RpdmVPYmplY3RzKSB7XG4gICAgICBmb3IgKGNvbnN0IG9iamVjdCBvZiBhY3RpdmVPYmplY3RzKSB7XG4gICAgICAgIHRoaXMuY2FudmFzLnJlbW92ZShvYmplY3QpO1xuICAgICAgfVxuICAgICAgdGhpcy5jYW52YXMuZGlzY2FyZEFjdGl2ZU9iamVjdCgpO1xuICAgICAgdGhpcy5jYW52YXMucmVuZGVyQWxsKCk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGJyaW5nU2VsZWN0ZWRPYmplY3RzVG9Gcm9udCgpOiB2b2lkIHtcbiAgICBjb25zdCBhY3RpdmVPYmplY3RzID0gdGhpcy5jYW52YXMuZ2V0QWN0aXZlT2JqZWN0cygpO1xuXG4gICAgaWYgKGFjdGl2ZU9iamVjdHMpIHtcbiAgICAgIGZvciAoY29uc3Qgb2JqZWN0IG9mIGFjdGl2ZU9iamVjdHMpIHtcbiAgICAgICAgdGhpcy5jYW52YXMuYnJpbmdUb0Zyb250KG9iamVjdCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHVibGljIHNlbmRTZWxlY3RlZE9iamVjdHNUb0JhY2soKTogdm9pZCB7XG4gICAgY29uc3QgYWN0aXZlT2JqZWN0cyA9IHRoaXMuY2FudmFzLmdldEFjdGl2ZU9iamVjdHMoKTtcblxuICAgIGlmIChhY3RpdmVPYmplY3RzKSB7XG4gICAgICBmb3IgKGNvbnN0IG9iamVjdCBvZiBhY3RpdmVPYmplY3RzKSB7XG4gICAgICAgIHRoaXMuY2FudmFzLnNlbmRUb0JhY2sob2JqZWN0KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwdWJsaWMganNvbkZyb21DYW52YXMoKTogSlNPTiB7XG4gICAgcmV0dXJuIHRoaXMuY2FudmFzLnRvSlNPTihbJ3dpZHRoJywgJ2hlaWdodCddKTtcbiAgfVxuXG4gIHB1YmxpYyBsb2FkZnJvbUpzb24oanNvbjogSlNPTik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuZGl2Q2FudmFzQ29udGFpbmVyO1xuXG4gICAgdGhpcy5zZXRDYW52YXNTaXplKGNvbnRhaW5lci5jbGllbnRXaWR0aCwgY29udGFpbmVyLmNsaWVudEhlaWdodCk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoXG4gICAgICAocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuYWRqdXN0Q2FudmFzKGpzb24pO1xuICAgICAgICB0aGlzLmNhbnZhcy5sb2FkRnJvbUpTT04oanNvbiwgdGhpcy5jYW52YXMucmVuZGVyQWxsLmJpbmQodGhpcy5jYW52YXMpKTtcbiAgICAgICAgdGhpcy5jYW52YXMucmVuZGVyQWxsKCk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgcHVibGljIGFkanVzdENhbnZhcyhqc29uOiBKU09OKTogdm9pZCB7XG4gICAgY29uc3QgYmFja2dyb3VuZEltYWdlID0ganNvblsnYmFja2dyb3VuZEltYWdlJ107XG5cbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmRpdkNhbnZhc0NvbnRhaW5lcjtcblxuICAgIGNvbnN0IHdpZHRoID0ganNvblsnd2lkdGgnXTtcbiAgICBjb25zdCBoZWlnaHQgPSBqc29uWydoZWlnaHQnXTtcblxuICAgIGNvbnN0IGNhbnZhc1dpZHRoID0gY29udGFpbmVyLmNsaWVudFdpZHRoO1xuICAgIGNvbnN0IGNhbnZhc0hlaWdodCA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQ7XG5cbiAgICBjb25zdCBjYW52YXNBc3BlY3QgPSBjYW52YXNXaWR0aCAvIGNhbnZhc0hlaWdodDtcbiAgICBjb25zdCBpbWdBc3BlY3QgPSB3aWR0aCAvIGhlaWdodDtcbiAgICBsZXQgc2NhbGVGYWN0b3IsIGxlZnQ7XG5cbiAgICBpZiAoY2FudmFzQXNwZWN0IDw9IGltZ0FzcGVjdCkge1xuICAgICAgc2NhbGVGYWN0b3IgPSBjYW52YXNXaWR0aCAvIHdpZHRoO1xuICAgICAgbGVmdCA9IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNjYWxlRmFjdG9yID0gY2FudmFzSGVpZ2h0IC8gaGVpZ2h0O1xuICAgICAgbGVmdCA9IC0od2lkdGggKiBzY2FsZUZhY3RvciAtIGNvbnRhaW5lci5jbGllbnRXaWR0aCkgLyAyO1xuICAgIH1cblxuICAgIHRoaXMubGVmdCA9IGxlZnQ7XG5cbiAgICBiYWNrZ3JvdW5kSW1hZ2VbJ3NjYWxlWCddICo9IHNjYWxlRmFjdG9yO1xuICAgIGJhY2tncm91bmRJbWFnZVsnc2NhbGVZJ10gKj0gc2NhbGVGYWN0b3I7XG5cbiAgICB0aGlzLnNldENhbnZhc1NpemUod2lkdGggKiBzY2FsZUZhY3RvciwgaGVpZ2h0ICogc2NhbGVGYWN0b3IpO1xuXG4gICAgY29uc3Qgb2JqZWN0cyA9IGpzb25bJ29iamVjdHMnXTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb2JqZWN0cy5sZW5ndGg7IGkrKykge1xuICAgICAgb2JqZWN0c1tpXVsnbGVmdCddICo9IHNjYWxlRmFjdG9yO1xuICAgICAgb2JqZWN0c1tpXVsndG9wJ10gKj0gc2NhbGVGYWN0b3I7XG4gICAgICBvYmplY3RzW2ldWydzY2FsZVgnXSAqPSBzY2FsZUZhY3RvcjtcbiAgICAgIG9iamVjdHNbaV1bJ3NjYWxlWSddICo9IHNjYWxlRmFjdG9yO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBleHBvcnRJbWFnZUFzRGF0YVVSTCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmNhbnZhcy50b0RhdGFVUkwoJ2ltYWdlL3BuZycpO1xuICB9XG5cbiAgcHVibGljIHNlbGVjdEl0ZW0oaXRlbU51bWJlcjogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5jYW52YXMuc2V0QWN0aXZlT2JqZWN0KHRoaXMuY2FudmFzLml0ZW0oaXRlbU51bWJlcikpO1xuICB9XG5cbiAgcHVibGljIGdldEluZGV4T2YoYWN0aXZlT2JqZWN0KTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5jYW52YXMuZ2V0T2JqZWN0cygpLmluZGV4T2YoYWN0aXZlT2JqZWN0KTtcbiAgfVxuXG4gIHByaXZhdGUgbWFya1NlbGVjdGVkT2JqZWN0c0RpcnR5KCk6IHZvaWQge1xuICAgIGNvbnN0IGFjdGl2ZU9iamVjdHMgPSB0aGlzLmNhbnZhcy5nZXRBY3RpdmVPYmplY3RzKCk7XG5cbiAgICBpZiAoYWN0aXZlT2JqZWN0cykge1xuICAgICAgZm9yIChjb25zdCBvYmplY3Qgb2YgYWN0aXZlT2JqZWN0cykge1xuICAgICAgICBvYmplY3Quc2V0KCdkaXJ0eScsIHRydWUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBhZGRTZWxlY3Rpb25SZWN0YW5nbGUoKTogdm9pZCB7XG4gICAgdGhpcy5jcm9wUmVjdGFuZ2xlID0gbmV3IGZhYnJpYy5SZWN0KHtcbiAgICAgIGZpbGw6ICd0cmFuc3BhcmVudCcsXG4gICAgICBvcmlnaW5YOiAnbGVmdCcsXG4gICAgICBvcmlnaW5ZOiAndG9wJyxcbiAgICAgIHN0cm9rZTogJyNjY2MnLFxuICAgICAgc3Ryb2tlRGFzaEFycmF5OiBbMiwgMl0sXG4gICAgICBvcGFjaXR5OiAxLFxuICAgICAgd2lkdGg6IDAsXG4gICAgICBoZWlnaHQ6IDBcbiAgICB9KTtcblxuICAgIHRoaXMuY3JvcFJlY3RhbmdsZS52aXNpYmxlID0gZmFsc2U7XG4gICAgdGhpcy5jYW52YXMuYWRkKHRoaXMuY3JvcFJlY3RhbmdsZSk7XG4gIH1cblxuICBwdWJsaWMgYWp1c3RDcm9wUmVjdGFuZ2xlRnJvbU1vdXNlKGV2ZW50OiBNb3VzZUV2ZW50KTogYm9vbGVhbiB7XG5cbiAgICBjb25zdCB4ID0gTWF0aC5taW4oZXZlbnQub2Zmc2V0WCwgdGhpcy5tb3VzZVBvc2l0aW9uLngpLFxuICAgICAgeSA9IE1hdGgubWluKGV2ZW50Lm9mZnNldFksIHRoaXMubW91c2VQb3NpdGlvbi55KSxcbiAgICAgIHcgPSBNYXRoLmFicyhldmVudC5vZmZzZXRYIC0gdGhpcy5tb3VzZVBvc2l0aW9uLngpLFxuICAgICAgaCA9IE1hdGguYWJzKGV2ZW50Lm9mZnNldFkgLSB0aGlzLm1vdXNlUG9zaXRpb24ueSk7XG5cbiAgICBpZiAoIXcgfHwgIWgpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB0aGlzLmNyb3BSZWN0YW5nbGVcbiAgICAgIC5zZXQoJ3RvcCcsIHkpXG4gICAgICAuc2V0KCdsZWZ0JywgeClcbiAgICAgIC5zZXQoJ3dpZHRoJywgdylcbiAgICAgIC5zZXQoJ2hlaWdodCcsIGgpO1xuXG4gICAgdGhpcy5jYW52YXMucmVuZGVyQWxsKCk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHB1YmxpYyBzdGFydFNlbGVjdGluZ0Nyb3BSZWN0YW5nbGVGcm9tTW91c2UoZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICB0aGlzLmNyb3BSZWN0YW5nbGUubGVmdCA9IGV2ZW50Lm9mZnNldFg7XG4gICAgdGhpcy5jcm9wUmVjdGFuZ2xlLnRvcCA9IGV2ZW50Lm9mZnNldFk7XG4gICAgdGhpcy5jcm9wUmVjdGFuZ2xlLnNldENvb3JkcygpO1xuXG4gICAgdGhpcy5tb3VzZVBvc2l0aW9uID0ge3g6IGV2ZW50Lm9mZnNldFgsIHk6IGV2ZW50Lm9mZnNldFkgfTtcblxuICAgIHRoaXMuY3JvcFJlY3RhbmdsZS52aXNpYmxlID0gdHJ1ZTtcbiAgICB0aGlzLmNhbnZhcy5icmluZ1RvRnJvbnQodGhpcy5jcm9wUmVjdGFuZ2xlKTtcbiAgfVxuXG4gIHB1YmxpYyBjcm9wSW1hZ2UoKTogdm9pZCB7XG4gICAgY29uc3QgbGVmdCA9IHRoaXMuY3JvcFJlY3RhbmdsZS5sZWZ0O1xuICAgIGNvbnN0IHRvcCA9IHRoaXMuY3JvcFJlY3RhbmdsZS50b3A7XG5cbiAgICBjb25zdCB3aWR0aCA9IHRoaXMuY3JvcFJlY3RhbmdsZS53aWR0aDtcbiAgICBjb25zdCBoZWlnaHQgPSB0aGlzLmNyb3BSZWN0YW5nbGUuaGVpZ2h0O1xuXG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5kaXZDYW52YXNDb250YWluZXI7XG5cbiAgICBjb25zdCBjYW52YXNXaWR0aCA9IGNvbnRhaW5lci5jbGllbnRXaWR0aDtcbiAgICBjb25zdCBjYW52YXNIZWlnaHQgPSBjb250YWluZXIuY2xpZW50SGVpZ2h0O1xuXG4gICAgY29uc3QgY2FudmFzQXNwZWN0ID0gY2FudmFzV2lkdGggLyBjYW52YXNIZWlnaHQ7XG4gICAgY29uc3QgaW1nQXNwZWN0ID0gd2lkdGggLyBoZWlnaHQ7XG4gICAgbGV0IHNjYWxlRmFjdG9yO1xuXG4gICAgaWYgKGNhbnZhc0FzcGVjdCA8PSBpbWdBc3BlY3QpIHtcbiAgICAgIHNjYWxlRmFjdG9yID0gY2FudmFzV2lkdGggLyB3aWR0aDtcbiAgICB9IGVsc2Uge1xuICAgICAgc2NhbGVGYWN0b3IgPSBjYW52YXNIZWlnaHQgLyBoZWlnaHQ7XG4gICAgfVxuXG4gICAgdGhpcy5zZXRDYW52YXNTaXplKHdpZHRoICogc2NhbGVGYWN0b3IsIGhlaWdodCAqIHNjYWxlRmFjdG9yKTtcblxuICAgIHRoaXMuY2FudmFzLmJhY2tncm91bmRJbWFnZS5zY2FsZVggKj0gc2NhbGVGYWN0b3I7XG4gICAgdGhpcy5jYW52YXMuYmFja2dyb3VuZEltYWdlLnNjYWxlWSAqPSBzY2FsZUZhY3RvcjtcblxuICAgIHRoaXMuY2FudmFzLmJhY2tncm91bmRJbWFnZS5sZWZ0IC09IGxlZnQ7XG4gICAgdGhpcy5jYW52YXMuYmFja2dyb3VuZEltYWdlLmxlZnQgKj0gc2NhbGVGYWN0b3I7XG4gICAgdGhpcy5jYW52YXMuYmFja2dyb3VuZEltYWdlLnRvcCAtPSB0b3AgLSBzY2FsZUZhY3RvcjtcbiAgICB0aGlzLmNhbnZhcy5iYWNrZ3JvdW5kSW1hZ2UudG9wICo9IHNjYWxlRmFjdG9yO1xuXG4gICAgdGhpcy5tb3ZlQWxsT2JqZWN0c0luQ2FudmFzKC0xICogbGVmdCwgLTEgKiB0b3AsIHNjYWxlRmFjdG9yKTtcblxuICAgIHRoaXMuZW5hYmxlU2xlY3Rpb24oKTtcbiAgICB0aGlzLmNyb3BSZWN0YW5nbGUudmlzaWJsZSA9IGZhbHNlO1xuXG4gICAgdGhpcy5jYW52YXMucmVtb3ZlKHRoaXMuY3JvcFJlY3RhbmdsZSk7XG5cbiAgICB0aGlzLmNhbnZhcy5yZW5kZXJBbGwoKTtcbiAgfVxuXG4gIHB1YmxpYyBlbmFibGVTbGVjdGlvbigpIHtcbiAgICB0aGlzLmNhbnZhcy5zZWxlY3RhYmxlID0gdHJ1ZTtcbiAgICB0aGlzLmNhbnZhcy5zZWxlY3Rpb24gPSB0cnVlO1xuICB9XG5cbiAgcHVibGljIGFqdXN0Q3JvcFJlY3RhbmdsZShldmVudCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHRvdWNoID0gZXZlbnQudG91Y2hlc1swXTtcblxuICAgIGNvbnN0IHJlY3QgPSBldmVudC50YXJnZXQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICBjb25zdCB4ID0gTWF0aC5taW4odG91Y2guY2xpZW50WCAtIHJlY3QubGVmdCwgdGhpcy5tb3VzZVBvc2l0aW9uLngpLFxuICAgICAgeSA9IE1hdGgubWluKHRvdWNoLmNsaWVudFkgLSByZWN0LnRvcCwgdGhpcy5tb3VzZVBvc2l0aW9uLnkpLFxuICAgICAgdyA9IE1hdGguYWJzKHRvdWNoLmNsaWVudFggLSByZWN0LmxlZnQgLSB0aGlzLm1vdXNlUG9zaXRpb24ueCksXG4gICAgICBoID0gTWF0aC5hYnModG91Y2guY2xpZW50WSAtIHJlY3QudG9wIC0gdGhpcy5tb3VzZVBvc2l0aW9uLnkpO1xuXG4gICAgaWYgKCF3IHx8ICFoKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdGhpcy5jcm9wUmVjdGFuZ2xlXG4gICAgICAuc2V0KCdsZWZ0JywgeClcbiAgICAgIC5zZXQoJ3RvcCcsIHkpXG4gICAgICAuc2V0KCd3aWR0aCcsIHcpXG4gICAgICAuc2V0KCdoZWlnaHQnLCBoKTtcblxuICAgIHRoaXMuY2FudmFzLnJlbmRlckFsbCgpO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBwdWJsaWMgc3RhcnRTZWxlY3RpbmdDcm9wUmVjdGFuZ2xlKGV2ZW50KTogdm9pZCB7XG4gICAgY29uc3QgdG91Y2ggPSBldmVudC50b3VjaGVzWzBdO1xuICAgIGNvbnN0IHJlY3QgPSBldmVudC50YXJnZXQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICB0aGlzLmNyb3BSZWN0YW5nbGUubGVmdCA9IHRvdWNoLmNsaWVudFggLSByZWN0LmxlZnQ7XG4gICAgdGhpcy5jcm9wUmVjdGFuZ2xlLnRvcCA9IHRvdWNoLmNsaWVudFkgLSByZWN0LnRvcDtcbiAgICB0aGlzLmNyb3BSZWN0YW5nbGUuc2V0Q29vcmRzKCk7XG5cbiAgICB0aGlzLm1vdXNlUG9zaXRpb24gPSB7IHg6IHRvdWNoLmNsaWVudFggLSByZWN0LmxlZnQsIHk6IHRvdWNoLmNsaWVudFkgLSByZWN0LnRvcCB9O1xuXG4gICAgdGhpcy5jYW52YXMucmVuZGVyQWxsKCk7XG4gICAgdGhpcy5jcm9wUmVjdGFuZ2xlLnZpc2libGUgPSB0cnVlO1xuICAgIHRoaXMuY2FudmFzLmJyaW5nVG9Gcm9udCh0aGlzLmNyb3BSZWN0YW5nbGUpO1xuICB9XG5cbiAgcHVibGljIGRpc2FibGVTZWxlY3Rpb24oKSB7XG4gICAgdGhpcy5jYW52YXMuc2VsZWN0aW9uID0gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIG1vdmVBbGxPYmplY3RzSW5DYW52YXMoeDogbnVtYmVyLCB5OiBudW1iZXIsIHNjYWxlRmFjdG9yOiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBvYmplY3RzID0gdGhpcy5jYW52YXMuZ2V0T2JqZWN0cygpO1xuICAgIGZvciAoY29uc3Qgb2JqIG9mIG9iamVjdHMpIHtcbiAgICAgIG9iai5sZWZ0ICs9IHg7XG4gICAgICBvYmoubGVmdCAqPSBzY2FsZUZhY3RvcjtcbiAgICAgIG9iai5zY2FsZVggKj0gc2NhbGVGYWN0b3I7XG4gICAgICBvYmoudG9wICs9IHk7XG4gICAgICBvYmouc2NhbGVZICo9IHNjYWxlRmFjdG9yO1xuICAgICAgb2JqLnRvcCAqPSBzY2FsZUZhY3RvcjtcbiAgICAgIG9iai5zZXRDb29yZHMoKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgZ3JvdXBTZWxlY3RlZE9iamVjdHMoKTogdm9pZCB7XG4gICAgY29uc3QgYWN0aXZlT2JqZWN0cyA9IHRoaXMuY2FudmFzLmdldEFjdGl2ZU9iamVjdHMoKTtcblxuICAgIGlmIChhY3RpdmVPYmplY3RzKSB7XG4gICAgICBjb25zdCBvYmplY3RzID0gW107XG5cbiAgICAgIGZvciAoY29uc3Qgb2JqZWN0IG9mIGFjdGl2ZU9iamVjdHMpIHtcbiAgICAgICAgb2JqZWN0cy5wdXNoKG9iamVjdCk7XG4gICAgICB9XG4gICAgICB0aGlzLmRlbGV0ZVNlbGVjdGVkT2JqZWN0cygpO1xuXG4gICAgICBjb25zdCBncm91cCA9IG5ldyBmYWJyaWMuR3JvdXAob2JqZWN0cyk7XG4gICAgICB0aGlzLmNhbnZhcy5hZGQoZ3JvdXApO1xuICAgICAgZ3JvdXAuc2V0Q29vcmRzKCk7XG5cbiAgICAgIHRoaXMuY2FudmFzLnNldEFjdGl2ZU9iamVjdChncm91cCk7XG5cbiAgICAgIHRoaXMuY2FudmFzLnJlbmRlckFsbCgpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBzZXRMYXN0UGFuUG9zaXRpb24oZXZlbnQpIHtcbiAgICB0aGlzLmxhc3RQYW5Qb3NpdGlvbiA9IG5ldyBmYWJyaWMuUG9pbnQoZXZlbnQudG91Y2hlc1swXS5jbGllbnRYLCBldmVudC50b3VjaGVzWzBdLmNsaWVudFkpO1xuICB9XG5cbiAgcHVibGljIHBhbkNhbnZhcyhldmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGRlbHRhID0gbmV3IGZhYnJpYy5Qb2ludChcbiAgICAgIGV2ZW50LnRvdWNoZXNbMF0uY2xpZW50WCAtIHRoaXMubGFzdFBhblBvc2l0aW9uLngsXG4gICAgICBldmVudC50b3VjaGVzWzBdLmNsaWVudFkgLSB0aGlzLmxhc3RQYW5Qb3NpdGlvbi55XG4gICAgKTtcblxuICAgIHRoaXMuY2FudmFzLnJlbGF0aXZlUGFuKGRlbHRhKTtcbiAgICB0aGlzLnByZXZlbnRQYW5PdXRzaWRlQ2FudmFzKCk7XG5cbiAgICB0aGlzLmNhbnZhcy5yZW5kZXJBbGwoKTtcbiAgICB0aGlzLnNldExhc3RQYW5Qb3NpdGlvbihldmVudCk7XG4gIH1cblxuICBwcml2YXRlIHByZXZlbnRQYW5PdXRzaWRlQ2FudmFzKCkge1xuICAgIGNvbnN0IGNhbnZhc1ZpZXdQb3J0ID0gdGhpcy5jYW52YXMudmlld3BvcnRUcmFuc2Zvcm07XG5cbiAgICBjb25zdCBib3R0b21FbmRQb2ludCA9IHRoaXMuY2FudmFzLmhlaWdodCAqIChjYW52YXNWaWV3UG9ydFswXSAtIDEpO1xuICAgIGlmIChjYW52YXNWaWV3UG9ydFs1XSA+PSAwIHx8IC1ib3R0b21FbmRQb2ludCA+IGNhbnZhc1ZpZXdQb3J0WzVdKSB7XG4gICAgICAgIGNhbnZhc1ZpZXdQb3J0WzVdID0gKGNhbnZhc1ZpZXdQb3J0WzVdID49IDApID8gMCA6IC1ib3R0b21FbmRQb2ludDtcbiAgICB9XG5cbiAgICBjb25zdCByaWdodEVuZFBvaW50ID0gdGhpcy5jYW52YXMud2lkdGggKiAoY2FudmFzVmlld1BvcnRbMF0gLSAxKTtcbiAgICBpZiAoY2FudmFzVmlld1BvcnRbNF0gPj0gMCB8fCAtcmlnaHRFbmRQb2ludCA+IGNhbnZhc1ZpZXdQb3J0WzRdKSB7XG4gICAgICAgIGNhbnZhc1ZpZXdQb3J0WzRdID0gKGNhbnZhc1ZpZXdQb3J0WzRdID49IDApID8gMCA6IC1yaWdodEVuZFBvaW50O1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyB6b29tKGV2ZW50KTogdm9pZCB7XG4gICAgaWYgKE1hdGguYWJzKGV2ZW50Lm92ZXJhbGxWZWxvY2l0eSkgPiAwLjAwNSkge1xuICAgICAgY29uc3QgcG9pbnQgPSBuZXcgZmFicmljLlBvaW50KGV2ZW50LmNlbnRlci54LCBldmVudC5jZW50ZXIueSk7XG5cbiAgICAgIGxldCB6b29tID0gdGhpcy5jYW52YXMuZ2V0Wm9vbSgpO1xuICAgICAgem9vbSA9IHpvb20gKyAoZXZlbnQuc2NhbGUgLSB6b29tKSAvIDIwO1xuXG5cbiAgICAgIGlmICh6b29tIDwgMSkge1xuICAgICAgICB6b29tID0gMTtcbiAgICAgICAgdGhpcy5jYW52YXMuem9vbVRvUG9pbnQobmV3IGZhYnJpYy5Qb2ludCgwLCAwKSwgem9vbSk7XG4gICAgICAgIHRoaXMuY2FudmFzLmFic29sdXRlUGFuKG5ldyBmYWJyaWMuUG9pbnQoMCwgMCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHpvb20gPiAxMCkge1xuICAgICAgICAgIHpvb20gPSAxMDtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNhbnZhcy56b29tVG9Qb2ludChwb2ludCwgem9vbSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0RnJlZURyYXdpbmdCcnVzaFdpZHRoRnJvbVpvb20oem9vbSk7XG4gICAgICB0aGlzLmNhbnZhcy5yZW5kZXJBbGwoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldENhbnZhc1NpemUod2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpIHtcbiAgICB0aGlzLmNhbnZhcy5zZXRXaWR0aCh3aWR0aCk7XG4gICAgdGhpcy5jYW52YXMuc2V0SGVpZ2h0KGhlaWdodCk7XG4gIH1cblxuICBwdWJsaWMgcmVzZXRab29tKCkge1xuICAgIHRoaXMuY2FudmFzLnpvb21Ub1BvaW50KG5ldyBmYWJyaWMuUG9pbnQoMCwgMCksIDEpO1xuICAgIHRoaXMuY2FudmFzLmFic29sdXRlUGFuKG5ldyBmYWJyaWMuUG9pbnQoMCwgMCkpO1xuICB9XG59XG4iXX0=