/******/ (() => { // webpackBootstrap
/******/ 	var __webpack_modules__ = ({

/***/ "./node_modules/hammerjs/hammer.js":
/*!*****************************************!*\
  !*** ./node_modules/hammerjs/hammer.js ***!
  \*****************************************/
/***/ ((module, exports, __webpack_require__) => {

var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v2.0.7 - 2016-04-22
 * http://hammerjs.github.io/
 *
 * Copyright (c) 2016 Jorik Tangelder;
 * Licensed under the MIT license */
(function(window, document, exportName, undefined) {
  'use strict';

var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
var TEST_ELEMENT = document.createElement('div');

var TYPE_FUNCTION = 'function';

var round = Math.round;
var abs = Math.abs;
var now = Date.now;

/**
 * set a timeout with a given scope
 * @param {Function} fn
 * @param {Number} timeout
 * @param {Object} context
 * @returns {number}
 */
function setTimeoutContext(fn, timeout, context) {
    return setTimeout(bindFn(fn, context), timeout);
}

/**
 * if the argument is an array, we want to execute the fn on each entry
 * if it aint an array we don't want to do a thing.
 * this is used by all the methods that accept a single and array argument.
 * @param {*|Array} arg
 * @param {String} fn
 * @param {Object} [context]
 * @returns {Boolean}
 */
function invokeArrayArg(arg, fn, context) {
    if (Array.isArray(arg)) {
        each(arg, context[fn], context);
        return true;
    }
    return false;
}

/**
 * walk objects and arrays
 * @param {Object} obj
 * @param {Function} iterator
 * @param {Object} context
 */
function each(obj, iterator, context) {
    var i;

    if (!obj) {
        return;
    }

    if (obj.forEach) {
        obj.forEach(iterator, context);
    } else if (obj.length !== undefined) {
        i = 0;
        while (i < obj.length) {
            iterator.call(context, obj[i], i, obj);
            i++;
        }
    } else {
        for (i in obj) {
            obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
        }
    }
}

/**
 * wrap a method with a deprecation warning and stack trace
 * @param {Function} method
 * @param {String} name
 * @param {String} message
 * @returns {Function} A new function wrapping the supplied method.
 */
function deprecate(method, name, message) {
    var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
    return function() {
        var e = new Error('get-stack-trace');
        var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
            .replace(/^\s+at\s+/gm, '')
            .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';

        var log = window.console && (window.console.warn || window.console.log);
        if (log) {
            log.call(window.console, deprecationMessage, stack);
        }
        return method.apply(this, arguments);
    };
}

/**
 * extend object.
 * means that properties in dest will be overwritten by the ones in src.
 * @param {Object} target
 * @param {...Object} objects_to_assign
 * @returns {Object} target
 */
var assign;
if (typeof Object.assign !== 'function') {
    assign = function assign(target) {
        if (target === undefined || target === null) {
            throw new TypeError('Cannot convert undefined or null to object');
        }

        var output = Object(target);
        for (var index = 1; index < arguments.length; index++) {
            var source = arguments[index];
            if (source !== undefined && source !== null) {
                for (var nextKey in source) {
                    if (source.hasOwnProperty(nextKey)) {
                        output[nextKey] = source[nextKey];
                    }
                }
            }
        }
        return output;
    };
} else {
    assign = Object.assign;
}

/**
 * extend object.
 * means that properties in dest will be overwritten by the ones in src.
 * @param {Object} dest
 * @param {Object} src
 * @param {Boolean} [merge=false]
 * @returns {Object} dest
 */
var extend = deprecate(function extend(dest, src, merge) {
    var keys = Object.keys(src);
    var i = 0;
    while (i < keys.length) {
        if (!merge || (merge && dest[keys[i]] === undefined)) {
            dest[keys[i]] = src[keys[i]];
        }
        i++;
    }
    return dest;
}, 'extend', 'Use `assign`.');

/**
 * merge the values from src in the dest.
 * means that properties that exist in dest will not be overwritten by src
 * @param {Object} dest
 * @param {Object} src
 * @returns {Object} dest
 */
var merge = deprecate(function merge(dest, src) {
    return extend(dest, src, true);
}, 'merge', 'Use `assign`.');

/**
 * simple class inheritance
 * @param {Function} child
 * @param {Function} base
 * @param {Object} [properties]
 */
function inherit(child, base, properties) {
    var baseP = base.prototype,
        childP;

    childP = child.prototype = Object.create(baseP);
    childP.constructor = child;
    childP._super = baseP;

    if (properties) {
        assign(childP, properties);
    }
}

/**
 * simple function bind
 * @param {Function} fn
 * @param {Object} context
 * @returns {Function}
 */
function bindFn(fn, context) {
    return function boundFn() {
        return fn.apply(context, arguments);
    };
}

/**
 * let a boolean value also be a function that must return a boolean
 * this first item in args will be used as the context
 * @param {Boolean|Function} val
 * @param {Array} [args]
 * @returns {Boolean}
 */
function boolOrFn(val, args) {
    if (typeof val == TYPE_FUNCTION) {
        return val.apply(args ? args[0] || undefined : undefined, args);
    }
    return val;
}

/**
 * use the val2 when val1 is undefined
 * @param {*} val1
 * @param {*} val2
 * @returns {*}
 */
function ifUndefined(val1, val2) {
    return (val1 === undefined) ? val2 : val1;
}

/**
 * addEventListener with multiple events at once
 * @param {EventTarget} target
 * @param {String} types
 * @param {Function} handler
 */
function addEventListeners(target, types, handler) {
    each(splitStr(types), function(type) {
        target.addEventListener(type, handler, false);
    });
}

/**
 * removeEventListener with multiple events at once
 * @param {EventTarget} target
 * @param {String} types
 * @param {Function} handler
 */
function removeEventListeners(target, types, handler) {
    each(splitStr(types), function(type) {
        target.removeEventListener(type, handler, false);
    });
}

/**
 * find if a node is in the given parent
 * @method hasParent
 * @param {HTMLElement} node
 * @param {HTMLElement} parent
 * @return {Boolean} found
 */
function hasParent(node, parent) {
    while (node) {
        if (node == parent) {
            return true;
        }
        node = node.parentNode;
    }
    return false;
}

/**
 * small indexOf wrapper
 * @param {String} str
 * @param {String} find
 * @returns {Boolean} found
 */
function inStr(str, find) {
    return str.indexOf(find) > -1;
}

/**
 * split string on whitespace
 * @param {String} str
 * @returns {Array} words
 */
function splitStr(str) {
    return str.trim().split(/\s+/g);
}

/**
 * find if a array contains the object using indexOf or a simple polyFill
 * @param {Array} src
 * @param {String} find
 * @param {String} [findByKey]
 * @return {Boolean|Number} false when not found, or the index
 */
function inArray(src, find, findByKey) {
    if (src.indexOf && !findByKey) {
        return src.indexOf(find);
    } else {
        var i = 0;
        while (i < src.length) {
            if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
                return i;
            }
            i++;
        }
        return -1;
    }
}

/**
 * convert array-like objects to real arrays
 * @param {Object} obj
 * @returns {Array}
 */
function toArray(obj) {
    return Array.prototype.slice.call(obj, 0);
}

/**
 * unique array with objects based on a key (like 'id') or just by the array's value
 * @param {Array} src [{id:1},{id:2},{id:1}]
 * @param {String} [key]
 * @param {Boolean} [sort=False]
 * @returns {Array} [{id:1},{id:2}]
 */
function uniqueArray(src, key, sort) {
    var results = [];
    var values = [];
    var i = 0;

    while (i < src.length) {
        var val = key ? src[i][key] : src[i];
        if (inArray(values, val) < 0) {
            results.push(src[i]);
        }
        values[i] = val;
        i++;
    }

    if (sort) {
        if (!key) {
            results = results.sort();
        } else {
            results = results.sort(function sortUniqueArray(a, b) {
                return a[key] > b[key];
            });
        }
    }

    return results;
}

/**
 * get the prefixed property
 * @param {Object} obj
 * @param {String} property
 * @returns {String|Undefined} prefixed
 */
function prefixed(obj, property) {
    var prefix, prop;
    var camelProp = property[0].toUpperCase() + property.slice(1);

    var i = 0;
    while (i < VENDOR_PREFIXES.length) {
        prefix = VENDOR_PREFIXES[i];
        prop = (prefix) ? prefix + camelProp : property;

        if (prop in obj) {
            return prop;
        }
        i++;
    }
    return undefined;
}

/**
 * get a unique id
 * @returns {number} uniqueId
 */
var _uniqueId = 1;
function uniqueId() {
    return _uniqueId++;
}

/**
 * get the window object of an element
 * @param {HTMLElement} element
 * @returns {DocumentView|Window}
 */
function getWindowForElement(element) {
    var doc = element.ownerDocument || element;
    return (doc.defaultView || doc.parentWindow || window);
}

var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;

var SUPPORT_TOUCH = ('ontouchstart' in window);
var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);

var INPUT_TYPE_TOUCH = 'touch';
var INPUT_TYPE_PEN = 'pen';
var INPUT_TYPE_MOUSE = 'mouse';
var INPUT_TYPE_KINECT = 'kinect';

var COMPUTE_INTERVAL = 25;

var INPUT_START = 1;
var INPUT_MOVE = 2;
var INPUT_END = 4;
var INPUT_CANCEL = 8;

var DIRECTION_NONE = 1;
var DIRECTION_LEFT = 2;
var DIRECTION_RIGHT = 4;
var DIRECTION_UP = 8;
var DIRECTION_DOWN = 16;

var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;

var PROPS_XY = ['x', 'y'];
var PROPS_CLIENT_XY = ['clientX', 'clientY'];

/**
 * create new input type manager
 * @param {Manager} manager
 * @param {Function} callback
 * @returns {Input}
 * @constructor
 */
function Input(manager, callback) {
    var self = this;
    this.manager = manager;
    this.callback = callback;
    this.element = manager.element;
    this.target = manager.options.inputTarget;

    // smaller wrapper around the handler, for the scope and the enabled state of the manager,
    // so when disabled the input events are completely bypassed.
    this.domHandler = function(ev) {
        if (boolOrFn(manager.options.enable, [manager])) {
            self.handler(ev);
        }
    };

    this.init();

}

Input.prototype = {
    /**
     * should handle the inputEvent data and trigger the callback
     * @virtual
     */
    handler: function() { },

    /**
     * bind the events
     */
    init: function() {
        this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
        this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
        this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
    },

    /**
     * unbind the events
     */
    destroy: function() {
        this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
        this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
        this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
    }
};

/**
 * create new input type manager
 * called by the Manager constructor
 * @param {Hammer} manager
 * @returns {Input}
 */
function createInputInstance(manager) {
    var Type;
    var inputClass = manager.options.inputClass;

    if (inputClass) {
        Type = inputClass;
    } else if (SUPPORT_POINTER_EVENTS) {
        Type = PointerEventInput;
    } else if (SUPPORT_ONLY_TOUCH) {
        Type = TouchInput;
    } else if (!SUPPORT_TOUCH) {
        Type = MouseInput;
    } else {
        Type = TouchMouseInput;
    }
    return new (Type)(manager, inputHandler);
}

/**
 * handle input events
 * @param {Manager} manager
 * @param {String} eventType
 * @param {Object} input
 */
function inputHandler(manager, eventType, input) {
    var pointersLen = input.pointers.length;
    var changedPointersLen = input.changedPointers.length;
    var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
    var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));

    input.isFirst = !!isFirst;
    input.isFinal = !!isFinal;

    if (isFirst) {
        manager.session = {};
    }

    // source event is the normalized value of the domEvents
    // like 'touchstart, mouseup, pointerdown'
    input.eventType = eventType;

    // compute scale, rotation etc
    computeInputData(manager, input);

    // emit secret event
    manager.emit('hammer.input', input);

    manager.recognize(input);
    manager.session.prevInput = input;
}

/**
 * extend the data with some usable properties like scale, rotate, velocity etc
 * @param {Object} manager
 * @param {Object} input
 */
function computeInputData(manager, input) {
    var session = manager.session;
    var pointers = input.pointers;
    var pointersLength = pointers.length;

    // store the first input to calculate the distance and direction
    if (!session.firstInput) {
        session.firstInput = simpleCloneInputData(input);
    }

    // to compute scale and rotation we need to store the multiple touches
    if (pointersLength > 1 && !session.firstMultiple) {
        session.firstMultiple = simpleCloneInputData(input);
    } else if (pointersLength === 1) {
        session.firstMultiple = false;
    }

    var firstInput = session.firstInput;
    var firstMultiple = session.firstMultiple;
    var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;

    var center = input.center = getCenter(pointers);
    input.timeStamp = now();
    input.deltaTime = input.timeStamp - firstInput.timeStamp;

    input.angle = getAngle(offsetCenter, center);
    input.distance = getDistance(offsetCenter, center);

    computeDeltaXY(session, input);
    input.offsetDirection = getDirection(input.deltaX, input.deltaY);

    var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
    input.overallVelocityX = overallVelocity.x;
    input.overallVelocityY = overallVelocity.y;
    input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;

    input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
    input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;

    input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
        session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);

    computeIntervalInputData(session, input);

    // find the correct target
    var target = manager.element;
    if (hasParent(input.srcEvent.target, target)) {
        target = input.srcEvent.target;
    }
    input.target = target;
}

function computeDeltaXY(session, input) {
    var center = input.center;
    var offset = session.offsetDelta || {};
    var prevDelta = session.prevDelta || {};
    var prevInput = session.prevInput || {};

    if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
        prevDelta = session.prevDelta = {
            x: prevInput.deltaX || 0,
            y: prevInput.deltaY || 0
        };

        offset = session.offsetDelta = {
            x: center.x,
            y: center.y
        };
    }

    input.deltaX = prevDelta.x + (center.x - offset.x);
    input.deltaY = prevDelta.y + (center.y - offset.y);
}

/**
 * velocity is calculated every x ms
 * @param {Object} session
 * @param {Object} input
 */
function computeIntervalInputData(session, input) {
    var last = session.lastInterval || input,
        deltaTime = input.timeStamp - last.timeStamp,
        velocity, velocityX, velocityY, direction;

    if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
        var deltaX = input.deltaX - last.deltaX;
        var deltaY = input.deltaY - last.deltaY;

        var v = getVelocity(deltaTime, deltaX, deltaY);
        velocityX = v.x;
        velocityY = v.y;
        velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
        direction = getDirection(deltaX, deltaY);

        session.lastInterval = input;
    } else {
        // use latest velocity info if it doesn't overtake a minimum period
        velocity = last.velocity;
        velocityX = last.velocityX;
        velocityY = last.velocityY;
        direction = last.direction;
    }

    input.velocity = velocity;
    input.velocityX = velocityX;
    input.velocityY = velocityY;
    input.direction = direction;
}

/**
 * create a simple clone from the input used for storage of firstInput and firstMultiple
 * @param {Object} input
 * @returns {Object} clonedInputData
 */
function simpleCloneInputData(input) {
    // make a simple copy of the pointers because we will get a reference if we don't
    // we only need clientXY for the calculations
    var pointers = [];
    var i = 0;
    while (i < input.pointers.length) {
        pointers[i] = {
            clientX: round(input.pointers[i].clientX),
            clientY: round(input.pointers[i].clientY)
        };
        i++;
    }

    return {
        timeStamp: now(),
        pointers: pointers,
        center: getCenter(pointers),
        deltaX: input.deltaX,
        deltaY: input.deltaY
    };
}

/**
 * get the center of all the pointers
 * @param {Array} pointers
 * @return {Object} center contains `x` and `y` properties
 */
function getCenter(pointers) {
    var pointersLength = pointers.length;

    // no need to loop when only one touch
    if (pointersLength === 1) {
        return {
            x: round(pointers[0].clientX),
            y: round(pointers[0].clientY)
        };
    }

    var x = 0, y = 0, i = 0;
    while (i < pointersLength) {
        x += pointers[i].clientX;
        y += pointers[i].clientY;
        i++;
    }

    return {
        x: round(x / pointersLength),
        y: round(y / pointersLength)
    };
}

/**
 * calculate the velocity between two points. unit is in px per ms.
 * @param {Number} deltaTime
 * @param {Number} x
 * @param {Number} y
 * @return {Object} velocity `x` and `y`
 */
function getVelocity(deltaTime, x, y) {
    return {
        x: x / deltaTime || 0,
        y: y / deltaTime || 0
    };
}

/**
 * get the direction between two points
 * @param {Number} x
 * @param {Number} y
 * @return {Number} direction
 */
function getDirection(x, y) {
    if (x === y) {
        return DIRECTION_NONE;
    }

    if (abs(x) >= abs(y)) {
        return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
    }
    return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
}

/**
 * calculate the absolute distance between two points
 * @param {Object} p1 {x, y}
 * @param {Object} p2 {x, y}
 * @param {Array} [props] containing x and y keys
 * @return {Number} distance
 */
function getDistance(p1, p2, props) {
    if (!props) {
        props = PROPS_XY;
    }
    var x = p2[props[0]] - p1[props[0]],
        y = p2[props[1]] - p1[props[1]];

    return Math.sqrt((x * x) + (y * y));
}

/**
 * calculate the angle between two coordinates
 * @param {Object} p1
 * @param {Object} p2
 * @param {Array} [props] containing x and y keys
 * @return {Number} angle
 */
function getAngle(p1, p2, props) {
    if (!props) {
        props = PROPS_XY;
    }
    var x = p2[props[0]] - p1[props[0]],
        y = p2[props[1]] - p1[props[1]];
    return Math.atan2(y, x) * 180 / Math.PI;
}

/**
 * calculate the rotation degrees between two pointersets
 * @param {Array} start array of pointers
 * @param {Array} end array of pointers
 * @return {Number} rotation
 */
function getRotation(start, end) {
    return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
}

/**
 * calculate the scale factor between two pointersets
 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
 * @param {Array} start array of pointers
 * @param {Array} end array of pointers
 * @return {Number} scale
 */
function getScale(start, end) {
    return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
}

var MOUSE_INPUT_MAP = {
    mousedown: INPUT_START,
    mousemove: INPUT_MOVE,
    mouseup: INPUT_END
};

var MOUSE_ELEMENT_EVENTS = 'mousedown';
var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';

/**
 * Mouse events input
 * @constructor
 * @extends Input
 */
function MouseInput() {
    this.evEl = MOUSE_ELEMENT_EVENTS;
    this.evWin = MOUSE_WINDOW_EVENTS;

    this.pressed = false; // mousedown state

    Input.apply(this, arguments);
}

inherit(MouseInput, Input, {
    /**
     * handle mouse events
     * @param {Object} ev
     */
    handler: function MEhandler(ev) {
        var eventType = MOUSE_INPUT_MAP[ev.type];

        // on start we want to have the left mouse button down
        if (eventType & INPUT_START && ev.button === 0) {
            this.pressed = true;
        }

        if (eventType & INPUT_MOVE && ev.which !== 1) {
            eventType = INPUT_END;
        }

        // mouse must be down
        if (!this.pressed) {
            return;
        }

        if (eventType & INPUT_END) {
            this.pressed = false;
        }

        this.callback(this.manager, eventType, {
            pointers: [ev],
            changedPointers: [ev],
            pointerType: INPUT_TYPE_MOUSE,
            srcEvent: ev
        });
    }
});

var POINTER_INPUT_MAP = {
    pointerdown: INPUT_START,
    pointermove: INPUT_MOVE,
    pointerup: INPUT_END,
    pointercancel: INPUT_CANCEL,
    pointerout: INPUT_CANCEL
};

// in IE10 the pointer types is defined as an enum
var IE10_POINTER_TYPE_ENUM = {
    2: INPUT_TYPE_TOUCH,
    3: INPUT_TYPE_PEN,
    4: INPUT_TYPE_MOUSE,
    5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
};

var POINTER_ELEMENT_EVENTS = 'pointerdown';
var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';

// IE10 has prefixed support, and case-sensitive
if (window.MSPointerEvent && !window.PointerEvent) {
    POINTER_ELEMENT_EVENTS = 'MSPointerDown';
    POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
}

/**
 * Pointer events input
 * @constructor
 * @extends Input
 */
function PointerEventInput() {
    this.evEl = POINTER_ELEMENT_EVENTS;
    this.evWin = POINTER_WINDOW_EVENTS;

    Input.apply(this, arguments);

    this.store = (this.manager.session.pointerEvents = []);
}

inherit(PointerEventInput, Input, {
    /**
     * handle mouse events
     * @param {Object} ev
     */
    handler: function PEhandler(ev) {
        var store = this.store;
        var removePointer = false;

        var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
        var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
        var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;

        var isTouch = (pointerType == INPUT_TYPE_TOUCH);

        // get index of the event in the store
        var storeIndex = inArray(store, ev.pointerId, 'pointerId');

        // start and mouse must be down
        if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
            if (storeIndex < 0) {
                store.push(ev);
                storeIndex = store.length - 1;
            }
        } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
            removePointer = true;
        }

        // it not found, so the pointer hasn't been down (so it's probably a hover)
        if (storeIndex < 0) {
            return;
        }

        // update the event in the store
        store[storeIndex] = ev;

        this.callback(this.manager, eventType, {
            pointers: store,
            changedPointers: [ev],
            pointerType: pointerType,
            srcEvent: ev
        });

        if (removePointer) {
            // remove from the store
            store.splice(storeIndex, 1);
        }
    }
});

var SINGLE_TOUCH_INPUT_MAP = {
    touchstart: INPUT_START,
    touchmove: INPUT_MOVE,
    touchend: INPUT_END,
    touchcancel: INPUT_CANCEL
};

var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';

/**
 * Touch events input
 * @constructor
 * @extends Input
 */
function SingleTouchInput() {
    this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
    this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
    this.started = false;

    Input.apply(this, arguments);
}

inherit(SingleTouchInput, Input, {
    handler: function TEhandler(ev) {
        var type = SINGLE_TOUCH_INPUT_MAP[ev.type];

        // should we handle the touch events?
        if (type === INPUT_START) {
            this.started = true;
        }

        if (!this.started) {
            return;
        }

        var touches = normalizeSingleTouches.call(this, ev, type);

        // when done, reset the started state
        if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
            this.started = false;
        }

        this.callback(this.manager, type, {
            pointers: touches[0],
            changedPointers: touches[1],
            pointerType: INPUT_TYPE_TOUCH,
            srcEvent: ev
        });
    }
});

/**
 * @this {TouchInput}
 * @param {Object} ev
 * @param {Number} type flag
 * @returns {undefined|Array} [all, changed]
 */
function normalizeSingleTouches(ev, type) {
    var all = toArray(ev.touches);
    var changed = toArray(ev.changedTouches);

    if (type & (INPUT_END | INPUT_CANCEL)) {
        all = uniqueArray(all.concat(changed), 'identifier', true);
    }

    return [all, changed];
}

var TOUCH_INPUT_MAP = {
    touchstart: INPUT_START,
    touchmove: INPUT_MOVE,
    touchend: INPUT_END,
    touchcancel: INPUT_CANCEL
};

var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';

/**
 * Multi-user touch events input
 * @constructor
 * @extends Input
 */
function TouchInput() {
    this.evTarget = TOUCH_TARGET_EVENTS;
    this.targetIds = {};

    Input.apply(this, arguments);
}

inherit(TouchInput, Input, {
    handler: function MTEhandler(ev) {
        var type = TOUCH_INPUT_MAP[ev.type];
        var touches = getTouches.call(this, ev, type);
        if (!touches) {
            return;
        }

        this.callback(this.manager, type, {
            pointers: touches[0],
            changedPointers: touches[1],
            pointerType: INPUT_TYPE_TOUCH,
            srcEvent: ev
        });
    }
});

/**
 * @this {TouchInput}
 * @param {Object} ev
 * @param {Number} type flag
 * @returns {undefined|Array} [all, changed]
 */
function getTouches(ev, type) {
    var allTouches = toArray(ev.touches);
    var targetIds = this.targetIds;

    // when there is only one touch, the process can be simplified
    if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
        targetIds[allTouches[0].identifier] = true;
        return [allTouches, allTouches];
    }

    var i,
        targetTouches,
        changedTouches = toArray(ev.changedTouches),
        changedTargetTouches = [],
        target = this.target;

    // get target touches from touches
    targetTouches = allTouches.filter(function(touch) {
        return hasParent(touch.target, target);
    });

    // collect touches
    if (type === INPUT_START) {
        i = 0;
        while (i < targetTouches.length) {
            targetIds[targetTouches[i].identifier] = true;
            i++;
        }
    }

    // filter changed touches to only contain touches that exist in the collected target ids
    i = 0;
    while (i < changedTouches.length) {
        if (targetIds[changedTouches[i].identifier]) {
            changedTargetTouches.push(changedTouches[i]);
        }

        // cleanup removed touches
        if (type & (INPUT_END | INPUT_CANCEL)) {
            delete targetIds[changedTouches[i].identifier];
        }
        i++;
    }

    if (!changedTargetTouches.length) {
        return;
    }

    return [
        // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
        uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
        changedTargetTouches
    ];
}

/**
 * Combined touch and mouse input
 *
 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
 * This because touch devices also emit mouse events while doing a touch.
 *
 * @constructor
 * @extends Input
 */

var DEDUP_TIMEOUT = 2500;
var DEDUP_DISTANCE = 25;

function TouchMouseInput() {
    Input.apply(this, arguments);

    var handler = bindFn(this.handler, this);
    this.touch = new TouchInput(this.manager, handler);
    this.mouse = new MouseInput(this.manager, handler);

    this.primaryTouch = null;
    this.lastTouches = [];
}

inherit(TouchMouseInput, Input, {
    /**
     * handle mouse and touch events
     * @param {Hammer} manager
     * @param {String} inputEvent
     * @param {Object} inputData
     */
    handler: function TMEhandler(manager, inputEvent, inputData) {
        var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
            isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);

        if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
            return;
        }

        // when we're in a touch event, record touches to  de-dupe synthetic mouse event
        if (isTouch) {
            recordTouches.call(this, inputEvent, inputData);
        } else if (isMouse && isSyntheticEvent.call(this, inputData)) {
            return;
        }

        this.callback(manager, inputEvent, inputData);
    },

    /**
     * remove the event listeners
     */
    destroy: function destroy() {
        this.touch.destroy();
        this.mouse.destroy();
    }
});

function recordTouches(eventType, eventData) {
    if (eventType & INPUT_START) {
        this.primaryTouch = eventData.changedPointers[0].identifier;
        setLastTouch.call(this, eventData);
    } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
        setLastTouch.call(this, eventData);
    }
}

function setLastTouch(eventData) {
    var touch = eventData.changedPointers[0];

    if (touch.identifier === this.primaryTouch) {
        var lastTouch = {x: touch.clientX, y: touch.clientY};
        this.lastTouches.push(lastTouch);
        var lts = this.lastTouches;
        var removeLastTouch = function() {
            var i = lts.indexOf(lastTouch);
            if (i > -1) {
                lts.splice(i, 1);
            }
        };
        setTimeout(removeLastTouch, DEDUP_TIMEOUT);
    }
}

function isSyntheticEvent(eventData) {
    var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
    for (var i = 0; i < this.lastTouches.length; i++) {
        var t = this.lastTouches[i];
        var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
        if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
            return true;
        }
    }
    return false;
}

var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;

// magical touchAction value
var TOUCH_ACTION_COMPUTE = 'compute';
var TOUCH_ACTION_AUTO = 'auto';
var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
var TOUCH_ACTION_NONE = 'none';
var TOUCH_ACTION_PAN_X = 'pan-x';
var TOUCH_ACTION_PAN_Y = 'pan-y';
var TOUCH_ACTION_MAP = getTouchActionProps();

/**
 * Touch Action
 * sets the touchAction property or uses the js alternative
 * @param {Manager} manager
 * @param {String} value
 * @constructor
 */
function TouchAction(manager, value) {
    this.manager = manager;
    this.set(value);
}

TouchAction.prototype = {
    /**
     * set the touchAction value on the element or enable the polyfill
     * @param {String} value
     */
    set: function(value) {
        // find out the touch-action by the event handlers
        if (value == TOUCH_ACTION_COMPUTE) {
            value = this.compute();
        }

        if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
            this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
        }
        this.actions = value.toLowerCase().trim();
    },

    /**
     * just re-set the touchAction value
     */
    update: function() {
        this.set(this.manager.options.touchAction);
    },

    /**
     * compute the value for the touchAction property based on the recognizer's settings
     * @returns {String} value
     */
    compute: function() {
        var actions = [];
        each(this.manager.recognizers, function(recognizer) {
            if (boolOrFn(recognizer.options.enable, [recognizer])) {
                actions = actions.concat(recognizer.getTouchAction());
            }
        });
        return cleanTouchActions(actions.join(' '));
    },

    /**
     * this method is called on each input cycle and provides the preventing of the browser behavior
     * @param {Object} input
     */
    preventDefaults: function(input) {
        var srcEvent = input.srcEvent;
        var direction = input.offsetDirection;

        // if the touch action did prevented once this session
        if (this.manager.session.prevented) {
            srcEvent.preventDefault();
            return;
        }

        var actions = this.actions;
        var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
        var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
        var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];

        if (hasNone) {
            //do not prevent defaults if this is a tap gesture

            var isTapPointer = input.pointers.length === 1;
            var isTapMovement = input.distance < 2;
            var isTapTouchTime = input.deltaTime < 250;

            if (isTapPointer && isTapMovement && isTapTouchTime) {
                return;
            }
        }

        if (hasPanX && hasPanY) {
            // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
            return;
        }

        if (hasNone ||
            (hasPanY && direction & DIRECTION_HORIZONTAL) ||
            (hasPanX && direction & DIRECTION_VERTICAL)) {
            return this.preventSrc(srcEvent);
        }
    },

    /**
     * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
     * @param {Object} srcEvent
     */
    preventSrc: function(srcEvent) {
        this.manager.session.prevented = true;
        srcEvent.preventDefault();
    }
};

/**
 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
 * @param {String} actions
 * @returns {*}
 */
function cleanTouchActions(actions) {
    // none
    if (inStr(actions, TOUCH_ACTION_NONE)) {
        return TOUCH_ACTION_NONE;
    }

    var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
    var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);

    // if both pan-x and pan-y are set (different recognizers
    // for different directions, e.g. horizontal pan but vertical swipe?)
    // we need none (as otherwise with pan-x pan-y combined none of these
    // recognizers will work, since the browser would handle all panning
    if (hasPanX && hasPanY) {
        return TOUCH_ACTION_NONE;
    }

    // pan-x OR pan-y
    if (hasPanX || hasPanY) {
        return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
    }

    // manipulation
    if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
        return TOUCH_ACTION_MANIPULATION;
    }

    return TOUCH_ACTION_AUTO;
}

function getTouchActionProps() {
    if (!NATIVE_TOUCH_ACTION) {
        return false;
    }
    var touchMap = {};
    var cssSupports = window.CSS && window.CSS.supports;
    ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {

        // If css.supports is not supported but there is native touch-action assume it supports
        // all values. This is the case for IE 10 and 11.
        touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
    });
    return touchMap;
}

/**
 * Recognizer flow explained; *
 * All recognizers have the initial state of POSSIBLE when a input session starts.
 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
 * Example session for mouse-input: mousedown -> mousemove -> mouseup
 *
 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
 * which determines with state it should be.
 *
 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
 * POSSIBLE to give it another change on the next cycle.
 *
 *               Possible
 *                  |
 *            +-----+---------------+
 *            |                     |
 *      +-----+-----+               |
 *      |           |               |
 *   Failed      Cancelled          |
 *                          +-------+------+
 *                          |              |
 *                      Recognized       Began
 *                                         |
 *                                      Changed
 *                                         |
 *                                  Ended/Recognized
 */
var STATE_POSSIBLE = 1;
var STATE_BEGAN = 2;
var STATE_CHANGED = 4;
var STATE_ENDED = 8;
var STATE_RECOGNIZED = STATE_ENDED;
var STATE_CANCELLED = 16;
var STATE_FAILED = 32;

/**
 * Recognizer
 * Every recognizer needs to extend from this class.
 * @constructor
 * @param {Object} options
 */
function Recognizer(options) {
    this.options = assign({}, this.defaults, options || {});

    this.id = uniqueId();

    this.manager = null;

    // default is enable true
    this.options.enable = ifUndefined(this.options.enable, true);

    this.state = STATE_POSSIBLE;

    this.simultaneous = {};
    this.requireFail = [];
}

Recognizer.prototype = {
    /**
     * @virtual
     * @type {Object}
     */
    defaults: {},

    /**
     * set options
     * @param {Object} options
     * @return {Recognizer}
     */
    set: function(options) {
        assign(this.options, options);

        // also update the touchAction, in case something changed about the directions/enabled state
        this.manager && this.manager.touchAction.update();
        return this;
    },

    /**
     * recognize simultaneous with an other recognizer.
     * @param {Recognizer} otherRecognizer
     * @returns {Recognizer} this
     */
    recognizeWith: function(otherRecognizer) {
        if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
            return this;
        }

        var simultaneous = this.simultaneous;
        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
        if (!simultaneous[otherRecognizer.id]) {
            simultaneous[otherRecognizer.id] = otherRecognizer;
            otherRecognizer.recognizeWith(this);
        }
        return this;
    },

    /**
     * drop the simultaneous link. it doesnt remove the link on the other recognizer.
     * @param {Recognizer} otherRecognizer
     * @returns {Recognizer} this
     */
    dropRecognizeWith: function(otherRecognizer) {
        if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
            return this;
        }

        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
        delete this.simultaneous[otherRecognizer.id];
        return this;
    },

    /**
     * recognizer can only run when an other is failing
     * @param {Recognizer} otherRecognizer
     * @returns {Recognizer} this
     */
    requireFailure: function(otherRecognizer) {
        if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
            return this;
        }

        var requireFail = this.requireFail;
        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
        if (inArray(requireFail, otherRecognizer) === -1) {
            requireFail.push(otherRecognizer);
            otherRecognizer.requireFailure(this);
        }
        return this;
    },

    /**
     * drop the requireFailure link. it does not remove the link on the other recognizer.
     * @param {Recognizer} otherRecognizer
     * @returns {Recognizer} this
     */
    dropRequireFailure: function(otherRecognizer) {
        if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
            return this;
        }

        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
        var index = inArray(this.requireFail, otherRecognizer);
        if (index > -1) {
            this.requireFail.splice(index, 1);
        }
        return this;
    },

    /**
     * has require failures boolean
     * @returns {boolean}
     */
    hasRequireFailures: function() {
        return this.requireFail.length > 0;
    },

    /**
     * if the recognizer can recognize simultaneous with an other recognizer
     * @param {Recognizer} otherRecognizer
     * @returns {Boolean}
     */
    canRecognizeWith: function(otherRecognizer) {
        return !!this.simultaneous[otherRecognizer.id];
    },

    /**
     * You should use `tryEmit` instead of `emit` directly to check
     * that all the needed recognizers has failed before emitting.
     * @param {Object} input
     */
    emit: function(input) {
        var self = this;
        var state = this.state;

        function emit(event) {
            self.manager.emit(event, input);
        }

        // 'panstart' and 'panmove'
        if (state < STATE_ENDED) {
            emit(self.options.event + stateStr(state));
        }

        emit(self.options.event); // simple 'eventName' events

        if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
            emit(input.additionalEvent);
        }

        // panend and pancancel
        if (state >= STATE_ENDED) {
            emit(self.options.event + stateStr(state));
        }
    },

    /**
     * Check that all the require failure recognizers has failed,
     * if true, it emits a gesture event,
     * otherwise, setup the state to FAILED.
     * @param {Object} input
     */
    tryEmit: function(input) {
        if (this.canEmit()) {
            return this.emit(input);
        }
        // it's failing anyway
        this.state = STATE_FAILED;
    },

    /**
     * can we emit?
     * @returns {boolean}
     */
    canEmit: function() {
        var i = 0;
        while (i < this.requireFail.length) {
            if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
                return false;
            }
            i++;
        }
        return true;
    },

    /**
     * update the recognizer
     * @param {Object} inputData
     */
    recognize: function(inputData) {
        // make a new copy of the inputData
        // so we can change the inputData without messing up the other recognizers
        var inputDataClone = assign({}, inputData);

        // is is enabled and allow recognizing?
        if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
            this.reset();
            this.state = STATE_FAILED;
            return;
        }

        // reset when we've reached the end
        if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
            this.state = STATE_POSSIBLE;
        }

        this.state = this.process(inputDataClone);

        // the recognizer has recognized a gesture
        // so trigger an event
        if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
            this.tryEmit(inputDataClone);
        }
    },

    /**
     * return the state of the recognizer
     * the actual recognizing happens in this method
     * @virtual
     * @param {Object} inputData
     * @returns {Const} STATE
     */
    process: function(inputData) { }, // jshint ignore:line

    /**
     * return the preferred touch-action
     * @virtual
     * @returns {Array}
     */
    getTouchAction: function() { },

    /**
     * called when the gesture isn't allowed to recognize
     * like when another is being recognized or it is disabled
     * @virtual
     */
    reset: function() { }
};

/**
 * get a usable string, used as event postfix
 * @param {Const} state
 * @returns {String} state
 */
function stateStr(state) {
    if (state & STATE_CANCELLED) {
        return 'cancel';
    } else if (state & STATE_ENDED) {
        return 'end';
    } else if (state & STATE_CHANGED) {
        return 'move';
    } else if (state & STATE_BEGAN) {
        return 'start';
    }
    return '';
}

/**
 * direction cons to string
 * @param {Const} direction
 * @returns {String}
 */
function directionStr(direction) {
    if (direction == DIRECTION_DOWN) {
        return 'down';
    } else if (direction == DIRECTION_UP) {
        return 'up';
    } else if (direction == DIRECTION_LEFT) {
        return 'left';
    } else if (direction == DIRECTION_RIGHT) {
        return 'right';
    }
    return '';
}

/**
 * get a recognizer by name if it is bound to a manager
 * @param {Recognizer|String} otherRecognizer
 * @param {Recognizer} recognizer
 * @returns {Recognizer}
 */
function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
    var manager = recognizer.manager;
    if (manager) {
        return manager.get(otherRecognizer);
    }
    return otherRecognizer;
}

/**
 * This recognizer is just used as a base for the simple attribute recognizers.
 * @constructor
 * @extends Recognizer
 */
function AttrRecognizer() {
    Recognizer.apply(this, arguments);
}

inherit(AttrRecognizer, Recognizer, {
    /**
     * @namespace
     * @memberof AttrRecognizer
     */
    defaults: {
        /**
         * @type {Number}
         * @default 1
         */
        pointers: 1
    },

    /**
     * Used to check if it the recognizer receives valid input, like input.distance > 10.
     * @memberof AttrRecognizer
     * @param {Object} input
     * @returns {Boolean} recognized
     */
    attrTest: function(input) {
        var optionPointers = this.options.pointers;
        return optionPointers === 0 || input.pointers.length === optionPointers;
    },

    /**
     * Process the input and return the state for the recognizer
     * @memberof AttrRecognizer
     * @param {Object} input
     * @returns {*} State
     */
    process: function(input) {
        var state = this.state;
        var eventType = input.eventType;

        var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
        var isValid = this.attrTest(input);

        // on cancel input and we've recognized before, return STATE_CANCELLED
        if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
            return state | STATE_CANCELLED;
        } else if (isRecognized || isValid) {
            if (eventType & INPUT_END) {
                return state | STATE_ENDED;
            } else if (!(state & STATE_BEGAN)) {
                return STATE_BEGAN;
            }
            return state | STATE_CHANGED;
        }
        return STATE_FAILED;
    }
});

/**
 * Pan
 * Recognized when the pointer is down and moved in the allowed direction.
 * @constructor
 * @extends AttrRecognizer
 */
function PanRecognizer() {
    AttrRecognizer.apply(this, arguments);

    this.pX = null;
    this.pY = null;
}

inherit(PanRecognizer, AttrRecognizer, {
    /**
     * @namespace
     * @memberof PanRecognizer
     */
    defaults: {
        event: 'pan',
        threshold: 10,
        pointers: 1,
        direction: DIRECTION_ALL
    },

    getTouchAction: function() {
        var direction = this.options.direction;
        var actions = [];
        if (direction & DIRECTION_HORIZONTAL) {
            actions.push(TOUCH_ACTION_PAN_Y);
        }
        if (direction & DIRECTION_VERTICAL) {
            actions.push(TOUCH_ACTION_PAN_X);
        }
        return actions;
    },

    directionTest: function(input) {
        var options = this.options;
        var hasMoved = true;
        var distance = input.distance;
        var direction = input.direction;
        var x = input.deltaX;
        var y = input.deltaY;

        // lock to axis?
        if (!(direction & options.direction)) {
            if (options.direction & DIRECTION_HORIZONTAL) {
                direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
                hasMoved = x != this.pX;
                distance = Math.abs(input.deltaX);
            } else {
                direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
                hasMoved = y != this.pY;
                distance = Math.abs(input.deltaY);
            }
        }
        input.direction = direction;
        return hasMoved && distance > options.threshold && direction & options.direction;
    },

    attrTest: function(input) {
        return AttrRecognizer.prototype.attrTest.call(this, input) &&
            (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
    },

    emit: function(input) {

        this.pX = input.deltaX;
        this.pY = input.deltaY;

        var direction = directionStr(input.direction);

        if (direction) {
            input.additionalEvent = this.options.event + direction;
        }
        this._super.emit.call(this, input);
    }
});

/**
 * Pinch
 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
 * @constructor
 * @extends AttrRecognizer
 */
function PinchRecognizer() {
    AttrRecognizer.apply(this, arguments);
}

inherit(PinchRecognizer, AttrRecognizer, {
    /**
     * @namespace
     * @memberof PinchRecognizer
     */
    defaults: {
        event: 'pinch',
        threshold: 0,
        pointers: 2
    },

    getTouchAction: function() {
        return [TOUCH_ACTION_NONE];
    },

    attrTest: function(input) {
        return this._super.attrTest.call(this, input) &&
            (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
    },

    emit: function(input) {
        if (input.scale !== 1) {
            var inOut = input.scale < 1 ? 'in' : 'out';
            input.additionalEvent = this.options.event + inOut;
        }
        this._super.emit.call(this, input);
    }
});

/**
 * Press
 * Recognized when the pointer is down for x ms without any movement.
 * @constructor
 * @extends Recognizer
 */
function PressRecognizer() {
    Recognizer.apply(this, arguments);

    this._timer = null;
    this._input = null;
}

inherit(PressRecognizer, Recognizer, {
    /**
     * @namespace
     * @memberof PressRecognizer
     */
    defaults: {
        event: 'press',
        pointers: 1,
        time: 251, // minimal time of the pointer to be pressed
        threshold: 9 // a minimal movement is ok, but keep it low
    },

    getTouchAction: function() {
        return [TOUCH_ACTION_AUTO];
    },

    process: function(input) {
        var options = this.options;
        var validPointers = input.pointers.length === options.pointers;
        var validMovement = input.distance < options.threshold;
        var validTime = input.deltaTime > options.time;

        this._input = input;

        // we only allow little movement
        // and we've reached an end event, so a tap is possible
        if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
            this.reset();
        } else if (input.eventType & INPUT_START) {
            this.reset();
            this._timer = setTimeoutContext(function() {
                this.state = STATE_RECOGNIZED;
                this.tryEmit();
            }, options.time, this);
        } else if (input.eventType & INPUT_END) {
            return STATE_RECOGNIZED;
        }
        return STATE_FAILED;
    },

    reset: function() {
        clearTimeout(this._timer);
    },

    emit: function(input) {
        if (this.state !== STATE_RECOGNIZED) {
            return;
        }

        if (input && (input.eventType & INPUT_END)) {
            this.manager.emit(this.options.event + 'up', input);
        } else {
            this._input.timeStamp = now();
            this.manager.emit(this.options.event, this._input);
        }
    }
});

/**
 * Rotate
 * Recognized when two or more pointer are moving in a circular motion.
 * @constructor
 * @extends AttrRecognizer
 */
function RotateRecognizer() {
    AttrRecognizer.apply(this, arguments);
}

inherit(RotateRecognizer, AttrRecognizer, {
    /**
     * @namespace
     * @memberof RotateRecognizer
     */
    defaults: {
        event: 'rotate',
        threshold: 0,
        pointers: 2
    },

    getTouchAction: function() {
        return [TOUCH_ACTION_NONE];
    },

    attrTest: function(input) {
        return this._super.attrTest.call(this, input) &&
            (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
    }
});

/**
 * Swipe
 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
 * @constructor
 * @extends AttrRecognizer
 */
function SwipeRecognizer() {
    AttrRecognizer.apply(this, arguments);
}

inherit(SwipeRecognizer, AttrRecognizer, {
    /**
     * @namespace
     * @memberof SwipeRecognizer
     */
    defaults: {
        event: 'swipe',
        threshold: 10,
        velocity: 0.3,
        direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
        pointers: 1
    },

    getTouchAction: function() {
        return PanRecognizer.prototype.getTouchAction.call(this);
    },

    attrTest: function(input) {
        var direction = this.options.direction;
        var velocity;

        if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
            velocity = input.overallVelocity;
        } else if (direction & DIRECTION_HORIZONTAL) {
            velocity = input.overallVelocityX;
        } else if (direction & DIRECTION_VERTICAL) {
            velocity = input.overallVelocityY;
        }

        return this._super.attrTest.call(this, input) &&
            direction & input.offsetDirection &&
            input.distance > this.options.threshold &&
            input.maxPointers == this.options.pointers &&
            abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
    },

    emit: function(input) {
        var direction = directionStr(input.offsetDirection);
        if (direction) {
            this.manager.emit(this.options.event + direction, input);
        }

        this.manager.emit(this.options.event, input);
    }
});

/**
 * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
 * a single tap.
 *
 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
 * multi-taps being recognized.
 * @constructor
 * @extends Recognizer
 */
function TapRecognizer() {
    Recognizer.apply(this, arguments);

    // previous time and center,
    // used for tap counting
    this.pTime = false;
    this.pCenter = false;

    this._timer = null;
    this._input = null;
    this.count = 0;
}

inherit(TapRecognizer, Recognizer, {
    /**
     * @namespace
     * @memberof PinchRecognizer
     */
    defaults: {
        event: 'tap',
        pointers: 1,
        taps: 1,
        interval: 300, // max time between the multi-tap taps
        time: 250, // max time of the pointer to be down (like finger on the screen)
        threshold: 9, // a minimal movement is ok, but keep it low
        posThreshold: 10 // a multi-tap can be a bit off the initial position
    },

    getTouchAction: function() {
        return [TOUCH_ACTION_MANIPULATION];
    },

    process: function(input) {
        var options = this.options;

        var validPointers = input.pointers.length === options.pointers;
        var validMovement = input.distance < options.threshold;
        var validTouchTime = input.deltaTime < options.time;

        this.reset();

        if ((input.eventType & INPUT_START) && (this.count === 0)) {
            return this.failTimeout();
        }

        // we only allow little movement
        // and we've reached an end event, so a tap is possible
        if (validMovement && validTouchTime && validPointers) {
            if (input.eventType != INPUT_END) {
                return this.failTimeout();
            }

            var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
            var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;

            this.pTime = input.timeStamp;
            this.pCenter = input.center;

            if (!validMultiTap || !validInterval) {
                this.count = 1;
            } else {
                this.count += 1;
            }

            this._input = input;

            // if tap count matches we have recognized it,
            // else it has began recognizing...
            var tapCount = this.count % options.taps;
            if (tapCount === 0) {
                // no failing requirements, immediately trigger the tap event
                // or wait as long as the multitap interval to trigger
                if (!this.hasRequireFailures()) {
                    return STATE_RECOGNIZED;
                } else {
                    this._timer = setTimeoutContext(function() {
                        this.state = STATE_RECOGNIZED;
                        this.tryEmit();
                    }, options.interval, this);
                    return STATE_BEGAN;
                }
            }
        }
        return STATE_FAILED;
    },

    failTimeout: function() {
        this._timer = setTimeoutContext(function() {
            this.state = STATE_FAILED;
        }, this.options.interval, this);
        return STATE_FAILED;
    },

    reset: function() {
        clearTimeout(this._timer);
    },

    emit: function() {
        if (this.state == STATE_RECOGNIZED) {
            this._input.tapCount = this.count;
            this.manager.emit(this.options.event, this._input);
        }
    }
});

/**
 * Simple way to create a manager with a default set of recognizers.
 * @param {HTMLElement} element
 * @param {Object} [options]
 * @constructor
 */
function Hammer(element, options) {
    options = options || {};
    options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
    return new Manager(element, options);
}

/**
 * @const {string}
 */
Hammer.VERSION = '2.0.7';

/**
 * default settings
 * @namespace
 */
Hammer.defaults = {
    /**
     * set if DOM events are being triggered.
     * But this is slower and unused by simple implementations, so disabled by default.
     * @type {Boolean}
     * @default false
     */
    domEvents: false,

    /**
     * The value for the touchAction property/fallback.
     * When set to `compute` it will magically set the correct value based on the added recognizers.
     * @type {String}
     * @default compute
     */
    touchAction: TOUCH_ACTION_COMPUTE,

    /**
     * @type {Boolean}
     * @default true
     */
    enable: true,

    /**
     * EXPERIMENTAL FEATURE -- can be removed/changed
     * Change the parent input target element.
     * If Null, then it is being set the to main element.
     * @type {Null|EventTarget}
     * @default null
     */
    inputTarget: null,

    /**
     * force an input class
     * @type {Null|Function}
     * @default null
     */
    inputClass: null,

    /**
     * Default recognizer setup when calling `Hammer()`
     * When creating a new Manager these will be skipped.
     * @type {Array}
     */
    preset: [
        // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
        [RotateRecognizer, {enable: false}],
        [PinchRecognizer, {enable: false}, ['rotate']],
        [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}],
        [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']],
        [TapRecognizer],
        [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']],
        [PressRecognizer]
    ],

    /**
     * Some CSS properties can be used to improve the working of Hammer.
     * Add them to this method and they will be set when creating a new Manager.
     * @namespace
     */
    cssProps: {
        /**
         * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
         * @type {String}
         * @default 'none'
         */
        userSelect: 'none',

        /**
         * Disable the Windows Phone grippers when pressing an element.
         * @type {String}
         * @default 'none'
         */
        touchSelect: 'none',

        /**
         * Disables the default callout shown when you touch and hold a touch target.
         * On iOS, when you touch and hold a touch target such as a link, Safari displays
         * a callout containing information about the link. This property allows you to disable that callout.
         * @type {String}
         * @default 'none'
         */
        touchCallout: 'none',

        /**
         * Specifies whether zooming is enabled. Used by IE10>
         * @type {String}
         * @default 'none'
         */
        contentZooming: 'none',

        /**
         * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
         * @type {String}
         * @default 'none'
         */
        userDrag: 'none',

        /**
         * Overrides the highlight color shown when the user taps a link or a JavaScript
         * clickable element in iOS. This property obeys the alpha value, if specified.
         * @type {String}
         * @default 'rgba(0,0,0,0)'
         */
        tapHighlightColor: 'rgba(0,0,0,0)'
    }
};

var STOP = 1;
var FORCED_STOP = 2;

/**
 * Manager
 * @param {HTMLElement} element
 * @param {Object} [options]
 * @constructor
 */
function Manager(element, options) {
    this.options = assign({}, Hammer.defaults, options || {});

    this.options.inputTarget = this.options.inputTarget || element;

    this.handlers = {};
    this.session = {};
    this.recognizers = [];
    this.oldCssProps = {};

    this.element = element;
    this.input = createInputInstance(this);
    this.touchAction = new TouchAction(this, this.options.touchAction);

    toggleCssProps(this, true);

    each(this.options.recognizers, function(item) {
        var recognizer = this.add(new (item[0])(item[1]));
        item[2] && recognizer.recognizeWith(item[2]);
        item[3] && recognizer.requireFailure(item[3]);
    }, this);
}

Manager.prototype = {
    /**
     * set options
     * @param {Object} options
     * @returns {Manager}
     */
    set: function(options) {
        assign(this.options, options);

        // Options that need a little more setup
        if (options.touchAction) {
            this.touchAction.update();
        }
        if (options.inputTarget) {
            // Clean up existing event listeners and reinitialize
            this.input.destroy();
            this.input.target = options.inputTarget;
            this.input.init();
        }
        return this;
    },

    /**
     * stop recognizing for this session.
     * This session will be discarded, when a new [input]start event is fired.
     * When forced, the recognizer cycle is stopped immediately.
     * @param {Boolean} [force]
     */
    stop: function(force) {
        this.session.stopped = force ? FORCED_STOP : STOP;
    },

    /**
     * run the recognizers!
     * called by the inputHandler function on every movement of the pointers (touches)
     * it walks through all the recognizers and tries to detect the gesture that is being made
     * @param {Object} inputData
     */
    recognize: function(inputData) {
        var session = this.session;
        if (session.stopped) {
            return;
        }

        // run the touch-action polyfill
        this.touchAction.preventDefaults(inputData);

        var recognizer;
        var recognizers = this.recognizers;

        // this holds the recognizer that is being recognized.
        // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
        // if no recognizer is detecting a thing, it is set to `null`
        var curRecognizer = session.curRecognizer;

        // reset when the last recognizer is recognized
        // or when we're in a new session
        if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
            curRecognizer = session.curRecognizer = null;
        }

        var i = 0;
        while (i < recognizers.length) {
            recognizer = recognizers[i];

            // find out if we are allowed try to recognize the input for this one.
            // 1.   allow if the session is NOT forced stopped (see the .stop() method)
            // 2.   allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
            //      that is being recognized.
            // 3.   allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
            //      this can be setup with the `recognizeWith()` method on the recognizer.
            if (session.stopped !== FORCED_STOP && ( // 1
                    !curRecognizer || recognizer == curRecognizer || // 2
                    recognizer.canRecognizeWith(curRecognizer))) { // 3
                recognizer.recognize(inputData);
            } else {
                recognizer.reset();
            }

            // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
            // current active recognizer. but only if we don't already have an active recognizer
            if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
                curRecognizer = session.curRecognizer = recognizer;
            }
            i++;
        }
    },

    /**
     * get a recognizer by its event name.
     * @param {Recognizer|String} recognizer
     * @returns {Recognizer|Null}
     */
    get: function(recognizer) {
        if (recognizer instanceof Recognizer) {
            return recognizer;
        }

        var recognizers = this.recognizers;
        for (var i = 0; i < recognizers.length; i++) {
            if (recognizers[i].options.event == recognizer) {
                return recognizers[i];
            }
        }
        return null;
    },

    /**
     * add a recognizer to the manager
     * existing recognizers with the same event name will be removed
     * @param {Recognizer} recognizer
     * @returns {Recognizer|Manager}
     */
    add: function(recognizer) {
        if (invokeArrayArg(recognizer, 'add', this)) {
            return this;
        }

        // remove existing
        var existing = this.get(recognizer.options.event);
        if (existing) {
            this.remove(existing);
        }

        this.recognizers.push(recognizer);
        recognizer.manager = this;

        this.touchAction.update();
        return recognizer;
    },

    /**
     * remove a recognizer by name or instance
     * @param {Recognizer|String} recognizer
     * @returns {Manager}
     */
    remove: function(recognizer) {
        if (invokeArrayArg(recognizer, 'remove', this)) {
            return this;
        }

        recognizer = this.get(recognizer);

        // let's make sure this recognizer exists
        if (recognizer) {
            var recognizers = this.recognizers;
            var index = inArray(recognizers, recognizer);

            if (index !== -1) {
                recognizers.splice(index, 1);
                this.touchAction.update();
            }
        }

        return this;
    },

    /**
     * bind event
     * @param {String} events
     * @param {Function} handler
     * @returns {EventEmitter} this
     */
    on: function(events, handler) {
        if (events === undefined) {
            return;
        }
        if (handler === undefined) {
            return;
        }

        var handlers = this.handlers;
        each(splitStr(events), function(event) {
            handlers[event] = handlers[event] || [];
            handlers[event].push(handler);
        });
        return this;
    },

    /**
     * unbind event, leave emit blank to remove all handlers
     * @param {String} events
     * @param {Function} [handler]
     * @returns {EventEmitter} this
     */
    off: function(events, handler) {
        if (events === undefined) {
            return;
        }

        var handlers = this.handlers;
        each(splitStr(events), function(event) {
            if (!handler) {
                delete handlers[event];
            } else {
                handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
            }
        });
        return this;
    },

    /**
     * emit event to the listeners
     * @param {String} event
     * @param {Object} data
     */
    emit: function(event, data) {
        // we also want to trigger dom events
        if (this.options.domEvents) {
            triggerDomEvent(event, data);
        }

        // no handlers, so skip it all
        var handlers = this.handlers[event] && this.handlers[event].slice();
        if (!handlers || !handlers.length) {
            return;
        }

        data.type = event;
        data.preventDefault = function() {
            data.srcEvent.preventDefault();
        };

        var i = 0;
        while (i < handlers.length) {
            handlers[i](data);
            i++;
        }
    },

    /**
     * destroy the manager and unbinds all events
     * it doesn't unbind dom events, that is the user own responsibility
     */
    destroy: function() {
        this.element && toggleCssProps(this, false);

        this.handlers = {};
        this.session = {};
        this.input.destroy();
        this.element = null;
    }
};

/**
 * add/remove the css properties as defined in manager.options.cssProps
 * @param {Manager} manager
 * @param {Boolean} add
 */
function toggleCssProps(manager, add) {
    var element = manager.element;
    if (!element.style) {
        return;
    }
    var prop;
    each(manager.options.cssProps, function(value, name) {
        prop = prefixed(element.style, name);
        if (add) {
            manager.oldCssProps[prop] = element.style[prop];
            element.style[prop] = value;
        } else {
            element.style[prop] = manager.oldCssProps[prop] || '';
        }
    });
    if (!add) {
        manager.oldCssProps = {};
    }
}

/**
 * trigger dom event
 * @param {String} event
 * @param {Object} data
 */
function triggerDomEvent(event, data) {
    var gestureEvent = document.createEvent('Event');
    gestureEvent.initEvent(event, true, true);
    gestureEvent.gesture = data;
    data.target.dispatchEvent(gestureEvent);
}

assign(Hammer, {
    INPUT_START: INPUT_START,
    INPUT_MOVE: INPUT_MOVE,
    INPUT_END: INPUT_END,
    INPUT_CANCEL: INPUT_CANCEL,

    STATE_POSSIBLE: STATE_POSSIBLE,
    STATE_BEGAN: STATE_BEGAN,
    STATE_CHANGED: STATE_CHANGED,
    STATE_ENDED: STATE_ENDED,
    STATE_RECOGNIZED: STATE_RECOGNIZED,
    STATE_CANCELLED: STATE_CANCELLED,
    STATE_FAILED: STATE_FAILED,

    DIRECTION_NONE: DIRECTION_NONE,
    DIRECTION_LEFT: DIRECTION_LEFT,
    DIRECTION_RIGHT: DIRECTION_RIGHT,
    DIRECTION_UP: DIRECTION_UP,
    DIRECTION_DOWN: DIRECTION_DOWN,
    DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
    DIRECTION_VERTICAL: DIRECTION_VERTICAL,
    DIRECTION_ALL: DIRECTION_ALL,

    Manager: Manager,
    Input: Input,
    TouchAction: TouchAction,

    TouchInput: TouchInput,
    MouseInput: MouseInput,
    PointerEventInput: PointerEventInput,
    TouchMouseInput: TouchMouseInput,
    SingleTouchInput: SingleTouchInput,

    Recognizer: Recognizer,
    AttrRecognizer: AttrRecognizer,
    Tap: TapRecognizer,
    Pan: PanRecognizer,
    Swipe: SwipeRecognizer,
    Pinch: PinchRecognizer,
    Rotate: RotateRecognizer,
    Press: PressRecognizer,

    on: addEventListeners,
    off: removeEventListeners,
    each: each,
    merge: merge,
    extend: extend,
    assign: assign,
    inherit: inherit,
    bindFn: bindFn,
    prefixed: prefixed
});

// this prevents errors when Hammer is loaded in the presence of an AMD
//  style loader but by script tag, not by the loader.
var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
freeGlobal.Hammer = Hammer;

if (true) {
    !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {
        return Hammer;
    }).call(exports, __webpack_require__, exports, module),
		__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
} else {}

})(window, document, 'Hammer');


/***/ }),

/***/ "./src/js/ArtworkSlider.js":
/*!*********************************!*\
  !*** ./src/js/ArtworkSlider.js ***!
  \*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ ArtworkSlider)
/* harmony export */ });

class ArtworkSlider {

	constructor(el) { 
		this.el = el;
		this.elControl = this.el.querySelectorAll('.slider')[0];
		this.elFore = this.el.querySelectorAll('.fore')[0];
		this.elKnob = this.el.querySelectorAll('.knob')[0];

		var self = this;

		var eventDown = 'mousedown';
		var eventMove = 'mousemove';
		var eventUp = 'mouseup';
		if ('ontouchstart' in window) { 
			eventDown = 'touchstart';
			eventMove = 'touchmove';
			eventUp = 'touchend';
		}

		this.elControl.addEventListener(eventDown, function () { 
			//console.log('ArtworkSlider.mouseDown() ');
			self.dragging = true;
			window.gaEvent('Artwork Slider', 'click', window.location.pathname);
		});
		
		window.addEventListener(eventMove, function (event) { 
			if (self.dragging) { 

				var x = event.clientX;
				if (event.touches) { 
					if (event.touches.length >= 1) {
						x = event.touches[0].clientX;
					}
				}
				//console.log('ArtworkSlider.mouseMove() ', self.dragging, x);

				var rect = self.elFore.getBoundingClientRect();
				var p = (x - rect.left) / (rect.right - rect.left);
				p = (p-0.05) / 0.9;
				if (p < 0) { 
					p = 0;
				}
				if (p > 1) { 
					p = 1;
				}
				self.elKnob.style.left = (p*(rect.right-rect.left-24))+'px';
				self.elFore.style.opacity = p;
			}
		});

		window.addEventListener(eventUp, function () { 
			//console.log('ArtworkSlider.mouseUp()');
			self.dragging = false;
		});
		

		this.dragging = false;

	}

	close() { 
		//console.log('ArtworkSlider.close()');

	}


}




/***/ }),

/***/ "./src/js/ArtworkZoom.js":
/*!*******************************!*\
  !*** ./src/js/ArtworkZoom.js ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ ArtworkZoom)
/* harmony export */ });
/* harmony import */ var hammerjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! hammerjs */ "./node_modules/hammerjs/hammer.js");
/* harmony import */ var hammerjs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(hammerjs__WEBPACK_IMPORTED_MODULE_0__);



class ArtworkZoom {

	constructor(el) { 

		this.el = el;
		this.elInner = this.el.querySelectorAll('.image-holder')[0];
		this.elHolder = this.el.querySelectorAll('.image-holder')[0];
		this.elArtwork = this.el.querySelectorAll('.image-holder img')[0];
		this.elButtonZoomOut = this.el.querySelectorAll('.button-zoom-out')[0];
		this.elButtonZoomIn = this.el.querySelectorAll('.button-zoom-in')[0];
		this.elTextZoom = this.el.querySelectorAll('.text-zoom-percent')[0];

		this.translateX = 0;
		this.translateY = 0;
		this.scale = 1;

		var self = this;

		//  
		this.resize = this.resize.bind(this);
		this.update = this.update.bind(this);
		this.close = this.close.bind(this);

		//  Click on zoom icon, photo zooms to 200%
		//  Drag on photo to pan
		//  Pinch zoom to zoom in and out
		//  Mouse wheel, and magic mouse, to zoom in and out

		this.hammer = new Hammer(this.elHolder, {inputClass: Hammer.TouchMouseInput});
		this.hammer.get('pinch').set({ enable: true });

		//  Pan
		this.hammer.on('pan', function(event) {
			self.translateX += event.velocityX * 10/self.scale;
			self.translateY += event.velocityY * 10/self.scale;
			self.update();
		});
		
		//  Pinch
		this.hammer.on("pinchin", function(e) {
			self.scale -= 0.12;
			self.update();
		});
		this.hammer.on("pinchout", function(e) {
			self.scale += 0.08;
			self.update();
		});

		//  Mousewheel
		this.elHolder.addEventListener('wheel', function (event) { 
			event.preventDefault();
			//console.log(event.wheelDeltaY);
			self.scale += event.wheelDeltaY/500;
			self.update();
		});

		//  Buttons
		this.elButtonZoomOut.addEventListener('click', function (event) { 
			event.preventDefault();
			self.scale -= 0.25;
			self.update();
		});
		this.elButtonZoomIn .addEventListener('click', function (event) { 
			event.preventDefault();
			self.scale += 0.25;
			self.update();
		});

		//  Resize
		window.addEventListener('resize', this.resize);
		this.resize();


	}

	resize(event) { 

		//console.log(this.elArtwork.offsetWidth, this.elArtwork.offsetHeight, this.elArtwork.complete, this.elArtwork.naturalHeight);
		if (this.elArtwork.complete == false) { 
			const self = this;
			setTimeout(function () {  
				self.resize();
			}, 100);
			return;
		}

		this.el.style.height = (window.innerHeight-56)+'px';
		this.elInner.style.height = (window.innerHeight-56)+'px';
		this.elHolder.style.height = (window.innerHeight-56)+'px';

		var aw = this.elArtwork.offsetWidth;
		var ah = this.elArtwork.offsetHeight;
		var cw = this.elHolder.offsetWidth;
		var ch = this.elHolder.offsetHeight;
		var w = cw;
		var h = ah/aw*cw;
		var t = (ch - h) * 0.5;
		var l = 0;
		if (aw/ah < cw/ch) { 
			var h = ch;
			var w = aw/ah*ch;
			var t = 0;
			var l = (cw - w) * 0.5;
		}
		this.elArtwork.style.width = w+'px';
		this.elArtwork.style.height = h+'px';
		this.elArtwork.style.left = l+'px';
		this.elArtwork.style.top = t+'px';
		this.update();
	}

	update() {

		if (this.scale < 1) { 
			this.scale = 1;
		}
		if (this.scale > 4) { 
			this.scale = 4;
		}

		this.elTextZoom.innerHTML = Math.floor(this.scale*100)+'%'

		var aw = this.elArtwork.offsetWidth;
		var ah = this.elArtwork.offsetHeight;
		var cw = this.elHolder.offsetWidth;
		var ch = this.elHolder.offsetHeight;

		var w = ((cw * (this.scale-1)) / this.scale) * 0.5;
		var h = ((ch * (this.scale-1)) / this.scale) * 0.5;

		if (this.translateX < -w) { 
			this.translateX = -w;
		} 
		if (this.translateX > w) { 
			this.translateX = w;
		}
		if (this.translateY < -h) { 
			this.translateY = -h;
		} 
		if (this.translateY > h) { 
			this.translateY = h;
		}
	
		this.elArtwork.style.transform = 'scale('+this.scale+') translate('+this.translateX+'px, '+this.translateY+'px)';
	}

	close() { 
		this.hammer.destroy();
		//console.log('ArtworkZoomer.close()');
	}


}




/***/ }),

/***/ "./src/js/AudioPlayer.js":
/*!*******************************!*\
  !*** ./src/js/AudioPlayer.js ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ AudioPlayer)
/* harmony export */ });

class AudioPlayer {

	constructor() { 

		this.el = document.getElementById('audio-player');
		this.buttonPlay = this.el.querySelectorAll('.button-play')[0];
		this.buttonPause = this.el.querySelectorAll('.button-pause')[0];
		this.buttonMute = this.el.querySelectorAll('.button-mute')[0];
		this.buttonUnmute = this.el.querySelectorAll('.button-unmute')[0];

		this.timeCurrent = this.el.querySelectorAll('.time .current')[0];
		this.timeDuration = this.el.querySelectorAll('.time .duration')[0];

		this.soundScapeURL = window.pluginBaseURL+"static/mp3/soundscape.mp3";

		this.show = this.show.bind(this);
		this.hide = this.hide.bind(this);

		this.elAudio = document.createElement("AUDIO"); 
		this.elAudio.preload = 'none';
		this.elAudio.autoplay = false;
		this.elAudio.controls = false;
		this.elAudio.src = this.soundScapeURL;
		this.elAudio.muted = false;
		this.elAudio.defaultMuted = false;
		this.elAudio.loop = true;

		const self = this;

		this.buttonPlay.addEventListener('click', function () { 
			self.buttonPlay.style.display = 'none';
			self.buttonPause.style.display = 'block';
			self.elAudio.play();
			window.gaEvent('Soundtrack', 'play', '');
		});
		this.buttonPause.addEventListener('click', function () { 
			self.buttonPlay.style.display = 'block';
			self.buttonPause.style.display = 'none';
			self.elAudio.pause();
			window.gaEvent('Soundtrack', 'pause', '');
		});
		this.buttonMute.addEventListener('click', function () { 
			self.buttonMute.style.display = 'none';
			self.buttonUnmute.style.display = 'block';
			self.elAudio.muted = true;
			window.gaEvent('Soundtrack', 'mute', '');
		});
		this.buttonUnmute.addEventListener('click', function () { 
			self.buttonMute.style.display = 'block';
			self.buttonUnmute.style.display = 'none';
			self.elAudio.muted = false;
			window.gaEvent('Soundtrack', 'unmute', '');
		});

		this.elAudio.addEventListener('timeupdate', function () { 
			self.timeCurrent.innerHTML = self.secondsAsTime(self.elAudio.currentTime);
			self.timeDuration.innerHTML = self.secondsAsTime(self.elAudio.duration);
		});

	}

	show() { 
		this.el.classList.add('open');
	}
	hide() { 
		this.el.classList.remove('open');
	}

	secondsAsTime(secs) {
		var hr  = Math.floor(secs / 3600);
		var min = Math.floor((secs - (hr * 3600))/60);
		var sec = Math.floor(secs - (hr * 3600) -  (min * 60));
		if (min < 10){ 
			min = "0" + min; 
		}
		if (sec < 10){ 
			sec  = "0" + sec;
		}
		return min + ':' + sec;
	}




}




/***/ }),

/***/ "./src/js/Content.js":
/*!***************************!*\
  !*** ./src/js/Content.js ***!
  \***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ Content)
/* harmony export */ });
/* harmony import */ var _TransitionWipe_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./TransitionWipe.js */ "./src/js/TransitionWipe.js");
/* harmony import */ var _ImageDetect_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ImageDetect.js */ "./src/js/ImageDetect.js");
/* harmony import */ var _ArtworkZoom_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ArtworkZoom.js */ "./src/js/ArtworkZoom.js");
/* harmony import */ var _ArtworkSlider_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./ArtworkSlider.js */ "./src/js/ArtworkSlider.js");
/* harmony import */ var _AudioPlayer_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./AudioPlayer.js */ "./src/js/AudioPlayer.js");
/* harmony import */ var _ShareYourVisit_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./ShareYourVisit.js */ "./src/js/ShareYourVisit.js");
/* harmony import */ var _SocialShare_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./SocialShare.js */ "./src/js/SocialShare.js");
/* harmony import */ var _Wall_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./Wall.js */ "./src/js/Wall.js");










class Content {

	constructor() { 

		this.currentPath = '';
		this.loadedContent = '';
		this.loadedTitle = '';
		this.browserBackButton = false;
		this.imageDetector = null;
		this.artworkZoom = null;
		this.artworkSliders = [];
		this.arLibraryLoading = false;
		this.arLibraryLoaded = false;
		this.socialShares = [];
		this.shareYourVisit = null;
		this.wall = null;

		//  Binds
		this.onLinkClick = this.onLinkClick.bind(this);
		this.linkClick = this.linkClick.bind(this);
		this.contentDisplay = this.contentDisplay.bind(this);
		this.onChangeContent = this.onChangeContent.bind(this);
		this.onPopState = this.onPopState.bind(this);
		this.onModalClose = this.onModalClose.bind(this);
		this.onModalCloseStartScan = this.onModalCloseStartScan.bind(this);
		this.scanSelectPhoto = this.scanSelectPhoto.bind(this);
		this.resize = this.resize.bind(this);

		//  Resize
		window.addEventListener('resize', this.resize);
		this.resize();

		//  Disable page scale on iOS
		if (this.iOS()) {
			window.document.addEventListener('touchmove', function(event) {
				if(event.scale !== 1) {
					event.preventDefault();
				}
			}, {passive: false});
		}

		//  Back button
		window.addEventListener('popstate', this.onPopState);

		//  Create Transition
		this.transition = new _TransitionWipe_js__WEBPACK_IMPORTED_MODULE_0__["default"](); 

		//  Create Audio Player
		this.audioPlayer = new _AudioPlayer_js__WEBPACK_IMPORTED_MODULE_4__["default"](); 

		//  Capture initial links
		this.applyEventsToDOM();

		//  Device specific CSS
		const body = document.getElementsByTagName('body')[0];
		if (this.iOS()) {
			body.classList.add('device-ios');
		} else if (navigator.userAgent.match(/android/i)) {
			body.classList.add('device-android');
		}
		
	}

	//  is iOS?
	iOS() {
		if (/iPad|iPhone|iPod/.test(navigator.platform)) {
			return true;
		} else {
			return navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform);
		}
	}
	iPad() {
		return navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform);
	}

	//  Resize
	resize(event) { 

		const modals = document.querySelectorAll('.modals')[0];
		if (modals) { 
			modals.style.height = (window.innerHeight-56)+'px';
		}
		
		const content = document.querySelectorAll('#content')[0];
		if (content) { 
			content.style.height = (window.innerHeight)+'px';
		}

		const introScrollPanel = document.querySelectorAll('.intro .scroll-panel')[0];
		if (introScrollPanel) { 
			introScrollPanel.style.height = (window.innerHeight-82)+'px';
		}


	}

	//  On browser back clicked
	onPopState () { 
		this.browserBackButton = true;
		this.contentLoad(window.location.href);
	}

	//  When a link is clicked
	onLinkClick(event) {
		event.preventDefault();
		this.linkClick(event.currentTarget.href);
	}
	linkClick(url) {
		if (this.transition.active) { 
			return;
		}
		//console.log('Captured link clicked: ', url);
		this.browserBackButton = false;

		//  Clean the scan camera
		if (this.imageDetector) { 
			this.imageDetector.stop();
		}

		//  Open the sensitive content modal
		if (this.cleanPath(url) == '/virtual-explore/varchive#sensitive-content') { 
			document.getElementById('sensitive-content').classList.add('open');
			return;
		}

		//  Troubleshoot platform detection
		if (this.cleanPath(url) == '/explore/troubleshoot') { 
			var platform = 'android';
			if (this.iPad()) { 
				platform = 'iPad';
			} else if (this.iOS()) { 
				platform = 'iOS';  
			}
			url = url+'/'+platform;
		}

		this.contentLoad(url);
	}


	//  Change the content in the middle of the transition
	onChangeContent() { 
		this.contentDisplay();
		if (this.browserBackButton == false) { 
			window.history.pushState(null, null, this.currentPath);
		}

		//  Show or hide the audio player
		const s = this.cleanPath(this.currentPath);
		if (s == '/virtual-explore' || s == '/explore') { 
			this.audioPlayer.hide();
		} else if (String(s).lastIndexOf('/virtual-explore/artwork/zoom/', 0) === 0) { 
			this.audioPlayer.hide();
		} else if (String(s).lastIndexOf('/virtual-explore/varchive/zoom/', 0) === 0) { 
			this.audioPlayer.hide();
		} else { 
			this.audioPlayer.show();
		} 

		//console.log('ga', 'send', 'pageview', this.cleanPath(this.currentPath));
		window.gaPageView(this.cleanPath(this.currentPath));
	

	}

	//  Modal Close
	onModalClose(event) { 
		//console.log('onModalClose');
		event.preventDefault();
		event.target.parentNode.parentNode.classList.toggle('open');
	}

	//  Modal close and start scan
	onModalCloseStartScan(event) { 
		//console.log('onModalCloseStartScan');
		event.preventDefault();		
		window.gaEvent('Scan', 'start', '');

		//  Close the modal
		event.target.parentNode.parentNode.classList.toggle('open');
		
		//  Show the spinner
		const spinner = document.getElementById('scan-spinner');
		if (spinner) { 
			spinner.style.opacity = 1;
		}

		//  In a second, load the image detector
		setTimeout(this.imageDetector.start, 1000);

	}

	//  Load the content at this path 
	contentLoad(path) { 
		if (this.currentPath == path) { 
			return;
		}
		this.currentPath = path;
		var path = this.cleanPath(path);
		this.transition.start(path, this.onChangeContent);
		var self = this;
		fetch(this.contentURL(path)+'?cc='+Math.random()).then(function (response) {
			response.text().then(function (text) {
				self.contentParse(text);
				self.transition.contentLoaded = true;
			});
		});
	}

	//  Parse the loaded content
	contentParse(responseText) { 
		const e = document.createElement('html');
		e.innerHTML = responseText;
		this.loadedContent = e.querySelector('#content').innerHTML;
		this.loadedTitle = e.querySelector('title').innerHTML;
	}

	//  Display the loaded content
	contentDisplay() { 
		document.title = this.loadedTitle;
		var contentElement = document.getElementById('content');
		contentElement.innerHTML = this.loadedContent;
		this.applyEventsToDOM();
		window.scrollTo(0, 0);
		this.resize();
	}

	//  Apply JavaScript events to the DOM that just loaded
	applyEventsToDOM() { 

		//  Capture links 
		for (var i=0; i<document.links.length; i++) {
			var link = document.links[i];
			var s = link.href.split(window.siteBaseURL).join('');
			if (s.indexOf('/explore') == 0 || s.indexOf('/virtual-explore') == 0) { 
				link.onclick = this.onLinkClick;
			}
		}

		//  Modal close buttons
		var closes = document.querySelectorAll('.modal .close');
		for (var i=0; i<closes.length; i++) {
			closes[i].onclick = this.onModalClose;
		}

		//  Scan Camera
		const cameraContainer = document.getElementById('camera-container');
		if (cameraContainer) { 
			
			var first = false;
			if (this.imageDetector == null) { 
				first = true;
				this.imageDetector = new _ImageDetect_js__WEBPACK_IMPORTED_MODULE_1__["default"]();

				//  Only open the scan instructions the first time the page loads
				const scanInstructions = document.getElementById('scan-instructions');
				if (scanInstructions) { 
					scanInstructions.classList.add('open');
				}
				var closes = scanInstructions.querySelectorAll('.close');
				for (var i=0; i<closes.length; i++) {
					closes[i].onclick = this.onModalCloseStartScan;
				}

			} 

			this.imageDetector.setParent(this);
			this.imageDetector.setContainer(cameraContainer);
			this.imageDetector.setCallback(this.scanSelectPhoto);
			this.imageDetector.resize();

			if (first == false) { 
				setTimeout(this.imageDetector.start, 1000);
			}

		}

		//  Artwork Zoom  (only ever once on the page)
		if (this.artworkZoom) { 
			this.artworkZoom.close();
		}
		var element = document.getElementById('artwork-zoom');
		if (element) { 
			this.artworkZoom = new _ArtworkZoom_js__WEBPACK_IMPORTED_MODULE_2__["default"](element);
		}
		
		//  Artwork Sliders
		for (var i=0; i<this.artworkSliders.length; i++) {
			this.artworkSliders[i].close();
		}
		this.artworkSliders = [];
		var elements = document.querySelectorAll('#content .artwork-slider');
		for (var i=0; i<elements.length; i++) {
			this.artworkSliders.push(new _ArtworkSlider_js__WEBPACK_IMPORTED_MODULE_3__["default"](elements[i]));
		}
		
		//  Social Shares
		/*
		for (var i=0; i<this.socialShares.length; i++) {
			this.socialShares[i].close();
		}
		this.socialShares = [];
		var elements = document.querySelectorAll('#content .social-share');
		for (var i=0; i<elements.length; i++) {
			this.socialShares.push(new SocialShare(elements[i]));
		}
		*/

		//  Wall  (only ever once on the page)
		if (this.wall) { 
			this.wall.close();
		}
		var element = document.querySelectorAll('#content .wall.photographs')[0];
		if (element) { 
			this.wall = new _Wall_js__WEBPACK_IMPORTED_MODULE_7__["default"](element, 'photographs');
		}
		var element = document.querySelectorAll('#content .wall.varchive')[0];
		if (element) { 
			this.wall = new _Wall_js__WEBPACK_IMPORTED_MODULE_7__["default"](element, 'varchive');
		}
		var element = document.querySelectorAll('#content .wall.dolls')[0];
		if (element) { 
			this.wall = new _Wall_js__WEBPACK_IMPORTED_MODULE_7__["default"](element, 'dolls');
		}

		//  Artwork AR
		/*
		if (document.querySelectorAll('#content .artwork-ar').length > 0) {
			//console.log('ModelViewer found');
			var self = this;
			if (this.arLibraryLoading && !this.arLibraryLoaded) { 
				//  Wait
				//console.log('ModelViewer loading...');
			} else if (this.arLibraryLoaded) { 
				//console.log('ModelViewer loaded');
				self.applyEventsToDOMArtworkAR();
			} else { 
				//console.log('ModelViewer, loading library...');
				this.arLibraryLoading = true;
				var script = document.createElement("script");
				script.type = 'module';
				script.src = window.pluginBaseURL+'static/js/model-viewer.min.js';
				script.onload = function () { 
					//console.log('ModelViewer, loaded library.');
					self.arLibraryLoaded = true;
					self.applyEventsToDOMArtworkAR();
				};
				document.head.appendChild(script);
				return;
			}
		}
		*/

	}

	//  Look for and replace Artwork AR interactions
	applyEventsToDOMArtworkAR() { 
		//console.log('ModelViewer, apply to dom');
		var elements = document.querySelectorAll('#content .artwork-ar');
		for (var i=0; i<elements.length; i++) {
			var element = elements[i];
			var slug = element.getAttribute('data-slug');
			var mv = document.createElement('model-viewer');
			mv.setAttribute('src', '/wp-content/plugins/powerhouse-digital-attendance/static/3d/'+slug+'.gltf?'+Math.random()+'');
			mv.setAttribute('ar', '');
			mv.setAttribute('reveal', 'auto');
			mv.setAttribute('ar-placement', 'wall');
			mv.setAttribute('ar-modes', 'webxr scene-viewer quick-look');
			mv.setAttribute('camera-controls', '');
			mv.setAttribute('alt', 'Use augmented reality to view this artwork within your home and get closer than ever');
			mv.onload = function () { 
				if (!mv.canActivateAR) { 
					mv.parentNode.parentNode.parentNode.remove();
				} 
			}
			element.appendChild(mv);
		}
	}

	//  Close all modals
	modalsCloseAll() { 
		var modals = document.querySelectorAll('.modal');
		for (var i=0; i<modals.length; i++) {
			modals[i].classList.remove('open');
		}
	}

	//  Photo selected
	scanSelectPhoto(slug) { 
		console.log("slug to select photo: ", slug);
		this.modalsCloseAll();
		const modal = document.getElementById('scan-artwork-summary-'+slug);
		if (modal) { 
			modal.classList.add('open');
			window.gaEvent('Scan', 'select', slug);
		}
	}

	//  The url for the content from the path
	contentURL(path) { 
		return window.pluginBaseURL+'pages'+path+'.html';
	}

	//  Clean the path 
	cleanPath(path) { 
		if (path.charAt(path.length-1) == "/") {
			path = path.slice(0, -1)
		}
		path = path.split(location.origin).join(''); 
		return path;
	}



}




/***/ }),

/***/ "./src/js/ImageDetect.js":
/*!*******************************!*\
  !*** ./src/js/ImageDetect.js ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ ImageDetect)
/* harmony export */ });

//import * as tf from '@tensorflow/tfjs';

class ImageDetect {

	constructor() { 
		//console.log('ImageDetect init');
		this.active = false;
		this.selectPhoto = null;
		this.libraryLoaded = false;
		this.modelLoaded = false;
		this.container = null; 
		this.parent = null;
		this.model;
		this.webcam;
		this.canvas;
		this.video;
		this.stream;
		this.modelPath = window.pluginBaseURL+"static/model/";
		this.start = this.start.bind(this);
		this.loop = this.loop.bind(this);
		this.webcamSize = [720,720];
		this.canvasSize = 224;
		this.lastSlug = '';
		this.currentPhoto = null;
		this.currentPhotoCounter = 0;
		
		this.slugOrder = [
			'two-faafafine',
			'two-faafafine-going-to-church',
			'spirit-of-the-ancestors-watching',
			'three-faafafine',
			'nafea-e-te-faaipoipo',
			'the-wizard',
			'siou-alofa-maria-hail-mary',
			'two-faafafine-on-the-beach',
			'faafafine-with-children',
			'genesis-9-16',
			'fonofono-o-le-nuanua',
			'paul-gauguin-with-a-hat',
			'auckland-art-gallery-visitors-book',
			'cast-of-paradise-camp',
			'documenting-climate-change-in-samoa',
			'faafafine-ancestors',
			'faafafine-aquarium',
			'gauguin-and-samoa',
			'gauguin-and-tourism-imagery-in-the-moana',
			'headlines',
			'new-zealands-colonial-adminstration-of-samoa',
			'pasifika-theirstories',
			'passports',
			'samoanising-christianity',
			'sunday-samoan-newspaper',
			'teachers-guide-to-year-10-students',
			'vailuluu-seamount',
			'venice-and-the-other',
			'world-peace-faafafine-beauty-pageants',
			'yuki-kihara-at-the-metropolitan-museum-of-art',
			'yuki-kihara-on-telecom-mobile-campaign',
			'faafafine-industry-variety-award', 
			'faafafine-ancestors-1',
			'faafafine-ancestors-2',
			'faafafine-ancestors-3',
			'faafafine-ancestors-4',
			'samoan-queer-lives',
			'samoan-origin-story',
			'faafafine-claim-myth-offensive',
			'paradise-camp-media',
			'ghost-forest-upolu-island',
			'mataafa-losefo-landmark-amaile',
			'tapas-siapo-1',
			'tapas-siapo-2',
			'tapas-siapo-3',
			'paradise-camp-book',
			'charles-kerry',
			'stamps',
			'gauguin-landscapes',
			'gauguin-landscapes-1',
			'gauguin-landscapes-2',
			'gauguin-landscapes-3',
			'gauguin-landscapes-4',
			'gauguin-landscapes-5',
			'gauguin-landscapes-6',
			'gauguin-landscapes-7',
			'gauguin-landscapes-8',
			'gauguin-landscapes-9',
			'gauguin-landscapes-10',
			'gauguin-landscapes-11',
			'gauguin-landscapes-12',
			'gauguin-landscapes-13',
			'gauguin-landscapes-14',
			'gauguin-landscapes-15',
			'gauguin-landscapes-16',
			'gauguin-landscapes-17',
			'gauguin-landscapes-18',
			'gauguin-landscapes-19',
			'charles-kerry-1',
			'charles-kerry-2',
			'charles-kerry-3',
			'charles-kerry-4',
			'charles-kerry-5',
			'charles-kerry-6',
			'charles-kerry-7',
			'charles-kerry-8',
			'charles-kerry-9',
			'charles-kerry-10',
			'charles-kerry-11',
			'charles-kerry-12',
			'charles-kerry-13',
			'berthaday-2016',
			'dangerous-desire-1991',
			'door-bitch-2001',
			'eaten-alive-1998',
			'faafafines-at-the-sydney-opera-house-2009',
			'law-reform-girl-1986',
			'madame-butterfly-1995',
			'over-the-rainbow',
			'queens-of-the-pacific-1994',
			'take-me-to-heaven-1992',
			'three-marys-2010',
		];

		//  
		this.resize = this.resize.bind(this);

		//  Resize
		window.addEventListener('resize', this.resize);
		this.resize();

	}

	resize(event) { 
		const scan = document.getElementById('scan');
		if (scan) { 
			scan.style.height = (window.innerHeight-56-56)+'px';
		}
	}

	setParent(p) { 
		//console.log('ImageDetect setParent', p);
		this.parent = p;
	}
	setContainer(element) { 
		//console.log('ImageDetect setContainer', element);
		this.container = element;
	}
	setCallback(callback) { 
		//console.log('ImageDetect setCallback', callback);
		this.selectPhoto = callback;
	}

	async start() { 
		//console.log('ImageDetect start');

		//  Confirm they support webcams
		if (window.location.protocol != "https:") {
			if (window.location.hostname != 'localhost') { 
				alert('WebRTC not supported over http.  Please enable https or use localhost.');
				return;
			}	
		}
		if (!window.navigator.mediaDevices || !window.navigator.mediaDevices.getUserMedia) {
			alert('Your browser does not support WebRTC. Please try another one.');
			return;
		}

		if (this.active) { 
			return;
		}
		this.active = true;

		//  Reference
		const self = this;

		//  Load the Tensorflow Libary only as it's needed, and only load it once.		
		if (this.libraryLoaded == false) {
			this.active = false;
			//console.log('ImageDetect, loading library...');
			var script = document.createElement("script");
			script.type = 'text/javascript';
			script.src = window.pluginBaseURL+'static/js/tensorflow.min.js';
			script.onload = function () { 
				//console.log('ImageDetect, loaded library.');
				self.libraryLoaded = true;
				self.start();
			};
			document.head.appendChild(script);
			return;
		}

		//  Load the model
		if (this.modelLoaded == false) { 
			this.modelLoaded = true;
			//console.log('ImageDetect, loading model...');
			this.model = await tf.loadLayersModel(this.modelPath+'model.json');
			//console.log('ImageDetect, loaded model.');
		}

		//  Version check
		//console.log('Tensorflow', tf.version.tfjs, tf.getBackend());

		//  Create the canvas
		this.canvas = document.createElement('canvas');
		this.canvas.width = this.canvasSize;
		this.canvas.height = this.canvasSize;

		//  Create the video object
		//console.log('ImageDetect, create video.');
		const video = document.createElement('video');
		this.video = null;
		this.video = video;

		//  Webcam constraints
		const constraints = { 
			audio: false, 
			video: { 
				width: 1280,
				height: 720, 
				facingMode:'environment' 
			} 
		};

		//  Start the webcam
		this.webcam = window.navigator.mediaDevices.getUserMedia(constraints)
		.then((stream) => {
			video.srcObject = stream;
			self.stream = stream;
			/*
			video.addEventListener('loadedmetadata', function (event)  {
				if (video.videoWidth != 0 && video.videoHeight != 0) { 
					console.log('ImageDetect, video metadata loaded, ', video.videoWidth, video.videoHeight);
				}
			});
			*/

			//  Hide the spinner
			const spinner = document.getElementById('scan-spinner');
			if (spinner) { 
				spinner.style.opacity = 0;
			}

			//  Show the target
			const target = document.getElementById('scan-target');
			if (target) { 
				target.style.opacity = 1;
			}

		})
		.catch((err) => {
			this.parent.linkClick('/explore/troubleshoot');
		});

		//  Add the video to the screen
		this.container.appendChild(video); 
		//console.log('ImageDetect, append video.', video);
		//this.container.appendChild(this.canvas);

		//  Written with "setAttribute" bc. iOS buggs otherwise :-)
		video.setAttribute("playsinline", true); 
		video.width = this.webcamSize[0];
		video.height = this.webcamSize[1];
		video.muted = "true"
		video.id = "webcamVideo";
	
		//  Play		
		video.play();
			
		//  Loop
		window.requestAnimationFrame(this.loop);

	}

	async stop() { 
		//console.log('ImageDetect stop');
		this.active = false;
		if (this.stream) { 
			this.stream.getTracks()[0].stop();
		}
		if (this.video) { 
			this.video.pause();
			this.video.remove();
			this.video = null;
		}
		this.canvas = null;
		//this.model = null;
		this.webcam = null;
	}

	async loop() {
		if (this.canvas && this.webcam) { 
			
			//  The size of the webcam video
			var w = this.webcamSize[0];
			var h = this.webcamSize[1];
			if (this.video.videoWidth != 0 && this.video.videoHeight != 0) { 
				w = this.video.videoWidth
				h = this.video.videoHeight;
			}

			//  Center square inset 20%
			var min = Math.min(w, h)*0.8;
			const tx = Math.floor((w-min)*0.5);
			const ty = Math.floor((h-min)*0.5);

			const ctx = this.canvas.getContext('2d');
			ctx.drawImage(this.video, tx, ty, min, min,   0,0,this.canvasSize,this.canvasSize);

			//  Predict
			const logits = tf.tidy(() => {
				const pixels = tf.browser.fromPixels(this.canvas);
				const pixelsExpanded = pixels.expandDims(0);
				const captured = pixelsExpanded.toFloat().div(tf.scalar(127)).sub(tf.scalar(1));
				return this.model.predict(captured);
			});

			//  Values
			const values = await logits.data();
			var indexMax = null;
			var valueMax = 0;

			for (var i=0; i<values.length; i++) { 
				var value = values[i];
				if (valueMax < value) { 
					valueMax = value;
					indexMax = i;
				}
			}

			//console.log("indexMax & valueMax: ", indexMax, valueMax);
			//console.log("Slug order: ", this.slugOrder);

			if (valueMax > 0.90) { 
				this.currentPhoto = indexMax;

				//  Lookup the slug for the best photo
				var slug = this.slugOrder[indexMax];
				//console.log("Slug: ", slug);
				//console.log(indexMax, slug);
				if (slug.indexOf('faafafine-ancestors') == 0) slug = 'faafafine-ancestors';
				if (slug.indexOf('tapas-siapo') == 0) slug = 'tapas-siapo';
				if (slug.indexOf('gauguin-landscapes') == 0) slug = 'gauguin-landscapes';
				if (slug.indexOf('charles-kerry') == 0) slug = 'charles-kerry';

				if (slug) { 
					if (this.lastSlug != slug) { 
						this.selectPhoto(slug);
					}
					this.lastSlug = slug;
				}

				//console.log('ImageDetect this.selectedPhoto = ', indexMax, slug);

			}

			
		}

		//  Loop
		if (this.active) {
			window.requestAnimationFrame(this.loop);
		}

	}



}





/***/ }),

/***/ "./src/js/ShareYourVisit.js":
/*!**********************************!*\
  !*** ./src/js/ShareYourVisit.js ***!
  \**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* unused harmony export default */



class ShareYourVisit {

	constructor(el) { 

		this.sending = false;

		this.el = el;
		
		this.el.innerHTML = '<div class="inner"> \
			<div class="form" > \
				<div class="container" >\
					<h2 class="upper" >Share your visit</h2>\
					<p class="info-block icon-info" >Your story will be shared with NZ at Venice and may be used on social media.</p>\
					<form>\
						<label for="message">Message</label>\
						<textarea autocomplete="off" name="message" class="message" rows="4" placeholder="Tell us about your visit" ></textarea>\
						<label for="details">Contact Details</label>\
						<input autocomplete="off" type="text" name="details" class="details" placeholder="Your email" />\
						<button class="submit button">Submit</button>\
					</form>\
				</div>\
			</div>\
			<div class="thankyou" >\
				<div class="container" >\
					<h2 class="upper" >Thank you</h2>\
					<p class="info-block icon-info" >Your story has been shared with us. Thank you.</p>\
					<button class="submit-again button">SUBMITTED</button>\
				</div>\
			</div>\
		</div>';

		this.elInner = this.el.querySelectorAll('.inner')[0];

		this.elForm = this.el.querySelectorAll('.form')[0];
		this.elThankyou = this.el.querySelectorAll('.thankyou')[0];

		this.buttonSubmit = this.el.querySelectorAll('.submit')[0];
		this.buttonSubmitAgain = this.el.querySelectorAll('.submit-again')[0];

		this.fieldDetails = this.el.querySelectorAll('.details')[0];
		this.fieldMessage = this.el.querySelectorAll('.message')[0];

		this.submit = this.submit.bind(this);
		this.submitted = this.submitted.bind(this);
		this.submitAgain = this.submitAgain.bind(this);
		this.close = this.close.bind(this);

		var self = this;

		this.buttonSubmit.addEventListener('click', this.submit);
		this.buttonSubmitAgain.addEventListener('click', this.submitAgain);


	}

	submit(event) { 
		event.preventDefault();

		if (this.fieldDetails.value == '' && this.fieldMessage.value == '') { 
			return;
		}

		if (this.sending) { 
			return;
		}
		this.sending = true;

		window.gaEvent('Share your visit', 'submit', window.location.pathname, 0);

		//  Send the field values
		var url = window.pluginBaseURL;
		url = url+'share-your-visit.php';
		url = url+'?details='+encodeURIComponent(this.fieldDetails.value);
		url = url+'&message='+encodeURIComponent(this.fieldMessage.value);
		url = url+'&cc='+Math.random();
		var self = this;
		fetch(url).then(function() { 
			self.sending = false;

			//  Slide to show thankyou
			self.elInner.style.transform = 'translateX(-100%)';
			
		});

	}

	submitted() { 
	}

	submitAgain(event) { 
		event.preventDefault();

		window.gaEvent('Share your visit', 'submit-again', window.location.pathname, 0);

		//  Slide back to the form
		this.elInner.style.transform = 'translateX(0%)';

		//  Wipe the message field
		this.fieldMessage.value = '';
		
	}

	close() { 
	}


}




/***/ }),

/***/ "./src/js/SocialShare.js":
/*!*******************************!*\
  !*** ./src/js/SocialShare.js ***!
  \*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* unused harmony export default */


//  

class SocialShare {

	constructor(el) { 

		this.el = el;

		this.confirmTimeout1 = null;
		this.confirmTimeout2 = null;

		this.openModal = this.openModal.bind(this);
		this.copyToClipboardClick = this.copyToClipboardClick.bind(this);
		this.clickTwitter = this.clickTwitter.bind(this);
		this.clickWhatsApp = this.clickWhatsApp.bind(this);

		//  Share this artwork button
		var btn = document.createElement("button");
		btn.classList.add('button');
		btn.innerHTML = '<span class="button-icon-left icon-share"></span>Share this artwork';
		btn.onclick = this.openModal;
		this.el.appendChild(btn);

		//  Buttons within the modal 
		var modal =  document.getElementById('modal-social-share');
		if (modal) { 

			//  Close 
			var btnClose = modal.querySelector('.close');
			if (btnClose) { 
				btnClose.onclick = this.closeModal;
			}

			//  Copy to clipboard
			var btnCopy = document.getElementById('button-social-share-copy');
			//btnCopy.innerHTML = this.url();
			btnCopy.innerHTML = 'Copy URL to clipboard';
			if (btnCopy) { 
				btnCopy.onclick = this.copyToClipboardClick;
			}

			//  Twitter
			var btnTwitter = document.getElementById('button-social-share-twitter');
			if (btnTwitter) { 
				btnTwitter.onclick = this.clickTwitter;
			}

			//  WhatsApp
			var btnWhatsApp = document.getElementById('button-social-share-whatsapp');
			if (btnWhatsApp) { 
				btnWhatsApp.onclick = this.clickWhatsApp;
			}

		}

	}

	openModal(event) { 
		event.preventDefault();
		var btnCopy = document.getElementById('button-social-share-copy');
		if (btnCopy) { 
			//btnCopy.innerHTML = this.url();
			btnCopy.innerHTML = 'Copy URL to clipboard';
		}
		var modal =  document.getElementById('modal-social-share');
		if (modal) { 
			modal.classList.add('open');
			window.gaEvent('Share Artwork Open', 'click', window.location.pathname);
		}	
	}

	closeModal(event) {
		event.preventDefault(); 
		var modal =  document.getElementById('modal-social-share');
		if (modal) { 
			modal.classList.remove('open');
		}
	}

	copyToClipboardClick(event) { 
		if (navigator.clipboard != undefined) { //Chrome
			navigator.clipboard.writeText(this.url());
		} else if(window.clipboardData) { // Internet Explorer
			window.clipboardData.setData("Text", this.url());
		}
		var confirm = document.getElementById('share-copy-confirm');
		if (confirm) { 
			clearTimeout(this.confirmTimeout1);
			clearTimeout(this.confirmTimeout2);
			confirm.style.display = 'block';
			confirm.style.opacity = 1;
			this.confirmTimeout1 = setTimeout(function () { 
				confirm.style.opacity = 0;
			}, 3000);
			this.confirmTimeout2 = setTimeout(function () { 
				confirm.style.display = 'none';
			}, 3500);
		}
		window.gaEvent('Share Artwork Copy to clipboard', 'click', window.location.pathname);
	}

	clickTwitter(event) { 
		window.gaEvent('Share Artwork Twitter', 'click', window.location.pathname);
		window.open('https://twitter.com/intent/tweet/?text='+encodeURIComponent(this.title())+'&url='+encodeURIComponent(this.url()), '_blank');
	}

	clickWhatsApp(event) { 
		window.gaEvent('Share Artwork WhatsApp', 'click', window.location.pathname);
		window.open('https://api.whatsapp.com/send?text='+encodeURIComponent(this.title())+'+'+encodeURIComponent(this.url()), '_blank');
	}

	url() { 
		return String(window.location).split('/explore/').join('/virtual-explore/');
	}
	title() { 
		return document.getElementsByTagName("title")[0].innerHTML;
	}

	close() { 
	}


}




















/***/ }),

/***/ "./src/js/TransitionWipe.js":
/*!**********************************!*\
  !*** ./src/js/TransitionWipe.js ***!
  \**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ TransitionWipe)
/* harmony export */ });

class TransitionWipe {

	constructor() { 
		this.URL = null;
		this.active = false;
		this.contentLoaded = false;
		this.onChangeContent = null;
		this.startTime = null;
		this.duration = 0.6;
		this.el = document.getElementById('transition');
		this.drawOn = this.drawOn.bind(this);
		this.drawOff = this.drawOff.bind(this);
		this.resize = this.resize.bind(this);

		//  Resize
		window.addEventListener('resize', this.resize);
		this.resize();
		
	}

	start(url, onChangeContent) { 
		if (!this.active) { 
			this.URL = url;
			this.active = true;
			this.contentLoaded = false;
			this.onChangeContent = onChangeContent;
			this.startTime = this.ms();
			this.drawOn();
		}
	}

	resize(event) { 
		this.el.style.height = (window.innerHeight)+'px';
	}

	ms() { 
		return performance.now()/1000;
	}

	//  Time so far as a percentage
	p() { 
		var p = (this.ms() - this.startTime) / (this.duration*0.5);
		if (p < 0) { 
			p = 0;
		}
		if (p > 1) { 
			p = 1;
		}
		return p;
	}

	drawOn() { 

		//  Draw on 
		var w = window.innerWidth;
		this.el.style.left = (-w + (this.p()*w))+'px';
		this.el.style.display = 'block';

		//  Wait for the draw on animation to finish and the content to load
		if (this.p() < 1 || this.contentLoaded == false) { 
			requestAnimationFrame(this.drawOn);
		} else { 

			//  Change the page content
			this.onChangeContent();

			//  Start the draw off
			this.startTime = this.ms();
			requestAnimationFrame(this.drawOff);

		}
	}

	drawOff() { 
		
		//  Draw off 
		var w = window.innerWidth;
		this.el.style.left = (this.p()*w)+'px';

		if (this.p() < 1) { 
			requestAnimationFrame(this.drawOff);
		} else { 
			this.el.style.display = 'none';
			this.active = false;
		}

	}

}




/***/ }),

/***/ "./src/js/Wall.js":
/*!************************!*\
  !*** ./src/js/Wall.js ***!
  \************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (/* binding */ Wall)
/* harmony export */ });
/* harmony import */ var hammerjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! hammerjs */ "./node_modules/hammerjs/hammer.js");
/* harmony import */ var hammerjs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(hammerjs__WEBPACK_IMPORTED_MODULE_0__);



class Wall {

	constructor(el, slug) { 
		
		this.multiply = 0.5;

		this.el = el;
		this.slug = slug;
		this.elControl = el;
		this.elInner = this.el.querySelectorAll('.inner')[0];
		console.log(slug);

		if (this.slug == 'photographs') {  
			this.width = 12708 * this.multiply;
			this.height = 3090 * this.multiply;
		} else if (this.slug == 'dolls') {
			this.width = 9171 * this.multiply;
			this.height = 3250 * this.multiply;
		} else {
			this.width = 39171 * this.multiply;
			this.height = 3250 * this.multiply;
		}

		this.translateX = 0;
		this.translateY = 0;

		this.scaleMin = (window.innerHeight-56-56) / this.height;
		this.scaleMax = 1.5;
		if (this.slug == 'varchive') { 
			this.scale = this.scaleMin + (this.scaleMax - this.scaleMin) * 0.5;
		} else {
			this.scale = this.scaleMin;
		}

		const s = this.getCookie('wallPosition-'+this.slug);
		if (s) { 
			const a = s.split(',');
			this.scale = Number(a[0]);
			this.translateX = Number(a[1]);
			this.translateY = Number(a[2]);
		}

		var self = this;

		this.hammer = new Hammer(this.elControl, {
			inputClass: Hammer.TouchMouseInput,
			transform_always_block: true, 
			touchAction: 'manipulation'
		});
		this.hammer.get('pinch').set({ enable: true });

		//  Pan
		this.hammer.on('pan', function(event) {
			self.translateX += event.velocityX * 18/self.scale;
			self.translateY += event.velocityY * 18/self.scale;
			self.update();
			if (event.isFinal) {
				window.gaEvent('Virtual Explore', 'pan', self.slug);
			}
		});
		
		//  Pinch
		this.hammer.on("pinchin", function(event) {
			self.scaleBy(event.center.x, event.center.y, -0.08);
		});
		this.hammer.on("pinchout", function(event) {
			self.scaleBy(event.center.x, event.center.y, 0.04);
		});
		this.hammer.on("pinchend", function(event) {
			window.gaEvent('Virtual Explore', 'pinch-zoom', self.slug);
		});

		//  Mousewheel
		this.elControl.addEventListener('wheel', function (event) { 
			event.preventDefault();
			self.scaleBy(event.pageX, event.pageY, event.wheelDeltaY/500);
			window.gaEvent('Virtual Explore', 'mouse-wheel', self.slug);
		});

		//  Button Instructions
		const buttonInstructions = this.el.querySelectorAll('.button-instructions')[0];
		if (buttonInstructions) { 
			buttonInstructions.addEventListener('click', function (event) { 
				event.preventDefault();
				const modal = document.getElementById('wall-instructions');
				if (modal) { 
					modal.classList.add('open');
					//modal.style.height = (window.innerHeight-56-56)+'px';
				}
				window.gaEvent('Virtual Explore', 'click', 'Instructions '+self.slug);
			});
		}

		//  Button Zoom In
		const buttonZoomIn = this.el.querySelectorAll('.button-zoom-in')[0];
		if (buttonZoomIn) { 
			buttonZoomIn.addEventListener('click', function (event) { 
				event.preventDefault();
				self.scale += 0.2; 
				self.update();
				window.gaEvent('Virtual Explore', 'zoom-in', self.slug);
			});
		}

		//  Button Zoom Out
		const buttonZoomOut = this.el.querySelectorAll('.button-zoom-out')[0];
		if (buttonZoomOut) { 
			buttonZoomOut.addEventListener('click', function (event) { 
				event.preventDefault();
				self.scale -= 0.2; 
				self.update();
				window.gaEvent('Virtual Explore', 'zoom-out', self.slug);
			});
		}

		//  
		this.resize = this.resize.bind(this);
		this.scaleBy = this.scaleBy.bind(this);
		this.update = this.update.bind(this);
		this.close = this.close.bind(this);

		//  Resize
		window.addEventListener('resize', this.resize);
		this.resize();

		//  Only open the wall instructions once a day
		if (this.getCookie('wallInstructionsClosed') != 'true') { 
			const element = document.getElementById('wall-instructions');
			if (element) { 
				element.classList.add('open');
				this.setCookie('wallInstructionsClosed', 'true', 1);
			}
		}

		this.update();

		this.el.style.opacity = 1;

	}

	resize(event) { 
		this.el.style.height = (window.innerHeight-56-56)+'px';
		this.scaleMin = (window.innerHeight-56-56) / this.height;
		this.update();
	}

	scaleBy(mx, my, n) { 

		var ax = 0 - this.translateX + (mx / this.scale);
		var ay = 0 - this.translateY + (my / this.scale);

		this.scale += n;

		if (this.scale < this.scaleMin) { 
			this.scale = this.scaleMin;
		}
		if (this.scale > this.scaleMax) { 
			this.scale = this.scaleMax;
		}

		var bx = 0 - this.translateX + (mx / this.scale);
		var by = 0 - this.translateY + (my / this.scale);

		this.translateX += (bx - ax);
		this.translateY += (by - ay);

		this.update();


	}

	update() {

		if (this.scale < this.scaleMin) { 
			this.scale = this.scaleMin;
		}
		if (this.scale > this.scaleMax) { 
			this.scale = this.scaleMax;
		}

		if (Number.isNaN(this.translateX)) { 
			this.translateX = 0;
		}
		if (Number.isNaN(this.translateY)) { 
			this.translateY = 0;
		}

		if (this.translateX < 0 - this.width + window.innerWidth/this.scale) { 
			this.translateX = 0 - this.width + window.innerWidth/this.scale;
		} 
		if (this.translateX > 0) { 
			this.translateX = 0;
		}
		if (this.translateY < 0 - this.height + (window.innerHeight-56-56)/this.scale) { 
			this.translateY = 0 - this.height + (window.innerHeight-56-56)/this.scale;
		} 
		if (this.translateY > 0) { 
			this.translateY = 0;
		}

		this.elInner.style.transform = 'scale('+this.scale+') translate('+this.translateX+'px, '+this.translateY+'px)';

		this.setCookie('wallPosition-'+this.slug, this.scale+','+this.translateX+','+this.translateY, 7);
	}

	close() { 
		this.hammer.destroy();
	}



	getCookie(name) {
		var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
		return v ? v[2] : null;
	}
	setCookie(name, value, days) {
		var d = new Date;
		d.setTime(d.getTime() + 24*60*60*1000*days);
		document.cookie = name + "=" + value + ";path=/;expires=" + d.toGMTString();
	}


}




/***/ })

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/compat get default export */
/******/ 	(() => {
/******/ 		// getDefaultExport function for compatibility with non-harmony modules
/******/ 		__webpack_require__.n = (module) => {
/******/ 			var getter = module && module.__esModule ?
/******/ 				() => (module['default']) :
/******/ 				() => (module);
/******/ 			__webpack_require__.d(getter, { a: getter });
/******/ 			return getter;
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be in strict mode.
(() => {
"use strict";
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/* harmony import */ var _js_Content_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./js/Content.js */ "./src/js/Content.js");






////////////////////////////////////////
////////////////////////////////////////
window.addEventListener('load', function(event) {

	//  The App
	content = new _js_Content_js__WEBPACK_IMPORTED_MODULE_0__["default"]();


});



////////////////////////////////////////
////////////////////////////////////////





})();

// This entry need to be wrapped in an IIFE because it need to be in strict mode.
(() => {
"use strict";
/*!************************!*\
  !*** ./src/index.scss ***!
  \************************/
// extracted by mini-css-extract-plugin

})();

/******/ })()
;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,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O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxTQUFTO0FBQ3BCLFdBQVcsVUFBVTtBQUNyQixhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCOztBQUUzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQixhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLE1BQU07QUFDTjtBQUNBLE1BQU07QUFDTjtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxTQUFTO0FBQ3BCLFdBQVcsUUFBUTtBQUNuQixXQUFXLFFBQVE7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsV0FBVyxRQUFRO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFD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RUE7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBOztBQUVBOztBQUVB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QUM5RSxpQ0FBaUMsY0FBYzs7QUFFL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7OztBQUdBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7OztBQUdBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUMxSmU7O0FBRWY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIOztBQUVB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QUN2QjtBQUNBO0FBQ0E7QUFDQSxtQkFBbUIsZ0RBQUk7QUFDdkI7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLGdEQUFJO0FBQ3ZCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsbUJBQW1CO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsaUJBQWlCO0FBQ2pDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQ3ZhQTs7QUFFZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxpQkFBaUIsaUJBQWlCO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7OztBQUlBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDM1dlOztBQUVmOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOzs7QUFHQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTs7Ozs7Ozs7Ozs7Ozs7Ozs7QUMzR0E7O0FBRWU7O0FBRWY7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsMENBQTBDO0FBQzFDO0FBQ0EsSUFBSSxnQ0FBZ0M7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7OztBQUdBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDM0hlOztBQUVmO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUN6RmtCOzs7QUFHSDs7QUFFZjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILGlDQUFpQyxjQUFjOztBQUUvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBLHFDQUFxQyxvQkFBb0IsS0FBSztBQUM5RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDLE9BQU87QUFDbEQ7OztBQUdBOzs7Ozs7Ozs7VUNqT0E7VUFDQTs7VUFFQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTs7VUFFQTtVQUNBOztVQUVBO1VBQ0E7VUFDQTs7Ozs7V0N0QkE7V0FDQTtXQUNBO1dBQ0E7V0FDQTtXQUNBLGlDQUFpQyxXQUFXO1dBQzVDO1dBQ0E7Ozs7O1dDUEE7V0FDQTtXQUNBO1dBQ0E7V0FDQSx5Q0FBeUMsd0NBQXdDO1dBQ2pGO1dBQ0E7V0FDQTs7Ozs7V0NQQTs7Ozs7Ozs7Ozs7OztBQ0NzQzs7Ozs7QUFLdEM7QUFDQTtBQUNBOztBQUVBO0FBQ0EsZUFBZSxzREFBTzs7O0FBR3RCLENBQUM7Ozs7QUFJRDtBQUNBOzs7Ozs7Ozs7Ozs7OztBQ25CQSIsInNvdXJjZXMiOlsid2VicGFjazovL256YXR2ZW5pY2UtZGlnaXRhbC1hdHRlbmRhbnQvLi9ub2RlX21vZHVsZXMvaGFtbWVyanMvaGFtbWVyLmpzIiwid2VicGFjazovL256YXR2ZW5pY2UtZGlnaXRhbC1hdHRlbmRhbnQvLi9zcmMvanMvQXJ0d29ya1NsaWRlci5qcyIsIndlYnBhY2s6Ly9uemF0dmVuaWNlLWRpZ2l0YWwtYXR0ZW5kYW50Ly4vc3JjL2pzL0FydHdvcmtab29tLmpzIiwid2VicGFjazovL256YXR2ZW5pY2UtZGlnaXRhbC1hdHRlbmRhbnQvLi9zcmMvanMvQXVkaW9QbGF5ZXIuanMiLCJ3ZWJwYWNrOi8vbnphdHZlbmljZS1kaWdpdGFsLWF0dGVuZGFudC8uL3NyYy9qcy9Db250ZW50LmpzIiwid2VicGFjazovL256YXR2ZW5pY2UtZGlnaXRhbC1hdHRlbmRhbnQvLi9zcmMvanMvSW1hZ2VEZXRlY3QuanMiLCJ3ZWJwYWNrOi8vbnphdHZlbmljZS1kaWdpdGFsLWF0dGVuZGFudC8uL3NyYy9qcy9TaGFyZVlvdXJWaXNpdC5qcyIsIndlYnBhY2s6Ly9uemF0dmVuaWNlLWRpZ2l0YWwtYXR0ZW5kYW50Ly4vc3JjL2pzL1NvY2lhbFNoYXJlLmpzIiwid2VicGFjazovL256YXR2ZW5pY2UtZGlnaXRhbC1hdHRlbmRhbnQvLi9zcmMvanMvVHJhbnNpdGlvbldpcGUuanMiLCJ3ZWJwYWNrOi8vbnphdHZlbmljZS1kaWdpdGFsLWF0dGVuZGFudC8uL3NyYy9qcy9XYWxsLmpzIiwid2VicGFjazovL256YXR2ZW5pY2UtZGlnaXRhbC1hdHRlbmRhbnQvd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vbnphdHZlbmljZS1kaWdpdGFsLWF0dGVuZGFudC93ZWJwYWNrL3J1bnRpbWUvY29tcGF0IGdldCBkZWZhdWx0IGV4cG9ydCIsIndlYnBhY2s6Ly9uemF0dmVuaWNlLWRpZ2l0YWwtYXR0ZW5kYW50L3dlYnBhY2svcnVudGltZS9kZWZpbmUgcHJvcGVydHkgZ2V0dGVycyIsIndlYnBhY2s6Ly9uemF0dmVuaWNlLWRpZ2l0YWwtYXR0ZW5kYW50L3dlYnBhY2svcnVudGltZS9oYXNPd25Qcm9wZXJ0eSBzaG9ydGhhbmQiLCJ3ZWJwYWNrOi8vbnphdHZlbmljZS1kaWdpdGFsLWF0dGVuZGFudC8uL3NyYy9pbmRleC5qcyIsIndlYnBhY2s6Ly9uemF0dmVuaWNlLWRpZ2l0YWwtYXR0ZW5kYW50Ly4vc3JjL2luZGV4LnNjc3M/OWE1NCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiEgSGFtbWVyLkpTIC0gdjIuMC43IC0gMjAxNi0wNC0yMlxuICogaHR0cDovL2hhbW1lcmpzLmdpdGh1Yi5pby9cbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTYgSm9yaWsgVGFuZ2VsZGVyO1xuICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlICovXG4oZnVuY3Rpb24od2luZG93LCBkb2N1bWVudCwgZXhwb3J0TmFtZSwgdW5kZWZpbmVkKSB7XG4gICd1c2Ugc3RyaWN0JztcblxudmFyIFZFTkRPUl9QUkVGSVhFUyA9IFsnJywgJ3dlYmtpdCcsICdNb3onLCAnTVMnLCAnbXMnLCAnbyddO1xudmFyIFRFU1RfRUxFTUVOVCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuXG52YXIgVFlQRV9GVU5DVElPTiA9ICdmdW5jdGlvbic7XG5cbnZhciByb3VuZCA9IE1hdGgucm91bmQ7XG52YXIgYWJzID0gTWF0aC5hYnM7XG52YXIgbm93ID0gRGF0ZS5ub3c7XG5cbi8qKlxuICogc2V0IGEgdGltZW91dCB3aXRoIGEgZ2l2ZW4gc2NvcGVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuXG4gKiBAcGFyYW0ge051bWJlcn0gdGltZW91dFxuICogQHBhcmFtIHtPYmplY3R9IGNvbnRleHRcbiAqIEByZXR1cm5zIHtudW1iZXJ9XG4gKi9cbmZ1bmN0aW9uIHNldFRpbWVvdXRDb250ZXh0KGZuLCB0aW1lb3V0LCBjb250ZXh0KSB7XG4gICAgcmV0dXJuIHNldFRpbWVvdXQoYmluZEZuKGZuLCBjb250ZXh0KSwgdGltZW91dCk7XG59XG5cbi8qKlxuICogaWYgdGhlIGFyZ3VtZW50IGlzIGFuIGFycmF5LCB3ZSB3YW50IHRvIGV4ZWN1dGUgdGhlIGZuIG9uIGVhY2ggZW50cnlcbiAqIGlmIGl0IGFpbnQgYW4gYXJyYXkgd2UgZG9uJ3Qgd2FudCB0byBkbyBhIHRoaW5nLlxuICogdGhpcyBpcyB1c2VkIGJ5IGFsbCB0aGUgbWV0aG9kcyB0aGF0IGFjY2VwdCBhIHNpbmdsZSBhbmQgYXJyYXkgYXJndW1lbnQuXG4gKiBAcGFyYW0geyp8QXJyYXl9IGFyZ1xuICogQHBhcmFtIHtTdHJpbmd9IGZuXG4gKiBAcGFyYW0ge09iamVjdH0gW2NvbnRleHRdXG4gKiBAcmV0dXJucyB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaW52b2tlQXJyYXlBcmcoYXJnLCBmbiwgY29udGV4dCkge1xuICAgIGlmIChBcnJheS5pc0FycmF5KGFyZykpIHtcbiAgICAgICAgZWFjaChhcmcsIGNvbnRleHRbZm5dLCBjb250ZXh0KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiB3YWxrIG9iamVjdHMgYW5kIGFycmF5c1xuICogQHBhcmFtIHtPYmplY3R9IG9ialxuICogQHBhcmFtIHtGdW5jdGlvbn0gaXRlcmF0b3JcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0XG4gKi9cbmZ1bmN0aW9uIGVhY2gob2JqLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIHZhciBpO1xuXG4gICAgaWYgKCFvYmopIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChvYmouZm9yRWFjaCkge1xuICAgICAgICBvYmouZm9yRWFjaChpdGVyYXRvciwgY29udGV4dCk7XG4gICAgfSBlbHNlIGlmIChvYmoubGVuZ3RoICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaSA9IDA7XG4gICAgICAgIHdoaWxlIChpIDwgb2JqLmxlbmd0aCkge1xuICAgICAgICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpbaV0sIGksIG9iaik7XG4gICAgICAgICAgICBpKys7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBmb3IgKGkgaW4gb2JqKSB7XG4gICAgICAgICAgICBvYmouaGFzT3duUHJvcGVydHkoaSkgJiYgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpbaV0sIGksIG9iaik7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogd3JhcCBhIG1ldGhvZCB3aXRoIGEgZGVwcmVjYXRpb24gd2FybmluZyBhbmQgc3RhY2sgdHJhY2VcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG1ldGhvZFxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWVcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gKiBAcmV0dXJucyB7RnVuY3Rpb259IEEgbmV3IGZ1bmN0aW9uIHdyYXBwaW5nIHRoZSBzdXBwbGllZCBtZXRob2QuXG4gKi9cbmZ1bmN0aW9uIGRlcHJlY2F0ZShtZXRob2QsIG5hbWUsIG1lc3NhZ2UpIHtcbiAgICB2YXIgZGVwcmVjYXRpb25NZXNzYWdlID0gJ0RFUFJFQ0FURUQgTUVUSE9EOiAnICsgbmFtZSArICdcXG4nICsgbWVzc2FnZSArICcgQVQgXFxuJztcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBlID0gbmV3IEVycm9yKCdnZXQtc3RhY2stdHJhY2UnKTtcbiAgICAgICAgdmFyIHN0YWNrID0gZSAmJiBlLnN0YWNrID8gZS5zdGFjay5yZXBsYWNlKC9eW15cXChdKz9bXFxuJF0vZ20sICcnKVxuICAgICAgICAgICAgLnJlcGxhY2UoL15cXHMrYXRcXHMrL2dtLCAnJylcbiAgICAgICAgICAgIC5yZXBsYWNlKC9eT2JqZWN0Ljxhbm9ueW1vdXM+XFxzKlxcKC9nbSwgJ3thbm9ueW1vdXN9KClAJykgOiAnVW5rbm93biBTdGFjayBUcmFjZSc7XG5cbiAgICAgICAgdmFyIGxvZyA9IHdpbmRvdy5jb25zb2xlICYmICh3aW5kb3cuY29uc29sZS53YXJuIHx8IHdpbmRvdy5jb25zb2xlLmxvZyk7XG4gICAgICAgIGlmIChsb2cpIHtcbiAgICAgICAgICAgIGxvZy5jYWxsKHdpbmRvdy5jb25zb2xlLCBkZXByZWNhdGlvbk1lc3NhZ2UsIHN0YWNrKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgfTtcbn1cblxuLyoqXG4gKiBleHRlbmQgb2JqZWN0LlxuICogbWVhbnMgdGhhdCBwcm9wZXJ0aWVzIGluIGRlc3Qgd2lsbCBiZSBvdmVyd3JpdHRlbiBieSB0aGUgb25lcyBpbiBzcmMuXG4gKiBAcGFyYW0ge09iamVjdH0gdGFyZ2V0XG4gKiBAcGFyYW0gey4uLk9iamVjdH0gb2JqZWN0c190b19hc3NpZ25cbiAqIEByZXR1cm5zIHtPYmplY3R9IHRhcmdldFxuICovXG52YXIgYXNzaWduO1xuaWYgKHR5cGVvZiBPYmplY3QuYXNzaWduICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgYXNzaWduID0gZnVuY3Rpb24gYXNzaWduKHRhcmdldCkge1xuICAgICAgICBpZiAodGFyZ2V0ID09PSB1bmRlZmluZWQgfHwgdGFyZ2V0ID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdDYW5ub3QgY29udmVydCB1bmRlZmluZWQgb3IgbnVsbCB0byBvYmplY3QnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBvdXRwdXQgPSBPYmplY3QodGFyZ2V0KTtcbiAgICAgICAgZm9yICh2YXIgaW5kZXggPSAxOyBpbmRleCA8IGFyZ3VtZW50cy5sZW5ndGg7IGluZGV4KyspIHtcbiAgICAgICAgICAgIHZhciBzb3VyY2UgPSBhcmd1bWVudHNbaW5kZXhdO1xuICAgICAgICAgICAgaWYgKHNvdXJjZSAhPT0gdW5kZWZpbmVkICYmIHNvdXJjZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIG5leHRLZXkgaW4gc291cmNlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzb3VyY2UuaGFzT3duUHJvcGVydHkobmV4dEtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dFtuZXh0S2V5XSA9IHNvdXJjZVtuZXh0S2V5XTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgIH07XG59IGVsc2Uge1xuICAgIGFzc2lnbiA9IE9iamVjdC5hc3NpZ247XG59XG5cbi8qKlxuICogZXh0ZW5kIG9iamVjdC5cbiAqIG1lYW5zIHRoYXQgcHJvcGVydGllcyBpbiBkZXN0IHdpbGwgYmUgb3ZlcndyaXR0ZW4gYnkgdGhlIG9uZXMgaW4gc3JjLlxuICogQHBhcmFtIHtPYmplY3R9IGRlc3RcbiAqIEBwYXJhbSB7T2JqZWN0fSBzcmNcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gW21lcmdlPWZhbHNlXVxuICogQHJldHVybnMge09iamVjdH0gZGVzdFxuICovXG52YXIgZXh0ZW5kID0gZGVwcmVjYXRlKGZ1bmN0aW9uIGV4dGVuZChkZXN0LCBzcmMsIG1lcmdlKSB7XG4gICAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyhzcmMpO1xuICAgIHZhciBpID0gMDtcbiAgICB3aGlsZSAoaSA8IGtleXMubGVuZ3RoKSB7XG4gICAgICAgIGlmICghbWVyZ2UgfHwgKG1lcmdlICYmIGRlc3Rba2V5c1tpXV0gPT09IHVuZGVmaW5lZCkpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5c1tpXV0gPSBzcmNba2V5c1tpXV07XG4gICAgICAgIH1cbiAgICAgICAgaSsrO1xuICAgIH1cbiAgICByZXR1cm4gZGVzdDtcbn0sICdleHRlbmQnLCAnVXNlIGBhc3NpZ25gLicpO1xuXG4vKipcbiAqIG1lcmdlIHRoZSB2YWx1ZXMgZnJvbSBzcmMgaW4gdGhlIGRlc3QuXG4gKiBtZWFucyB0aGF0IHByb3BlcnRpZXMgdGhhdCBleGlzdCBpbiBkZXN0IHdpbGwgbm90IGJlIG92ZXJ3cml0dGVuIGJ5IHNyY1xuICogQHBhcmFtIHtPYmplY3R9IGRlc3RcbiAqIEBwYXJhbSB7T2JqZWN0fSBzcmNcbiAqIEByZXR1cm5zIHtPYmplY3R9IGRlc3RcbiAqL1xudmFyIG1lcmdlID0gZGVwcmVjYXRlKGZ1bmN0aW9uIG1lcmdlKGRlc3QsIHNyYykge1xuICAgIHJldHVybiBleHRlbmQoZGVzdCwgc3JjLCB0cnVlKTtcbn0sICdtZXJnZScsICdVc2UgYGFzc2lnbmAuJyk7XG5cbi8qKlxuICogc2ltcGxlIGNsYXNzIGluaGVyaXRhbmNlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjaGlsZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gYmFzZVxuICogQHBhcmFtIHtPYmplY3R9IFtwcm9wZXJ0aWVzXVxuICovXG5mdW5jdGlvbiBpbmhlcml0KGNoaWxkLCBiYXNlLCBwcm9wZXJ0aWVzKSB7XG4gICAgdmFyIGJhc2VQID0gYmFzZS5wcm90b3R5cGUsXG4gICAgICAgIGNoaWxkUDtcblxuICAgIGNoaWxkUCA9IGNoaWxkLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoYmFzZVApO1xuICAgIGNoaWxkUC5jb25zdHJ1Y3RvciA9IGNoaWxkO1xuICAgIGNoaWxkUC5fc3VwZXIgPSBiYXNlUDtcblxuICAgIGlmIChwcm9wZXJ0aWVzKSB7XG4gICAgICAgIGFzc2lnbihjaGlsZFAsIHByb3BlcnRpZXMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBzaW1wbGUgZnVuY3Rpb24gYmluZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm5cbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0XG4gKiBAcmV0dXJucyB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIGJpbmRGbihmbiwgY29udGV4dCkge1xuICAgIHJldHVybiBmdW5jdGlvbiBib3VuZEZuKCkge1xuICAgICAgICByZXR1cm4gZm4uYXBwbHkoY29udGV4dCwgYXJndW1lbnRzKTtcbiAgICB9O1xufVxuXG4vKipcbiAqIGxldCBhIGJvb2xlYW4gdmFsdWUgYWxzbyBiZSBhIGZ1bmN0aW9uIHRoYXQgbXVzdCByZXR1cm4gYSBib29sZWFuXG4gKiB0aGlzIGZpcnN0IGl0ZW0gaW4gYXJncyB3aWxsIGJlIHVzZWQgYXMgdGhlIGNvbnRleHRcbiAqIEBwYXJhbSB7Qm9vbGVhbnxGdW5jdGlvbn0gdmFsXG4gKiBAcGFyYW0ge0FycmF5fSBbYXJnc11cbiAqIEByZXR1cm5zIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBib29sT3JGbih2YWwsIGFyZ3MpIHtcbiAgICBpZiAodHlwZW9mIHZhbCA9PSBUWVBFX0ZVTkNUSU9OKSB7XG4gICAgICAgIHJldHVybiB2YWwuYXBwbHkoYXJncyA/IGFyZ3NbMF0gfHwgdW5kZWZpbmVkIDogdW5kZWZpbmVkLCBhcmdzKTtcbiAgICB9XG4gICAgcmV0dXJuIHZhbDtcbn1cblxuLyoqXG4gKiB1c2UgdGhlIHZhbDIgd2hlbiB2YWwxIGlzIHVuZGVmaW5lZFxuICogQHBhcmFtIHsqfSB2YWwxXG4gKiBAcGFyYW0geyp9IHZhbDJcbiAqIEByZXR1cm5zIHsqfVxuICovXG5mdW5jdGlvbiBpZlVuZGVmaW5lZCh2YWwxLCB2YWwyKSB7XG4gICAgcmV0dXJuICh2YWwxID09PSB1bmRlZmluZWQpID8gdmFsMiA6IHZhbDE7XG59XG5cbi8qKlxuICogYWRkRXZlbnRMaXN0ZW5lciB3aXRoIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlXG4gKiBAcGFyYW0ge0V2ZW50VGFyZ2V0fSB0YXJnZXRcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlc1xuICogQHBhcmFtIHtGdW5jdGlvbn0gaGFuZGxlclxuICovXG5mdW5jdGlvbiBhZGRFdmVudExpc3RlbmVycyh0YXJnZXQsIHR5cGVzLCBoYW5kbGVyKSB7XG4gICAgZWFjaChzcGxpdFN0cih0eXBlcyksIGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgdGFyZ2V0LmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgaGFuZGxlciwgZmFsc2UpO1xuICAgIH0pO1xufVxuXG4vKipcbiAqIHJlbW92ZUV2ZW50TGlzdGVuZXIgd2l0aCBtdWx0aXBsZSBldmVudHMgYXQgb25jZVxuICogQHBhcmFtIHtFdmVudFRhcmdldH0gdGFyZ2V0XG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZXNcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGhhbmRsZXJcbiAqL1xuZnVuY3Rpb24gcmVtb3ZlRXZlbnRMaXN0ZW5lcnModGFyZ2V0LCB0eXBlcywgaGFuZGxlcikge1xuICAgIGVhY2goc3BsaXRTdHIodHlwZXMpLCBmdW5jdGlvbih0eXBlKSB7XG4gICAgICAgIHRhcmdldC5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIGhhbmRsZXIsIGZhbHNlKTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBmaW5kIGlmIGEgbm9kZSBpcyBpbiB0aGUgZ2l2ZW4gcGFyZW50XG4gKiBAbWV0aG9kIGhhc1BhcmVudFxuICogQHBhcmFtIHtIVE1MRWxlbWVudH0gbm9kZVxuICogQHBhcmFtIHtIVE1MRWxlbWVudH0gcGFyZW50XG4gKiBAcmV0dXJuIHtCb29sZWFufSBmb3VuZFxuICovXG5mdW5jdGlvbiBoYXNQYXJlbnQobm9kZSwgcGFyZW50KSB7XG4gICAgd2hpbGUgKG5vZGUpIHtcbiAgICAgICAgaWYgKG5vZGUgPT0gcGFyZW50KSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogc21hbGwgaW5kZXhPZiB3cmFwcGVyXG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyXG4gKiBAcGFyYW0ge1N0cmluZ30gZmluZFxuICogQHJldHVybnMge0Jvb2xlYW59IGZvdW5kXG4gKi9cbmZ1bmN0aW9uIGluU3RyKHN0ciwgZmluZCkge1xuICAgIHJldHVybiBzdHIuaW5kZXhPZihmaW5kKSA+IC0xO1xufVxuXG4vKipcbiAqIHNwbGl0IHN0cmluZyBvbiB3aGl0ZXNwYWNlXG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyXG4gKiBAcmV0dXJucyB7QXJyYXl9IHdvcmRzXG4gKi9cbmZ1bmN0aW9uIHNwbGl0U3RyKHN0cikge1xuICAgIHJldHVybiBzdHIudHJpbSgpLnNwbGl0KC9cXHMrL2cpO1xufVxuXG4vKipcbiAqIGZpbmQgaWYgYSBhcnJheSBjb250YWlucyB0aGUgb2JqZWN0IHVzaW5nIGluZGV4T2Ygb3IgYSBzaW1wbGUgcG9seUZpbGxcbiAqIEBwYXJhbSB7QXJyYXl9IHNyY1xuICogQHBhcmFtIHtTdHJpbmd9IGZpbmRcbiAqIEBwYXJhbSB7U3RyaW5nfSBbZmluZEJ5S2V5XVxuICogQHJldHVybiB7Qm9vbGVhbnxOdW1iZXJ9IGZhbHNlIHdoZW4gbm90IGZvdW5kLCBvciB0aGUgaW5kZXhcbiAqL1xuZnVuY3Rpb24gaW5BcnJheShzcmMsIGZpbmQsIGZpbmRCeUtleSkge1xuICAgIGlmIChzcmMuaW5kZXhPZiAmJiAhZmluZEJ5S2V5KSB7XG4gICAgICAgIHJldHVybiBzcmMuaW5kZXhPZihmaW5kKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgaSA9IDA7XG4gICAgICAgIHdoaWxlIChpIDwgc3JjLmxlbmd0aCkge1xuICAgICAgICAgICAgaWYgKChmaW5kQnlLZXkgJiYgc3JjW2ldW2ZpbmRCeUtleV0gPT0gZmluZCkgfHwgKCFmaW5kQnlLZXkgJiYgc3JjW2ldID09PSBmaW5kKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaSsrO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG59XG5cbi8qKlxuICogY29udmVydCBhcnJheS1saWtlIG9iamVjdHMgdG8gcmVhbCBhcnJheXNcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmpcbiAqIEByZXR1cm5zIHtBcnJheX1cbiAqL1xuZnVuY3Rpb24gdG9BcnJheShvYmopIHtcbiAgICByZXR1cm4gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwob2JqLCAwKTtcbn1cblxuLyoqXG4gKiB1bmlxdWUgYXJyYXkgd2l0aCBvYmplY3RzIGJhc2VkIG9uIGEga2V5IChsaWtlICdpZCcpIG9yIGp1c3QgYnkgdGhlIGFycmF5J3MgdmFsdWVcbiAqIEBwYXJhbSB7QXJyYXl9IHNyYyBbe2lkOjF9LHtpZDoyfSx7aWQ6MX1dXG4gKiBAcGFyYW0ge1N0cmluZ30gW2tleV1cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gW3NvcnQ9RmFsc2VdXG4gKiBAcmV0dXJucyB7QXJyYXl9IFt7aWQ6MX0se2lkOjJ9XVxuICovXG5mdW5jdGlvbiB1bmlxdWVBcnJheShzcmMsIGtleSwgc29ydCkge1xuICAgIHZhciByZXN1bHRzID0gW107XG4gICAgdmFyIHZhbHVlcyA9IFtdO1xuICAgIHZhciBpID0gMDtcblxuICAgIHdoaWxlIChpIDwgc3JjLmxlbmd0aCkge1xuICAgICAgICB2YXIgdmFsID0ga2V5ID8gc3JjW2ldW2tleV0gOiBzcmNbaV07XG4gICAgICAgIGlmIChpbkFycmF5KHZhbHVlcywgdmFsKSA8IDApIHtcbiAgICAgICAgICAgIHJlc3VsdHMucHVzaChzcmNbaV0pO1xuICAgICAgICB9XG4gICAgICAgIHZhbHVlc1tpXSA9IHZhbDtcbiAgICAgICAgaSsrO1xuICAgIH1cblxuICAgIGlmIChzb3J0KSB7XG4gICAgICAgIGlmICgha2V5KSB7XG4gICAgICAgICAgICByZXN1bHRzID0gcmVzdWx0cy5zb3J0KCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXN1bHRzID0gcmVzdWx0cy5zb3J0KGZ1bmN0aW9uIHNvcnRVbmlxdWVBcnJheShhLCBiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFba2V5XSA+IGJba2V5XTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdHM7XG59XG5cbi8qKlxuICogZ2V0IHRoZSBwcmVmaXhlZCBwcm9wZXJ0eVxuICogQHBhcmFtIHtPYmplY3R9IG9ialxuICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5XG4gKiBAcmV0dXJucyB7U3RyaW5nfFVuZGVmaW5lZH0gcHJlZml4ZWRcbiAqL1xuZnVuY3Rpb24gcHJlZml4ZWQob2JqLCBwcm9wZXJ0eSkge1xuICAgIHZhciBwcmVmaXgsIHByb3A7XG4gICAgdmFyIGNhbWVsUHJvcCA9IHByb3BlcnR5WzBdLnRvVXBwZXJDYXNlKCkgKyBwcm9wZXJ0eS5zbGljZSgxKTtcblxuICAgIHZhciBpID0gMDtcbiAgICB3aGlsZSAoaSA8IFZFTkRPUl9QUkVGSVhFUy5sZW5ndGgpIHtcbiAgICAgICAgcHJlZml4ID0gVkVORE9SX1BSRUZJWEVTW2ldO1xuICAgICAgICBwcm9wID0gKHByZWZpeCkgPyBwcmVmaXggKyBjYW1lbFByb3AgOiBwcm9wZXJ0eTtcblxuICAgICAgICBpZiAocHJvcCBpbiBvYmopIHtcbiAgICAgICAgICAgIHJldHVybiBwcm9wO1xuICAgICAgICB9XG4gICAgICAgIGkrKztcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBnZXQgYSB1bmlxdWUgaWRcbiAqIEByZXR1cm5zIHtudW1iZXJ9IHVuaXF1ZUlkXG4gKi9cbnZhciBfdW5pcXVlSWQgPSAxO1xuZnVuY3Rpb24gdW5pcXVlSWQoKSB7XG4gICAgcmV0dXJuIF91bmlxdWVJZCsrO1xufVxuXG4vKipcbiAqIGdldCB0aGUgd2luZG93IG9iamVjdCBvZiBhbiBlbGVtZW50XG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbGVtZW50XG4gKiBAcmV0dXJucyB7RG9jdW1lbnRWaWV3fFdpbmRvd31cbiAqL1xuZnVuY3Rpb24gZ2V0V2luZG93Rm9yRWxlbWVudChlbGVtZW50KSB7XG4gICAgdmFyIGRvYyA9IGVsZW1lbnQub3duZXJEb2N1bWVudCB8fCBlbGVtZW50O1xuICAgIHJldHVybiAoZG9jLmRlZmF1bHRWaWV3IHx8IGRvYy5wYXJlbnRXaW5kb3cgfHwgd2luZG93KTtcbn1cblxudmFyIE1PQklMRV9SRUdFWCA9IC9tb2JpbGV8dGFibGV0fGlwKGFkfGhvbmV8b2QpfGFuZHJvaWQvaTtcblxudmFyIFNVUFBPUlRfVE9VQ0ggPSAoJ29udG91Y2hzdGFydCcgaW4gd2luZG93KTtcbnZhciBTVVBQT1JUX1BPSU5URVJfRVZFTlRTID0gcHJlZml4ZWQod2luZG93LCAnUG9pbnRlckV2ZW50JykgIT09IHVuZGVmaW5lZDtcbnZhciBTVVBQT1JUX09OTFlfVE9VQ0ggPSBTVVBQT1JUX1RPVUNIICYmIE1PQklMRV9SRUdFWC50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuXG52YXIgSU5QVVRfVFlQRV9UT1VDSCA9ICd0b3VjaCc7XG52YXIgSU5QVVRfVFlQRV9QRU4gPSAncGVuJztcbnZhciBJTlBVVF9UWVBFX01PVVNFID0gJ21vdXNlJztcbnZhciBJTlBVVF9UWVBFX0tJTkVDVCA9ICdraW5lY3QnO1xuXG52YXIgQ09NUFVURV9JTlRFUlZBTCA9IDI1O1xuXG52YXIgSU5QVVRfU1RBUlQgPSAxO1xudmFyIElOUFVUX01PVkUgPSAyO1xudmFyIElOUFVUX0VORCA9IDQ7XG52YXIgSU5QVVRfQ0FOQ0VMID0gODtcblxudmFyIERJUkVDVElPTl9OT05FID0gMTtcbnZhciBESVJFQ1RJT05fTEVGVCA9IDI7XG52YXIgRElSRUNUSU9OX1JJR0hUID0gNDtcbnZhciBESVJFQ1RJT05fVVAgPSA4O1xudmFyIERJUkVDVElPTl9ET1dOID0gMTY7XG5cbnZhciBESVJFQ1RJT05fSE9SSVpPTlRBTCA9IERJUkVDVElPTl9MRUZUIHwgRElSRUNUSU9OX1JJR0hUO1xudmFyIERJUkVDVElPTl9WRVJUSUNBTCA9IERJUkVDVElPTl9VUCB8IERJUkVDVElPTl9ET1dOO1xudmFyIERJUkVDVElPTl9BTEwgPSBESVJFQ1RJT05fSE9SSVpPTlRBTCB8IERJUkVDVElPTl9WRVJUSUNBTDtcblxudmFyIFBST1BTX1hZID0gWyd4JywgJ3knXTtcbnZhciBQUk9QU19DTElFTlRfWFkgPSBbJ2NsaWVudFgnLCAnY2xpZW50WSddO1xuXG4vKipcbiAqIGNyZWF0ZSBuZXcgaW5wdXQgdHlwZSBtYW5hZ2VyXG4gKiBAcGFyYW0ge01hbmFnZXJ9IG1hbmFnZXJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gKiBAcmV0dXJucyB7SW5wdXR9XG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZnVuY3Rpb24gSW5wdXQobWFuYWdlciwgY2FsbGJhY2spIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5tYW5hZ2VyID0gbWFuYWdlcjtcbiAgICB0aGlzLmNhbGxiYWNrID0gY2FsbGJhY2s7XG4gICAgdGhpcy5lbGVtZW50ID0gbWFuYWdlci5lbGVtZW50O1xuICAgIHRoaXMudGFyZ2V0ID0gbWFuYWdlci5vcHRpb25zLmlucHV0VGFyZ2V0O1xuXG4gICAgLy8gc21hbGxlciB3cmFwcGVyIGFyb3VuZCB0aGUgaGFuZGxlciwgZm9yIHRoZSBzY29wZSBhbmQgdGhlIGVuYWJsZWQgc3RhdGUgb2YgdGhlIG1hbmFnZXIsXG4gICAgLy8gc28gd2hlbiBkaXNhYmxlZCB0aGUgaW5wdXQgZXZlbnRzIGFyZSBjb21wbGV0ZWx5IGJ5cGFzc2VkLlxuICAgIHRoaXMuZG9tSGFuZGxlciA9IGZ1bmN0aW9uKGV2KSB7XG4gICAgICAgIGlmIChib29sT3JGbihtYW5hZ2VyLm9wdGlvbnMuZW5hYmxlLCBbbWFuYWdlcl0pKSB7XG4gICAgICAgICAgICBzZWxmLmhhbmRsZXIoZXYpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMuaW5pdCgpO1xuXG59XG5cbklucHV0LnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBzaG91bGQgaGFuZGxlIHRoZSBpbnB1dEV2ZW50IGRhdGEgYW5kIHRyaWdnZXIgdGhlIGNhbGxiYWNrXG4gICAgICogQHZpcnR1YWxcbiAgICAgKi9cbiAgICBoYW5kbGVyOiBmdW5jdGlvbigpIHsgfSxcblxuICAgIC8qKlxuICAgICAqIGJpbmQgdGhlIGV2ZW50c1xuICAgICAqL1xuICAgIGluaXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLmV2RWwgJiYgYWRkRXZlbnRMaXN0ZW5lcnModGhpcy5lbGVtZW50LCB0aGlzLmV2RWwsIHRoaXMuZG9tSGFuZGxlcik7XG4gICAgICAgIHRoaXMuZXZUYXJnZXQgJiYgYWRkRXZlbnRMaXN0ZW5lcnModGhpcy50YXJnZXQsIHRoaXMuZXZUYXJnZXQsIHRoaXMuZG9tSGFuZGxlcik7XG4gICAgICAgIHRoaXMuZXZXaW4gJiYgYWRkRXZlbnRMaXN0ZW5lcnMoZ2V0V2luZG93Rm9yRWxlbWVudCh0aGlzLmVsZW1lbnQpLCB0aGlzLmV2V2luLCB0aGlzLmRvbUhhbmRsZXIpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiB1bmJpbmQgdGhlIGV2ZW50c1xuICAgICAqL1xuICAgIGRlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLmV2RWwgJiYgcmVtb3ZlRXZlbnRMaXN0ZW5lcnModGhpcy5lbGVtZW50LCB0aGlzLmV2RWwsIHRoaXMuZG9tSGFuZGxlcik7XG4gICAgICAgIHRoaXMuZXZUYXJnZXQgJiYgcmVtb3ZlRXZlbnRMaXN0ZW5lcnModGhpcy50YXJnZXQsIHRoaXMuZXZUYXJnZXQsIHRoaXMuZG9tSGFuZGxlcik7XG4gICAgICAgIHRoaXMuZXZXaW4gJiYgcmVtb3ZlRXZlbnRMaXN0ZW5lcnMoZ2V0V2luZG93Rm9yRWxlbWVudCh0aGlzLmVsZW1lbnQpLCB0aGlzLmV2V2luLCB0aGlzLmRvbUhhbmRsZXIpO1xuICAgIH1cbn07XG5cbi8qKlxuICogY3JlYXRlIG5ldyBpbnB1dCB0eXBlIG1hbmFnZXJcbiAqIGNhbGxlZCBieSB0aGUgTWFuYWdlciBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHtIYW1tZXJ9IG1hbmFnZXJcbiAqIEByZXR1cm5zIHtJbnB1dH1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlSW5wdXRJbnN0YW5jZShtYW5hZ2VyKSB7XG4gICAgdmFyIFR5cGU7XG4gICAgdmFyIGlucHV0Q2xhc3MgPSBtYW5hZ2VyLm9wdGlvbnMuaW5wdXRDbGFzcztcblxuICAgIGlmIChpbnB1dENsYXNzKSB7XG4gICAgICAgIFR5cGUgPSBpbnB1dENsYXNzO1xuICAgIH0gZWxzZSBpZiAoU1VQUE9SVF9QT0lOVEVSX0VWRU5UUykge1xuICAgICAgICBUeXBlID0gUG9pbnRlckV2ZW50SW5wdXQ7XG4gICAgfSBlbHNlIGlmIChTVVBQT1JUX09OTFlfVE9VQ0gpIHtcbiAgICAgICAgVHlwZSA9IFRvdWNoSW5wdXQ7XG4gICAgfSBlbHNlIGlmICghU1VQUE9SVF9UT1VDSCkge1xuICAgICAgICBUeXBlID0gTW91c2VJbnB1dDtcbiAgICB9IGVsc2Uge1xuICAgICAgICBUeXBlID0gVG91Y2hNb3VzZUlucHV0O1xuICAgIH1cbiAgICByZXR1cm4gbmV3IChUeXBlKShtYW5hZ2VyLCBpbnB1dEhhbmRsZXIpO1xufVxuXG4vKipcbiAqIGhhbmRsZSBpbnB1dCBldmVudHNcbiAqIEBwYXJhbSB7TWFuYWdlcn0gbWFuYWdlclxuICogQHBhcmFtIHtTdHJpbmd9IGV2ZW50VHlwZVxuICogQHBhcmFtIHtPYmplY3R9IGlucHV0XG4gKi9cbmZ1bmN0aW9uIGlucHV0SGFuZGxlcihtYW5hZ2VyLCBldmVudFR5cGUsIGlucHV0KSB7XG4gICAgdmFyIHBvaW50ZXJzTGVuID0gaW5wdXQucG9pbnRlcnMubGVuZ3RoO1xuICAgIHZhciBjaGFuZ2VkUG9pbnRlcnNMZW4gPSBpbnB1dC5jaGFuZ2VkUG9pbnRlcnMubGVuZ3RoO1xuICAgIHZhciBpc0ZpcnN0ID0gKGV2ZW50VHlwZSAmIElOUFVUX1NUQVJUICYmIChwb2ludGVyc0xlbiAtIGNoYW5nZWRQb2ludGVyc0xlbiA9PT0gMCkpO1xuICAgIHZhciBpc0ZpbmFsID0gKGV2ZW50VHlwZSAmIChJTlBVVF9FTkQgfCBJTlBVVF9DQU5DRUwpICYmIChwb2ludGVyc0xlbiAtIGNoYW5nZWRQb2ludGVyc0xlbiA9PT0gMCkpO1xuXG4gICAgaW5wdXQuaXNGaXJzdCA9ICEhaXNGaXJzdDtcbiAgICBpbnB1dC5pc0ZpbmFsID0gISFpc0ZpbmFsO1xuXG4gICAgaWYgKGlzRmlyc3QpIHtcbiAgICAgICAgbWFuYWdlci5zZXNzaW9uID0ge307XG4gICAgfVxuXG4gICAgLy8gc291cmNlIGV2ZW50IGlzIHRoZSBub3JtYWxpemVkIHZhbHVlIG9mIHRoZSBkb21FdmVudHNcbiAgICAvLyBsaWtlICd0b3VjaHN0YXJ0LCBtb3VzZXVwLCBwb2ludGVyZG93bidcbiAgICBpbnB1dC5ldmVudFR5cGUgPSBldmVudFR5cGU7XG5cbiAgICAvLyBjb21wdXRlIHNjYWxlLCByb3RhdGlvbiBldGNcbiAgICBjb21wdXRlSW5wdXREYXRhKG1hbmFnZXIsIGlucHV0KTtcblxuICAgIC8vIGVtaXQgc2VjcmV0IGV2ZW50XG4gICAgbWFuYWdlci5lbWl0KCdoYW1tZXIuaW5wdXQnLCBpbnB1dCk7XG5cbiAgICBtYW5hZ2VyLnJlY29nbml6ZShpbnB1dCk7XG4gICAgbWFuYWdlci5zZXNzaW9uLnByZXZJbnB1dCA9IGlucHV0O1xufVxuXG4vKipcbiAqIGV4dGVuZCB0aGUgZGF0YSB3aXRoIHNvbWUgdXNhYmxlIHByb3BlcnRpZXMgbGlrZSBzY2FsZSwgcm90YXRlLCB2ZWxvY2l0eSBldGNcbiAqIEBwYXJhbSB7T2JqZWN0fSBtYW5hZ2VyXG4gKiBAcGFyYW0ge09iamVjdH0gaW5wdXRcbiAqL1xuZnVuY3Rpb24gY29tcHV0ZUlucHV0RGF0YShtYW5hZ2VyLCBpbnB1dCkge1xuICAgIHZhciBzZXNzaW9uID0gbWFuYWdlci5zZXNzaW9uO1xuICAgIHZhciBwb2ludGVycyA9IGlucHV0LnBvaW50ZXJzO1xuICAgIHZhciBwb2ludGVyc0xlbmd0aCA9IHBvaW50ZXJzLmxlbmd0aDtcblxuICAgIC8vIHN0b3JlIHRoZSBmaXJzdCBpbnB1dCB0byBjYWxjdWxhdGUgdGhlIGRpc3RhbmNlIGFuZCBkaXJlY3Rpb25cbiAgICBpZiAoIXNlc3Npb24uZmlyc3RJbnB1dCkge1xuICAgICAgICBzZXNzaW9uLmZpcnN0SW5wdXQgPSBzaW1wbGVDbG9uZUlucHV0RGF0YShpbnB1dCk7XG4gICAgfVxuXG4gICAgLy8gdG8gY29tcHV0ZSBzY2FsZSBhbmQgcm90YXRpb24gd2UgbmVlZCB0byBzdG9yZSB0aGUgbXVsdGlwbGUgdG91Y2hlc1xuICAgIGlmIChwb2ludGVyc0xlbmd0aCA+IDEgJiYgIXNlc3Npb24uZmlyc3RNdWx0aXBsZSkge1xuICAgICAgICBzZXNzaW9uLmZpcnN0TXVsdGlwbGUgPSBzaW1wbGVDbG9uZUlucHV0RGF0YShpbnB1dCk7XG4gICAgfSBlbHNlIGlmIChwb2ludGVyc0xlbmd0aCA9PT0gMSkge1xuICAgICAgICBzZXNzaW9uLmZpcnN0TXVsdGlwbGUgPSBmYWxzZTtcbiAgICB9XG5cbiAgICB2YXIgZmlyc3RJbnB1dCA9IHNlc3Npb24uZmlyc3RJbnB1dDtcbiAgICB2YXIgZmlyc3RNdWx0aXBsZSA9IHNlc3Npb24uZmlyc3RNdWx0aXBsZTtcbiAgICB2YXIgb2Zmc2V0Q2VudGVyID0gZmlyc3RNdWx0aXBsZSA/IGZpcnN0TXVsdGlwbGUuY2VudGVyIDogZmlyc3RJbnB1dC5jZW50ZXI7XG5cbiAgICB2YXIgY2VudGVyID0gaW5wdXQuY2VudGVyID0gZ2V0Q2VudGVyKHBvaW50ZXJzKTtcbiAgICBpbnB1dC50aW1lU3RhbXAgPSBub3coKTtcbiAgICBpbnB1dC5kZWx0YVRpbWUgPSBpbnB1dC50aW1lU3RhbXAgLSBmaXJzdElucHV0LnRpbWVTdGFtcDtcblxuICAgIGlucHV0LmFuZ2xlID0gZ2V0QW5nbGUob2Zmc2V0Q2VudGVyLCBjZW50ZXIpO1xuICAgIGlucHV0LmRpc3RhbmNlID0gZ2V0RGlzdGFuY2Uob2Zmc2V0Q2VudGVyLCBjZW50ZXIpO1xuXG4gICAgY29tcHV0ZURlbHRhWFkoc2Vzc2lvbiwgaW5wdXQpO1xuICAgIGlucHV0Lm9mZnNldERpcmVjdGlvbiA9IGdldERpcmVjdGlvbihpbnB1dC5kZWx0YVgsIGlucHV0LmRlbHRhWSk7XG5cbiAgICB2YXIgb3ZlcmFsbFZlbG9jaXR5ID0gZ2V0VmVsb2NpdHkoaW5wdXQuZGVsdGFUaW1lLCBpbnB1dC5kZWx0YVgsIGlucHV0LmRlbHRhWSk7XG4gICAgaW5wdXQub3ZlcmFsbFZlbG9jaXR5WCA9IG92ZXJhbGxWZWxvY2l0eS54O1xuICAgIGlucHV0Lm92ZXJhbGxWZWxvY2l0eVkgPSBvdmVyYWxsVmVsb2NpdHkueTtcbiAgICBpbnB1dC5vdmVyYWxsVmVsb2NpdHkgPSAoYWJzKG92ZXJhbGxWZWxvY2l0eS54KSA+IGFicyhvdmVyYWxsVmVsb2NpdHkueSkpID8gb3ZlcmFsbFZlbG9jaXR5LnggOiBvdmVyYWxsVmVsb2NpdHkueTtcblxuICAgIGlucHV0LnNjYWxlID0gZmlyc3RNdWx0aXBsZSA/IGdldFNjYWxlKGZpcnN0TXVsdGlwbGUucG9pbnRlcnMsIHBvaW50ZXJzKSA6IDE7XG4gICAgaW5wdXQucm90YXRpb24gPSBmaXJzdE11bHRpcGxlID8gZ2V0Um90YXRpb24oZmlyc3RNdWx0aXBsZS5wb2ludGVycywgcG9pbnRlcnMpIDogMDtcblxuICAgIGlucHV0Lm1heFBvaW50ZXJzID0gIXNlc3Npb24ucHJldklucHV0ID8gaW5wdXQucG9pbnRlcnMubGVuZ3RoIDogKChpbnB1dC5wb2ludGVycy5sZW5ndGggPlxuICAgICAgICBzZXNzaW9uLnByZXZJbnB1dC5tYXhQb2ludGVycykgPyBpbnB1dC5wb2ludGVycy5sZW5ndGggOiBzZXNzaW9uLnByZXZJbnB1dC5tYXhQb2ludGVycyk7XG5cbiAgICBjb21wdXRlSW50ZXJ2YWxJbnB1dERhdGEoc2Vzc2lvbiwgaW5wdXQpO1xuXG4gICAgLy8gZmluZCB0aGUgY29ycmVjdCB0YXJnZXRcbiAgICB2YXIgdGFyZ2V0ID0gbWFuYWdlci5lbGVtZW50O1xuICAgIGlmIChoYXNQYXJlbnQoaW5wdXQuc3JjRXZlbnQudGFyZ2V0LCB0YXJnZXQpKSB7XG4gICAgICAgIHRhcmdldCA9IGlucHV0LnNyY0V2ZW50LnRhcmdldDtcbiAgICB9XG4gICAgaW5wdXQudGFyZ2V0ID0gdGFyZ2V0O1xufVxuXG5mdW5jdGlvbiBjb21wdXRlRGVsdGFYWShzZXNzaW9uLCBpbnB1dCkge1xuICAgIHZhciBjZW50ZXIgPSBpbnB1dC5jZW50ZXI7XG4gICAgdmFyIG9mZnNldCA9IHNlc3Npb24ub2Zmc2V0RGVsdGEgfHwge307XG4gICAgdmFyIHByZXZEZWx0YSA9IHNlc3Npb24ucHJldkRlbHRhIHx8IHt9O1xuICAgIHZhciBwcmV2SW5wdXQgPSBzZXNzaW9uLnByZXZJbnB1dCB8fCB7fTtcblxuICAgIGlmIChpbnB1dC5ldmVudFR5cGUgPT09IElOUFVUX1NUQVJUIHx8IHByZXZJbnB1dC5ldmVudFR5cGUgPT09IElOUFVUX0VORCkge1xuICAgICAgICBwcmV2RGVsdGEgPSBzZXNzaW9uLnByZXZEZWx0YSA9IHtcbiAgICAgICAgICAgIHg6IHByZXZJbnB1dC5kZWx0YVggfHwgMCxcbiAgICAgICAgICAgIHk6IHByZXZJbnB1dC5kZWx0YVkgfHwgMFxuICAgICAgICB9O1xuXG4gICAgICAgIG9mZnNldCA9IHNlc3Npb24ub2Zmc2V0RGVsdGEgPSB7XG4gICAgICAgICAgICB4OiBjZW50ZXIueCxcbiAgICAgICAgICAgIHk6IGNlbnRlci55XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgaW5wdXQuZGVsdGFYID0gcHJldkRlbHRhLnggKyAoY2VudGVyLnggLSBvZmZzZXQueCk7XG4gICAgaW5wdXQuZGVsdGFZID0gcHJldkRlbHRhLnkgKyAoY2VudGVyLnkgLSBvZmZzZXQueSk7XG59XG5cbi8qKlxuICogdmVsb2NpdHkgaXMgY2FsY3VsYXRlZCBldmVyeSB4IG1zXG4gKiBAcGFyYW0ge09iamVjdH0gc2Vzc2lvblxuICogQHBhcmFtIHtPYmplY3R9IGlucHV0XG4gKi9cbmZ1bmN0aW9uIGNvbXB1dGVJbnRlcnZhbElucHV0RGF0YShzZXNzaW9uLCBpbnB1dCkge1xuICAgIHZhciBsYXN0ID0gc2Vzc2lvbi5sYXN0SW50ZXJ2YWwgfHwgaW5wdXQsXG4gICAgICAgIGRlbHRhVGltZSA9IGlucHV0LnRpbWVTdGFtcCAtIGxhc3QudGltZVN0YW1wLFxuICAgICAgICB2ZWxvY2l0eSwgdmVsb2NpdHlYLCB2ZWxvY2l0eVksIGRpcmVjdGlvbjtcblxuICAgIGlmIChpbnB1dC5ldmVudFR5cGUgIT0gSU5QVVRfQ0FOQ0VMICYmIChkZWx0YVRpbWUgPiBDT01QVVRFX0lOVEVSVkFMIHx8IGxhc3QudmVsb2NpdHkgPT09IHVuZGVmaW5lZCkpIHtcbiAgICAgICAgdmFyIGRlbHRhWCA9IGlucHV0LmRlbHRhWCAtIGxhc3QuZGVsdGFYO1xuICAgICAgICB2YXIgZGVsdGFZID0gaW5wdXQuZGVsdGFZIC0gbGFzdC5kZWx0YVk7XG5cbiAgICAgICAgdmFyIHYgPSBnZXRWZWxvY2l0eShkZWx0YVRpbWUsIGRlbHRhWCwgZGVsdGFZKTtcbiAgICAgICAgdmVsb2NpdHlYID0gdi54O1xuICAgICAgICB2ZWxvY2l0eVkgPSB2Lnk7XG4gICAgICAgIHZlbG9jaXR5ID0gKGFicyh2LngpID4gYWJzKHYueSkpID8gdi54IDogdi55O1xuICAgICAgICBkaXJlY3Rpb24gPSBnZXREaXJlY3Rpb24oZGVsdGFYLCBkZWx0YVkpO1xuXG4gICAgICAgIHNlc3Npb24ubGFzdEludGVydmFsID0gaW5wdXQ7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdXNlIGxhdGVzdCB2ZWxvY2l0eSBpbmZvIGlmIGl0IGRvZXNuJ3Qgb3ZlcnRha2UgYSBtaW5pbXVtIHBlcmlvZFxuICAgICAgICB2ZWxvY2l0eSA9IGxhc3QudmVsb2NpdHk7XG4gICAgICAgIHZlbG9jaXR5WCA9IGxhc3QudmVsb2NpdHlYO1xuICAgICAgICB2ZWxvY2l0eVkgPSBsYXN0LnZlbG9jaXR5WTtcbiAgICAgICAgZGlyZWN0aW9uID0gbGFzdC5kaXJlY3Rpb247XG4gICAgfVxuXG4gICAgaW5wdXQudmVsb2NpdHkgPSB2ZWxvY2l0eTtcbiAgICBpbnB1dC52ZWxvY2l0eVggPSB2ZWxvY2l0eVg7XG4gICAgaW5wdXQudmVsb2NpdHlZID0gdmVsb2NpdHlZO1xuICAgIGlucHV0LmRpcmVjdGlvbiA9IGRpcmVjdGlvbjtcbn1cblxuLyoqXG4gKiBjcmVhdGUgYSBzaW1wbGUgY2xvbmUgZnJvbSB0aGUgaW5wdXQgdXNlZCBmb3Igc3RvcmFnZSBvZiBmaXJzdElucHV0IGFuZCBmaXJzdE11bHRpcGxlXG4gKiBAcGFyYW0ge09iamVjdH0gaW5wdXRcbiAqIEByZXR1cm5zIHtPYmplY3R9IGNsb25lZElucHV0RGF0YVxuICovXG5mdW5jdGlvbiBzaW1wbGVDbG9uZUlucHV0RGF0YShpbnB1dCkge1xuICAgIC8vIG1ha2UgYSBzaW1wbGUgY29weSBvZiB0aGUgcG9pbnRlcnMgYmVjYXVzZSB3ZSB3aWxsIGdldCBhIHJlZmVyZW5jZSBpZiB3ZSBkb24ndFxuICAgIC8vIHdlIG9ubHkgbmVlZCBjbGllbnRYWSBmb3IgdGhlIGNhbGN1bGF0aW9uc1xuICAgIHZhciBwb2ludGVycyA9IFtdO1xuICAgIHZhciBpID0gMDtcbiAgICB3aGlsZSAoaSA8IGlucHV0LnBvaW50ZXJzLmxlbmd0aCkge1xuICAgICAgICBwb2ludGVyc1tpXSA9IHtcbiAgICAgICAgICAgIGNsaWVudFg6IHJvdW5kKGlucHV0LnBvaW50ZXJzW2ldLmNsaWVudFgpLFxuICAgICAgICAgICAgY2xpZW50WTogcm91bmQoaW5wdXQucG9pbnRlcnNbaV0uY2xpZW50WSlcbiAgICAgICAgfTtcbiAgICAgICAgaSsrO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAgIHRpbWVTdGFtcDogbm93KCksXG4gICAgICAgIHBvaW50ZXJzOiBwb2ludGVycyxcbiAgICAgICAgY2VudGVyOiBnZXRDZW50ZXIocG9pbnRlcnMpLFxuICAgICAgICBkZWx0YVg6IGlucHV0LmRlbHRhWCxcbiAgICAgICAgZGVsdGFZOiBpbnB1dC5kZWx0YVlcbiAgICB9O1xufVxuXG4vKipcbiAqIGdldCB0aGUgY2VudGVyIG9mIGFsbCB0aGUgcG9pbnRlcnNcbiAqIEBwYXJhbSB7QXJyYXl9IHBvaW50ZXJzXG4gKiBAcmV0dXJuIHtPYmplY3R9IGNlbnRlciBjb250YWlucyBgeGAgYW5kIGB5YCBwcm9wZXJ0aWVzXG4gKi9cbmZ1bmN0aW9uIGdldENlbnRlcihwb2ludGVycykge1xuICAgIHZhciBwb2ludGVyc0xlbmd0aCA9IHBvaW50ZXJzLmxlbmd0aDtcblxuICAgIC8vIG5vIG5lZWQgdG8gbG9vcCB3aGVuIG9ubHkgb25lIHRvdWNoXG4gICAgaWYgKHBvaW50ZXJzTGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB4OiByb3VuZChwb2ludGVyc1swXS5jbGllbnRYKSxcbiAgICAgICAgICAgIHk6IHJvdW5kKHBvaW50ZXJzWzBdLmNsaWVudFkpXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIHggPSAwLCB5ID0gMCwgaSA9IDA7XG4gICAgd2hpbGUgKGkgPCBwb2ludGVyc0xlbmd0aCkge1xuICAgICAgICB4ICs9IHBvaW50ZXJzW2ldLmNsaWVudFg7XG4gICAgICAgIHkgKz0gcG9pbnRlcnNbaV0uY2xpZW50WTtcbiAgICAgICAgaSsrO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAgIHg6IHJvdW5kKHggLyBwb2ludGVyc0xlbmd0aCksXG4gICAgICAgIHk6IHJvdW5kKHkgLyBwb2ludGVyc0xlbmd0aClcbiAgICB9O1xufVxuXG4vKipcbiAqIGNhbGN1bGF0ZSB0aGUgdmVsb2NpdHkgYmV0d2VlbiB0d28gcG9pbnRzLiB1bml0IGlzIGluIHB4IHBlciBtcy5cbiAqIEBwYXJhbSB7TnVtYmVyfSBkZWx0YVRpbWVcbiAqIEBwYXJhbSB7TnVtYmVyfSB4XG4gKiBAcGFyYW0ge051bWJlcn0geVxuICogQHJldHVybiB7T2JqZWN0fSB2ZWxvY2l0eSBgeGAgYW5kIGB5YFxuICovXG5mdW5jdGlvbiBnZXRWZWxvY2l0eShkZWx0YVRpbWUsIHgsIHkpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICB4OiB4IC8gZGVsdGFUaW1lIHx8IDAsXG4gICAgICAgIHk6IHkgLyBkZWx0YVRpbWUgfHwgMFxuICAgIH07XG59XG5cbi8qKlxuICogZ2V0IHRoZSBkaXJlY3Rpb24gYmV0d2VlbiB0d28gcG9pbnRzXG4gKiBAcGFyYW0ge051bWJlcn0geFxuICogQHBhcmFtIHtOdW1iZXJ9IHlcbiAqIEByZXR1cm4ge051bWJlcn0gZGlyZWN0aW9uXG4gKi9cbmZ1bmN0aW9uIGdldERpcmVjdGlvbih4LCB5KSB7XG4gICAgaWYgKHggPT09IHkpIHtcbiAgICAgICAgcmV0dXJuIERJUkVDVElPTl9OT05FO1xuICAgIH1cblxuICAgIGlmIChhYnMoeCkgPj0gYWJzKHkpKSB7XG4gICAgICAgIHJldHVybiB4IDwgMCA/IERJUkVDVElPTl9MRUZUIDogRElSRUNUSU9OX1JJR0hUO1xuICAgIH1cbiAgICByZXR1cm4geSA8IDAgPyBESVJFQ1RJT05fVVAgOiBESVJFQ1RJT05fRE9XTjtcbn1cblxuLyoqXG4gKiBjYWxjdWxhdGUgdGhlIGFic29sdXRlIGRpc3RhbmNlIGJldHdlZW4gdHdvIHBvaW50c1xuICogQHBhcmFtIHtPYmplY3R9IHAxIHt4LCB5fVxuICogQHBhcmFtIHtPYmplY3R9IHAyIHt4LCB5fVxuICogQHBhcmFtIHtBcnJheX0gW3Byb3BzXSBjb250YWluaW5nIHggYW5kIHkga2V5c1xuICogQHJldHVybiB7TnVtYmVyfSBkaXN0YW5jZVxuICovXG5mdW5jdGlvbiBnZXREaXN0YW5jZShwMSwgcDIsIHByb3BzKSB7XG4gICAgaWYgKCFwcm9wcykge1xuICAgICAgICBwcm9wcyA9IFBST1BTX1hZO1xuICAgIH1cbiAgICB2YXIgeCA9IHAyW3Byb3BzWzBdXSAtIHAxW3Byb3BzWzBdXSxcbiAgICAgICAgeSA9IHAyW3Byb3BzWzFdXSAtIHAxW3Byb3BzWzFdXTtcblxuICAgIHJldHVybiBNYXRoLnNxcnQoKHggKiB4KSArICh5ICogeSkpO1xufVxuXG4vKipcbiAqIGNhbGN1bGF0ZSB0aGUgYW5nbGUgYmV0d2VlbiB0d28gY29vcmRpbmF0ZXNcbiAqIEBwYXJhbSB7T2JqZWN0fSBwMVxuICogQHBhcmFtIHtPYmplY3R9IHAyXG4gKiBAcGFyYW0ge0FycmF5fSBbcHJvcHNdIGNvbnRhaW5pbmcgeCBhbmQgeSBrZXlzXG4gKiBAcmV0dXJuIHtOdW1iZXJ9IGFuZ2xlXG4gKi9cbmZ1bmN0aW9uIGdldEFuZ2xlKHAxLCBwMiwgcHJvcHMpIHtcbiAgICBpZiAoIXByb3BzKSB7XG4gICAgICAgIHByb3BzID0gUFJPUFNfWFk7XG4gICAgfVxuICAgIHZhciB4ID0gcDJbcHJvcHNbMF1dIC0gcDFbcHJvcHNbMF1dLFxuICAgICAgICB5ID0gcDJbcHJvcHNbMV1dIC0gcDFbcHJvcHNbMV1dO1xuICAgIHJldHVybiBNYXRoLmF0YW4yKHksIHgpICogMTgwIC8gTWF0aC5QSTtcbn1cblxuLyoqXG4gKiBjYWxjdWxhdGUgdGhlIHJvdGF0aW9uIGRlZ3JlZXMgYmV0d2VlbiB0d28gcG9pbnRlcnNldHNcbiAqIEBwYXJhbSB7QXJyYXl9IHN0YXJ0IGFycmF5IG9mIHBvaW50ZXJzXG4gKiBAcGFyYW0ge0FycmF5fSBlbmQgYXJyYXkgb2YgcG9pbnRlcnNcbiAqIEByZXR1cm4ge051bWJlcn0gcm90YXRpb25cbiAqL1xuZnVuY3Rpb24gZ2V0Um90YXRpb24oc3RhcnQsIGVuZCkge1xuICAgIHJldHVybiBnZXRBbmdsZShlbmRbMV0sIGVuZFswXSwgUFJPUFNfQ0xJRU5UX1hZKSArIGdldEFuZ2xlKHN0YXJ0WzFdLCBzdGFydFswXSwgUFJPUFNfQ0xJRU5UX1hZKTtcbn1cblxuLyoqXG4gKiBjYWxjdWxhdGUgdGhlIHNjYWxlIGZhY3RvciBiZXR3ZWVuIHR3byBwb2ludGVyc2V0c1xuICogbm8gc2NhbGUgaXMgMSwgYW5kIGdvZXMgZG93biB0byAwIHdoZW4gcGluY2hlZCB0b2dldGhlciwgYW5kIGJpZ2dlciB3aGVuIHBpbmNoZWQgb3V0XG4gKiBAcGFyYW0ge0FycmF5fSBzdGFydCBhcnJheSBvZiBwb2ludGVyc1xuICogQHBhcmFtIHtBcnJheX0gZW5kIGFycmF5IG9mIHBvaW50ZXJzXG4gKiBAcmV0dXJuIHtOdW1iZXJ9IHNjYWxlXG4gKi9cbmZ1bmN0aW9uIGdldFNjYWxlKHN0YXJ0LCBlbmQpIHtcbiAgICByZXR1cm4gZ2V0RGlzdGFuY2UoZW5kWzBdLCBlbmRbMV0sIFBST1BTX0NMSUVOVF9YWSkgLyBnZXREaXN0YW5jZShzdGFydFswXSwgc3RhcnRbMV0sIFBST1BTX0NMSUVOVF9YWSk7XG59XG5cbnZhciBNT1VTRV9JTlBVVF9NQVAgPSB7XG4gICAgbW91c2Vkb3duOiBJTlBVVF9TVEFSVCxcbiAgICBtb3VzZW1vdmU6IElOUFVUX01PVkUsXG4gICAgbW91c2V1cDogSU5QVVRfRU5EXG59O1xuXG52YXIgTU9VU0VfRUxFTUVOVF9FVkVOVFMgPSAnbW91c2Vkb3duJztcbnZhciBNT1VTRV9XSU5ET1dfRVZFTlRTID0gJ21vdXNlbW92ZSBtb3VzZXVwJztcblxuLyoqXG4gKiBNb3VzZSBldmVudHMgaW5wdXRcbiAqIEBjb25zdHJ1Y3RvclxuICogQGV4dGVuZHMgSW5wdXRcbiAqL1xuZnVuY3Rpb24gTW91c2VJbnB1dCgpIHtcbiAgICB0aGlzLmV2RWwgPSBNT1VTRV9FTEVNRU5UX0VWRU5UUztcbiAgICB0aGlzLmV2V2luID0gTU9VU0VfV0lORE9XX0VWRU5UUztcblxuICAgIHRoaXMucHJlc3NlZCA9IGZhbHNlOyAvLyBtb3VzZWRvd24gc3RhdGVcblxuICAgIElucHV0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cbmluaGVyaXQoTW91c2VJbnB1dCwgSW5wdXQsIHtcbiAgICAvKipcbiAgICAgKiBoYW5kbGUgbW91c2UgZXZlbnRzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGV2XG4gICAgICovXG4gICAgaGFuZGxlcjogZnVuY3Rpb24gTUVoYW5kbGVyKGV2KSB7XG4gICAgICAgIHZhciBldmVudFR5cGUgPSBNT1VTRV9JTlBVVF9NQVBbZXYudHlwZV07XG5cbiAgICAgICAgLy8gb24gc3RhcnQgd2Ugd2FudCB0byBoYXZlIHRoZSBsZWZ0IG1vdXNlIGJ1dHRvbiBkb3duXG4gICAgICAgIGlmIChldmVudFR5cGUgJiBJTlBVVF9TVEFSVCAmJiBldi5idXR0b24gPT09IDApIHtcbiAgICAgICAgICAgIHRoaXMucHJlc3NlZCA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnRUeXBlICYgSU5QVVRfTU9WRSAmJiBldi53aGljaCAhPT0gMSkge1xuICAgICAgICAgICAgZXZlbnRUeXBlID0gSU5QVVRfRU5EO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbW91c2UgbXVzdCBiZSBkb3duXG4gICAgICAgIGlmICghdGhpcy5wcmVzc2VkKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnRUeXBlICYgSU5QVVRfRU5EKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNzZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY2FsbGJhY2sodGhpcy5tYW5hZ2VyLCBldmVudFR5cGUsIHtcbiAgICAgICAgICAgIHBvaW50ZXJzOiBbZXZdLFxuICAgICAgICAgICAgY2hhbmdlZFBvaW50ZXJzOiBbZXZdLFxuICAgICAgICAgICAgcG9pbnRlclR5cGU6IElOUFVUX1RZUEVfTU9VU0UsXG4gICAgICAgICAgICBzcmNFdmVudDogZXZcbiAgICAgICAgfSk7XG4gICAgfVxufSk7XG5cbnZhciBQT0lOVEVSX0lOUFVUX01BUCA9IHtcbiAgICBwb2ludGVyZG93bjogSU5QVVRfU1RBUlQsXG4gICAgcG9pbnRlcm1vdmU6IElOUFVUX01PVkUsXG4gICAgcG9pbnRlcnVwOiBJTlBVVF9FTkQsXG4gICAgcG9pbnRlcmNhbmNlbDogSU5QVVRfQ0FOQ0VMLFxuICAgIHBvaW50ZXJvdXQ6IElOUFVUX0NBTkNFTFxufTtcblxuLy8gaW4gSUUxMCB0aGUgcG9pbnRlciB0eXBlcyBpcyBkZWZpbmVkIGFzIGFuIGVudW1cbnZhciBJRTEwX1BPSU5URVJfVFlQRV9FTlVNID0ge1xuICAgIDI6IElOUFVUX1RZUEVfVE9VQ0gsXG4gICAgMzogSU5QVVRfVFlQRV9QRU4sXG4gICAgNDogSU5QVVRfVFlQRV9NT1VTRSxcbiAgICA1OiBJTlBVVF9UWVBFX0tJTkVDVCAvLyBzZWUgaHR0cHM6Ly90d2l0dGVyLmNvbS9qYWNvYnJvc3NpL3N0YXR1cy80ODA1OTY0Mzg0ODk4OTA4MTZcbn07XG5cbnZhciBQT0lOVEVSX0VMRU1FTlRfRVZFTlRTID0gJ3BvaW50ZXJkb3duJztcbnZhciBQT0lOVEVSX1dJTkRPV19FVkVOVFMgPSAncG9pbnRlcm1vdmUgcG9pbnRlcnVwIHBvaW50ZXJjYW5jZWwnO1xuXG4vLyBJRTEwIGhhcyBwcmVmaXhlZCBzdXBwb3J0LCBhbmQgY2FzZS1zZW5zaXRpdmVcbmlmICh3aW5kb3cuTVNQb2ludGVyRXZlbnQgJiYgIXdpbmRvdy5Qb2ludGVyRXZlbnQpIHtcbiAgICBQT0lOVEVSX0VMRU1FTlRfRVZFTlRTID0gJ01TUG9pbnRlckRvd24nO1xuICAgIFBPSU5URVJfV0lORE9XX0VWRU5UUyA9ICdNU1BvaW50ZXJNb3ZlIE1TUG9pbnRlclVwIE1TUG9pbnRlckNhbmNlbCc7XG59XG5cbi8qKlxuICogUG9pbnRlciBldmVudHMgaW5wdXRcbiAqIEBjb25zdHJ1Y3RvclxuICogQGV4dGVuZHMgSW5wdXRcbiAqL1xuZnVuY3Rpb24gUG9pbnRlckV2ZW50SW5wdXQoKSB7XG4gICAgdGhpcy5ldkVsID0gUE9JTlRFUl9FTEVNRU5UX0VWRU5UUztcbiAgICB0aGlzLmV2V2luID0gUE9JTlRFUl9XSU5ET1dfRVZFTlRTO1xuXG4gICAgSW5wdXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIHRoaXMuc3RvcmUgPSAodGhpcy5tYW5hZ2VyLnNlc3Npb24ucG9pbnRlckV2ZW50cyA9IFtdKTtcbn1cblxuaW5oZXJpdChQb2ludGVyRXZlbnRJbnB1dCwgSW5wdXQsIHtcbiAgICAvKipcbiAgICAgKiBoYW5kbGUgbW91c2UgZXZlbnRzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGV2XG4gICAgICovXG4gICAgaGFuZGxlcjogZnVuY3Rpb24gUEVoYW5kbGVyKGV2KSB7XG4gICAgICAgIHZhciBzdG9yZSA9IHRoaXMuc3RvcmU7XG4gICAgICAgIHZhciByZW1vdmVQb2ludGVyID0gZmFsc2U7XG5cbiAgICAgICAgdmFyIGV2ZW50VHlwZU5vcm1hbGl6ZWQgPSBldi50eXBlLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnbXMnLCAnJyk7XG4gICAgICAgIHZhciBldmVudFR5cGUgPSBQT0lOVEVSX0lOUFVUX01BUFtldmVudFR5cGVOb3JtYWxpemVkXTtcbiAgICAgICAgdmFyIHBvaW50ZXJUeXBlID0gSUUxMF9QT0lOVEVSX1RZUEVfRU5VTVtldi5wb2ludGVyVHlwZV0gfHwgZXYucG9pbnRlclR5cGU7XG5cbiAgICAgICAgdmFyIGlzVG91Y2ggPSAocG9pbnRlclR5cGUgPT0gSU5QVVRfVFlQRV9UT1VDSCk7XG5cbiAgICAgICAgLy8gZ2V0IGluZGV4IG9mIHRoZSBldmVudCBpbiB0aGUgc3RvcmVcbiAgICAgICAgdmFyIHN0b3JlSW5kZXggPSBpbkFycmF5KHN0b3JlLCBldi5wb2ludGVySWQsICdwb2ludGVySWQnKTtcblxuICAgICAgICAvLyBzdGFydCBhbmQgbW91c2UgbXVzdCBiZSBkb3duXG4gICAgICAgIGlmIChldmVudFR5cGUgJiBJTlBVVF9TVEFSVCAmJiAoZXYuYnV0dG9uID09PSAwIHx8IGlzVG91Y2gpKSB7XG4gICAgICAgICAgICBpZiAoc3RvcmVJbmRleCA8IDApIHtcbiAgICAgICAgICAgICAgICBzdG9yZS5wdXNoKGV2KTtcbiAgICAgICAgICAgICAgICBzdG9yZUluZGV4ID0gc3RvcmUubGVuZ3RoIC0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChldmVudFR5cGUgJiAoSU5QVVRfRU5EIHwgSU5QVVRfQ0FOQ0VMKSkge1xuICAgICAgICAgICAgcmVtb3ZlUG9pbnRlciA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpdCBub3QgZm91bmQsIHNvIHRoZSBwb2ludGVyIGhhc24ndCBiZWVuIGRvd24gKHNvIGl0J3MgcHJvYmFibHkgYSBob3ZlcilcbiAgICAgICAgaWYgKHN0b3JlSW5kZXggPCAwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyB1cGRhdGUgdGhlIGV2ZW50IGluIHRoZSBzdG9yZVxuICAgICAgICBzdG9yZVtzdG9yZUluZGV4XSA9IGV2O1xuXG4gICAgICAgIHRoaXMuY2FsbGJhY2sodGhpcy5tYW5hZ2VyLCBldmVudFR5cGUsIHtcbiAgICAgICAgICAgIHBvaW50ZXJzOiBzdG9yZSxcbiAgICAgICAgICAgIGNoYW5nZWRQb2ludGVyczogW2V2XSxcbiAgICAgICAgICAgIHBvaW50ZXJUeXBlOiBwb2ludGVyVHlwZSxcbiAgICAgICAgICAgIHNyY0V2ZW50OiBldlxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAocmVtb3ZlUG9pbnRlcikge1xuICAgICAgICAgICAgLy8gcmVtb3ZlIGZyb20gdGhlIHN0b3JlXG4gICAgICAgICAgICBzdG9yZS5zcGxpY2Uoc3RvcmVJbmRleCwgMSk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxudmFyIFNJTkdMRV9UT1VDSF9JTlBVVF9NQVAgPSB7XG4gICAgdG91Y2hzdGFydDogSU5QVVRfU1RBUlQsXG4gICAgdG91Y2htb3ZlOiBJTlBVVF9NT1ZFLFxuICAgIHRvdWNoZW5kOiBJTlBVVF9FTkQsXG4gICAgdG91Y2hjYW5jZWw6IElOUFVUX0NBTkNFTFxufTtcblxudmFyIFNJTkdMRV9UT1VDSF9UQVJHRVRfRVZFTlRTID0gJ3RvdWNoc3RhcnQnO1xudmFyIFNJTkdMRV9UT1VDSF9XSU5ET1dfRVZFTlRTID0gJ3RvdWNoc3RhcnQgdG91Y2htb3ZlIHRvdWNoZW5kIHRvdWNoY2FuY2VsJztcblxuLyoqXG4gKiBUb3VjaCBldmVudHMgaW5wdXRcbiAqIEBjb25zdHJ1Y3RvclxuICogQGV4dGVuZHMgSW5wdXRcbiAqL1xuZnVuY3Rpb24gU2luZ2xlVG91Y2hJbnB1dCgpIHtcbiAgICB0aGlzLmV2VGFyZ2V0ID0gU0lOR0xFX1RPVUNIX1RBUkdFVF9FVkVOVFM7XG4gICAgdGhpcy5ldldpbiA9IFNJTkdMRV9UT1VDSF9XSU5ET1dfRVZFTlRTO1xuICAgIHRoaXMuc3RhcnRlZCA9IGZhbHNlO1xuXG4gICAgSW5wdXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuaW5oZXJpdChTaW5nbGVUb3VjaElucHV0LCBJbnB1dCwge1xuICAgIGhhbmRsZXI6IGZ1bmN0aW9uIFRFaGFuZGxlcihldikge1xuICAgICAgICB2YXIgdHlwZSA9IFNJTkdMRV9UT1VDSF9JTlBVVF9NQVBbZXYudHlwZV07XG5cbiAgICAgICAgLy8gc2hvdWxkIHdlIGhhbmRsZSB0aGUgdG91Y2ggZXZlbnRzP1xuICAgICAgICBpZiAodHlwZSA9PT0gSU5QVVRfU1RBUlQpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhcnRlZCA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMuc3RhcnRlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHRvdWNoZXMgPSBub3JtYWxpemVTaW5nbGVUb3VjaGVzLmNhbGwodGhpcywgZXYsIHR5cGUpO1xuXG4gICAgICAgIC8vIHdoZW4gZG9uZSwgcmVzZXQgdGhlIHN0YXJ0ZWQgc3RhdGVcbiAgICAgICAgaWYgKHR5cGUgJiAoSU5QVVRfRU5EIHwgSU5QVVRfQ0FOQ0VMKSAmJiB0b3VjaGVzWzBdLmxlbmd0aCAtIHRvdWNoZXNbMV0ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLnN0YXJ0ZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY2FsbGJhY2sodGhpcy5tYW5hZ2VyLCB0eXBlLCB7XG4gICAgICAgICAgICBwb2ludGVyczogdG91Y2hlc1swXSxcbiAgICAgICAgICAgIGNoYW5nZWRQb2ludGVyczogdG91Y2hlc1sxXSxcbiAgICAgICAgICAgIHBvaW50ZXJUeXBlOiBJTlBVVF9UWVBFX1RPVUNILFxuICAgICAgICAgICAgc3JjRXZlbnQ6IGV2XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG4vKipcbiAqIEB0aGlzIHtUb3VjaElucHV0fVxuICogQHBhcmFtIHtPYmplY3R9IGV2XG4gKiBAcGFyYW0ge051bWJlcn0gdHlwZSBmbGFnXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfEFycmF5fSBbYWxsLCBjaGFuZ2VkXVxuICovXG5mdW5jdGlvbiBub3JtYWxpemVTaW5nbGVUb3VjaGVzKGV2LCB0eXBlKSB7XG4gICAgdmFyIGFsbCA9IHRvQXJyYXkoZXYudG91Y2hlcyk7XG4gICAgdmFyIGNoYW5nZWQgPSB0b0FycmF5KGV2LmNoYW5nZWRUb3VjaGVzKTtcblxuICAgIGlmICh0eXBlICYgKElOUFVUX0VORCB8IElOUFVUX0NBTkNFTCkpIHtcbiAgICAgICAgYWxsID0gdW5pcXVlQXJyYXkoYWxsLmNvbmNhdChjaGFuZ2VkKSwgJ2lkZW50aWZpZXInLCB0cnVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gW2FsbCwgY2hhbmdlZF07XG59XG5cbnZhciBUT1VDSF9JTlBVVF9NQVAgPSB7XG4gICAgdG91Y2hzdGFydDogSU5QVVRfU1RBUlQsXG4gICAgdG91Y2htb3ZlOiBJTlBVVF9NT1ZFLFxuICAgIHRvdWNoZW5kOiBJTlBVVF9FTkQsXG4gICAgdG91Y2hjYW5jZWw6IElOUFVUX0NBTkNFTFxufTtcblxudmFyIFRPVUNIX1RBUkdFVF9FVkVOVFMgPSAndG91Y2hzdGFydCB0b3VjaG1vdmUgdG91Y2hlbmQgdG91Y2hjYW5jZWwnO1xuXG4vKipcbiAqIE11bHRpLXVzZXIgdG91Y2ggZXZlbnRzIGlucHV0XG4gKiBAY29uc3RydWN0b3JcbiAqIEBleHRlbmRzIElucHV0XG4gKi9cbmZ1bmN0aW9uIFRvdWNoSW5wdXQoKSB7XG4gICAgdGhpcy5ldlRhcmdldCA9IFRPVUNIX1RBUkdFVF9FVkVOVFM7XG4gICAgdGhpcy50YXJnZXRJZHMgPSB7fTtcblxuICAgIElucHV0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cbmluaGVyaXQoVG91Y2hJbnB1dCwgSW5wdXQsIHtcbiAgICBoYW5kbGVyOiBmdW5jdGlvbiBNVEVoYW5kbGVyKGV2KSB7XG4gICAgICAgIHZhciB0eXBlID0gVE9VQ0hfSU5QVVRfTUFQW2V2LnR5cGVdO1xuICAgICAgICB2YXIgdG91Y2hlcyA9IGdldFRvdWNoZXMuY2FsbCh0aGlzLCBldiwgdHlwZSk7XG4gICAgICAgIGlmICghdG91Y2hlcykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jYWxsYmFjayh0aGlzLm1hbmFnZXIsIHR5cGUsIHtcbiAgICAgICAgICAgIHBvaW50ZXJzOiB0b3VjaGVzWzBdLFxuICAgICAgICAgICAgY2hhbmdlZFBvaW50ZXJzOiB0b3VjaGVzWzFdLFxuICAgICAgICAgICAgcG9pbnRlclR5cGU6IElOUFVUX1RZUEVfVE9VQ0gsXG4gICAgICAgICAgICBzcmNFdmVudDogZXZcbiAgICAgICAgfSk7XG4gICAgfVxufSk7XG5cbi8qKlxuICogQHRoaXMge1RvdWNoSW5wdXR9XG4gKiBAcGFyYW0ge09iamVjdH0gZXZcbiAqIEBwYXJhbSB7TnVtYmVyfSB0eXBlIGZsYWdcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR8QXJyYXl9IFthbGwsIGNoYW5nZWRdXG4gKi9cbmZ1bmN0aW9uIGdldFRvdWNoZXMoZXYsIHR5cGUpIHtcbiAgICB2YXIgYWxsVG91Y2hlcyA9IHRvQXJyYXkoZXYudG91Y2hlcyk7XG4gICAgdmFyIHRhcmdldElkcyA9IHRoaXMudGFyZ2V0SWRzO1xuXG4gICAgLy8gd2hlbiB0aGVyZSBpcyBvbmx5IG9uZSB0b3VjaCwgdGhlIHByb2Nlc3MgY2FuIGJlIHNpbXBsaWZpZWRcbiAgICBpZiAodHlwZSAmIChJTlBVVF9TVEFSVCB8IElOUFVUX01PVkUpICYmIGFsbFRvdWNoZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHRhcmdldElkc1thbGxUb3VjaGVzWzBdLmlkZW50aWZpZXJdID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIFthbGxUb3VjaGVzLCBhbGxUb3VjaGVzXTtcbiAgICB9XG5cbiAgICB2YXIgaSxcbiAgICAgICAgdGFyZ2V0VG91Y2hlcyxcbiAgICAgICAgY2hhbmdlZFRvdWNoZXMgPSB0b0FycmF5KGV2LmNoYW5nZWRUb3VjaGVzKSxcbiAgICAgICAgY2hhbmdlZFRhcmdldFRvdWNoZXMgPSBbXSxcbiAgICAgICAgdGFyZ2V0ID0gdGhpcy50YXJnZXQ7XG5cbiAgICAvLyBnZXQgdGFyZ2V0IHRvdWNoZXMgZnJvbSB0b3VjaGVzXG4gICAgdGFyZ2V0VG91Y2hlcyA9IGFsbFRvdWNoZXMuZmlsdGVyKGZ1bmN0aW9uKHRvdWNoKSB7XG4gICAgICAgIHJldHVybiBoYXNQYXJlbnQodG91Y2gudGFyZ2V0LCB0YXJnZXQpO1xuICAgIH0pO1xuXG4gICAgLy8gY29sbGVjdCB0b3VjaGVzXG4gICAgaWYgKHR5cGUgPT09IElOUFVUX1NUQVJUKSB7XG4gICAgICAgIGkgPSAwO1xuICAgICAgICB3aGlsZSAoaSA8IHRhcmdldFRvdWNoZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0YXJnZXRJZHNbdGFyZ2V0VG91Y2hlc1tpXS5pZGVudGlmaWVyXSA9IHRydWU7XG4gICAgICAgICAgICBpKys7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBmaWx0ZXIgY2hhbmdlZCB0b3VjaGVzIHRvIG9ubHkgY29udGFpbiB0b3VjaGVzIHRoYXQgZXhpc3QgaW4gdGhlIGNvbGxlY3RlZCB0YXJnZXQgaWRzXG4gICAgaSA9IDA7XG4gICAgd2hpbGUgKGkgPCBjaGFuZ2VkVG91Y2hlcy5sZW5ndGgpIHtcbiAgICAgICAgaWYgKHRhcmdldElkc1tjaGFuZ2VkVG91Y2hlc1tpXS5pZGVudGlmaWVyXSkge1xuICAgICAgICAgICAgY2hhbmdlZFRhcmdldFRvdWNoZXMucHVzaChjaGFuZ2VkVG91Y2hlc1tpXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBjbGVhbnVwIHJlbW92ZWQgdG91Y2hlc1xuICAgICAgICBpZiAodHlwZSAmIChJTlBVVF9FTkQgfCBJTlBVVF9DQU5DRUwpKSB7XG4gICAgICAgICAgICBkZWxldGUgdGFyZ2V0SWRzW2NoYW5nZWRUb3VjaGVzW2ldLmlkZW50aWZpZXJdO1xuICAgICAgICB9XG4gICAgICAgIGkrKztcbiAgICB9XG5cbiAgICBpZiAoIWNoYW5nZWRUYXJnZXRUb3VjaGVzLmxlbmd0aCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgcmV0dXJuIFtcbiAgICAgICAgLy8gbWVyZ2UgdGFyZ2V0VG91Y2hlcyB3aXRoIGNoYW5nZWRUYXJnZXRUb3VjaGVzIHNvIGl0IGNvbnRhaW5zIEFMTCB0b3VjaGVzLCBpbmNsdWRpbmcgJ2VuZCcgYW5kICdjYW5jZWwnXG4gICAgICAgIHVuaXF1ZUFycmF5KHRhcmdldFRvdWNoZXMuY29uY2F0KGNoYW5nZWRUYXJnZXRUb3VjaGVzKSwgJ2lkZW50aWZpZXInLCB0cnVlKSxcbiAgICAgICAgY2hhbmdlZFRhcmdldFRvdWNoZXNcbiAgICBdO1xufVxuXG4vKipcbiAqIENvbWJpbmVkIHRvdWNoIGFuZCBtb3VzZSBpbnB1dFxuICpcbiAqIFRvdWNoIGhhcyBhIGhpZ2hlciBwcmlvcml0eSB0aGVuIG1vdXNlLCBhbmQgd2hpbGUgdG91Y2hpbmcgbm8gbW91c2UgZXZlbnRzIGFyZSBhbGxvd2VkLlxuICogVGhpcyBiZWNhdXNlIHRvdWNoIGRldmljZXMgYWxzbyBlbWl0IG1vdXNlIGV2ZW50cyB3aGlsZSBkb2luZyBhIHRvdWNoLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQGV4dGVuZHMgSW5wdXRcbiAqL1xuXG52YXIgREVEVVBfVElNRU9VVCA9IDI1MDA7XG52YXIgREVEVVBfRElTVEFOQ0UgPSAyNTtcblxuZnVuY3Rpb24gVG91Y2hNb3VzZUlucHV0KCkge1xuICAgIElucHV0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICB2YXIgaGFuZGxlciA9IGJpbmRGbih0aGlzLmhhbmRsZXIsIHRoaXMpO1xuICAgIHRoaXMudG91Y2ggPSBuZXcgVG91Y2hJbnB1dCh0aGlzLm1hbmFnZXIsIGhhbmRsZXIpO1xuICAgIHRoaXMubW91c2UgPSBuZXcgTW91c2VJbnB1dCh0aGlzLm1hbmFnZXIsIGhhbmRsZXIpO1xuXG4gICAgdGhpcy5wcmltYXJ5VG91Y2ggPSBudWxsO1xuICAgIHRoaXMubGFzdFRvdWNoZXMgPSBbXTtcbn1cblxuaW5oZXJpdChUb3VjaE1vdXNlSW5wdXQsIElucHV0LCB7XG4gICAgLyoqXG4gICAgICogaGFuZGxlIG1vdXNlIGFuZCB0b3VjaCBldmVudHNcbiAgICAgKiBAcGFyYW0ge0hhbW1lcn0gbWFuYWdlclxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dEV2ZW50XG4gICAgICogQHBhcmFtIHtPYmplY3R9IGlucHV0RGF0YVxuICAgICAqL1xuICAgIGhhbmRsZXI6IGZ1bmN0aW9uIFRNRWhhbmRsZXIobWFuYWdlciwgaW5wdXRFdmVudCwgaW5wdXREYXRhKSB7XG4gICAgICAgIHZhciBpc1RvdWNoID0gKGlucHV0RGF0YS5wb2ludGVyVHlwZSA9PSBJTlBVVF9UWVBFX1RPVUNIKSxcbiAgICAgICAgICAgIGlzTW91c2UgPSAoaW5wdXREYXRhLnBvaW50ZXJUeXBlID09IElOUFVUX1RZUEVfTU9VU0UpO1xuXG4gICAgICAgIGlmIChpc01vdXNlICYmIGlucHV0RGF0YS5zb3VyY2VDYXBhYmlsaXRpZXMgJiYgaW5wdXREYXRhLnNvdXJjZUNhcGFiaWxpdGllcy5maXJlc1RvdWNoRXZlbnRzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyB3aGVuIHdlJ3JlIGluIGEgdG91Y2ggZXZlbnQsIHJlY29yZCB0b3VjaGVzIHRvICBkZS1kdXBlIHN5bnRoZXRpYyBtb3VzZSBldmVudFxuICAgICAgICBpZiAoaXNUb3VjaCkge1xuICAgICAgICAgICAgcmVjb3JkVG91Y2hlcy5jYWxsKHRoaXMsIGlucHV0RXZlbnQsIGlucHV0RGF0YSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNNb3VzZSAmJiBpc1N5bnRoZXRpY0V2ZW50LmNhbGwodGhpcywgaW5wdXREYXRhKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jYWxsYmFjayhtYW5hZ2VyLCBpbnB1dEV2ZW50LCBpbnB1dERhdGEpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiByZW1vdmUgdGhlIGV2ZW50IGxpc3RlbmVyc1xuICAgICAqL1xuICAgIGRlc3Ryb3k6IGZ1bmN0aW9uIGRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMudG91Y2guZGVzdHJveSgpO1xuICAgICAgICB0aGlzLm1vdXNlLmRlc3Ryb3koKTtcbiAgICB9XG59KTtcblxuZnVuY3Rpb24gcmVjb3JkVG91Y2hlcyhldmVudFR5cGUsIGV2ZW50RGF0YSkge1xuICAgIGlmIChldmVudFR5cGUgJiBJTlBVVF9TVEFSVCkge1xuICAgICAgICB0aGlzLnByaW1hcnlUb3VjaCA9IGV2ZW50RGF0YS5jaGFuZ2VkUG9pbnRlcnNbMF0uaWRlbnRpZmllcjtcbiAgICAgICAgc2V0TGFzdFRvdWNoLmNhbGwodGhpcywgZXZlbnREYXRhKTtcbiAgICB9IGVsc2UgaWYgKGV2ZW50VHlwZSAmIChJTlBVVF9FTkQgfCBJTlBVVF9DQU5DRUwpKSB7XG4gICAgICAgIHNldExhc3RUb3VjaC5jYWxsKHRoaXMsIGV2ZW50RGF0YSk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBzZXRMYXN0VG91Y2goZXZlbnREYXRhKSB7XG4gICAgdmFyIHRvdWNoID0gZXZlbnREYXRhLmNoYW5nZWRQb2ludGVyc1swXTtcblxuICAgIGlmICh0b3VjaC5pZGVudGlmaWVyID09PSB0aGlzLnByaW1hcnlUb3VjaCkge1xuICAgICAgICB2YXIgbGFzdFRvdWNoID0ge3g6IHRvdWNoLmNsaWVudFgsIHk6IHRvdWNoLmNsaWVudFl9O1xuICAgICAgICB0aGlzLmxhc3RUb3VjaGVzLnB1c2gobGFzdFRvdWNoKTtcbiAgICAgICAgdmFyIGx0cyA9IHRoaXMubGFzdFRvdWNoZXM7XG4gICAgICAgIHZhciByZW1vdmVMYXN0VG91Y2ggPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpID0gbHRzLmluZGV4T2YobGFzdFRvdWNoKTtcbiAgICAgICAgICAgIGlmIChpID4gLTEpIHtcbiAgICAgICAgICAgICAgICBsdHMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBzZXRUaW1lb3V0KHJlbW92ZUxhc3RUb3VjaCwgREVEVVBfVElNRU9VVCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBpc1N5bnRoZXRpY0V2ZW50KGV2ZW50RGF0YSkge1xuICAgIHZhciB4ID0gZXZlbnREYXRhLnNyY0V2ZW50LmNsaWVudFgsIHkgPSBldmVudERhdGEuc3JjRXZlbnQuY2xpZW50WTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGFzdFRvdWNoZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHQgPSB0aGlzLmxhc3RUb3VjaGVzW2ldO1xuICAgICAgICB2YXIgZHggPSBNYXRoLmFicyh4IC0gdC54KSwgZHkgPSBNYXRoLmFicyh5IC0gdC55KTtcbiAgICAgICAgaWYgKGR4IDw9IERFRFVQX0RJU1RBTkNFICYmIGR5IDw9IERFRFVQX0RJU1RBTkNFKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbnZhciBQUkVGSVhFRF9UT1VDSF9BQ1RJT04gPSBwcmVmaXhlZChURVNUX0VMRU1FTlQuc3R5bGUsICd0b3VjaEFjdGlvbicpO1xudmFyIE5BVElWRV9UT1VDSF9BQ1RJT04gPSBQUkVGSVhFRF9UT1VDSF9BQ1RJT04gIT09IHVuZGVmaW5lZDtcblxuLy8gbWFnaWNhbCB0b3VjaEFjdGlvbiB2YWx1ZVxudmFyIFRPVUNIX0FDVElPTl9DT01QVVRFID0gJ2NvbXB1dGUnO1xudmFyIFRPVUNIX0FDVElPTl9BVVRPID0gJ2F1dG8nO1xudmFyIFRPVUNIX0FDVElPTl9NQU5JUFVMQVRJT04gPSAnbWFuaXB1bGF0aW9uJzsgLy8gbm90IGltcGxlbWVudGVkXG52YXIgVE9VQ0hfQUNUSU9OX05PTkUgPSAnbm9uZSc7XG52YXIgVE9VQ0hfQUNUSU9OX1BBTl9YID0gJ3Bhbi14JztcbnZhciBUT1VDSF9BQ1RJT05fUEFOX1kgPSAncGFuLXknO1xudmFyIFRPVUNIX0FDVElPTl9NQVAgPSBnZXRUb3VjaEFjdGlvblByb3BzKCk7XG5cbi8qKlxuICogVG91Y2ggQWN0aW9uXG4gKiBzZXRzIHRoZSB0b3VjaEFjdGlvbiBwcm9wZXJ0eSBvciB1c2VzIHRoZSBqcyBhbHRlcm5hdGl2ZVxuICogQHBhcmFtIHtNYW5hZ2VyfSBtYW5hZ2VyXG4gKiBAcGFyYW0ge1N0cmluZ30gdmFsdWVcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBUb3VjaEFjdGlvbihtYW5hZ2VyLCB2YWx1ZSkge1xuICAgIHRoaXMubWFuYWdlciA9IG1hbmFnZXI7XG4gICAgdGhpcy5zZXQodmFsdWUpO1xufVxuXG5Ub3VjaEFjdGlvbi5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogc2V0IHRoZSB0b3VjaEFjdGlvbiB2YWx1ZSBvbiB0aGUgZWxlbWVudCBvciBlbmFibGUgdGhlIHBvbHlmaWxsXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHZhbHVlXG4gICAgICovXG4gICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAvLyBmaW5kIG91dCB0aGUgdG91Y2gtYWN0aW9uIGJ5IHRoZSBldmVudCBoYW5kbGVyc1xuICAgICAgICBpZiAodmFsdWUgPT0gVE9VQ0hfQUNUSU9OX0NPTVBVVEUpIHtcbiAgICAgICAgICAgIHZhbHVlID0gdGhpcy5jb21wdXRlKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoTkFUSVZFX1RPVUNIX0FDVElPTiAmJiB0aGlzLm1hbmFnZXIuZWxlbWVudC5zdHlsZSAmJiBUT1VDSF9BQ1RJT05fTUFQW3ZhbHVlXSkge1xuICAgICAgICAgICAgdGhpcy5tYW5hZ2VyLmVsZW1lbnQuc3R5bGVbUFJFRklYRURfVE9VQ0hfQUNUSU9OXSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYWN0aW9ucyA9IHZhbHVlLnRvTG93ZXJDYXNlKCkudHJpbSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBqdXN0IHJlLXNldCB0aGUgdG91Y2hBY3Rpb24gdmFsdWVcbiAgICAgKi9cbiAgICB1cGRhdGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLnNldCh0aGlzLm1hbmFnZXIub3B0aW9ucy50b3VjaEFjdGlvbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIGNvbXB1dGUgdGhlIHZhbHVlIGZvciB0aGUgdG91Y2hBY3Rpb24gcHJvcGVydHkgYmFzZWQgb24gdGhlIHJlY29nbml6ZXIncyBzZXR0aW5nc1xuICAgICAqIEByZXR1cm5zIHtTdHJpbmd9IHZhbHVlXG4gICAgICovXG4gICAgY29tcHV0ZTogZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBhY3Rpb25zID0gW107XG4gICAgICAgIGVhY2godGhpcy5tYW5hZ2VyLnJlY29nbml6ZXJzLCBmdW5jdGlvbihyZWNvZ25pemVyKSB7XG4gICAgICAgICAgICBpZiAoYm9vbE9yRm4ocmVjb2duaXplci5vcHRpb25zLmVuYWJsZSwgW3JlY29nbml6ZXJdKSkge1xuICAgICAgICAgICAgICAgIGFjdGlvbnMgPSBhY3Rpb25zLmNvbmNhdChyZWNvZ25pemVyLmdldFRvdWNoQWN0aW9uKCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGNsZWFuVG91Y2hBY3Rpb25zKGFjdGlvbnMuam9pbignICcpKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogdGhpcyBtZXRob2QgaXMgY2FsbGVkIG9uIGVhY2ggaW5wdXQgY3ljbGUgYW5kIHByb3ZpZGVzIHRoZSBwcmV2ZW50aW5nIG9mIHRoZSBicm93c2VyIGJlaGF2aW9yXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGlucHV0XG4gICAgICovXG4gICAgcHJldmVudERlZmF1bHRzOiBmdW5jdGlvbihpbnB1dCkge1xuICAgICAgICB2YXIgc3JjRXZlbnQgPSBpbnB1dC5zcmNFdmVudDtcbiAgICAgICAgdmFyIGRpcmVjdGlvbiA9IGlucHV0Lm9mZnNldERpcmVjdGlvbjtcblxuICAgICAgICAvLyBpZiB0aGUgdG91Y2ggYWN0aW9uIGRpZCBwcmV2ZW50ZWQgb25jZSB0aGlzIHNlc3Npb25cbiAgICAgICAgaWYgKHRoaXMubWFuYWdlci5zZXNzaW9uLnByZXZlbnRlZCkge1xuICAgICAgICAgICAgc3JjRXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBhY3Rpb25zID0gdGhpcy5hY3Rpb25zO1xuICAgICAgICB2YXIgaGFzTm9uZSA9IGluU3RyKGFjdGlvbnMsIFRPVUNIX0FDVElPTl9OT05FKSAmJiAhVE9VQ0hfQUNUSU9OX01BUFtUT1VDSF9BQ1RJT05fTk9ORV07XG4gICAgICAgIHZhciBoYXNQYW5ZID0gaW5TdHIoYWN0aW9ucywgVE9VQ0hfQUNUSU9OX1BBTl9ZKSAmJiAhVE9VQ0hfQUNUSU9OX01BUFtUT1VDSF9BQ1RJT05fUEFOX1ldO1xuICAgICAgICB2YXIgaGFzUGFuWCA9IGluU3RyKGFjdGlvbnMsIFRPVUNIX0FDVElPTl9QQU5fWCkgJiYgIVRPVUNIX0FDVElPTl9NQVBbVE9VQ0hfQUNUSU9OX1BBTl9YXTtcblxuICAgICAgICBpZiAoaGFzTm9uZSkge1xuICAgICAgICAgICAgLy9kbyBub3QgcHJldmVudCBkZWZhdWx0cyBpZiB0aGlzIGlzIGEgdGFwIGdlc3R1cmVcblxuICAgICAgICAgICAgdmFyIGlzVGFwUG9pbnRlciA9IGlucHV0LnBvaW50ZXJzLmxlbmd0aCA9PT0gMTtcbiAgICAgICAgICAgIHZhciBpc1RhcE1vdmVtZW50ID0gaW5wdXQuZGlzdGFuY2UgPCAyO1xuICAgICAgICAgICAgdmFyIGlzVGFwVG91Y2hUaW1lID0gaW5wdXQuZGVsdGFUaW1lIDwgMjUwO1xuXG4gICAgICAgICAgICBpZiAoaXNUYXBQb2ludGVyICYmIGlzVGFwTW92ZW1lbnQgJiYgaXNUYXBUb3VjaFRpbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaGFzUGFuWCAmJiBoYXNQYW5ZKSB7XG4gICAgICAgICAgICAvLyBgcGFuLXggcGFuLXlgIG1lYW5zIGJyb3dzZXIgaGFuZGxlcyBhbGwgc2Nyb2xsaW5nL3Bhbm5pbmcsIGRvIG5vdCBwcmV2ZW50XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaGFzTm9uZSB8fFxuICAgICAgICAgICAgKGhhc1BhblkgJiYgZGlyZWN0aW9uICYgRElSRUNUSU9OX0hPUklaT05UQUwpIHx8XG4gICAgICAgICAgICAoaGFzUGFuWCAmJiBkaXJlY3Rpb24gJiBESVJFQ1RJT05fVkVSVElDQUwpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wcmV2ZW50U3JjKHNyY0V2ZW50KTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBjYWxsIHByZXZlbnREZWZhdWx0IHRvIHByZXZlbnQgdGhlIGJyb3dzZXIncyBkZWZhdWx0IGJlaGF2aW9yIChzY3JvbGxpbmcgaW4gbW9zdCBjYXNlcylcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gc3JjRXZlbnRcbiAgICAgKi9cbiAgICBwcmV2ZW50U3JjOiBmdW5jdGlvbihzcmNFdmVudCkge1xuICAgICAgICB0aGlzLm1hbmFnZXIuc2Vzc2lvbi5wcmV2ZW50ZWQgPSB0cnVlO1xuICAgICAgICBzcmNFdmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cbn07XG5cbi8qKlxuICogd2hlbiB0aGUgdG91Y2hBY3Rpb25zIGFyZSBjb2xsZWN0ZWQgdGhleSBhcmUgbm90IGEgdmFsaWQgdmFsdWUsIHNvIHdlIG5lZWQgdG8gY2xlYW4gdGhpbmdzIHVwLiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gYWN0aW9uc1xuICogQHJldHVybnMgeyp9XG4gKi9cbmZ1bmN0aW9uIGNsZWFuVG91Y2hBY3Rpb25zKGFjdGlvbnMpIHtcbiAgICAvLyBub25lXG4gICAgaWYgKGluU3RyKGFjdGlvbnMsIFRPVUNIX0FDVElPTl9OT05FKSkge1xuICAgICAgICByZXR1cm4gVE9VQ0hfQUNUSU9OX05PTkU7XG4gICAgfVxuXG4gICAgdmFyIGhhc1BhblggPSBpblN0cihhY3Rpb25zLCBUT1VDSF9BQ1RJT05fUEFOX1gpO1xuICAgIHZhciBoYXNQYW5ZID0gaW5TdHIoYWN0aW9ucywgVE9VQ0hfQUNUSU9OX1BBTl9ZKTtcblxuICAgIC8vIGlmIGJvdGggcGFuLXggYW5kIHBhbi15IGFyZSBzZXQgKGRpZmZlcmVudCByZWNvZ25pemVyc1xuICAgIC8vIGZvciBkaWZmZXJlbnQgZGlyZWN0aW9ucywgZS5nLiBob3Jpem9udGFsIHBhbiBidXQgdmVydGljYWwgc3dpcGU/KVxuICAgIC8vIHdlIG5lZWQgbm9uZSAoYXMgb3RoZXJ3aXNlIHdpdGggcGFuLXggcGFuLXkgY29tYmluZWQgbm9uZSBvZiB0aGVzZVxuICAgIC8vIHJlY29nbml6ZXJzIHdpbGwgd29yaywgc2luY2UgdGhlIGJyb3dzZXIgd291bGQgaGFuZGxlIGFsbCBwYW5uaW5nXG4gICAgaWYgKGhhc1BhblggJiYgaGFzUGFuWSkge1xuICAgICAgICByZXR1cm4gVE9VQ0hfQUNUSU9OX05PTkU7XG4gICAgfVxuXG4gICAgLy8gcGFuLXggT1IgcGFuLXlcbiAgICBpZiAoaGFzUGFuWCB8fCBoYXNQYW5ZKSB7XG4gICAgICAgIHJldHVybiBoYXNQYW5YID8gVE9VQ0hfQUNUSU9OX1BBTl9YIDogVE9VQ0hfQUNUSU9OX1BBTl9ZO1xuICAgIH1cblxuICAgIC8vIG1hbmlwdWxhdGlvblxuICAgIGlmIChpblN0cihhY3Rpb25zLCBUT1VDSF9BQ1RJT05fTUFOSVBVTEFUSU9OKSkge1xuICAgICAgICByZXR1cm4gVE9VQ0hfQUNUSU9OX01BTklQVUxBVElPTjtcbiAgICB9XG5cbiAgICByZXR1cm4gVE9VQ0hfQUNUSU9OX0FVVE87XG59XG5cbmZ1bmN0aW9uIGdldFRvdWNoQWN0aW9uUHJvcHMoKSB7XG4gICAgaWYgKCFOQVRJVkVfVE9VQ0hfQUNUSU9OKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdmFyIHRvdWNoTWFwID0ge307XG4gICAgdmFyIGNzc1N1cHBvcnRzID0gd2luZG93LkNTUyAmJiB3aW5kb3cuQ1NTLnN1cHBvcnRzO1xuICAgIFsnYXV0bycsICdtYW5pcHVsYXRpb24nLCAncGFuLXknLCAncGFuLXgnLCAncGFuLXggcGFuLXknLCAnbm9uZSddLmZvckVhY2goZnVuY3Rpb24odmFsKSB7XG5cbiAgICAgICAgLy8gSWYgY3NzLnN1cHBvcnRzIGlzIG5vdCBzdXBwb3J0ZWQgYnV0IHRoZXJlIGlzIG5hdGl2ZSB0b3VjaC1hY3Rpb24gYXNzdW1lIGl0IHN1cHBvcnRzXG4gICAgICAgIC8vIGFsbCB2YWx1ZXMuIFRoaXMgaXMgdGhlIGNhc2UgZm9yIElFIDEwIGFuZCAxMS5cbiAgICAgICAgdG91Y2hNYXBbdmFsXSA9IGNzc1N1cHBvcnRzID8gd2luZG93LkNTUy5zdXBwb3J0cygndG91Y2gtYWN0aW9uJywgdmFsKSA6IHRydWU7XG4gICAgfSk7XG4gICAgcmV0dXJuIHRvdWNoTWFwO1xufVxuXG4vKipcbiAqIFJlY29nbml6ZXIgZmxvdyBleHBsYWluZWQ7ICpcbiAqIEFsbCByZWNvZ25pemVycyBoYXZlIHRoZSBpbml0aWFsIHN0YXRlIG9mIFBPU1NJQkxFIHdoZW4gYSBpbnB1dCBzZXNzaW9uIHN0YXJ0cy5cbiAqIFRoZSBkZWZpbml0aW9uIG9mIGEgaW5wdXQgc2Vzc2lvbiBpcyBmcm9tIHRoZSBmaXJzdCBpbnB1dCB1bnRpbCB0aGUgbGFzdCBpbnB1dCwgd2l0aCBhbGwgaXQncyBtb3ZlbWVudCBpbiBpdC4gKlxuICogRXhhbXBsZSBzZXNzaW9uIGZvciBtb3VzZS1pbnB1dDogbW91c2Vkb3duIC0+IG1vdXNlbW92ZSAtPiBtb3VzZXVwXG4gKlxuICogT24gZWFjaCByZWNvZ25pemluZyBjeWNsZSAoc2VlIE1hbmFnZXIucmVjb2duaXplKSB0aGUgLnJlY29nbml6ZSgpIG1ldGhvZCBpcyBleGVjdXRlZFxuICogd2hpY2ggZGV0ZXJtaW5lcyB3aXRoIHN0YXRlIGl0IHNob3VsZCBiZS5cbiAqXG4gKiBJZiB0aGUgcmVjb2duaXplciBoYXMgdGhlIHN0YXRlIEZBSUxFRCwgQ0FOQ0VMTEVEIG9yIFJFQ09HTklaRUQgKGVxdWFscyBFTkRFRCksIGl0IGlzIHJlc2V0IHRvXG4gKiBQT1NTSUJMRSB0byBnaXZlIGl0IGFub3RoZXIgY2hhbmdlIG9uIHRoZSBuZXh0IGN5Y2xlLlxuICpcbiAqICAgICAgICAgICAgICAgUG9zc2libGVcbiAqICAgICAgICAgICAgICAgICAgfFxuICogICAgICAgICAgICArLS0tLS0rLS0tLS0tLS0tLS0tLS0tK1xuICogICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfFxuICogICAgICArLS0tLS0rLS0tLS0rICAgICAgICAgICAgICAgfFxuICogICAgICB8ICAgICAgICAgICB8ICAgICAgICAgICAgICAgfFxuICogICBGYWlsZWQgICAgICBDYW5jZWxsZWQgICAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICstLS0tLS0tKy0tLS0tLStcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgICBSZWNvZ25pemVkICAgICAgIEJlZ2FuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENoYW5nZWRcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbmRlZC9SZWNvZ25pemVkXG4gKi9cbnZhciBTVEFURV9QT1NTSUJMRSA9IDE7XG52YXIgU1RBVEVfQkVHQU4gPSAyO1xudmFyIFNUQVRFX0NIQU5HRUQgPSA0O1xudmFyIFNUQVRFX0VOREVEID0gODtcbnZhciBTVEFURV9SRUNPR05JWkVEID0gU1RBVEVfRU5ERUQ7XG52YXIgU1RBVEVfQ0FOQ0VMTEVEID0gMTY7XG52YXIgU1RBVEVfRkFJTEVEID0gMzI7XG5cbi8qKlxuICogUmVjb2duaXplclxuICogRXZlcnkgcmVjb2duaXplciBuZWVkcyB0byBleHRlbmQgZnJvbSB0aGlzIGNsYXNzLlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICovXG5mdW5jdGlvbiBSZWNvZ25pemVyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBhc3NpZ24oe30sIHRoaXMuZGVmYXVsdHMsIG9wdGlvbnMgfHwge30pO1xuXG4gICAgdGhpcy5pZCA9IHVuaXF1ZUlkKCk7XG5cbiAgICB0aGlzLm1hbmFnZXIgPSBudWxsO1xuXG4gICAgLy8gZGVmYXVsdCBpcyBlbmFibGUgdHJ1ZVxuICAgIHRoaXMub3B0aW9ucy5lbmFibGUgPSBpZlVuZGVmaW5lZCh0aGlzLm9wdGlvbnMuZW5hYmxlLCB0cnVlKTtcblxuICAgIHRoaXMuc3RhdGUgPSBTVEFURV9QT1NTSUJMRTtcblxuICAgIHRoaXMuc2ltdWx0YW5lb3VzID0ge307XG4gICAgdGhpcy5yZXF1aXJlRmFpbCA9IFtdO1xufVxuXG5SZWNvZ25pemVyLnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBAdmlydHVhbFxuICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICovXG4gICAgZGVmYXVsdHM6IHt9LFxuXG4gICAgLyoqXG4gICAgICogc2V0IG9wdGlvbnNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICAgICAqIEByZXR1cm4ge1JlY29nbml6ZXJ9XG4gICAgICovXG4gICAgc2V0OiBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgICAgIGFzc2lnbih0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIC8vIGFsc28gdXBkYXRlIHRoZSB0b3VjaEFjdGlvbiwgaW4gY2FzZSBzb21ldGhpbmcgY2hhbmdlZCBhYm91dCB0aGUgZGlyZWN0aW9ucy9lbmFibGVkIHN0YXRlXG4gICAgICAgIHRoaXMubWFuYWdlciAmJiB0aGlzLm1hbmFnZXIudG91Y2hBY3Rpb24udXBkYXRlKCk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiByZWNvZ25pemUgc2ltdWx0YW5lb3VzIHdpdGggYW4gb3RoZXIgcmVjb2duaXplci5cbiAgICAgKiBAcGFyYW0ge1JlY29nbml6ZXJ9IG90aGVyUmVjb2duaXplclxuICAgICAqIEByZXR1cm5zIHtSZWNvZ25pemVyfSB0aGlzXG4gICAgICovXG4gICAgcmVjb2duaXplV2l0aDogZnVuY3Rpb24ob3RoZXJSZWNvZ25pemVyKSB7XG4gICAgICAgIGlmIChpbnZva2VBcnJheUFyZyhvdGhlclJlY29nbml6ZXIsICdyZWNvZ25pemVXaXRoJywgdGhpcykpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHNpbXVsdGFuZW91cyA9IHRoaXMuc2ltdWx0YW5lb3VzO1xuICAgICAgICBvdGhlclJlY29nbml6ZXIgPSBnZXRSZWNvZ25pemVyQnlOYW1lSWZNYW5hZ2VyKG90aGVyUmVjb2duaXplciwgdGhpcyk7XG4gICAgICAgIGlmICghc2ltdWx0YW5lb3VzW290aGVyUmVjb2duaXplci5pZF0pIHtcbiAgICAgICAgICAgIHNpbXVsdGFuZW91c1tvdGhlclJlY29nbml6ZXIuaWRdID0gb3RoZXJSZWNvZ25pemVyO1xuICAgICAgICAgICAgb3RoZXJSZWNvZ25pemVyLnJlY29nbml6ZVdpdGgodGhpcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIGRyb3AgdGhlIHNpbXVsdGFuZW91cyBsaW5rLiBpdCBkb2VzbnQgcmVtb3ZlIHRoZSBsaW5rIG9uIHRoZSBvdGhlciByZWNvZ25pemVyLlxuICAgICAqIEBwYXJhbSB7UmVjb2duaXplcn0gb3RoZXJSZWNvZ25pemVyXG4gICAgICogQHJldHVybnMge1JlY29nbml6ZXJ9IHRoaXNcbiAgICAgKi9cbiAgICBkcm9wUmVjb2duaXplV2l0aDogZnVuY3Rpb24ob3RoZXJSZWNvZ25pemVyKSB7XG4gICAgICAgIGlmIChpbnZva2VBcnJheUFyZyhvdGhlclJlY29nbml6ZXIsICdkcm9wUmVjb2duaXplV2l0aCcsIHRoaXMpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIG90aGVyUmVjb2duaXplciA9IGdldFJlY29nbml6ZXJCeU5hbWVJZk1hbmFnZXIob3RoZXJSZWNvZ25pemVyLCB0aGlzKTtcbiAgICAgICAgZGVsZXRlIHRoaXMuc2ltdWx0YW5lb3VzW290aGVyUmVjb2duaXplci5pZF07XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiByZWNvZ25pemVyIGNhbiBvbmx5IHJ1biB3aGVuIGFuIG90aGVyIGlzIGZhaWxpbmdcbiAgICAgKiBAcGFyYW0ge1JlY29nbml6ZXJ9IG90aGVyUmVjb2duaXplclxuICAgICAqIEByZXR1cm5zIHtSZWNvZ25pemVyfSB0aGlzXG4gICAgICovXG4gICAgcmVxdWlyZUZhaWx1cmU6IGZ1bmN0aW9uKG90aGVyUmVjb2duaXplcikge1xuICAgICAgICBpZiAoaW52b2tlQXJyYXlBcmcob3RoZXJSZWNvZ25pemVyLCAncmVxdWlyZUZhaWx1cmUnLCB0aGlzKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcmVxdWlyZUZhaWwgPSB0aGlzLnJlcXVpcmVGYWlsO1xuICAgICAgICBvdGhlclJlY29nbml6ZXIgPSBnZXRSZWNvZ25pemVyQnlOYW1lSWZNYW5hZ2VyKG90aGVyUmVjb2duaXplciwgdGhpcyk7XG4gICAgICAgIGlmIChpbkFycmF5KHJlcXVpcmVGYWlsLCBvdGhlclJlY29nbml6ZXIpID09PSAtMSkge1xuICAgICAgICAgICAgcmVxdWlyZUZhaWwucHVzaChvdGhlclJlY29nbml6ZXIpO1xuICAgICAgICAgICAgb3RoZXJSZWNvZ25pemVyLnJlcXVpcmVGYWlsdXJlKHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBkcm9wIHRoZSByZXF1aXJlRmFpbHVyZSBsaW5rLiBpdCBkb2VzIG5vdCByZW1vdmUgdGhlIGxpbmsgb24gdGhlIG90aGVyIHJlY29nbml6ZXIuXG4gICAgICogQHBhcmFtIHtSZWNvZ25pemVyfSBvdGhlclJlY29nbml6ZXJcbiAgICAgKiBAcmV0dXJucyB7UmVjb2duaXplcn0gdGhpc1xuICAgICAqL1xuICAgIGRyb3BSZXF1aXJlRmFpbHVyZTogZnVuY3Rpb24ob3RoZXJSZWNvZ25pemVyKSB7XG4gICAgICAgIGlmIChpbnZva2VBcnJheUFyZyhvdGhlclJlY29nbml6ZXIsICdkcm9wUmVxdWlyZUZhaWx1cmUnLCB0aGlzKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICBvdGhlclJlY29nbml6ZXIgPSBnZXRSZWNvZ25pemVyQnlOYW1lSWZNYW5hZ2VyKG90aGVyUmVjb2duaXplciwgdGhpcyk7XG4gICAgICAgIHZhciBpbmRleCA9IGluQXJyYXkodGhpcy5yZXF1aXJlRmFpbCwgb3RoZXJSZWNvZ25pemVyKTtcbiAgICAgICAgaWYgKGluZGV4ID4gLTEpIHtcbiAgICAgICAgICAgIHRoaXMucmVxdWlyZUZhaWwuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogaGFzIHJlcXVpcmUgZmFpbHVyZXMgYm9vbGVhblxuICAgICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgICAqL1xuICAgIGhhc1JlcXVpcmVGYWlsdXJlczogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlcXVpcmVGYWlsLmxlbmd0aCA+IDA7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIGlmIHRoZSByZWNvZ25pemVyIGNhbiByZWNvZ25pemUgc2ltdWx0YW5lb3VzIHdpdGggYW4gb3RoZXIgcmVjb2duaXplclxuICAgICAqIEBwYXJhbSB7UmVjb2duaXplcn0gb3RoZXJSZWNvZ25pemVyXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59XG4gICAgICovXG4gICAgY2FuUmVjb2duaXplV2l0aDogZnVuY3Rpb24ob3RoZXJSZWNvZ25pemVyKSB7XG4gICAgICAgIHJldHVybiAhIXRoaXMuc2ltdWx0YW5lb3VzW290aGVyUmVjb2duaXplci5pZF07XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFlvdSBzaG91bGQgdXNlIGB0cnlFbWl0YCBpbnN0ZWFkIG9mIGBlbWl0YCBkaXJlY3RseSB0byBjaGVja1xuICAgICAqIHRoYXQgYWxsIHRoZSBuZWVkZWQgcmVjb2duaXplcnMgaGFzIGZhaWxlZCBiZWZvcmUgZW1pdHRpbmcuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGlucHV0XG4gICAgICovXG4gICAgZW1pdDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB2YXIgc3RhdGUgPSB0aGlzLnN0YXRlO1xuXG4gICAgICAgIGZ1bmN0aW9uIGVtaXQoZXZlbnQpIHtcbiAgICAgICAgICAgIHNlbGYubWFuYWdlci5lbWl0KGV2ZW50LCBpbnB1dCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAncGFuc3RhcnQnIGFuZCAncGFubW92ZSdcbiAgICAgICAgaWYgKHN0YXRlIDwgU1RBVEVfRU5ERUQpIHtcbiAgICAgICAgICAgIGVtaXQoc2VsZi5vcHRpb25zLmV2ZW50ICsgc3RhdGVTdHIoc3RhdGUpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGVtaXQoc2VsZi5vcHRpb25zLmV2ZW50KTsgLy8gc2ltcGxlICdldmVudE5hbWUnIGV2ZW50c1xuXG4gICAgICAgIGlmIChpbnB1dC5hZGRpdGlvbmFsRXZlbnQpIHsgLy8gYWRkaXRpb25hbCBldmVudChwYW5sZWZ0LCBwYW5yaWdodCwgcGluY2hpbiwgcGluY2hvdXQuLi4pXG4gICAgICAgICAgICBlbWl0KGlucHV0LmFkZGl0aW9uYWxFdmVudCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBwYW5lbmQgYW5kIHBhbmNhbmNlbFxuICAgICAgICBpZiAoc3RhdGUgPj0gU1RBVEVfRU5ERUQpIHtcbiAgICAgICAgICAgIGVtaXQoc2VsZi5vcHRpb25zLmV2ZW50ICsgc3RhdGVTdHIoc3RhdGUpKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDaGVjayB0aGF0IGFsbCB0aGUgcmVxdWlyZSBmYWlsdXJlIHJlY29nbml6ZXJzIGhhcyBmYWlsZWQsXG4gICAgICogaWYgdHJ1ZSwgaXQgZW1pdHMgYSBnZXN0dXJlIGV2ZW50LFxuICAgICAqIG90aGVyd2lzZSwgc2V0dXAgdGhlIHN0YXRlIHRvIEZBSUxFRC5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gaW5wdXRcbiAgICAgKi9cbiAgICB0cnlFbWl0OiBmdW5jdGlvbihpbnB1dCkge1xuICAgICAgICBpZiAodGhpcy5jYW5FbWl0KCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmVtaXQoaW5wdXQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIGl0J3MgZmFpbGluZyBhbnl3YXlcbiAgICAgICAgdGhpcy5zdGF0ZSA9IFNUQVRFX0ZBSUxFRDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogY2FuIHdlIGVtaXQ/XG4gICAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAgICovXG4gICAgY2FuRW1pdDogZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpID0gMDtcbiAgICAgICAgd2hpbGUgKGkgPCB0aGlzLnJlcXVpcmVGYWlsLmxlbmd0aCkge1xuICAgICAgICAgICAgaWYgKCEodGhpcy5yZXF1aXJlRmFpbFtpXS5zdGF0ZSAmIChTVEFURV9GQUlMRUQgfCBTVEFURV9QT1NTSUJMRSkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaSsrO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiB1cGRhdGUgdGhlIHJlY29nbml6ZXJcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gaW5wdXREYXRhXG4gICAgICovXG4gICAgcmVjb2duaXplOiBmdW5jdGlvbihpbnB1dERhdGEpIHtcbiAgICAgICAgLy8gbWFrZSBhIG5ldyBjb3B5IG9mIHRoZSBpbnB1dERhdGFcbiAgICAgICAgLy8gc28gd2UgY2FuIGNoYW5nZSB0aGUgaW5wdXREYXRhIHdpdGhvdXQgbWVzc2luZyB1cCB0aGUgb3RoZXIgcmVjb2duaXplcnNcbiAgICAgICAgdmFyIGlucHV0RGF0YUNsb25lID0gYXNzaWduKHt9LCBpbnB1dERhdGEpO1xuXG4gICAgICAgIC8vIGlzIGlzIGVuYWJsZWQgYW5kIGFsbG93IHJlY29nbml6aW5nP1xuICAgICAgICBpZiAoIWJvb2xPckZuKHRoaXMub3B0aW9ucy5lbmFibGUsIFt0aGlzLCBpbnB1dERhdGFDbG9uZV0pKSB7XG4gICAgICAgICAgICB0aGlzLnJlc2V0KCk7XG4gICAgICAgICAgICB0aGlzLnN0YXRlID0gU1RBVEVfRkFJTEVEO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gcmVzZXQgd2hlbiB3ZSd2ZSByZWFjaGVkIHRoZSBlbmRcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUgJiAoU1RBVEVfUkVDT0dOSVpFRCB8IFNUQVRFX0NBTkNFTExFRCB8IFNUQVRFX0ZBSUxFRCkpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUgPSBTVEFURV9QT1NTSUJMRTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc3RhdGUgPSB0aGlzLnByb2Nlc3MoaW5wdXREYXRhQ2xvbmUpO1xuXG4gICAgICAgIC8vIHRoZSByZWNvZ25pemVyIGhhcyByZWNvZ25pemVkIGEgZ2VzdHVyZVxuICAgICAgICAvLyBzbyB0cmlnZ2VyIGFuIGV2ZW50XG4gICAgICAgIGlmICh0aGlzLnN0YXRlICYgKFNUQVRFX0JFR0FOIHwgU1RBVEVfQ0hBTkdFRCB8IFNUQVRFX0VOREVEIHwgU1RBVEVfQ0FOQ0VMTEVEKSkge1xuICAgICAgICAgICAgdGhpcy50cnlFbWl0KGlucHV0RGF0YUNsb25lKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiByZXR1cm4gdGhlIHN0YXRlIG9mIHRoZSByZWNvZ25pemVyXG4gICAgICogdGhlIGFjdHVhbCByZWNvZ25pemluZyBoYXBwZW5zIGluIHRoaXMgbWV0aG9kXG4gICAgICogQHZpcnR1YWxcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gaW5wdXREYXRhXG4gICAgICogQHJldHVybnMge0NvbnN0fSBTVEFURVxuICAgICAqL1xuICAgIHByb2Nlc3M6IGZ1bmN0aW9uKGlucHV0RGF0YSkgeyB9LCAvLyBqc2hpbnQgaWdub3JlOmxpbmVcblxuICAgIC8qKlxuICAgICAqIHJldHVybiB0aGUgcHJlZmVycmVkIHRvdWNoLWFjdGlvblxuICAgICAqIEB2aXJ0dWFsXG4gICAgICogQHJldHVybnMge0FycmF5fVxuICAgICAqL1xuICAgIGdldFRvdWNoQWN0aW9uOiBmdW5jdGlvbigpIHsgfSxcblxuICAgIC8qKlxuICAgICAqIGNhbGxlZCB3aGVuIHRoZSBnZXN0dXJlIGlzbid0IGFsbG93ZWQgdG8gcmVjb2duaXplXG4gICAgICogbGlrZSB3aGVuIGFub3RoZXIgaXMgYmVpbmcgcmVjb2duaXplZCBvciBpdCBpcyBkaXNhYmxlZFxuICAgICAqIEB2aXJ0dWFsXG4gICAgICovXG4gICAgcmVzZXQ6IGZ1bmN0aW9uKCkgeyB9XG59O1xuXG4vKipcbiAqIGdldCBhIHVzYWJsZSBzdHJpbmcsIHVzZWQgYXMgZXZlbnQgcG9zdGZpeFxuICogQHBhcmFtIHtDb25zdH0gc3RhdGVcbiAqIEByZXR1cm5zIHtTdHJpbmd9IHN0YXRlXG4gKi9cbmZ1bmN0aW9uIHN0YXRlU3RyKHN0YXRlKSB7XG4gICAgaWYgKHN0YXRlICYgU1RBVEVfQ0FOQ0VMTEVEKSB7XG4gICAgICAgIHJldHVybiAnY2FuY2VsJztcbiAgICB9IGVsc2UgaWYgKHN0YXRlICYgU1RBVEVfRU5ERUQpIHtcbiAgICAgICAgcmV0dXJuICdlbmQnO1xuICAgIH0gZWxzZSBpZiAoc3RhdGUgJiBTVEFURV9DSEFOR0VEKSB7XG4gICAgICAgIHJldHVybiAnbW92ZSc7XG4gICAgfSBlbHNlIGlmIChzdGF0ZSAmIFNUQVRFX0JFR0FOKSB7XG4gICAgICAgIHJldHVybiAnc3RhcnQnO1xuICAgIH1cbiAgICByZXR1cm4gJyc7XG59XG5cbi8qKlxuICogZGlyZWN0aW9uIGNvbnMgdG8gc3RyaW5nXG4gKiBAcGFyYW0ge0NvbnN0fSBkaXJlY3Rpb25cbiAqIEByZXR1cm5zIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGRpcmVjdGlvblN0cihkaXJlY3Rpb24pIHtcbiAgICBpZiAoZGlyZWN0aW9uID09IERJUkVDVElPTl9ET1dOKSB7XG4gICAgICAgIHJldHVybiAnZG93bic7XG4gICAgfSBlbHNlIGlmIChkaXJlY3Rpb24gPT0gRElSRUNUSU9OX1VQKSB7XG4gICAgICAgIHJldHVybiAndXAnO1xuICAgIH0gZWxzZSBpZiAoZGlyZWN0aW9uID09IERJUkVDVElPTl9MRUZUKSB7XG4gICAgICAgIHJldHVybiAnbGVmdCc7XG4gICAgfSBlbHNlIGlmIChkaXJlY3Rpb24gPT0gRElSRUNUSU9OX1JJR0hUKSB7XG4gICAgICAgIHJldHVybiAncmlnaHQnO1xuICAgIH1cbiAgICByZXR1cm4gJyc7XG59XG5cbi8qKlxuICogZ2V0IGEgcmVjb2duaXplciBieSBuYW1lIGlmIGl0IGlzIGJvdW5kIHRvIGEgbWFuYWdlclxuICogQHBhcmFtIHtSZWNvZ25pemVyfFN0cmluZ30gb3RoZXJSZWNvZ25pemVyXG4gKiBAcGFyYW0ge1JlY29nbml6ZXJ9IHJlY29nbml6ZXJcbiAqIEByZXR1cm5zIHtSZWNvZ25pemVyfVxuICovXG5mdW5jdGlvbiBnZXRSZWNvZ25pemVyQnlOYW1lSWZNYW5hZ2VyKG90aGVyUmVjb2duaXplciwgcmVjb2duaXplcikge1xuICAgIHZhciBtYW5hZ2VyID0gcmVjb2duaXplci5tYW5hZ2VyO1xuICAgIGlmIChtYW5hZ2VyKSB7XG4gICAgICAgIHJldHVybiBtYW5hZ2VyLmdldChvdGhlclJlY29nbml6ZXIpO1xuICAgIH1cbiAgICByZXR1cm4gb3RoZXJSZWNvZ25pemVyO1xufVxuXG4vKipcbiAqIFRoaXMgcmVjb2duaXplciBpcyBqdXN0IHVzZWQgYXMgYSBiYXNlIGZvciB0aGUgc2ltcGxlIGF0dHJpYnV0ZSByZWNvZ25pemVycy5cbiAqIEBjb25zdHJ1Y3RvclxuICogQGV4dGVuZHMgUmVjb2duaXplclxuICovXG5mdW5jdGlvbiBBdHRyUmVjb2duaXplcigpIHtcbiAgICBSZWNvZ25pemVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cbmluaGVyaXQoQXR0clJlY29nbml6ZXIsIFJlY29nbml6ZXIsIHtcbiAgICAvKipcbiAgICAgKiBAbmFtZXNwYWNlXG4gICAgICogQG1lbWJlcm9mIEF0dHJSZWNvZ25pemVyXG4gICAgICovXG4gICAgZGVmYXVsdHM6IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEB0eXBlIHtOdW1iZXJ9XG4gICAgICAgICAqIEBkZWZhdWx0IDFcbiAgICAgICAgICovXG4gICAgICAgIHBvaW50ZXJzOiAxXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVzZWQgdG8gY2hlY2sgaWYgaXQgdGhlIHJlY29nbml6ZXIgcmVjZWl2ZXMgdmFsaWQgaW5wdXQsIGxpa2UgaW5wdXQuZGlzdGFuY2UgPiAxMC5cbiAgICAgKiBAbWVtYmVyb2YgQXR0clJlY29nbml6ZXJcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gaW5wdXRcbiAgICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gcmVjb2duaXplZFxuICAgICAqL1xuICAgIGF0dHJUZXN0OiBmdW5jdGlvbihpbnB1dCkge1xuICAgICAgICB2YXIgb3B0aW9uUG9pbnRlcnMgPSB0aGlzLm9wdGlvbnMucG9pbnRlcnM7XG4gICAgICAgIHJldHVybiBvcHRpb25Qb2ludGVycyA9PT0gMCB8fCBpbnB1dC5wb2ludGVycy5sZW5ndGggPT09IG9wdGlvblBvaW50ZXJzO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQcm9jZXNzIHRoZSBpbnB1dCBhbmQgcmV0dXJuIHRoZSBzdGF0ZSBmb3IgdGhlIHJlY29nbml6ZXJcbiAgICAgKiBAbWVtYmVyb2YgQXR0clJlY29nbml6ZXJcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gaW5wdXRcbiAgICAgKiBAcmV0dXJucyB7Kn0gU3RhdGVcbiAgICAgKi9cbiAgICBwcm9jZXNzOiBmdW5jdGlvbihpbnB1dCkge1xuICAgICAgICB2YXIgc3RhdGUgPSB0aGlzLnN0YXRlO1xuICAgICAgICB2YXIgZXZlbnRUeXBlID0gaW5wdXQuZXZlbnRUeXBlO1xuXG4gICAgICAgIHZhciBpc1JlY29nbml6ZWQgPSBzdGF0ZSAmIChTVEFURV9CRUdBTiB8IFNUQVRFX0NIQU5HRUQpO1xuICAgICAgICB2YXIgaXNWYWxpZCA9IHRoaXMuYXR0clRlc3QoaW5wdXQpO1xuXG4gICAgICAgIC8vIG9uIGNhbmNlbCBpbnB1dCBhbmQgd2UndmUgcmVjb2duaXplZCBiZWZvcmUsIHJldHVybiBTVEFURV9DQU5DRUxMRURcbiAgICAgICAgaWYgKGlzUmVjb2duaXplZCAmJiAoZXZlbnRUeXBlICYgSU5QVVRfQ0FOQ0VMIHx8ICFpc1ZhbGlkKSkge1xuICAgICAgICAgICAgcmV0dXJuIHN0YXRlIHwgU1RBVEVfQ0FOQ0VMTEVEO1xuICAgICAgICB9IGVsc2UgaWYgKGlzUmVjb2duaXplZCB8fCBpc1ZhbGlkKSB7XG4gICAgICAgICAgICBpZiAoZXZlbnRUeXBlICYgSU5QVVRfRU5EKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0YXRlIHwgU1RBVEVfRU5ERUQ7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCEoc3RhdGUgJiBTVEFURV9CRUdBTikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gU1RBVEVfQkVHQU47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gc3RhdGUgfCBTVEFURV9DSEFOR0VEO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBTVEFURV9GQUlMRUQ7XG4gICAgfVxufSk7XG5cbi8qKlxuICogUGFuXG4gKiBSZWNvZ25pemVkIHdoZW4gdGhlIHBvaW50ZXIgaXMgZG93biBhbmQgbW92ZWQgaW4gdGhlIGFsbG93ZWQgZGlyZWN0aW9uLlxuICogQGNvbnN0cnVjdG9yXG4gKiBAZXh0ZW5kcyBBdHRyUmVjb2duaXplclxuICovXG5mdW5jdGlvbiBQYW5SZWNvZ25pemVyKCkge1xuICAgIEF0dHJSZWNvZ25pemVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICB0aGlzLnBYID0gbnVsbDtcbiAgICB0aGlzLnBZID0gbnVsbDtcbn1cblxuaW5oZXJpdChQYW5SZWNvZ25pemVyLCBBdHRyUmVjb2duaXplciwge1xuICAgIC8qKlxuICAgICAqIEBuYW1lc3BhY2VcbiAgICAgKiBAbWVtYmVyb2YgUGFuUmVjb2duaXplclxuICAgICAqL1xuICAgIGRlZmF1bHRzOiB7XG4gICAgICAgIGV2ZW50OiAncGFuJyxcbiAgICAgICAgdGhyZXNob2xkOiAxMCxcbiAgICAgICAgcG9pbnRlcnM6IDEsXG4gICAgICAgIGRpcmVjdGlvbjogRElSRUNUSU9OX0FMTFxuICAgIH0sXG5cbiAgICBnZXRUb3VjaEFjdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBkaXJlY3Rpb24gPSB0aGlzLm9wdGlvbnMuZGlyZWN0aW9uO1xuICAgICAgICB2YXIgYWN0aW9ucyA9IFtdO1xuICAgICAgICBpZiAoZGlyZWN0aW9uICYgRElSRUNUSU9OX0hPUklaT05UQUwpIHtcbiAgICAgICAgICAgIGFjdGlvbnMucHVzaChUT1VDSF9BQ1RJT05fUEFOX1kpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkaXJlY3Rpb24gJiBESVJFQ1RJT05fVkVSVElDQUwpIHtcbiAgICAgICAgICAgIGFjdGlvbnMucHVzaChUT1VDSF9BQ1RJT05fUEFOX1gpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhY3Rpb25zO1xuICAgIH0sXG5cbiAgICBkaXJlY3Rpb25UZXN0OiBmdW5jdGlvbihpbnB1dCkge1xuICAgICAgICB2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcbiAgICAgICAgdmFyIGhhc01vdmVkID0gdHJ1ZTtcbiAgICAgICAgdmFyIGRpc3RhbmNlID0gaW5wdXQuZGlzdGFuY2U7XG4gICAgICAgIHZhciBkaXJlY3Rpb24gPSBpbnB1dC5kaXJlY3Rpb247XG4gICAgICAgIHZhciB4ID0gaW5wdXQuZGVsdGFYO1xuICAgICAgICB2YXIgeSA9IGlucHV0LmRlbHRhWTtcblxuICAgICAgICAvLyBsb2NrIHRvIGF4aXM/XG4gICAgICAgIGlmICghKGRpcmVjdGlvbiAmIG9wdGlvbnMuZGlyZWN0aW9uKSkge1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMuZGlyZWN0aW9uICYgRElSRUNUSU9OX0hPUklaT05UQUwpIHtcbiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAoeCA9PT0gMCkgPyBESVJFQ1RJT05fTk9ORSA6ICh4IDwgMCkgPyBESVJFQ1RJT05fTEVGVCA6IERJUkVDVElPTl9SSUdIVDtcbiAgICAgICAgICAgICAgICBoYXNNb3ZlZCA9IHggIT0gdGhpcy5wWDtcbiAgICAgICAgICAgICAgICBkaXN0YW5jZSA9IE1hdGguYWJzKGlucHV0LmRlbHRhWCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICh5ID09PSAwKSA/IERJUkVDVElPTl9OT05FIDogKHkgPCAwKSA/IERJUkVDVElPTl9VUCA6IERJUkVDVElPTl9ET1dOO1xuICAgICAgICAgICAgICAgIGhhc01vdmVkID0geSAhPSB0aGlzLnBZO1xuICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gTWF0aC5hYnMoaW5wdXQuZGVsdGFZKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpbnB1dC5kaXJlY3Rpb24gPSBkaXJlY3Rpb247XG4gICAgICAgIHJldHVybiBoYXNNb3ZlZCAmJiBkaXN0YW5jZSA+IG9wdGlvbnMudGhyZXNob2xkICYmIGRpcmVjdGlvbiAmIG9wdGlvbnMuZGlyZWN0aW9uO1xuICAgIH0sXG5cbiAgICBhdHRyVGVzdDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIEF0dHJSZWNvZ25pemVyLnByb3RvdHlwZS5hdHRyVGVzdC5jYWxsKHRoaXMsIGlucHV0KSAmJlxuICAgICAgICAgICAgKHRoaXMuc3RhdGUgJiBTVEFURV9CRUdBTiB8fCAoISh0aGlzLnN0YXRlICYgU1RBVEVfQkVHQU4pICYmIHRoaXMuZGlyZWN0aW9uVGVzdChpbnB1dCkpKTtcbiAgICB9LFxuXG4gICAgZW1pdDogZnVuY3Rpb24oaW5wdXQpIHtcblxuICAgICAgICB0aGlzLnBYID0gaW5wdXQuZGVsdGFYO1xuICAgICAgICB0aGlzLnBZID0gaW5wdXQuZGVsdGFZO1xuXG4gICAgICAgIHZhciBkaXJlY3Rpb24gPSBkaXJlY3Rpb25TdHIoaW5wdXQuZGlyZWN0aW9uKTtcblxuICAgICAgICBpZiAoZGlyZWN0aW9uKSB7XG4gICAgICAgICAgICBpbnB1dC5hZGRpdGlvbmFsRXZlbnQgPSB0aGlzLm9wdGlvbnMuZXZlbnQgKyBkaXJlY3Rpb247XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fc3VwZXIuZW1pdC5jYWxsKHRoaXMsIGlucHV0KTtcbiAgICB9XG59KTtcblxuLyoqXG4gKiBQaW5jaFxuICogUmVjb2duaXplZCB3aGVuIHR3byBvciBtb3JlIHBvaW50ZXJzIGFyZSBtb3ZpbmcgdG93YXJkICh6b29tLWluKSBvciBhd2F5IGZyb20gZWFjaCBvdGhlciAoem9vbS1vdXQpLlxuICogQGNvbnN0cnVjdG9yXG4gKiBAZXh0ZW5kcyBBdHRyUmVjb2duaXplclxuICovXG5mdW5jdGlvbiBQaW5jaFJlY29nbml6ZXIoKSB7XG4gICAgQXR0clJlY29nbml6ZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuaW5oZXJpdChQaW5jaFJlY29nbml6ZXIsIEF0dHJSZWNvZ25pemVyLCB7XG4gICAgLyoqXG4gICAgICogQG5hbWVzcGFjZVxuICAgICAqIEBtZW1iZXJvZiBQaW5jaFJlY29nbml6ZXJcbiAgICAgKi9cbiAgICBkZWZhdWx0czoge1xuICAgICAgICBldmVudDogJ3BpbmNoJyxcbiAgICAgICAgdGhyZXNob2xkOiAwLFxuICAgICAgICBwb2ludGVyczogMlxuICAgIH0sXG5cbiAgICBnZXRUb3VjaEFjdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBbVE9VQ0hfQUNUSU9OX05PTkVdO1xuICAgIH0sXG5cbiAgICBhdHRyVGVzdDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N1cGVyLmF0dHJUZXN0LmNhbGwodGhpcywgaW5wdXQpICYmXG4gICAgICAgICAgICAoTWF0aC5hYnMoaW5wdXQuc2NhbGUgLSAxKSA+IHRoaXMub3B0aW9ucy50aHJlc2hvbGQgfHwgdGhpcy5zdGF0ZSAmIFNUQVRFX0JFR0FOKTtcbiAgICB9LFxuXG4gICAgZW1pdDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgaWYgKGlucHV0LnNjYWxlICE9PSAxKSB7XG4gICAgICAgICAgICB2YXIgaW5PdXQgPSBpbnB1dC5zY2FsZSA8IDEgPyAnaW4nIDogJ291dCc7XG4gICAgICAgICAgICBpbnB1dC5hZGRpdGlvbmFsRXZlbnQgPSB0aGlzLm9wdGlvbnMuZXZlbnQgKyBpbk91dDtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9zdXBlci5lbWl0LmNhbGwodGhpcywgaW5wdXQpO1xuICAgIH1cbn0pO1xuXG4vKipcbiAqIFByZXNzXG4gKiBSZWNvZ25pemVkIHdoZW4gdGhlIHBvaW50ZXIgaXMgZG93biBmb3IgeCBtcyB3aXRob3V0IGFueSBtb3ZlbWVudC5cbiAqIEBjb25zdHJ1Y3RvclxuICogQGV4dGVuZHMgUmVjb2duaXplclxuICovXG5mdW5jdGlvbiBQcmVzc1JlY29nbml6ZXIoKSB7XG4gICAgUmVjb2duaXplci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgdGhpcy5fdGltZXIgPSBudWxsO1xuICAgIHRoaXMuX2lucHV0ID0gbnVsbDtcbn1cblxuaW5oZXJpdChQcmVzc1JlY29nbml6ZXIsIFJlY29nbml6ZXIsIHtcbiAgICAvKipcbiAgICAgKiBAbmFtZXNwYWNlXG4gICAgICogQG1lbWJlcm9mIFByZXNzUmVjb2duaXplclxuICAgICAqL1xuICAgIGRlZmF1bHRzOiB7XG4gICAgICAgIGV2ZW50OiAncHJlc3MnLFxuICAgICAgICBwb2ludGVyczogMSxcbiAgICAgICAgdGltZTogMjUxLCAvLyBtaW5pbWFsIHRpbWUgb2YgdGhlIHBvaW50ZXIgdG8gYmUgcHJlc3NlZFxuICAgICAgICB0aHJlc2hvbGQ6IDkgLy8gYSBtaW5pbWFsIG1vdmVtZW50IGlzIG9rLCBidXQga2VlcCBpdCBsb3dcbiAgICB9LFxuXG4gICAgZ2V0VG91Y2hBY3Rpb246IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gW1RPVUNIX0FDVElPTl9BVVRPXTtcbiAgICB9LFxuXG4gICAgcHJvY2VzczogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgdmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG4gICAgICAgIHZhciB2YWxpZFBvaW50ZXJzID0gaW5wdXQucG9pbnRlcnMubGVuZ3RoID09PSBvcHRpb25zLnBvaW50ZXJzO1xuICAgICAgICB2YXIgdmFsaWRNb3ZlbWVudCA9IGlucHV0LmRpc3RhbmNlIDwgb3B0aW9ucy50aHJlc2hvbGQ7XG4gICAgICAgIHZhciB2YWxpZFRpbWUgPSBpbnB1dC5kZWx0YVRpbWUgPiBvcHRpb25zLnRpbWU7XG5cbiAgICAgICAgdGhpcy5faW5wdXQgPSBpbnB1dDtcblxuICAgICAgICAvLyB3ZSBvbmx5IGFsbG93IGxpdHRsZSBtb3ZlbWVudFxuICAgICAgICAvLyBhbmQgd2UndmUgcmVhY2hlZCBhbiBlbmQgZXZlbnQsIHNvIGEgdGFwIGlzIHBvc3NpYmxlXG4gICAgICAgIGlmICghdmFsaWRNb3ZlbWVudCB8fCAhdmFsaWRQb2ludGVycyB8fCAoaW5wdXQuZXZlbnRUeXBlICYgKElOUFVUX0VORCB8IElOUFVUX0NBTkNFTCkgJiYgIXZhbGlkVGltZSkpIHtcbiAgICAgICAgICAgIHRoaXMucmVzZXQoKTtcbiAgICAgICAgfSBlbHNlIGlmIChpbnB1dC5ldmVudFR5cGUgJiBJTlBVVF9TVEFSVCkge1xuICAgICAgICAgICAgdGhpcy5yZXNldCgpO1xuICAgICAgICAgICAgdGhpcy5fdGltZXIgPSBzZXRUaW1lb3V0Q29udGV4dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlID0gU1RBVEVfUkVDT0dOSVpFRDtcbiAgICAgICAgICAgICAgICB0aGlzLnRyeUVtaXQoKTtcbiAgICAgICAgICAgIH0sIG9wdGlvbnMudGltZSwgdGhpcyk7XG4gICAgICAgIH0gZWxzZSBpZiAoaW5wdXQuZXZlbnRUeXBlICYgSU5QVVRfRU5EKSB7XG4gICAgICAgICAgICByZXR1cm4gU1RBVEVfUkVDT0dOSVpFRDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gU1RBVEVfRkFJTEVEO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24oKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLl90aW1lcik7XG4gICAgfSxcblxuICAgIGVtaXQ6IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlICE9PSBTVEFURV9SRUNPR05JWkVEKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5wdXQgJiYgKGlucHV0LmV2ZW50VHlwZSAmIElOUFVUX0VORCkpIHtcbiAgICAgICAgICAgIHRoaXMubWFuYWdlci5lbWl0KHRoaXMub3B0aW9ucy5ldmVudCArICd1cCcsIGlucHV0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX2lucHV0LnRpbWVTdGFtcCA9IG5vdygpO1xuICAgICAgICAgICAgdGhpcy5tYW5hZ2VyLmVtaXQodGhpcy5vcHRpb25zLmV2ZW50LCB0aGlzLl9pbnB1dCk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBSb3RhdGVcbiAqIFJlY29nbml6ZWQgd2hlbiB0d28gb3IgbW9yZSBwb2ludGVyIGFyZSBtb3ZpbmcgaW4gYSBjaXJjdWxhciBtb3Rpb24uXG4gKiBAY29uc3RydWN0b3JcbiAqIEBleHRlbmRzIEF0dHJSZWNvZ25pemVyXG4gKi9cbmZ1bmN0aW9uIFJvdGF0ZVJlY29nbml6ZXIoKSB7XG4gICAgQXR0clJlY29nbml6ZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuaW5oZXJpdChSb3RhdGVSZWNvZ25pemVyLCBBdHRyUmVjb2duaXplciwge1xuICAgIC8qKlxuICAgICAqIEBuYW1lc3BhY2VcbiAgICAgKiBAbWVtYmVyb2YgUm90YXRlUmVjb2duaXplclxuICAgICAqL1xuICAgIGRlZmF1bHRzOiB7XG4gICAgICAgIGV2ZW50OiAncm90YXRlJyxcbiAgICAgICAgdGhyZXNob2xkOiAwLFxuICAgICAgICBwb2ludGVyczogMlxuICAgIH0sXG5cbiAgICBnZXRUb3VjaEFjdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBbVE9VQ0hfQUNUSU9OX05PTkVdO1xuICAgIH0sXG5cbiAgICBhdHRyVGVzdDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N1cGVyLmF0dHJUZXN0LmNhbGwodGhpcywgaW5wdXQpICYmXG4gICAgICAgICAgICAoTWF0aC5hYnMoaW5wdXQucm90YXRpb24pID4gdGhpcy5vcHRpb25zLnRocmVzaG9sZCB8fCB0aGlzLnN0YXRlICYgU1RBVEVfQkVHQU4pO1xuICAgIH1cbn0pO1xuXG4vKipcbiAqIFN3aXBlXG4gKiBSZWNvZ25pemVkIHdoZW4gdGhlIHBvaW50ZXIgaXMgbW92aW5nIGZhc3QgKHZlbG9jaXR5KSwgd2l0aCBlbm91Z2ggZGlzdGFuY2UgaW4gdGhlIGFsbG93ZWQgZGlyZWN0aW9uLlxuICogQGNvbnN0cnVjdG9yXG4gKiBAZXh0ZW5kcyBBdHRyUmVjb2duaXplclxuICovXG5mdW5jdGlvbiBTd2lwZVJlY29nbml6ZXIoKSB7XG4gICAgQXR0clJlY29nbml6ZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuaW5oZXJpdChTd2lwZVJlY29nbml6ZXIsIEF0dHJSZWNvZ25pemVyLCB7XG4gICAgLyoqXG4gICAgICogQG5hbWVzcGFjZVxuICAgICAqIEBtZW1iZXJvZiBTd2lwZVJlY29nbml6ZXJcbiAgICAgKi9cbiAgICBkZWZhdWx0czoge1xuICAgICAgICBldmVudDogJ3N3aXBlJyxcbiAgICAgICAgdGhyZXNob2xkOiAxMCxcbiAgICAgICAgdmVsb2NpdHk6IDAuMyxcbiAgICAgICAgZGlyZWN0aW9uOiBESVJFQ1RJT05fSE9SSVpPTlRBTCB8IERJUkVDVElPTl9WRVJUSUNBTCxcbiAgICAgICAgcG9pbnRlcnM6IDFcbiAgICB9LFxuXG4gICAgZ2V0VG91Y2hBY3Rpb246IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gUGFuUmVjb2duaXplci5wcm90b3R5cGUuZ2V0VG91Y2hBY3Rpb24uY2FsbCh0aGlzKTtcbiAgICB9LFxuXG4gICAgYXR0clRlc3Q6IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgICAgIHZhciBkaXJlY3Rpb24gPSB0aGlzLm9wdGlvbnMuZGlyZWN0aW9uO1xuICAgICAgICB2YXIgdmVsb2NpdHk7XG5cbiAgICAgICAgaWYgKGRpcmVjdGlvbiAmIChESVJFQ1RJT05fSE9SSVpPTlRBTCB8IERJUkVDVElPTl9WRVJUSUNBTCkpIHtcbiAgICAgICAgICAgIHZlbG9jaXR5ID0gaW5wdXQub3ZlcmFsbFZlbG9jaXR5O1xuICAgICAgICB9IGVsc2UgaWYgKGRpcmVjdGlvbiAmIERJUkVDVElPTl9IT1JJWk9OVEFMKSB7XG4gICAgICAgICAgICB2ZWxvY2l0eSA9IGlucHV0Lm92ZXJhbGxWZWxvY2l0eVg7XG4gICAgICAgIH0gZWxzZSBpZiAoZGlyZWN0aW9uICYgRElSRUNUSU9OX1ZFUlRJQ0FMKSB7XG4gICAgICAgICAgICB2ZWxvY2l0eSA9IGlucHV0Lm92ZXJhbGxWZWxvY2l0eVk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5fc3VwZXIuYXR0clRlc3QuY2FsbCh0aGlzLCBpbnB1dCkgJiZcbiAgICAgICAgICAgIGRpcmVjdGlvbiAmIGlucHV0Lm9mZnNldERpcmVjdGlvbiAmJlxuICAgICAgICAgICAgaW5wdXQuZGlzdGFuY2UgPiB0aGlzLm9wdGlvbnMudGhyZXNob2xkICYmXG4gICAgICAgICAgICBpbnB1dC5tYXhQb2ludGVycyA9PSB0aGlzLm9wdGlvbnMucG9pbnRlcnMgJiZcbiAgICAgICAgICAgIGFicyh2ZWxvY2l0eSkgPiB0aGlzLm9wdGlvbnMudmVsb2NpdHkgJiYgaW5wdXQuZXZlbnRUeXBlICYgSU5QVVRfRU5EO1xuICAgIH0sXG5cbiAgICBlbWl0OiBmdW5jdGlvbihpbnB1dCkge1xuICAgICAgICB2YXIgZGlyZWN0aW9uID0gZGlyZWN0aW9uU3RyKGlucHV0Lm9mZnNldERpcmVjdGlvbik7XG4gICAgICAgIGlmIChkaXJlY3Rpb24pIHtcbiAgICAgICAgICAgIHRoaXMubWFuYWdlci5lbWl0KHRoaXMub3B0aW9ucy5ldmVudCArIGRpcmVjdGlvbiwgaW5wdXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tYW5hZ2VyLmVtaXQodGhpcy5vcHRpb25zLmV2ZW50LCBpbnB1dCk7XG4gICAgfVxufSk7XG5cbi8qKlxuICogQSB0YXAgaXMgZWNvZ25pemVkIHdoZW4gdGhlIHBvaW50ZXIgaXMgZG9pbmcgYSBzbWFsbCB0YXAvY2xpY2suIE11bHRpcGxlIHRhcHMgYXJlIHJlY29nbml6ZWQgaWYgdGhleSBvY2N1clxuICogYmV0d2VlbiB0aGUgZ2l2ZW4gaW50ZXJ2YWwgYW5kIHBvc2l0aW9uLiBUaGUgZGVsYXkgb3B0aW9uIGNhbiBiZSB1c2VkIHRvIHJlY29nbml6ZSBtdWx0aS10YXBzIHdpdGhvdXQgZmlyaW5nXG4gKiBhIHNpbmdsZSB0YXAuXG4gKlxuICogVGhlIGV2ZW50RGF0YSBmcm9tIHRoZSBlbWl0dGVkIGV2ZW50IGNvbnRhaW5zIHRoZSBwcm9wZXJ0eSBgdGFwQ291bnRgLCB3aGljaCBjb250YWlucyB0aGUgYW1vdW50IG9mXG4gKiBtdWx0aS10YXBzIGJlaW5nIHJlY29nbml6ZWQuXG4gKiBAY29uc3RydWN0b3JcbiAqIEBleHRlbmRzIFJlY29nbml6ZXJcbiAqL1xuZnVuY3Rpb24gVGFwUmVjb2duaXplcigpIHtcbiAgICBSZWNvZ25pemVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAvLyBwcmV2aW91cyB0aW1lIGFuZCBjZW50ZXIsXG4gICAgLy8gdXNlZCBmb3IgdGFwIGNvdW50aW5nXG4gICAgdGhpcy5wVGltZSA9IGZhbHNlO1xuICAgIHRoaXMucENlbnRlciA9IGZhbHNlO1xuXG4gICAgdGhpcy5fdGltZXIgPSBudWxsO1xuICAgIHRoaXMuX2lucHV0ID0gbnVsbDtcbiAgICB0aGlzLmNvdW50ID0gMDtcbn1cblxuaW5oZXJpdChUYXBSZWNvZ25pemVyLCBSZWNvZ25pemVyLCB7XG4gICAgLyoqXG4gICAgICogQG5hbWVzcGFjZVxuICAgICAqIEBtZW1iZXJvZiBQaW5jaFJlY29nbml6ZXJcbiAgICAgKi9cbiAgICBkZWZhdWx0czoge1xuICAgICAgICBldmVudDogJ3RhcCcsXG4gICAgICAgIHBvaW50ZXJzOiAxLFxuICAgICAgICB0YXBzOiAxLFxuICAgICAgICBpbnRlcnZhbDogMzAwLCAvLyBtYXggdGltZSBiZXR3ZWVuIHRoZSBtdWx0aS10YXAgdGFwc1xuICAgICAgICB0aW1lOiAyNTAsIC8vIG1heCB0aW1lIG9mIHRoZSBwb2ludGVyIHRvIGJlIGRvd24gKGxpa2UgZmluZ2VyIG9uIHRoZSBzY3JlZW4pXG4gICAgICAgIHRocmVzaG9sZDogOSwgLy8gYSBtaW5pbWFsIG1vdmVtZW50IGlzIG9rLCBidXQga2VlcCBpdCBsb3dcbiAgICAgICAgcG9zVGhyZXNob2xkOiAxMCAvLyBhIG11bHRpLXRhcCBjYW4gYmUgYSBiaXQgb2ZmIHRoZSBpbml0aWFsIHBvc2l0aW9uXG4gICAgfSxcblxuICAgIGdldFRvdWNoQWN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIFtUT1VDSF9BQ1RJT05fTUFOSVBVTEFUSU9OXTtcbiAgICB9LFxuXG4gICAgcHJvY2VzczogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgdmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cbiAgICAgICAgdmFyIHZhbGlkUG9pbnRlcnMgPSBpbnB1dC5wb2ludGVycy5sZW5ndGggPT09IG9wdGlvbnMucG9pbnRlcnM7XG4gICAgICAgIHZhciB2YWxpZE1vdmVtZW50ID0gaW5wdXQuZGlzdGFuY2UgPCBvcHRpb25zLnRocmVzaG9sZDtcbiAgICAgICAgdmFyIHZhbGlkVG91Y2hUaW1lID0gaW5wdXQuZGVsdGFUaW1lIDwgb3B0aW9ucy50aW1lO1xuXG4gICAgICAgIHRoaXMucmVzZXQoKTtcblxuICAgICAgICBpZiAoKGlucHV0LmV2ZW50VHlwZSAmIElOUFVUX1NUQVJUKSAmJiAodGhpcy5jb3VudCA9PT0gMCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmZhaWxUaW1lb3V0KCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB3ZSBvbmx5IGFsbG93IGxpdHRsZSBtb3ZlbWVudFxuICAgICAgICAvLyBhbmQgd2UndmUgcmVhY2hlZCBhbiBlbmQgZXZlbnQsIHNvIGEgdGFwIGlzIHBvc3NpYmxlXG4gICAgICAgIGlmICh2YWxpZE1vdmVtZW50ICYmIHZhbGlkVG91Y2hUaW1lICYmIHZhbGlkUG9pbnRlcnMpIHtcbiAgICAgICAgICAgIGlmIChpbnB1dC5ldmVudFR5cGUgIT0gSU5QVVRfRU5EKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZmFpbFRpbWVvdXQoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHZhbGlkSW50ZXJ2YWwgPSB0aGlzLnBUaW1lID8gKGlucHV0LnRpbWVTdGFtcCAtIHRoaXMucFRpbWUgPCBvcHRpb25zLmludGVydmFsKSA6IHRydWU7XG4gICAgICAgICAgICB2YXIgdmFsaWRNdWx0aVRhcCA9ICF0aGlzLnBDZW50ZXIgfHwgZ2V0RGlzdGFuY2UodGhpcy5wQ2VudGVyLCBpbnB1dC5jZW50ZXIpIDwgb3B0aW9ucy5wb3NUaHJlc2hvbGQ7XG5cbiAgICAgICAgICAgIHRoaXMucFRpbWUgPSBpbnB1dC50aW1lU3RhbXA7XG4gICAgICAgICAgICB0aGlzLnBDZW50ZXIgPSBpbnB1dC5jZW50ZXI7XG5cbiAgICAgICAgICAgIGlmICghdmFsaWRNdWx0aVRhcCB8fCAhdmFsaWRJbnRlcnZhbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY291bnQgPSAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvdW50ICs9IDE7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX2lucHV0ID0gaW5wdXQ7XG5cbiAgICAgICAgICAgIC8vIGlmIHRhcCBjb3VudCBtYXRjaGVzIHdlIGhhdmUgcmVjb2duaXplZCBpdCxcbiAgICAgICAgICAgIC8vIGVsc2UgaXQgaGFzIGJlZ2FuIHJlY29nbml6aW5nLi4uXG4gICAgICAgICAgICB2YXIgdGFwQ291bnQgPSB0aGlzLmNvdW50ICUgb3B0aW9ucy50YXBzO1xuICAgICAgICAgICAgaWYgKHRhcENvdW50ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgLy8gbm8gZmFpbGluZyByZXF1aXJlbWVudHMsIGltbWVkaWF0ZWx5IHRyaWdnZXIgdGhlIHRhcCBldmVudFxuICAgICAgICAgICAgICAgIC8vIG9yIHdhaXQgYXMgbG9uZyBhcyB0aGUgbXVsdGl0YXAgaW50ZXJ2YWwgdG8gdHJpZ2dlclxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5oYXNSZXF1aXJlRmFpbHVyZXMoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gU1RBVEVfUkVDT0dOSVpFRDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl90aW1lciA9IHNldFRpbWVvdXRDb250ZXh0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zdGF0ZSA9IFNUQVRFX1JFQ09HTklaRUQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnRyeUVtaXQoKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgb3B0aW9ucy5pbnRlcnZhbCwgdGhpcyk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBTVEFURV9CRUdBTjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFNUQVRFX0ZBSUxFRDtcbiAgICB9LFxuXG4gICAgZmFpbFRpbWVvdXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLl90aW1lciA9IHNldFRpbWVvdXRDb250ZXh0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdGhpcy5zdGF0ZSA9IFNUQVRFX0ZBSUxFRDtcbiAgICAgICAgfSwgdGhpcy5vcHRpb25zLmludGVydmFsLCB0aGlzKTtcbiAgICAgICAgcmV0dXJuIFNUQVRFX0ZBSUxFRDtcbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5fdGltZXIpO1xuICAgIH0sXG5cbiAgICBlbWl0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUgPT0gU1RBVEVfUkVDT0dOSVpFRCkge1xuICAgICAgICAgICAgdGhpcy5faW5wdXQudGFwQ291bnQgPSB0aGlzLmNvdW50O1xuICAgICAgICAgICAgdGhpcy5tYW5hZ2VyLmVtaXQodGhpcy5vcHRpb25zLmV2ZW50LCB0aGlzLl9pbnB1dCk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBTaW1wbGUgd2F5IHRvIGNyZWF0ZSBhIG1hbmFnZXIgd2l0aCBhIGRlZmF1bHQgc2V0IG9mIHJlY29nbml6ZXJzLlxuICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWxlbWVudFxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIEhhbW1lcihlbGVtZW50LCBvcHRpb25zKSB7XG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgb3B0aW9ucy5yZWNvZ25pemVycyA9IGlmVW5kZWZpbmVkKG9wdGlvbnMucmVjb2duaXplcnMsIEhhbW1lci5kZWZhdWx0cy5wcmVzZXQpO1xuICAgIHJldHVybiBuZXcgTWFuYWdlcihlbGVtZW50LCBvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBAY29uc3Qge3N0cmluZ31cbiAqL1xuSGFtbWVyLlZFUlNJT04gPSAnMi4wLjcnO1xuXG4vKipcbiAqIGRlZmF1bHQgc2V0dGluZ3NcbiAqIEBuYW1lc3BhY2VcbiAqL1xuSGFtbWVyLmRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIHNldCBpZiBET00gZXZlbnRzIGFyZSBiZWluZyB0cmlnZ2VyZWQuXG4gICAgICogQnV0IHRoaXMgaXMgc2xvd2VyIGFuZCB1bnVzZWQgYnkgc2ltcGxlIGltcGxlbWVudGF0aW9ucywgc28gZGlzYWJsZWQgYnkgZGVmYXVsdC5cbiAgICAgKiBAdHlwZSB7Qm9vbGVhbn1cbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgICAqL1xuICAgIGRvbUV2ZW50czogZmFsc2UsXG5cbiAgICAvKipcbiAgICAgKiBUaGUgdmFsdWUgZm9yIHRoZSB0b3VjaEFjdGlvbiBwcm9wZXJ0eS9mYWxsYmFjay5cbiAgICAgKiBXaGVuIHNldCB0byBgY29tcHV0ZWAgaXQgd2lsbCBtYWdpY2FsbHkgc2V0IHRoZSBjb3JyZWN0IHZhbHVlIGJhc2VkIG9uIHRoZSBhZGRlZCByZWNvZ25pemVycy5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqIEBkZWZhdWx0IGNvbXB1dGVcbiAgICAgKi9cbiAgICB0b3VjaEFjdGlvbjogVE9VQ0hfQUNUSU9OX0NPTVBVVEUsXG5cbiAgICAvKipcbiAgICAgKiBAdHlwZSB7Qm9vbGVhbn1cbiAgICAgKiBAZGVmYXVsdCB0cnVlXG4gICAgICovXG4gICAgZW5hYmxlOiB0cnVlLFxuXG4gICAgLyoqXG4gICAgICogRVhQRVJJTUVOVEFMIEZFQVRVUkUgLS0gY2FuIGJlIHJlbW92ZWQvY2hhbmdlZFxuICAgICAqIENoYW5nZSB0aGUgcGFyZW50IGlucHV0IHRhcmdldCBlbGVtZW50LlxuICAgICAqIElmIE51bGwsIHRoZW4gaXQgaXMgYmVpbmcgc2V0IHRoZSB0byBtYWluIGVsZW1lbnQuXG4gICAgICogQHR5cGUge051bGx8RXZlbnRUYXJnZXR9XG4gICAgICogQGRlZmF1bHQgbnVsbFxuICAgICAqL1xuICAgIGlucHV0VGFyZ2V0OiBudWxsLFxuXG4gICAgLyoqXG4gICAgICogZm9yY2UgYW4gaW5wdXQgY2xhc3NcbiAgICAgKiBAdHlwZSB7TnVsbHxGdW5jdGlvbn1cbiAgICAgKiBAZGVmYXVsdCBudWxsXG4gICAgICovXG4gICAgaW5wdXRDbGFzczogbnVsbCxcblxuICAgIC8qKlxuICAgICAqIERlZmF1bHQgcmVjb2duaXplciBzZXR1cCB3aGVuIGNhbGxpbmcgYEhhbW1lcigpYFxuICAgICAqIFdoZW4gY3JlYXRpbmcgYSBuZXcgTWFuYWdlciB0aGVzZSB3aWxsIGJlIHNraXBwZWQuXG4gICAgICogQHR5cGUge0FycmF5fVxuICAgICAqL1xuICAgIHByZXNldDogW1xuICAgICAgICAvLyBSZWNvZ25pemVyQ2xhc3MsIG9wdGlvbnMsIFtyZWNvZ25pemVXaXRoLCAuLi5dLCBbcmVxdWlyZUZhaWx1cmUsIC4uLl1cbiAgICAgICAgW1JvdGF0ZVJlY29nbml6ZXIsIHtlbmFibGU6IGZhbHNlfV0sXG4gICAgICAgIFtQaW5jaFJlY29nbml6ZXIsIHtlbmFibGU6IGZhbHNlfSwgWydyb3RhdGUnXV0sXG4gICAgICAgIFtTd2lwZVJlY29nbml6ZXIsIHtkaXJlY3Rpb246IERJUkVDVElPTl9IT1JJWk9OVEFMfV0sXG4gICAgICAgIFtQYW5SZWNvZ25pemVyLCB7ZGlyZWN0aW9uOiBESVJFQ1RJT05fSE9SSVpPTlRBTH0sIFsnc3dpcGUnXV0sXG4gICAgICAgIFtUYXBSZWNvZ25pemVyXSxcbiAgICAgICAgW1RhcFJlY29nbml6ZXIsIHtldmVudDogJ2RvdWJsZXRhcCcsIHRhcHM6IDJ9LCBbJ3RhcCddXSxcbiAgICAgICAgW1ByZXNzUmVjb2duaXplcl1cbiAgICBdLFxuXG4gICAgLyoqXG4gICAgICogU29tZSBDU1MgcHJvcGVydGllcyBjYW4gYmUgdXNlZCB0byBpbXByb3ZlIHRoZSB3b3JraW5nIG9mIEhhbW1lci5cbiAgICAgKiBBZGQgdGhlbSB0byB0aGlzIG1ldGhvZCBhbmQgdGhleSB3aWxsIGJlIHNldCB3aGVuIGNyZWF0aW5nIGEgbmV3IE1hbmFnZXIuXG4gICAgICogQG5hbWVzcGFjZVxuICAgICAqL1xuICAgIGNzc1Byb3BzOiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEaXNhYmxlcyB0ZXh0IHNlbGVjdGlvbiB0byBpbXByb3ZlIHRoZSBkcmFnZ2luZyBnZXN0dXJlLiBNYWlubHkgZm9yIGRlc2t0b3AgYnJvd3NlcnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqIEBkZWZhdWx0ICdub25lJ1xuICAgICAgICAgKi9cbiAgICAgICAgdXNlclNlbGVjdDogJ25vbmUnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEaXNhYmxlIHRoZSBXaW5kb3dzIFBob25lIGdyaXBwZXJzIHdoZW4gcHJlc3NpbmcgYW4gZWxlbWVudC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICogQGRlZmF1bHQgJ25vbmUnXG4gICAgICAgICAqL1xuICAgICAgICB0b3VjaFNlbGVjdDogJ25vbmUnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEaXNhYmxlcyB0aGUgZGVmYXVsdCBjYWxsb3V0IHNob3duIHdoZW4geW91IHRvdWNoIGFuZCBob2xkIGEgdG91Y2ggdGFyZ2V0LlxuICAgICAgICAgKiBPbiBpT1MsIHdoZW4geW91IHRvdWNoIGFuZCBob2xkIGEgdG91Y2ggdGFyZ2V0IHN1Y2ggYXMgYSBsaW5rLCBTYWZhcmkgZGlzcGxheXNcbiAgICAgICAgICogYSBjYWxsb3V0IGNvbnRhaW5pbmcgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGxpbmsuIFRoaXMgcHJvcGVydHkgYWxsb3dzIHlvdSB0byBkaXNhYmxlIHRoYXQgY2FsbG91dC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICogQGRlZmF1bHQgJ25vbmUnXG4gICAgICAgICAqL1xuICAgICAgICB0b3VjaENhbGxvdXQ6ICdub25lJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU3BlY2lmaWVzIHdoZXRoZXIgem9vbWluZyBpcyBlbmFibGVkLiBVc2VkIGJ5IElFMTA+XG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqIEBkZWZhdWx0ICdub25lJ1xuICAgICAgICAgKi9cbiAgICAgICAgY29udGVudFpvb21pbmc6ICdub25lJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU3BlY2lmaWVzIHRoYXQgYW4gZW50aXJlIGVsZW1lbnQgc2hvdWxkIGJlIGRyYWdnYWJsZSBpbnN0ZWFkIG9mIGl0cyBjb250ZW50cy4gTWFpbmx5IGZvciBkZXNrdG9wIGJyb3dzZXJzLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKiBAZGVmYXVsdCAnbm9uZSdcbiAgICAgICAgICovXG4gICAgICAgIHVzZXJEcmFnOiAnbm9uZScsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE92ZXJyaWRlcyB0aGUgaGlnaGxpZ2h0IGNvbG9yIHNob3duIHdoZW4gdGhlIHVzZXIgdGFwcyBhIGxpbmsgb3IgYSBKYXZhU2NyaXB0XG4gICAgICAgICAqIGNsaWNrYWJsZSBlbGVtZW50IGluIGlPUy4gVGhpcyBwcm9wZXJ0eSBvYmV5cyB0aGUgYWxwaGEgdmFsdWUsIGlmIHNwZWNpZmllZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICogQGRlZmF1bHQgJ3JnYmEoMCwwLDAsMCknXG4gICAgICAgICAqL1xuICAgICAgICB0YXBIaWdobGlnaHRDb2xvcjogJ3JnYmEoMCwwLDAsMCknXG4gICAgfVxufTtcblxudmFyIFNUT1AgPSAxO1xudmFyIEZPUkNFRF9TVE9QID0gMjtcblxuLyoqXG4gKiBNYW5hZ2VyXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbGVtZW50XG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnNdXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZnVuY3Rpb24gTWFuYWdlcihlbGVtZW50LCBvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gYXNzaWduKHt9LCBIYW1tZXIuZGVmYXVsdHMsIG9wdGlvbnMgfHwge30pO1xuXG4gICAgdGhpcy5vcHRpb25zLmlucHV0VGFyZ2V0ID0gdGhpcy5vcHRpb25zLmlucHV0VGFyZ2V0IHx8IGVsZW1lbnQ7XG5cbiAgICB0aGlzLmhhbmRsZXJzID0ge307XG4gICAgdGhpcy5zZXNzaW9uID0ge307XG4gICAgdGhpcy5yZWNvZ25pemVycyA9IFtdO1xuICAgIHRoaXMub2xkQ3NzUHJvcHMgPSB7fTtcblxuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgdGhpcy5pbnB1dCA9IGNyZWF0ZUlucHV0SW5zdGFuY2UodGhpcyk7XG4gICAgdGhpcy50b3VjaEFjdGlvbiA9IG5ldyBUb3VjaEFjdGlvbih0aGlzLCB0aGlzLm9wdGlvbnMudG91Y2hBY3Rpb24pO1xuXG4gICAgdG9nZ2xlQ3NzUHJvcHModGhpcywgdHJ1ZSk7XG5cbiAgICBlYWNoKHRoaXMub3B0aW9ucy5yZWNvZ25pemVycywgZnVuY3Rpb24oaXRlbSkge1xuICAgICAgICB2YXIgcmVjb2duaXplciA9IHRoaXMuYWRkKG5ldyAoaXRlbVswXSkoaXRlbVsxXSkpO1xuICAgICAgICBpdGVtWzJdICYmIHJlY29nbml6ZXIucmVjb2duaXplV2l0aChpdGVtWzJdKTtcbiAgICAgICAgaXRlbVszXSAmJiByZWNvZ25pemVyLnJlcXVpcmVGYWlsdXJlKGl0ZW1bM10pO1xuICAgIH0sIHRoaXMpO1xufVxuXG5NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBzZXQgb3B0aW9uc1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gICAgICogQHJldHVybnMge01hbmFnZXJ9XG4gICAgICovXG4gICAgc2V0OiBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgICAgIGFzc2lnbih0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIC8vIE9wdGlvbnMgdGhhdCBuZWVkIGEgbGl0dGxlIG1vcmUgc2V0dXBcbiAgICAgICAgaWYgKG9wdGlvbnMudG91Y2hBY3Rpb24pIHtcbiAgICAgICAgICAgIHRoaXMudG91Y2hBY3Rpb24udXBkYXRlKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuaW5wdXRUYXJnZXQpIHtcbiAgICAgICAgICAgIC8vIENsZWFuIHVwIGV4aXN0aW5nIGV2ZW50IGxpc3RlbmVycyBhbmQgcmVpbml0aWFsaXplXG4gICAgICAgICAgICB0aGlzLmlucHV0LmRlc3Ryb3koKTtcbiAgICAgICAgICAgIHRoaXMuaW5wdXQudGFyZ2V0ID0gb3B0aW9ucy5pbnB1dFRhcmdldDtcbiAgICAgICAgICAgIHRoaXMuaW5wdXQuaW5pdCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBzdG9wIHJlY29nbml6aW5nIGZvciB0aGlzIHNlc3Npb24uXG4gICAgICogVGhpcyBzZXNzaW9uIHdpbGwgYmUgZGlzY2FyZGVkLCB3aGVuIGEgbmV3IFtpbnB1dF1zdGFydCBldmVudCBpcyBmaXJlZC5cbiAgICAgKiBXaGVuIGZvcmNlZCwgdGhlIHJlY29nbml6ZXIgY3ljbGUgaXMgc3RvcHBlZCBpbW1lZGlhdGVseS5cbiAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IFtmb3JjZV1cbiAgICAgKi9cbiAgICBzdG9wOiBmdW5jdGlvbihmb3JjZSkge1xuICAgICAgICB0aGlzLnNlc3Npb24uc3RvcHBlZCA9IGZvcmNlID8gRk9SQ0VEX1NUT1AgOiBTVE9QO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBydW4gdGhlIHJlY29nbml6ZXJzIVxuICAgICAqIGNhbGxlZCBieSB0aGUgaW5wdXRIYW5kbGVyIGZ1bmN0aW9uIG9uIGV2ZXJ5IG1vdmVtZW50IG9mIHRoZSBwb2ludGVycyAodG91Y2hlcylcbiAgICAgKiBpdCB3YWxrcyB0aHJvdWdoIGFsbCB0aGUgcmVjb2duaXplcnMgYW5kIHRyaWVzIHRvIGRldGVjdCB0aGUgZ2VzdHVyZSB0aGF0IGlzIGJlaW5nIG1hZGVcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gaW5wdXREYXRhXG4gICAgICovXG4gICAgcmVjb2duaXplOiBmdW5jdGlvbihpbnB1dERhdGEpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb247XG4gICAgICAgIGlmIChzZXNzaW9uLnN0b3BwZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHJ1biB0aGUgdG91Y2gtYWN0aW9uIHBvbHlmaWxsXG4gICAgICAgIHRoaXMudG91Y2hBY3Rpb24ucHJldmVudERlZmF1bHRzKGlucHV0RGF0YSk7XG5cbiAgICAgICAgdmFyIHJlY29nbml6ZXI7XG4gICAgICAgIHZhciByZWNvZ25pemVycyA9IHRoaXMucmVjb2duaXplcnM7XG5cbiAgICAgICAgLy8gdGhpcyBob2xkcyB0aGUgcmVjb2duaXplciB0aGF0IGlzIGJlaW5nIHJlY29nbml6ZWQuXG4gICAgICAgIC8vIHNvIHRoZSByZWNvZ25pemVyJ3Mgc3RhdGUgbmVlZHMgdG8gYmUgQkVHQU4sIENIQU5HRUQsIEVOREVEIG9yIFJFQ09HTklaRURcbiAgICAgICAgLy8gaWYgbm8gcmVjb2duaXplciBpcyBkZXRlY3RpbmcgYSB0aGluZywgaXQgaXMgc2V0IHRvIGBudWxsYFxuICAgICAgICB2YXIgY3VyUmVjb2duaXplciA9IHNlc3Npb24uY3VyUmVjb2duaXplcjtcblxuICAgICAgICAvLyByZXNldCB3aGVuIHRoZSBsYXN0IHJlY29nbml6ZXIgaXMgcmVjb2duaXplZFxuICAgICAgICAvLyBvciB3aGVuIHdlJ3JlIGluIGEgbmV3IHNlc3Npb25cbiAgICAgICAgaWYgKCFjdXJSZWNvZ25pemVyIHx8IChjdXJSZWNvZ25pemVyICYmIGN1clJlY29nbml6ZXIuc3RhdGUgJiBTVEFURV9SRUNPR05JWkVEKSkge1xuICAgICAgICAgICAgY3VyUmVjb2duaXplciA9IHNlc3Npb24uY3VyUmVjb2duaXplciA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgaSA9IDA7XG4gICAgICAgIHdoaWxlIChpIDwgcmVjb2duaXplcnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZWNvZ25pemVyID0gcmVjb2duaXplcnNbaV07XG5cbiAgICAgICAgICAgIC8vIGZpbmQgb3V0IGlmIHdlIGFyZSBhbGxvd2VkIHRyeSB0byByZWNvZ25pemUgdGhlIGlucHV0IGZvciB0aGlzIG9uZS5cbiAgICAgICAgICAgIC8vIDEuICAgYWxsb3cgaWYgdGhlIHNlc3Npb24gaXMgTk9UIGZvcmNlZCBzdG9wcGVkIChzZWUgdGhlIC5zdG9wKCkgbWV0aG9kKVxuICAgICAgICAgICAgLy8gMi4gICBhbGxvdyBpZiB3ZSBzdGlsbCBoYXZlbid0IHJlY29nbml6ZWQgYSBnZXN0dXJlIGluIHRoaXMgc2Vzc2lvbiwgb3IgdGhlIHRoaXMgcmVjb2duaXplciBpcyB0aGUgb25lXG4gICAgICAgICAgICAvLyAgICAgIHRoYXQgaXMgYmVpbmcgcmVjb2duaXplZC5cbiAgICAgICAgICAgIC8vIDMuICAgYWxsb3cgaWYgdGhlIHJlY29nbml6ZXIgaXMgYWxsb3dlZCB0byBydW4gc2ltdWx0YW5lb3VzIHdpdGggdGhlIGN1cnJlbnQgcmVjb2duaXplZCByZWNvZ25pemVyLlxuICAgICAgICAgICAgLy8gICAgICB0aGlzIGNhbiBiZSBzZXR1cCB3aXRoIHRoZSBgcmVjb2duaXplV2l0aCgpYCBtZXRob2Qgb24gdGhlIHJlY29nbml6ZXIuXG4gICAgICAgICAgICBpZiAoc2Vzc2lvbi5zdG9wcGVkICE9PSBGT1JDRURfU1RPUCAmJiAoIC8vIDFcbiAgICAgICAgICAgICAgICAgICAgIWN1clJlY29nbml6ZXIgfHwgcmVjb2duaXplciA9PSBjdXJSZWNvZ25pemVyIHx8IC8vIDJcbiAgICAgICAgICAgICAgICAgICAgcmVjb2duaXplci5jYW5SZWNvZ25pemVXaXRoKGN1clJlY29nbml6ZXIpKSkgeyAvLyAzXG4gICAgICAgICAgICAgICAgcmVjb2duaXplci5yZWNvZ25pemUoaW5wdXREYXRhKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVjb2duaXplci5yZXNldCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBpZiB0aGUgcmVjb2duaXplciBoYXMgYmVlbiByZWNvZ25pemluZyB0aGUgaW5wdXQgYXMgYSB2YWxpZCBnZXN0dXJlLCB3ZSB3YW50IHRvIHN0b3JlIHRoaXMgb25lIGFzIHRoZVxuICAgICAgICAgICAgLy8gY3VycmVudCBhY3RpdmUgcmVjb2duaXplci4gYnV0IG9ubHkgaWYgd2UgZG9uJ3QgYWxyZWFkeSBoYXZlIGFuIGFjdGl2ZSByZWNvZ25pemVyXG4gICAgICAgICAgICBpZiAoIWN1clJlY29nbml6ZXIgJiYgcmVjb2duaXplci5zdGF0ZSAmIChTVEFURV9CRUdBTiB8IFNUQVRFX0NIQU5HRUQgfCBTVEFURV9FTkRFRCkpIHtcbiAgICAgICAgICAgICAgICBjdXJSZWNvZ25pemVyID0gc2Vzc2lvbi5jdXJSZWNvZ25pemVyID0gcmVjb2duaXplcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGkrKztcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBnZXQgYSByZWNvZ25pemVyIGJ5IGl0cyBldmVudCBuYW1lLlxuICAgICAqIEBwYXJhbSB7UmVjb2duaXplcnxTdHJpbmd9IHJlY29nbml6ZXJcbiAgICAgKiBAcmV0dXJucyB7UmVjb2duaXplcnxOdWxsfVxuICAgICAqL1xuICAgIGdldDogZnVuY3Rpb24ocmVjb2duaXplcikge1xuICAgICAgICBpZiAocmVjb2duaXplciBpbnN0YW5jZW9mIFJlY29nbml6ZXIpIHtcbiAgICAgICAgICAgIHJldHVybiByZWNvZ25pemVyO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlY29nbml6ZXJzID0gdGhpcy5yZWNvZ25pemVycztcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZWNvZ25pemVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHJlY29nbml6ZXJzW2ldLm9wdGlvbnMuZXZlbnQgPT0gcmVjb2duaXplcikge1xuICAgICAgICAgICAgICAgIHJldHVybiByZWNvZ25pemVyc1tpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogYWRkIGEgcmVjb2duaXplciB0byB0aGUgbWFuYWdlclxuICAgICAqIGV4aXN0aW5nIHJlY29nbml6ZXJzIHdpdGggdGhlIHNhbWUgZXZlbnQgbmFtZSB3aWxsIGJlIHJlbW92ZWRcbiAgICAgKiBAcGFyYW0ge1JlY29nbml6ZXJ9IHJlY29nbml6ZXJcbiAgICAgKiBAcmV0dXJucyB7UmVjb2duaXplcnxNYW5hZ2VyfVxuICAgICAqL1xuICAgIGFkZDogZnVuY3Rpb24ocmVjb2duaXplcikge1xuICAgICAgICBpZiAoaW52b2tlQXJyYXlBcmcocmVjb2duaXplciwgJ2FkZCcsIHRoaXMpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHJlbW92ZSBleGlzdGluZ1xuICAgICAgICB2YXIgZXhpc3RpbmcgPSB0aGlzLmdldChyZWNvZ25pemVyLm9wdGlvbnMuZXZlbnQpO1xuICAgICAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlKGV4aXN0aW5nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVjb2duaXplcnMucHVzaChyZWNvZ25pemVyKTtcbiAgICAgICAgcmVjb2duaXplci5tYW5hZ2VyID0gdGhpcztcblxuICAgICAgICB0aGlzLnRvdWNoQWN0aW9uLnVwZGF0ZSgpO1xuICAgICAgICByZXR1cm4gcmVjb2duaXplcjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogcmVtb3ZlIGEgcmVjb2duaXplciBieSBuYW1lIG9yIGluc3RhbmNlXG4gICAgICogQHBhcmFtIHtSZWNvZ25pemVyfFN0cmluZ30gcmVjb2duaXplclxuICAgICAqIEByZXR1cm5zIHtNYW5hZ2VyfVxuICAgICAqL1xuICAgIHJlbW92ZTogZnVuY3Rpb24ocmVjb2duaXplcikge1xuICAgICAgICBpZiAoaW52b2tlQXJyYXlBcmcocmVjb2duaXplciwgJ3JlbW92ZScsIHRoaXMpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIHJlY29nbml6ZXIgPSB0aGlzLmdldChyZWNvZ25pemVyKTtcblxuICAgICAgICAvLyBsZXQncyBtYWtlIHN1cmUgdGhpcyByZWNvZ25pemVyIGV4aXN0c1xuICAgICAgICBpZiAocmVjb2duaXplcikge1xuICAgICAgICAgICAgdmFyIHJlY29nbml6ZXJzID0gdGhpcy5yZWNvZ25pemVycztcbiAgICAgICAgICAgIHZhciBpbmRleCA9IGluQXJyYXkocmVjb2duaXplcnMsIHJlY29nbml6ZXIpO1xuXG4gICAgICAgICAgICBpZiAoaW5kZXggIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmVjb2duaXplcnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgICAgICAgICB0aGlzLnRvdWNoQWN0aW9uLnVwZGF0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIGJpbmQgZXZlbnRcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gZXZlbnRzXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gaGFuZGxlclxuICAgICAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IHRoaXNcbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24oZXZlbnRzLCBoYW5kbGVyKSB7XG4gICAgICAgIGlmIChldmVudHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChoYW5kbGVyID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBoYW5kbGVycyA9IHRoaXMuaGFuZGxlcnM7XG4gICAgICAgIGVhY2goc3BsaXRTdHIoZXZlbnRzKSwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAgICAgICAgIGhhbmRsZXJzW2V2ZW50XSA9IGhhbmRsZXJzW2V2ZW50XSB8fCBbXTtcbiAgICAgICAgICAgIGhhbmRsZXJzW2V2ZW50XS5wdXNoKGhhbmRsZXIpO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIHVuYmluZCBldmVudCwgbGVhdmUgZW1pdCBibGFuayB0byByZW1vdmUgYWxsIGhhbmRsZXJzXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGV2ZW50c1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtoYW5kbGVyXVxuICAgICAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IHRoaXNcbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uKGV2ZW50cywgaGFuZGxlcikge1xuICAgICAgICBpZiAoZXZlbnRzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBoYW5kbGVycyA9IHRoaXMuaGFuZGxlcnM7XG4gICAgICAgIGVhY2goc3BsaXRTdHIoZXZlbnRzKSwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAgICAgICAgIGlmICghaGFuZGxlcikge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBoYW5kbGVyc1tldmVudF07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGhhbmRsZXJzW2V2ZW50XSAmJiBoYW5kbGVyc1tldmVudF0uc3BsaWNlKGluQXJyYXkoaGFuZGxlcnNbZXZlbnRdLCBoYW5kbGVyKSwgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogZW1pdCBldmVudCB0byB0aGUgbGlzdGVuZXJzXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGV2ZW50XG4gICAgICogQHBhcmFtIHtPYmplY3R9IGRhdGFcbiAgICAgKi9cbiAgICBlbWl0OiBmdW5jdGlvbihldmVudCwgZGF0YSkge1xuICAgICAgICAvLyB3ZSBhbHNvIHdhbnQgdG8gdHJpZ2dlciBkb20gZXZlbnRzXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZG9tRXZlbnRzKSB7XG4gICAgICAgICAgICB0cmlnZ2VyRG9tRXZlbnQoZXZlbnQsIGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbm8gaGFuZGxlcnMsIHNvIHNraXAgaXQgYWxsXG4gICAgICAgIHZhciBoYW5kbGVycyA9IHRoaXMuaGFuZGxlcnNbZXZlbnRdICYmIHRoaXMuaGFuZGxlcnNbZXZlbnRdLnNsaWNlKCk7XG4gICAgICAgIGlmICghaGFuZGxlcnMgfHwgIWhhbmRsZXJzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZGF0YS50eXBlID0gZXZlbnQ7XG4gICAgICAgIGRhdGEucHJldmVudERlZmF1bHQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGRhdGEuc3JjRXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaSA9IDA7XG4gICAgICAgIHdoaWxlIChpIDwgaGFuZGxlcnMubGVuZ3RoKSB7XG4gICAgICAgICAgICBoYW5kbGVyc1tpXShkYXRhKTtcbiAgICAgICAgICAgIGkrKztcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBkZXN0cm95IHRoZSBtYW5hZ2VyIGFuZCB1bmJpbmRzIGFsbCBldmVudHNcbiAgICAgKiBpdCBkb2Vzbid0IHVuYmluZCBkb20gZXZlbnRzLCB0aGF0IGlzIHRoZSB1c2VyIG93biByZXNwb25zaWJpbGl0eVxuICAgICAqL1xuICAgIGRlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLmVsZW1lbnQgJiYgdG9nZ2xlQ3NzUHJvcHModGhpcywgZmFsc2UpO1xuXG4gICAgICAgIHRoaXMuaGFuZGxlcnMgPSB7fTtcbiAgICAgICAgdGhpcy5zZXNzaW9uID0ge307XG4gICAgICAgIHRoaXMuaW5wdXQuZGVzdHJveSgpO1xuICAgICAgICB0aGlzLmVsZW1lbnQgPSBudWxsO1xuICAgIH1cbn07XG5cbi8qKlxuICogYWRkL3JlbW92ZSB0aGUgY3NzIHByb3BlcnRpZXMgYXMgZGVmaW5lZCBpbiBtYW5hZ2VyLm9wdGlvbnMuY3NzUHJvcHNcbiAqIEBwYXJhbSB7TWFuYWdlcn0gbWFuYWdlclxuICogQHBhcmFtIHtCb29sZWFufSBhZGRcbiAqL1xuZnVuY3Rpb24gdG9nZ2xlQ3NzUHJvcHMobWFuYWdlciwgYWRkKSB7XG4gICAgdmFyIGVsZW1lbnQgPSBtYW5hZ2VyLmVsZW1lbnQ7XG4gICAgaWYgKCFlbGVtZW50LnN0eWxlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHByb3A7XG4gICAgZWFjaChtYW5hZ2VyLm9wdGlvbnMuY3NzUHJvcHMsIGZ1bmN0aW9uKHZhbHVlLCBuYW1lKSB7XG4gICAgICAgIHByb3AgPSBwcmVmaXhlZChlbGVtZW50LnN0eWxlLCBuYW1lKTtcbiAgICAgICAgaWYgKGFkZCkge1xuICAgICAgICAgICAgbWFuYWdlci5vbGRDc3NQcm9wc1twcm9wXSA9IGVsZW1lbnQuc3R5bGVbcHJvcF07XG4gICAgICAgICAgICBlbGVtZW50LnN0eWxlW3Byb3BdID0gdmFsdWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBlbGVtZW50LnN0eWxlW3Byb3BdID0gbWFuYWdlci5vbGRDc3NQcm9wc1twcm9wXSB8fCAnJztcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIGlmICghYWRkKSB7XG4gICAgICAgIG1hbmFnZXIub2xkQ3NzUHJvcHMgPSB7fTtcbiAgICB9XG59XG5cbi8qKlxuICogdHJpZ2dlciBkb20gZXZlbnRcbiAqIEBwYXJhbSB7U3RyaW5nfSBldmVudFxuICogQHBhcmFtIHtPYmplY3R9IGRhdGFcbiAqL1xuZnVuY3Rpb24gdHJpZ2dlckRvbUV2ZW50KGV2ZW50LCBkYXRhKSB7XG4gICAgdmFyIGdlc3R1cmVFdmVudCA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50KCdFdmVudCcpO1xuICAgIGdlc3R1cmVFdmVudC5pbml0RXZlbnQoZXZlbnQsIHRydWUsIHRydWUpO1xuICAgIGdlc3R1cmVFdmVudC5nZXN0dXJlID0gZGF0YTtcbiAgICBkYXRhLnRhcmdldC5kaXNwYXRjaEV2ZW50KGdlc3R1cmVFdmVudCk7XG59XG5cbmFzc2lnbihIYW1tZXIsIHtcbiAgICBJTlBVVF9TVEFSVDogSU5QVVRfU1RBUlQsXG4gICAgSU5QVVRfTU9WRTogSU5QVVRfTU9WRSxcbiAgICBJTlBVVF9FTkQ6IElOUFVUX0VORCxcbiAgICBJTlBVVF9DQU5DRUw6IElOUFVUX0NBTkNFTCxcblxuICAgIFNUQVRFX1BPU1NJQkxFOiBTVEFURV9QT1NTSUJMRSxcbiAgICBTVEFURV9CRUdBTjogU1RBVEVfQkVHQU4sXG4gICAgU1RBVEVfQ0hBTkdFRDogU1RBVEVfQ0hBTkdFRCxcbiAgICBTVEFURV9FTkRFRDogU1RBVEVfRU5ERUQsXG4gICAgU1RBVEVfUkVDT0dOSVpFRDogU1RBVEVfUkVDT0dOSVpFRCxcbiAgICBTVEFURV9DQU5DRUxMRUQ6IFNUQVRFX0NBTkNFTExFRCxcbiAgICBTVEFURV9GQUlMRUQ6IFNUQVRFX0ZBSUxFRCxcblxuICAgIERJUkVDVElPTl9OT05FOiBESVJFQ1RJT05fTk9ORSxcbiAgICBESVJFQ1RJT05fTEVGVDogRElSRUNUSU9OX0xFRlQsXG4gICAgRElSRUNUSU9OX1JJR0hUOiBESVJFQ1RJT05fUklHSFQsXG4gICAgRElSRUNUSU9OX1VQOiBESVJFQ1RJT05fVVAsXG4gICAgRElSRUNUSU9OX0RPV046IERJUkVDVElPTl9ET1dOLFxuICAgIERJUkVDVElPTl9IT1JJWk9OVEFMOiBESVJFQ1RJT05fSE9SSVpPTlRBTCxcbiAgICBESVJFQ1RJT05fVkVSVElDQUw6IERJUkVDVElPTl9WRVJUSUNBTCxcbiAgICBESVJFQ1RJT05fQUxMOiBESVJFQ1RJT05fQUxMLFxuXG4gICAgTWFuYWdlcjogTWFuYWdlcixcbiAgICBJbnB1dDogSW5wdXQsXG4gICAgVG91Y2hBY3Rpb246IFRvdWNoQWN0aW9uLFxuXG4gICAgVG91Y2hJbnB1dDogVG91Y2hJbnB1dCxcbiAgICBNb3VzZUlucHV0OiBNb3VzZUlucHV0LFxuICAgIFBvaW50ZXJFdmVudElucHV0OiBQb2ludGVyRXZlbnRJbnB1dCxcbiAgICBUb3VjaE1vdXNlSW5wdXQ6IFRvdWNoTW91c2VJbnB1dCxcbiAgICBTaW5nbGVUb3VjaElucHV0OiBTaW5nbGVUb3VjaElucHV0LFxuXG4gICAgUmVjb2duaXplcjogUmVjb2duaXplcixcbiAgICBBdHRyUmVjb2duaXplcjogQXR0clJlY29nbml6ZXIsXG4gICAgVGFwOiBUYXBSZWNvZ25pemVyLFxuICAgIFBhbjogUGFuUmVjb2duaXplcixcbiAgICBTd2lwZTogU3dpcGVSZWNvZ25pemVyLFxuICAgIFBpbmNoOiBQaW5jaFJlY29nbml6ZXIsXG4gICAgUm90YXRlOiBSb3RhdGVSZWNvZ25pemVyLFxuICAgIFByZXNzOiBQcmVzc1JlY29nbml6ZXIsXG5cbiAgICBvbjogYWRkRXZlbnRMaXN0ZW5lcnMsXG4gICAgb2ZmOiByZW1vdmVFdmVudExpc3RlbmVycyxcbiAgICBlYWNoOiBlYWNoLFxuICAgIG1lcmdlOiBtZXJnZSxcbiAgICBleHRlbmQ6IGV4dGVuZCxcbiAgICBhc3NpZ246IGFzc2lnbixcbiAgICBpbmhlcml0OiBpbmhlcml0LFxuICAgIGJpbmRGbjogYmluZEZuLFxuICAgIHByZWZpeGVkOiBwcmVmaXhlZFxufSk7XG5cbi8vIHRoaXMgcHJldmVudHMgZXJyb3JzIHdoZW4gSGFtbWVyIGlzIGxvYWRlZCBpbiB0aGUgcHJlc2VuY2Ugb2YgYW4gQU1EXG4vLyAgc3R5bGUgbG9hZGVyIGJ1dCBieSBzY3JpcHQgdGFnLCBub3QgYnkgdGhlIGxvYWRlci5cbnZhciBmcmVlR2xvYmFsID0gKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnID8gd2luZG93IDogKHR5cGVvZiBzZWxmICE9PSAndW5kZWZpbmVkJyA/IHNlbGYgOiB7fSkpOyAvLyBqc2hpbnQgaWdub3JlOmxpbmVcbmZyZWVHbG9iYWwuSGFtbWVyID0gSGFtbWVyO1xuXG5pZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XG4gICAgZGVmaW5lKGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gSGFtbWVyO1xuICAgIH0pO1xufSBlbHNlIGlmICh0eXBlb2YgbW9kdWxlICE9ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBIYW1tZXI7XG59IGVsc2Uge1xuICAgIHdpbmRvd1tleHBvcnROYW1lXSA9IEhhbW1lcjtcbn1cblxufSkod2luZG93LCBkb2N1bWVudCwgJ0hhbW1lcicpO1xuIiwiXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBcnR3b3JrU2xpZGVyIHtcblxuXHRjb25zdHJ1Y3RvcihlbCkgeyBcblx0XHR0aGlzLmVsID0gZWw7XG5cdFx0dGhpcy5lbENvbnRyb2wgPSB0aGlzLmVsLnF1ZXJ5U2VsZWN0b3JBbGwoJy5zbGlkZXInKVswXTtcblx0XHR0aGlzLmVsRm9yZSA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmZvcmUnKVswXTtcblx0XHR0aGlzLmVsS25vYiA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmtub2InKVswXTtcblxuXHRcdHZhciBzZWxmID0gdGhpcztcblxuXHRcdHZhciBldmVudERvd24gPSAnbW91c2Vkb3duJztcblx0XHR2YXIgZXZlbnRNb3ZlID0gJ21vdXNlbW92ZSc7XG5cdFx0dmFyIGV2ZW50VXAgPSAnbW91c2V1cCc7XG5cdFx0aWYgKCdvbnRvdWNoc3RhcnQnIGluIHdpbmRvdykgeyBcblx0XHRcdGV2ZW50RG93biA9ICd0b3VjaHN0YXJ0Jztcblx0XHRcdGV2ZW50TW92ZSA9ICd0b3VjaG1vdmUnO1xuXHRcdFx0ZXZlbnRVcCA9ICd0b3VjaGVuZCc7XG5cdFx0fVxuXG5cdFx0dGhpcy5lbENvbnRyb2wuYWRkRXZlbnRMaXN0ZW5lcihldmVudERvd24sIGZ1bmN0aW9uICgpIHsgXG5cdFx0XHQvL2NvbnNvbGUubG9nKCdBcnR3b3JrU2xpZGVyLm1vdXNlRG93bigpICcpO1xuXHRcdFx0c2VsZi5kcmFnZ2luZyA9IHRydWU7XG5cdFx0XHR3aW5kb3cuZ2FFdmVudCgnQXJ0d29yayBTbGlkZXInLCAnY2xpY2snLCB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUpO1xuXHRcdH0pO1xuXHRcdFxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKGV2ZW50TW92ZSwgZnVuY3Rpb24gKGV2ZW50KSB7IFxuXHRcdFx0aWYgKHNlbGYuZHJhZ2dpbmcpIHsgXG5cblx0XHRcdFx0dmFyIHggPSBldmVudC5jbGllbnRYO1xuXHRcdFx0XHRpZiAoZXZlbnQudG91Y2hlcykgeyBcblx0XHRcdFx0XHRpZiAoZXZlbnQudG91Y2hlcy5sZW5ndGggPj0gMSkge1xuXHRcdFx0XHRcdFx0eCA9IGV2ZW50LnRvdWNoZXNbMF0uY2xpZW50WDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0Ly9jb25zb2xlLmxvZygnQXJ0d29ya1NsaWRlci5tb3VzZU1vdmUoKSAnLCBzZWxmLmRyYWdnaW5nLCB4KTtcblxuXHRcdFx0XHR2YXIgcmVjdCA9IHNlbGYuZWxGb3JlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdFx0XHR2YXIgcCA9ICh4IC0gcmVjdC5sZWZ0KSAvIChyZWN0LnJpZ2h0IC0gcmVjdC5sZWZ0KTtcblx0XHRcdFx0cCA9IChwLTAuMDUpIC8gMC45O1xuXHRcdFx0XHRpZiAocCA8IDApIHsgXG5cdFx0XHRcdFx0cCA9IDA7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKHAgPiAxKSB7IFxuXHRcdFx0XHRcdHAgPSAxO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHNlbGYuZWxLbm9iLnN0eWxlLmxlZnQgPSAocCoocmVjdC5yaWdodC1yZWN0LmxlZnQtMjQpKSsncHgnO1xuXHRcdFx0XHRzZWxmLmVsRm9yZS5zdHlsZS5vcGFjaXR5ID0gcDtcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKGV2ZW50VXAsIGZ1bmN0aW9uICgpIHsgXG5cdFx0XHQvL2NvbnNvbGUubG9nKCdBcnR3b3JrU2xpZGVyLm1vdXNlVXAoKScpO1xuXHRcdFx0c2VsZi5kcmFnZ2luZyA9IGZhbHNlO1xuXHRcdH0pO1xuXHRcdFxuXG5cdFx0dGhpcy5kcmFnZ2luZyA9IGZhbHNlO1xuXG5cdH1cblxuXHRjbG9zZSgpIHsgXG5cdFx0Ly9jb25zb2xlLmxvZygnQXJ0d29ya1NsaWRlci5jbG9zZSgpJyk7XG5cblx0fVxuXG5cbn1cblxuXG4iLCJpbXBvcnQgJ2hhbW1lcmpzJztcblxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBcnR3b3JrWm9vbSB7XG5cblx0Y29uc3RydWN0b3IoZWwpIHsgXG5cblx0XHR0aGlzLmVsID0gZWw7XG5cdFx0dGhpcy5lbElubmVyID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuaW1hZ2UtaG9sZGVyJylbMF07XG5cdFx0dGhpcy5lbEhvbGRlciA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmltYWdlLWhvbGRlcicpWzBdO1xuXHRcdHRoaXMuZWxBcnR3b3JrID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuaW1hZ2UtaG9sZGVyIGltZycpWzBdO1xuXHRcdHRoaXMuZWxCdXR0b25ab29tT3V0ID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuYnV0dG9uLXpvb20tb3V0JylbMF07XG5cdFx0dGhpcy5lbEJ1dHRvblpvb21JbiA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmJ1dHRvbi16b29tLWluJylbMF07XG5cdFx0dGhpcy5lbFRleHRab29tID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcudGV4dC16b29tLXBlcmNlbnQnKVswXTtcblxuXHRcdHRoaXMudHJhbnNsYXRlWCA9IDA7XG5cdFx0dGhpcy50cmFuc2xhdGVZID0gMDtcblx0XHR0aGlzLnNjYWxlID0gMTtcblxuXHRcdHZhciBzZWxmID0gdGhpcztcblxuXHRcdC8vICBcblx0XHR0aGlzLnJlc2l6ZSA9IHRoaXMucmVzaXplLmJpbmQodGhpcyk7XG5cdFx0dGhpcy51cGRhdGUgPSB0aGlzLnVwZGF0ZS5iaW5kKHRoaXMpO1xuXHRcdHRoaXMuY2xvc2UgPSB0aGlzLmNsb3NlLmJpbmQodGhpcyk7XG5cblx0XHQvLyAgQ2xpY2sgb24gem9vbSBpY29uLCBwaG90byB6b29tcyB0byAyMDAlXG5cdFx0Ly8gIERyYWcgb24gcGhvdG8gdG8gcGFuXG5cdFx0Ly8gIFBpbmNoIHpvb20gdG8gem9vbSBpbiBhbmQgb3V0XG5cdFx0Ly8gIE1vdXNlIHdoZWVsLCBhbmQgbWFnaWMgbW91c2UsIHRvIHpvb20gaW4gYW5kIG91dFxuXG5cdFx0dGhpcy5oYW1tZXIgPSBuZXcgSGFtbWVyKHRoaXMuZWxIb2xkZXIsIHtpbnB1dENsYXNzOiBIYW1tZXIuVG91Y2hNb3VzZUlucHV0fSk7XG5cdFx0dGhpcy5oYW1tZXIuZ2V0KCdwaW5jaCcpLnNldCh7IGVuYWJsZTogdHJ1ZSB9KTtcblxuXHRcdC8vICBQYW5cblx0XHR0aGlzLmhhbW1lci5vbigncGFuJywgZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRcdHNlbGYudHJhbnNsYXRlWCArPSBldmVudC52ZWxvY2l0eVggKiAxMC9zZWxmLnNjYWxlO1xuXHRcdFx0c2VsZi50cmFuc2xhdGVZICs9IGV2ZW50LnZlbG9jaXR5WSAqIDEwL3NlbGYuc2NhbGU7XG5cdFx0XHRzZWxmLnVwZGF0ZSgpO1xuXHRcdH0pO1xuXHRcdFxuXHRcdC8vICBQaW5jaFxuXHRcdHRoaXMuaGFtbWVyLm9uKFwicGluY2hpblwiLCBmdW5jdGlvbihlKSB7XG5cdFx0XHRzZWxmLnNjYWxlIC09IDAuMTI7XG5cdFx0XHRzZWxmLnVwZGF0ZSgpO1xuXHRcdH0pO1xuXHRcdHRoaXMuaGFtbWVyLm9uKFwicGluY2hvdXRcIiwgZnVuY3Rpb24oZSkge1xuXHRcdFx0c2VsZi5zY2FsZSArPSAwLjA4O1xuXHRcdFx0c2VsZi51cGRhdGUoKTtcblx0XHR9KTtcblxuXHRcdC8vICBNb3VzZXdoZWVsXG5cdFx0dGhpcy5lbEhvbGRlci5hZGRFdmVudExpc3RlbmVyKCd3aGVlbCcsIGZ1bmN0aW9uIChldmVudCkgeyBcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHQvL2NvbnNvbGUubG9nKGV2ZW50LndoZWVsRGVsdGFZKTtcblx0XHRcdHNlbGYuc2NhbGUgKz0gZXZlbnQud2hlZWxEZWx0YVkvNTAwO1xuXHRcdFx0c2VsZi51cGRhdGUoKTtcblx0XHR9KTtcblxuXHRcdC8vICBCdXR0b25zXG5cdFx0dGhpcy5lbEJ1dHRvblpvb21PdXQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbiAoZXZlbnQpIHsgXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0c2VsZi5zY2FsZSAtPSAwLjI1O1xuXHRcdFx0c2VsZi51cGRhdGUoKTtcblx0XHR9KTtcblx0XHR0aGlzLmVsQnV0dG9uWm9vbUluIC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uIChldmVudCkgeyBcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRzZWxmLnNjYWxlICs9IDAuMjU7XG5cdFx0XHRzZWxmLnVwZGF0ZSgpO1xuXHRcdH0pO1xuXG5cdFx0Ly8gIFJlc2l6ZVxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCB0aGlzLnJlc2l6ZSk7XG5cdFx0dGhpcy5yZXNpemUoKTtcblxuXG5cdH1cblxuXHRyZXNpemUoZXZlbnQpIHsgXG5cblx0XHQvL2NvbnNvbGUubG9nKHRoaXMuZWxBcnR3b3JrLm9mZnNldFdpZHRoLCB0aGlzLmVsQXJ0d29yay5vZmZzZXRIZWlnaHQsIHRoaXMuZWxBcnR3b3JrLmNvbXBsZXRlLCB0aGlzLmVsQXJ0d29yay5uYXR1cmFsSGVpZ2h0KTtcblx0XHRpZiAodGhpcy5lbEFydHdvcmsuY29tcGxldGUgPT0gZmFsc2UpIHsgXG5cdFx0XHRjb25zdCBzZWxmID0gdGhpcztcblx0XHRcdHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyAgXG5cdFx0XHRcdHNlbGYucmVzaXplKCk7XG5cdFx0XHR9LCAxMDApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuZWwuc3R5bGUuaGVpZ2h0ID0gKHdpbmRvdy5pbm5lckhlaWdodC01NikrJ3B4Jztcblx0XHR0aGlzLmVsSW5uZXIuc3R5bGUuaGVpZ2h0ID0gKHdpbmRvdy5pbm5lckhlaWdodC01NikrJ3B4Jztcblx0XHR0aGlzLmVsSG9sZGVyLnN0eWxlLmhlaWdodCA9ICh3aW5kb3cuaW5uZXJIZWlnaHQtNTYpKydweCc7XG5cblx0XHR2YXIgYXcgPSB0aGlzLmVsQXJ0d29yay5vZmZzZXRXaWR0aDtcblx0XHR2YXIgYWggPSB0aGlzLmVsQXJ0d29yay5vZmZzZXRIZWlnaHQ7XG5cdFx0dmFyIGN3ID0gdGhpcy5lbEhvbGRlci5vZmZzZXRXaWR0aDtcblx0XHR2YXIgY2ggPSB0aGlzLmVsSG9sZGVyLm9mZnNldEhlaWdodDtcblx0XHR2YXIgdyA9IGN3O1xuXHRcdHZhciBoID0gYWgvYXcqY3c7XG5cdFx0dmFyIHQgPSAoY2ggLSBoKSAqIDAuNTtcblx0XHR2YXIgbCA9IDA7XG5cdFx0aWYgKGF3L2FoIDwgY3cvY2gpIHsgXG5cdFx0XHR2YXIgaCA9IGNoO1xuXHRcdFx0dmFyIHcgPSBhdy9haCpjaDtcblx0XHRcdHZhciB0ID0gMDtcblx0XHRcdHZhciBsID0gKGN3IC0gdykgKiAwLjU7XG5cdFx0fVxuXHRcdHRoaXMuZWxBcnR3b3JrLnN0eWxlLndpZHRoID0gdysncHgnO1xuXHRcdHRoaXMuZWxBcnR3b3JrLnN0eWxlLmhlaWdodCA9IGgrJ3B4Jztcblx0XHR0aGlzLmVsQXJ0d29yay5zdHlsZS5sZWZ0ID0gbCsncHgnO1xuXHRcdHRoaXMuZWxBcnR3b3JrLnN0eWxlLnRvcCA9IHQrJ3B4Jztcblx0XHR0aGlzLnVwZGF0ZSgpO1xuXHR9XG5cblx0dXBkYXRlKCkge1xuXG5cdFx0aWYgKHRoaXMuc2NhbGUgPCAxKSB7IFxuXHRcdFx0dGhpcy5zY2FsZSA9IDE7XG5cdFx0fVxuXHRcdGlmICh0aGlzLnNjYWxlID4gNCkgeyBcblx0XHRcdHRoaXMuc2NhbGUgPSA0O1xuXHRcdH1cblxuXHRcdHRoaXMuZWxUZXh0Wm9vbS5pbm5lckhUTUwgPSBNYXRoLmZsb29yKHRoaXMuc2NhbGUqMTAwKSsnJSdcblxuXHRcdHZhciBhdyA9IHRoaXMuZWxBcnR3b3JrLm9mZnNldFdpZHRoO1xuXHRcdHZhciBhaCA9IHRoaXMuZWxBcnR3b3JrLm9mZnNldEhlaWdodDtcblx0XHR2YXIgY3cgPSB0aGlzLmVsSG9sZGVyLm9mZnNldFdpZHRoO1xuXHRcdHZhciBjaCA9IHRoaXMuZWxIb2xkZXIub2Zmc2V0SGVpZ2h0O1xuXG5cdFx0dmFyIHcgPSAoKGN3ICogKHRoaXMuc2NhbGUtMSkpIC8gdGhpcy5zY2FsZSkgKiAwLjU7XG5cdFx0dmFyIGggPSAoKGNoICogKHRoaXMuc2NhbGUtMSkpIC8gdGhpcy5zY2FsZSkgKiAwLjU7XG5cblx0XHRpZiAodGhpcy50cmFuc2xhdGVYIDwgLXcpIHsgXG5cdFx0XHR0aGlzLnRyYW5zbGF0ZVggPSAtdztcblx0XHR9IFxuXHRcdGlmICh0aGlzLnRyYW5zbGF0ZVggPiB3KSB7IFxuXHRcdFx0dGhpcy50cmFuc2xhdGVYID0gdztcblx0XHR9XG5cdFx0aWYgKHRoaXMudHJhbnNsYXRlWSA8IC1oKSB7IFxuXHRcdFx0dGhpcy50cmFuc2xhdGVZID0gLWg7XG5cdFx0fSBcblx0XHRpZiAodGhpcy50cmFuc2xhdGVZID4gaCkgeyBcblx0XHRcdHRoaXMudHJhbnNsYXRlWSA9IGg7XG5cdFx0fVxuXHRcblx0XHR0aGlzLmVsQXJ0d29yay5zdHlsZS50cmFuc2Zvcm0gPSAnc2NhbGUoJyt0aGlzLnNjYWxlKycpIHRyYW5zbGF0ZSgnK3RoaXMudHJhbnNsYXRlWCsncHgsICcrdGhpcy50cmFuc2xhdGVZKydweCknO1xuXHR9XG5cblx0Y2xvc2UoKSB7IFxuXHRcdHRoaXMuaGFtbWVyLmRlc3Ryb3koKTtcblx0XHQvL2NvbnNvbGUubG9nKCdBcnR3b3JrWm9vbWVyLmNsb3NlKCknKTtcblx0fVxuXG5cbn1cblxuXG4iLCJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEF1ZGlvUGxheWVyIHtcblxuXHRjb25zdHJ1Y3RvcigpIHsgXG5cblx0XHR0aGlzLmVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2F1ZGlvLXBsYXllcicpO1xuXHRcdHRoaXMuYnV0dG9uUGxheSA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmJ1dHRvbi1wbGF5JylbMF07XG5cdFx0dGhpcy5idXR0b25QYXVzZSA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmJ1dHRvbi1wYXVzZScpWzBdO1xuXHRcdHRoaXMuYnV0dG9uTXV0ZSA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmJ1dHRvbi1tdXRlJylbMF07XG5cdFx0dGhpcy5idXR0b25Vbm11dGUgPSB0aGlzLmVsLnF1ZXJ5U2VsZWN0b3JBbGwoJy5idXR0b24tdW5tdXRlJylbMF07XG5cblx0XHR0aGlzLnRpbWVDdXJyZW50ID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcudGltZSAuY3VycmVudCcpWzBdO1xuXHRcdHRoaXMudGltZUR1cmF0aW9uID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcudGltZSAuZHVyYXRpb24nKVswXTtcblxuXHRcdHRoaXMuc291bmRTY2FwZVVSTCA9IHdpbmRvdy5wbHVnaW5CYXNlVVJMK1wic3RhdGljL21wMy9zb3VuZHNjYXBlLm1wM1wiO1xuXG5cdFx0dGhpcy5zaG93ID0gdGhpcy5zaG93LmJpbmQodGhpcyk7XG5cdFx0dGhpcy5oaWRlID0gdGhpcy5oaWRlLmJpbmQodGhpcyk7XG5cblx0XHR0aGlzLmVsQXVkaW8gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiQVVESU9cIik7IFxuXHRcdHRoaXMuZWxBdWRpby5wcmVsb2FkID0gJ25vbmUnO1xuXHRcdHRoaXMuZWxBdWRpby5hdXRvcGxheSA9IGZhbHNlO1xuXHRcdHRoaXMuZWxBdWRpby5jb250cm9scyA9IGZhbHNlO1xuXHRcdHRoaXMuZWxBdWRpby5zcmMgPSB0aGlzLnNvdW5kU2NhcGVVUkw7XG5cdFx0dGhpcy5lbEF1ZGlvLm11dGVkID0gZmFsc2U7XG5cdFx0dGhpcy5lbEF1ZGlvLmRlZmF1bHRNdXRlZCA9IGZhbHNlO1xuXHRcdHRoaXMuZWxBdWRpby5sb29wID0gdHJ1ZTtcblxuXHRcdGNvbnN0IHNlbGYgPSB0aGlzO1xuXG5cdFx0dGhpcy5idXR0b25QbGF5LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24gKCkgeyBcblx0XHRcdHNlbGYuYnV0dG9uUGxheS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuXHRcdFx0c2VsZi5idXR0b25QYXVzZS5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblx0XHRcdHNlbGYuZWxBdWRpby5wbGF5KCk7XG5cdFx0XHR3aW5kb3cuZ2FFdmVudCgnU291bmR0cmFjaycsICdwbGF5JywgJycpO1xuXHRcdH0pO1xuXHRcdHRoaXMuYnV0dG9uUGF1c2UuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbiAoKSB7IFxuXHRcdFx0c2VsZi5idXR0b25QbGF5LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuXHRcdFx0c2VsZi5idXR0b25QYXVzZS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuXHRcdFx0c2VsZi5lbEF1ZGlvLnBhdXNlKCk7XG5cdFx0XHR3aW5kb3cuZ2FFdmVudCgnU291bmR0cmFjaycsICdwYXVzZScsICcnKTtcblx0XHR9KTtcblx0XHR0aGlzLmJ1dHRvbk11dGUuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbiAoKSB7IFxuXHRcdFx0c2VsZi5idXR0b25NdXRlLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdFx0XHRzZWxmLmJ1dHRvblVubXV0ZS5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblx0XHRcdHNlbGYuZWxBdWRpby5tdXRlZCA9IHRydWU7XG5cdFx0XHR3aW5kb3cuZ2FFdmVudCgnU291bmR0cmFjaycsICdtdXRlJywgJycpO1xuXHRcdH0pO1xuXHRcdHRoaXMuYnV0dG9uVW5tdXRlLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24gKCkgeyBcblx0XHRcdHNlbGYuYnV0dG9uTXV0ZS5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblx0XHRcdHNlbGYuYnV0dG9uVW5tdXRlLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdFx0XHRzZWxmLmVsQXVkaW8ubXV0ZWQgPSBmYWxzZTtcblx0XHRcdHdpbmRvdy5nYUV2ZW50KCdTb3VuZHRyYWNrJywgJ3VubXV0ZScsICcnKTtcblx0XHR9KTtcblxuXHRcdHRoaXMuZWxBdWRpby5hZGRFdmVudExpc3RlbmVyKCd0aW1ldXBkYXRlJywgZnVuY3Rpb24gKCkgeyBcblx0XHRcdHNlbGYudGltZUN1cnJlbnQuaW5uZXJIVE1MID0gc2VsZi5zZWNvbmRzQXNUaW1lKHNlbGYuZWxBdWRpby5jdXJyZW50VGltZSk7XG5cdFx0XHRzZWxmLnRpbWVEdXJhdGlvbi5pbm5lckhUTUwgPSBzZWxmLnNlY29uZHNBc1RpbWUoc2VsZi5lbEF1ZGlvLmR1cmF0aW9uKTtcblx0XHR9KTtcblxuXHR9XG5cblx0c2hvdygpIHsgXG5cdFx0dGhpcy5lbC5jbGFzc0xpc3QuYWRkKCdvcGVuJyk7XG5cdH1cblx0aGlkZSgpIHsgXG5cdFx0dGhpcy5lbC5jbGFzc0xpc3QucmVtb3ZlKCdvcGVuJyk7XG5cdH1cblxuXHRzZWNvbmRzQXNUaW1lKHNlY3MpIHtcblx0XHR2YXIgaHIgID0gTWF0aC5mbG9vcihzZWNzIC8gMzYwMCk7XG5cdFx0dmFyIG1pbiA9IE1hdGguZmxvb3IoKHNlY3MgLSAoaHIgKiAzNjAwKSkvNjApO1xuXHRcdHZhciBzZWMgPSBNYXRoLmZsb29yKHNlY3MgLSAoaHIgKiAzNjAwKSAtICAobWluICogNjApKTtcblx0XHRpZiAobWluIDwgMTApeyBcblx0XHRcdG1pbiA9IFwiMFwiICsgbWluOyBcblx0XHR9XG5cdFx0aWYgKHNlYyA8IDEwKXsgXG5cdFx0XHRzZWMgID0gXCIwXCIgKyBzZWM7XG5cdFx0fVxuXHRcdHJldHVybiBtaW4gKyAnOicgKyBzZWM7XG5cdH1cblxuXG5cblxufVxuXG5cbiIsIlxuaW1wb3J0IFRyYW5zaXRpb25XaXBlIGZyb20gJy4vVHJhbnNpdGlvbldpcGUuanMnO1xuaW1wb3J0IEltYWdlRGV0ZWN0IGZyb20gJy4vSW1hZ2VEZXRlY3QuanMnO1xuaW1wb3J0IEFydHdvcmtab29tIGZyb20gJy4vQXJ0d29ya1pvb20uanMnO1xuaW1wb3J0IEFydHdvcmtTbGlkZXIgZnJvbSAnLi9BcnR3b3JrU2xpZGVyLmpzJztcbmltcG9ydCBBdWRpb1BsYXllciBmcm9tICcuL0F1ZGlvUGxheWVyLmpzJztcbmltcG9ydCBTaGFyZVlvdXJWaXNpdCBmcm9tICcuL1NoYXJlWW91clZpc2l0LmpzJztcbmltcG9ydCBTb2NpYWxTaGFyZSBmcm9tICcuL1NvY2lhbFNoYXJlLmpzJztcbmltcG9ydCBXYWxsIGZyb20gJy4vV2FsbC5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIENvbnRlbnQge1xuXG5cdGNvbnN0cnVjdG9yKCkgeyBcblxuXHRcdHRoaXMuY3VycmVudFBhdGggPSAnJztcblx0XHR0aGlzLmxvYWRlZENvbnRlbnQgPSAnJztcblx0XHR0aGlzLmxvYWRlZFRpdGxlID0gJyc7XG5cdFx0dGhpcy5icm93c2VyQmFja0J1dHRvbiA9IGZhbHNlO1xuXHRcdHRoaXMuaW1hZ2VEZXRlY3RvciA9IG51bGw7XG5cdFx0dGhpcy5hcnR3b3JrWm9vbSA9IG51bGw7XG5cdFx0dGhpcy5hcnR3b3JrU2xpZGVycyA9IFtdO1xuXHRcdHRoaXMuYXJMaWJyYXJ5TG9hZGluZyA9IGZhbHNlO1xuXHRcdHRoaXMuYXJMaWJyYXJ5TG9hZGVkID0gZmFsc2U7XG5cdFx0dGhpcy5zb2NpYWxTaGFyZXMgPSBbXTtcblx0XHR0aGlzLnNoYXJlWW91clZpc2l0ID0gbnVsbDtcblx0XHR0aGlzLndhbGwgPSBudWxsO1xuXG5cdFx0Ly8gIEJpbmRzXG5cdFx0dGhpcy5vbkxpbmtDbGljayA9IHRoaXMub25MaW5rQ2xpY2suYmluZCh0aGlzKTtcblx0XHR0aGlzLmxpbmtDbGljayA9IHRoaXMubGlua0NsaWNrLmJpbmQodGhpcyk7XG5cdFx0dGhpcy5jb250ZW50RGlzcGxheSA9IHRoaXMuY29udGVudERpc3BsYXkuYmluZCh0aGlzKTtcblx0XHR0aGlzLm9uQ2hhbmdlQ29udGVudCA9IHRoaXMub25DaGFuZ2VDb250ZW50LmJpbmQodGhpcyk7XG5cdFx0dGhpcy5vblBvcFN0YXRlID0gdGhpcy5vblBvcFN0YXRlLmJpbmQodGhpcyk7XG5cdFx0dGhpcy5vbk1vZGFsQ2xvc2UgPSB0aGlzLm9uTW9kYWxDbG9zZS5iaW5kKHRoaXMpO1xuXHRcdHRoaXMub25Nb2RhbENsb3NlU3RhcnRTY2FuID0gdGhpcy5vbk1vZGFsQ2xvc2VTdGFydFNjYW4uYmluZCh0aGlzKTtcblx0XHR0aGlzLnNjYW5TZWxlY3RQaG90byA9IHRoaXMuc2NhblNlbGVjdFBob3RvLmJpbmQodGhpcyk7XG5cdFx0dGhpcy5yZXNpemUgPSB0aGlzLnJlc2l6ZS5iaW5kKHRoaXMpO1xuXG5cdFx0Ly8gIFJlc2l6ZVxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCB0aGlzLnJlc2l6ZSk7XG5cdFx0dGhpcy5yZXNpemUoKTtcblxuXHRcdC8vICBEaXNhYmxlIHBhZ2Ugc2NhbGUgb24gaU9TXG5cdFx0aWYgKHRoaXMuaU9TKCkpIHtcblx0XHRcdHdpbmRvdy5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCBmdW5jdGlvbihldmVudCkge1xuXHRcdFx0XHRpZihldmVudC5zY2FsZSAhPT0gMSkge1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdH1cblx0XHRcdH0sIHtwYXNzaXZlOiBmYWxzZX0pO1xuXHRcdH1cblxuXHRcdC8vICBCYWNrIGJ1dHRvblxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwb3BzdGF0ZScsIHRoaXMub25Qb3BTdGF0ZSk7XG5cblx0XHQvLyAgQ3JlYXRlIFRyYW5zaXRpb25cblx0XHR0aGlzLnRyYW5zaXRpb24gPSBuZXcgVHJhbnNpdGlvbldpcGUoKTsgXG5cblx0XHQvLyAgQ3JlYXRlIEF1ZGlvIFBsYXllclxuXHRcdHRoaXMuYXVkaW9QbGF5ZXIgPSBuZXcgQXVkaW9QbGF5ZXIoKTsgXG5cblx0XHQvLyAgQ2FwdHVyZSBpbml0aWFsIGxpbmtzXG5cdFx0dGhpcy5hcHBseUV2ZW50c1RvRE9NKCk7XG5cblx0XHQvLyAgRGV2aWNlIHNwZWNpZmljIENTU1xuXHRcdGNvbnN0IGJvZHkgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnYm9keScpWzBdO1xuXHRcdGlmICh0aGlzLmlPUygpKSB7XG5cdFx0XHRib2R5LmNsYXNzTGlzdC5hZGQoJ2RldmljZS1pb3MnKTtcblx0XHR9IGVsc2UgaWYgKG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL2FuZHJvaWQvaSkpIHtcblx0XHRcdGJvZHkuY2xhc3NMaXN0LmFkZCgnZGV2aWNlLWFuZHJvaWQnKTtcblx0XHR9XG5cdFx0XG5cdH1cblxuXHQvLyAgaXMgaU9TP1xuXHRpT1MoKSB7XG5cdFx0aWYgKC9pUGFkfGlQaG9uZXxpUG9kLy50ZXN0KG5hdmlnYXRvci5wbGF0Zm9ybSkpIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gbmF2aWdhdG9yLm1heFRvdWNoUG9pbnRzICYmIG5hdmlnYXRvci5tYXhUb3VjaFBvaW50cyA+IDIgJiYgL01hY0ludGVsLy50ZXN0KG5hdmlnYXRvci5wbGF0Zm9ybSk7XG5cdFx0fVxuXHR9XG5cdGlQYWQoKSB7XG5cdFx0cmV0dXJuIG5hdmlnYXRvci5tYXhUb3VjaFBvaW50cyAmJiBuYXZpZ2F0b3IubWF4VG91Y2hQb2ludHMgPiAyICYmIC9NYWNJbnRlbC8udGVzdChuYXZpZ2F0b3IucGxhdGZvcm0pO1xuXHR9XG5cblx0Ly8gIFJlc2l6ZVxuXHRyZXNpemUoZXZlbnQpIHsgXG5cblx0XHRjb25zdCBtb2RhbHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcubW9kYWxzJylbMF07XG5cdFx0aWYgKG1vZGFscykgeyBcblx0XHRcdG1vZGFscy5zdHlsZS5oZWlnaHQgPSAod2luZG93LmlubmVySGVpZ2h0LTU2KSsncHgnO1xuXHRcdH1cblx0XHRcblx0XHRjb25zdCBjb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2NvbnRlbnQnKVswXTtcblx0XHRpZiAoY29udGVudCkgeyBcblx0XHRcdGNvbnRlbnQuc3R5bGUuaGVpZ2h0ID0gKHdpbmRvdy5pbm5lckhlaWdodCkrJ3B4Jztcblx0XHR9XG5cblx0XHRjb25zdCBpbnRyb1Njcm9sbFBhbmVsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLmludHJvIC5zY3JvbGwtcGFuZWwnKVswXTtcblx0XHRpZiAoaW50cm9TY3JvbGxQYW5lbCkgeyBcblx0XHRcdGludHJvU2Nyb2xsUGFuZWwuc3R5bGUuaGVpZ2h0ID0gKHdpbmRvdy5pbm5lckhlaWdodC04MikrJ3B4Jztcblx0XHR9XG5cblxuXHR9XG5cblx0Ly8gIE9uIGJyb3dzZXIgYmFjayBjbGlja2VkXG5cdG9uUG9wU3RhdGUgKCkgeyBcblx0XHR0aGlzLmJyb3dzZXJCYWNrQnV0dG9uID0gdHJ1ZTtcblx0XHR0aGlzLmNvbnRlbnRMb2FkKHdpbmRvdy5sb2NhdGlvbi5ocmVmKTtcblx0fVxuXG5cdC8vICBXaGVuIGEgbGluayBpcyBjbGlja2VkXG5cdG9uTGlua0NsaWNrKGV2ZW50KSB7XG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHR0aGlzLmxpbmtDbGljayhldmVudC5jdXJyZW50VGFyZ2V0LmhyZWYpO1xuXHR9XG5cdGxpbmtDbGljayh1cmwpIHtcblx0XHRpZiAodGhpcy50cmFuc2l0aW9uLmFjdGl2ZSkgeyBcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0Ly9jb25zb2xlLmxvZygnQ2FwdHVyZWQgbGluayBjbGlja2VkOiAnLCB1cmwpO1xuXHRcdHRoaXMuYnJvd3NlckJhY2tCdXR0b24gPSBmYWxzZTtcblxuXHRcdC8vICBDbGVhbiB0aGUgc2NhbiBjYW1lcmFcblx0XHRpZiAodGhpcy5pbWFnZURldGVjdG9yKSB7IFxuXHRcdFx0dGhpcy5pbWFnZURldGVjdG9yLnN0b3AoKTtcblx0XHR9XG5cblx0XHQvLyAgT3BlbiB0aGUgc2Vuc2l0aXZlIGNvbnRlbnQgbW9kYWxcblx0XHRpZiAodGhpcy5jbGVhblBhdGgodXJsKSA9PSAnL3ZpcnR1YWwtZXhwbG9yZS92YXJjaGl2ZSNzZW5zaXRpdmUtY29udGVudCcpIHsgXG5cdFx0XHRkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2Vuc2l0aXZlLWNvbnRlbnQnKS5jbGFzc0xpc3QuYWRkKCdvcGVuJyk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gIFRyb3VibGVzaG9vdCBwbGF0Zm9ybSBkZXRlY3Rpb25cblx0XHRpZiAodGhpcy5jbGVhblBhdGgodXJsKSA9PSAnL2V4cGxvcmUvdHJvdWJsZXNob290JykgeyBcblx0XHRcdHZhciBwbGF0Zm9ybSA9ICdhbmRyb2lkJztcblx0XHRcdGlmICh0aGlzLmlQYWQoKSkgeyBcblx0XHRcdFx0cGxhdGZvcm0gPSAnaVBhZCc7XG5cdFx0XHR9IGVsc2UgaWYgKHRoaXMuaU9TKCkpIHsgXG5cdFx0XHRcdHBsYXRmb3JtID0gJ2lPUyc7ICBcblx0XHRcdH1cblx0XHRcdHVybCA9IHVybCsnLycrcGxhdGZvcm07XG5cdFx0fVxuXG5cdFx0dGhpcy5jb250ZW50TG9hZCh1cmwpO1xuXHR9XG5cblxuXHQvLyAgQ2hhbmdlIHRoZSBjb250ZW50IGluIHRoZSBtaWRkbGUgb2YgdGhlIHRyYW5zaXRpb25cblx0b25DaGFuZ2VDb250ZW50KCkgeyBcblx0XHR0aGlzLmNvbnRlbnREaXNwbGF5KCk7XG5cdFx0aWYgKHRoaXMuYnJvd3NlckJhY2tCdXR0b24gPT0gZmFsc2UpIHsgXG5cdFx0XHR3aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUobnVsbCwgbnVsbCwgdGhpcy5jdXJyZW50UGF0aCk7XG5cdFx0fVxuXG5cdFx0Ly8gIFNob3cgb3IgaGlkZSB0aGUgYXVkaW8gcGxheWVyXG5cdFx0Y29uc3QgcyA9IHRoaXMuY2xlYW5QYXRoKHRoaXMuY3VycmVudFBhdGgpO1xuXHRcdGlmIChzID09ICcvdmlydHVhbC1leHBsb3JlJyB8fCBzID09ICcvZXhwbG9yZScpIHsgXG5cdFx0XHR0aGlzLmF1ZGlvUGxheWVyLmhpZGUoKTtcblx0XHR9IGVsc2UgaWYgKFN0cmluZyhzKS5sYXN0SW5kZXhPZignL3ZpcnR1YWwtZXhwbG9yZS9hcnR3b3JrL3pvb20vJywgMCkgPT09IDApIHsgXG5cdFx0XHR0aGlzLmF1ZGlvUGxheWVyLmhpZGUoKTtcblx0XHR9IGVsc2UgaWYgKFN0cmluZyhzKS5sYXN0SW5kZXhPZignL3ZpcnR1YWwtZXhwbG9yZS92YXJjaGl2ZS96b29tLycsIDApID09PSAwKSB7IFxuXHRcdFx0dGhpcy5hdWRpb1BsYXllci5oaWRlKCk7XG5cdFx0fSBlbHNlIHsgXG5cdFx0XHR0aGlzLmF1ZGlvUGxheWVyLnNob3coKTtcblx0XHR9IFxuXG5cdFx0Ly9jb25zb2xlLmxvZygnZ2EnLCAnc2VuZCcsICdwYWdldmlldycsIHRoaXMuY2xlYW5QYXRoKHRoaXMuY3VycmVudFBhdGgpKTtcblx0XHR3aW5kb3cuZ2FQYWdlVmlldyh0aGlzLmNsZWFuUGF0aCh0aGlzLmN1cnJlbnRQYXRoKSk7XG5cdFxuXG5cdH1cblxuXHQvLyAgTW9kYWwgQ2xvc2Vcblx0b25Nb2RhbENsb3NlKGV2ZW50KSB7IFxuXHRcdC8vY29uc29sZS5sb2coJ29uTW9kYWxDbG9zZScpO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0ZXZlbnQudGFyZ2V0LnBhcmVudE5vZGUucGFyZW50Tm9kZS5jbGFzc0xpc3QudG9nZ2xlKCdvcGVuJyk7XG5cdH1cblxuXHQvLyAgTW9kYWwgY2xvc2UgYW5kIHN0YXJ0IHNjYW5cblx0b25Nb2RhbENsb3NlU3RhcnRTY2FuKGV2ZW50KSB7IFxuXHRcdC8vY29uc29sZS5sb2coJ29uTW9kYWxDbG9zZVN0YXJ0U2NhbicpO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHRcdFxuXHRcdHdpbmRvdy5nYUV2ZW50KCdTY2FuJywgJ3N0YXJ0JywgJycpO1xuXG5cdFx0Ly8gIENsb3NlIHRoZSBtb2RhbFxuXHRcdGV2ZW50LnRhcmdldC5wYXJlbnROb2RlLnBhcmVudE5vZGUuY2xhc3NMaXN0LnRvZ2dsZSgnb3BlbicpO1xuXHRcdFxuXHRcdC8vICBTaG93IHRoZSBzcGlubmVyXG5cdFx0Y29uc3Qgc3Bpbm5lciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzY2FuLXNwaW5uZXInKTtcblx0XHRpZiAoc3Bpbm5lcikgeyBcblx0XHRcdHNwaW5uZXIuc3R5bGUub3BhY2l0eSA9IDE7XG5cdFx0fVxuXG5cdFx0Ly8gIEluIGEgc2Vjb25kLCBsb2FkIHRoZSBpbWFnZSBkZXRlY3RvclxuXHRcdHNldFRpbWVvdXQodGhpcy5pbWFnZURldGVjdG9yLnN0YXJ0LCAxMDAwKTtcblxuXHR9XG5cblx0Ly8gIExvYWQgdGhlIGNvbnRlbnQgYXQgdGhpcyBwYXRoIFxuXHRjb250ZW50TG9hZChwYXRoKSB7IFxuXHRcdGlmICh0aGlzLmN1cnJlbnRQYXRoID09IHBhdGgpIHsgXG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMuY3VycmVudFBhdGggPSBwYXRoO1xuXHRcdHZhciBwYXRoID0gdGhpcy5jbGVhblBhdGgocGF0aCk7XG5cdFx0dGhpcy50cmFuc2l0aW9uLnN0YXJ0KHBhdGgsIHRoaXMub25DaGFuZ2VDb250ZW50KTtcblx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cdFx0ZmV0Y2godGhpcy5jb250ZW50VVJMKHBhdGgpKyc/Y2M9JytNYXRoLnJhbmRvbSgpKS50aGVuKGZ1bmN0aW9uIChyZXNwb25zZSkge1xuXHRcdFx0cmVzcG9uc2UudGV4dCgpLnRoZW4oZnVuY3Rpb24gKHRleHQpIHtcblx0XHRcdFx0c2VsZi5jb250ZW50UGFyc2UodGV4dCk7XG5cdFx0XHRcdHNlbGYudHJhbnNpdGlvbi5jb250ZW50TG9hZGVkID0gdHJ1ZTtcblx0XHRcdH0pO1xuXHRcdH0pO1xuXHR9XG5cblx0Ly8gIFBhcnNlIHRoZSBsb2FkZWQgY29udGVudFxuXHRjb250ZW50UGFyc2UocmVzcG9uc2VUZXh0KSB7IFxuXHRcdGNvbnN0IGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdodG1sJyk7XG5cdFx0ZS5pbm5lckhUTUwgPSByZXNwb25zZVRleHQ7XG5cdFx0dGhpcy5sb2FkZWRDb250ZW50ID0gZS5xdWVyeVNlbGVjdG9yKCcjY29udGVudCcpLmlubmVySFRNTDtcblx0XHR0aGlzLmxvYWRlZFRpdGxlID0gZS5xdWVyeVNlbGVjdG9yKCd0aXRsZScpLmlubmVySFRNTDtcblx0fVxuXG5cdC8vICBEaXNwbGF5IHRoZSBsb2FkZWQgY29udGVudFxuXHRjb250ZW50RGlzcGxheSgpIHsgXG5cdFx0ZG9jdW1lbnQudGl0bGUgPSB0aGlzLmxvYWRlZFRpdGxlO1xuXHRcdHZhciBjb250ZW50RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjb250ZW50Jyk7XG5cdFx0Y29udGVudEVsZW1lbnQuaW5uZXJIVE1MID0gdGhpcy5sb2FkZWRDb250ZW50O1xuXHRcdHRoaXMuYXBwbHlFdmVudHNUb0RPTSgpO1xuXHRcdHdpbmRvdy5zY3JvbGxUbygwLCAwKTtcblx0XHR0aGlzLnJlc2l6ZSgpO1xuXHR9XG5cblx0Ly8gIEFwcGx5IEphdmFTY3JpcHQgZXZlbnRzIHRvIHRoZSBET00gdGhhdCBqdXN0IGxvYWRlZFxuXHRhcHBseUV2ZW50c1RvRE9NKCkgeyBcblxuXHRcdC8vICBDYXB0dXJlIGxpbmtzIFxuXHRcdGZvciAodmFyIGk9MDsgaTxkb2N1bWVudC5saW5rcy5sZW5ndGg7IGkrKykge1xuXHRcdFx0dmFyIGxpbmsgPSBkb2N1bWVudC5saW5rc1tpXTtcblx0XHRcdHZhciBzID0gbGluay5ocmVmLnNwbGl0KHdpbmRvdy5zaXRlQmFzZVVSTCkuam9pbignJyk7XG5cdFx0XHRpZiAocy5pbmRleE9mKCcvZXhwbG9yZScpID09IDAgfHwgcy5pbmRleE9mKCcvdmlydHVhbC1leHBsb3JlJykgPT0gMCkgeyBcblx0XHRcdFx0bGluay5vbmNsaWNrID0gdGhpcy5vbkxpbmtDbGljaztcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyAgTW9kYWwgY2xvc2UgYnV0dG9uc1xuXHRcdHZhciBjbG9zZXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcubW9kYWwgLmNsb3NlJyk7XG5cdFx0Zm9yICh2YXIgaT0wOyBpPGNsb3Nlcy5sZW5ndGg7IGkrKykge1xuXHRcdFx0Y2xvc2VzW2ldLm9uY2xpY2sgPSB0aGlzLm9uTW9kYWxDbG9zZTtcblx0XHR9XG5cblx0XHQvLyAgU2NhbiBDYW1lcmFcblx0XHRjb25zdCBjYW1lcmFDb250YWluZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY2FtZXJhLWNvbnRhaW5lcicpO1xuXHRcdGlmIChjYW1lcmFDb250YWluZXIpIHsgXG5cdFx0XHRcblx0XHRcdHZhciBmaXJzdCA9IGZhbHNlO1xuXHRcdFx0aWYgKHRoaXMuaW1hZ2VEZXRlY3RvciA9PSBudWxsKSB7IFxuXHRcdFx0XHRmaXJzdCA9IHRydWU7XG5cdFx0XHRcdHRoaXMuaW1hZ2VEZXRlY3RvciA9IG5ldyBJbWFnZURldGVjdCgpO1xuXG5cdFx0XHRcdC8vICBPbmx5IG9wZW4gdGhlIHNjYW4gaW5zdHJ1Y3Rpb25zIHRoZSBmaXJzdCB0aW1lIHRoZSBwYWdlIGxvYWRzXG5cdFx0XHRcdGNvbnN0IHNjYW5JbnN0cnVjdGlvbnMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2Nhbi1pbnN0cnVjdGlvbnMnKTtcblx0XHRcdFx0aWYgKHNjYW5JbnN0cnVjdGlvbnMpIHsgXG5cdFx0XHRcdFx0c2Nhbkluc3RydWN0aW9ucy5jbGFzc0xpc3QuYWRkKCdvcGVuJyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dmFyIGNsb3NlcyA9IHNjYW5JbnN0cnVjdGlvbnMucXVlcnlTZWxlY3RvckFsbCgnLmNsb3NlJyk7XG5cdFx0XHRcdGZvciAodmFyIGk9MDsgaTxjbG9zZXMubGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0XHRjbG9zZXNbaV0ub25jbGljayA9IHRoaXMub25Nb2RhbENsb3NlU3RhcnRTY2FuO1xuXHRcdFx0XHR9XG5cblx0XHRcdH0gXG5cblx0XHRcdHRoaXMuaW1hZ2VEZXRlY3Rvci5zZXRQYXJlbnQodGhpcyk7XG5cdFx0XHR0aGlzLmltYWdlRGV0ZWN0b3Iuc2V0Q29udGFpbmVyKGNhbWVyYUNvbnRhaW5lcik7XG5cdFx0XHR0aGlzLmltYWdlRGV0ZWN0b3Iuc2V0Q2FsbGJhY2sodGhpcy5zY2FuU2VsZWN0UGhvdG8pO1xuXHRcdFx0dGhpcy5pbWFnZURldGVjdG9yLnJlc2l6ZSgpO1xuXG5cdFx0XHRpZiAoZmlyc3QgPT0gZmFsc2UpIHsgXG5cdFx0XHRcdHNldFRpbWVvdXQodGhpcy5pbWFnZURldGVjdG9yLnN0YXJ0LCAxMDAwKTtcblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vICBBcnR3b3JrIFpvb20gIChvbmx5IGV2ZXIgb25jZSBvbiB0aGUgcGFnZSlcblx0XHRpZiAodGhpcy5hcnR3b3JrWm9vbSkgeyBcblx0XHRcdHRoaXMuYXJ0d29ya1pvb20uY2xvc2UoKTtcblx0XHR9XG5cdFx0dmFyIGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYXJ0d29yay16b29tJyk7XG5cdFx0aWYgKGVsZW1lbnQpIHsgXG5cdFx0XHR0aGlzLmFydHdvcmtab29tID0gbmV3IEFydHdvcmtab29tKGVsZW1lbnQpO1xuXHRcdH1cblx0XHRcblx0XHQvLyAgQXJ0d29yayBTbGlkZXJzXG5cdFx0Zm9yICh2YXIgaT0wOyBpPHRoaXMuYXJ0d29ya1NsaWRlcnMubGVuZ3RoOyBpKyspIHtcblx0XHRcdHRoaXMuYXJ0d29ya1NsaWRlcnNbaV0uY2xvc2UoKTtcblx0XHR9XG5cdFx0dGhpcy5hcnR3b3JrU2xpZGVycyA9IFtdO1xuXHRcdHZhciBlbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNjb250ZW50IC5hcnR3b3JrLXNsaWRlcicpO1xuXHRcdGZvciAodmFyIGk9MDsgaTxlbGVtZW50cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0dGhpcy5hcnR3b3JrU2xpZGVycy5wdXNoKG5ldyBBcnR3b3JrU2xpZGVyKGVsZW1lbnRzW2ldKSk7XG5cdFx0fVxuXHRcdFxuXHRcdC8vICBTb2NpYWwgU2hhcmVzXG5cdFx0Lypcblx0XHRmb3IgKHZhciBpPTA7IGk8dGhpcy5zb2NpYWxTaGFyZXMubGVuZ3RoOyBpKyspIHtcblx0XHRcdHRoaXMuc29jaWFsU2hhcmVzW2ldLmNsb3NlKCk7XG5cdFx0fVxuXHRcdHRoaXMuc29jaWFsU2hhcmVzID0gW107XG5cdFx0dmFyIGVsZW1lbnRzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2NvbnRlbnQgLnNvY2lhbC1zaGFyZScpO1xuXHRcdGZvciAodmFyIGk9MDsgaTxlbGVtZW50cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0dGhpcy5zb2NpYWxTaGFyZXMucHVzaChuZXcgU29jaWFsU2hhcmUoZWxlbWVudHNbaV0pKTtcblx0XHR9XG5cdFx0Ki9cblxuXHRcdC8vICBXYWxsICAob25seSBldmVyIG9uY2Ugb24gdGhlIHBhZ2UpXG5cdFx0aWYgKHRoaXMud2FsbCkgeyBcblx0XHRcdHRoaXMud2FsbC5jbG9zZSgpO1xuXHRcdH1cblx0XHR2YXIgZWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNjb250ZW50IC53YWxsLnBob3RvZ3JhcGhzJylbMF07XG5cdFx0aWYgKGVsZW1lbnQpIHsgXG5cdFx0XHR0aGlzLndhbGwgPSBuZXcgV2FsbChlbGVtZW50LCAncGhvdG9ncmFwaHMnKTtcblx0XHR9XG5cdFx0dmFyIGVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcjY29udGVudCAud2FsbC52YXJjaGl2ZScpWzBdO1xuXHRcdGlmIChlbGVtZW50KSB7IFxuXHRcdFx0dGhpcy53YWxsID0gbmV3IFdhbGwoZWxlbWVudCwgJ3ZhcmNoaXZlJyk7XG5cdFx0fVxuXHRcdHZhciBlbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2NvbnRlbnQgLndhbGwuZG9sbHMnKVswXTtcblx0XHRpZiAoZWxlbWVudCkgeyBcblx0XHRcdHRoaXMud2FsbCA9IG5ldyBXYWxsKGVsZW1lbnQsICdkb2xscycpO1xuXHRcdH1cblxuXHRcdC8vICBBcnR3b3JrIEFSXG5cdFx0Lypcblx0XHRpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2NvbnRlbnQgLmFydHdvcmstYXInKS5sZW5ndGggPiAwKSB7XG5cdFx0XHQvL2NvbnNvbGUubG9nKCdNb2RlbFZpZXdlciBmb3VuZCcpO1xuXHRcdFx0dmFyIHNlbGYgPSB0aGlzO1xuXHRcdFx0aWYgKHRoaXMuYXJMaWJyYXJ5TG9hZGluZyAmJiAhdGhpcy5hckxpYnJhcnlMb2FkZWQpIHsgXG5cdFx0XHRcdC8vICBXYWl0XG5cdFx0XHRcdC8vY29uc29sZS5sb2coJ01vZGVsVmlld2VyIGxvYWRpbmcuLi4nKTtcblx0XHRcdH0gZWxzZSBpZiAodGhpcy5hckxpYnJhcnlMb2FkZWQpIHsgXG5cdFx0XHRcdC8vY29uc29sZS5sb2coJ01vZGVsVmlld2VyIGxvYWRlZCcpO1xuXHRcdFx0XHRzZWxmLmFwcGx5RXZlbnRzVG9ET01BcnR3b3JrQVIoKTtcblx0XHRcdH0gZWxzZSB7IFxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdNb2RlbFZpZXdlciwgbG9hZGluZyBsaWJyYXJ5Li4uJyk7XG5cdFx0XHRcdHRoaXMuYXJMaWJyYXJ5TG9hZGluZyA9IHRydWU7XG5cdFx0XHRcdHZhciBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic2NyaXB0XCIpO1xuXHRcdFx0XHRzY3JpcHQudHlwZSA9ICdtb2R1bGUnO1xuXHRcdFx0XHRzY3JpcHQuc3JjID0gd2luZG93LnBsdWdpbkJhc2VVUkwrJ3N0YXRpYy9qcy9tb2RlbC12aWV3ZXIubWluLmpzJztcblx0XHRcdFx0c2NyaXB0Lm9ubG9hZCA9IGZ1bmN0aW9uICgpIHsgXG5cdFx0XHRcdFx0Ly9jb25zb2xlLmxvZygnTW9kZWxWaWV3ZXIsIGxvYWRlZCBsaWJyYXJ5LicpO1xuXHRcdFx0XHRcdHNlbGYuYXJMaWJyYXJ5TG9hZGVkID0gdHJ1ZTtcblx0XHRcdFx0XHRzZWxmLmFwcGx5RXZlbnRzVG9ET01BcnR3b3JrQVIoKTtcblx0XHRcdFx0fTtcblx0XHRcdFx0ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChzY3JpcHQpO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0fVxuXHRcdCovXG5cblx0fVxuXG5cdC8vICBMb29rIGZvciBhbmQgcmVwbGFjZSBBcnR3b3JrIEFSIGludGVyYWN0aW9uc1xuXHRhcHBseUV2ZW50c1RvRE9NQXJ0d29ya0FSKCkgeyBcblx0XHQvL2NvbnNvbGUubG9nKCdNb2RlbFZpZXdlciwgYXBwbHkgdG8gZG9tJyk7XG5cdFx0dmFyIGVsZW1lbnRzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnI2NvbnRlbnQgLmFydHdvcmstYXInKTtcblx0XHRmb3IgKHZhciBpPTA7IGk8ZWxlbWVudHMubGVuZ3RoOyBpKyspIHtcblx0XHRcdHZhciBlbGVtZW50ID0gZWxlbWVudHNbaV07XG5cdFx0XHR2YXIgc2x1ZyA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXNsdWcnKTtcblx0XHRcdHZhciBtdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ21vZGVsLXZpZXdlcicpO1xuXHRcdFx0bXYuc2V0QXR0cmlidXRlKCdzcmMnLCAnL3dwLWNvbnRlbnQvcGx1Z2lucy9wb3dlcmhvdXNlLWRpZ2l0YWwtYXR0ZW5kYW5jZS9zdGF0aWMvM2QvJytzbHVnKycuZ2x0Zj8nK01hdGgucmFuZG9tKCkrJycpO1xuXHRcdFx0bXYuc2V0QXR0cmlidXRlKCdhcicsICcnKTtcblx0XHRcdG12LnNldEF0dHJpYnV0ZSgncmV2ZWFsJywgJ2F1dG8nKTtcblx0XHRcdG12LnNldEF0dHJpYnV0ZSgnYXItcGxhY2VtZW50JywgJ3dhbGwnKTtcblx0XHRcdG12LnNldEF0dHJpYnV0ZSgnYXItbW9kZXMnLCAnd2VieHIgc2NlbmUtdmlld2VyIHF1aWNrLWxvb2snKTtcblx0XHRcdG12LnNldEF0dHJpYnV0ZSgnY2FtZXJhLWNvbnRyb2xzJywgJycpO1xuXHRcdFx0bXYuc2V0QXR0cmlidXRlKCdhbHQnLCAnVXNlIGF1Z21lbnRlZCByZWFsaXR5IHRvIHZpZXcgdGhpcyBhcnR3b3JrIHdpdGhpbiB5b3VyIGhvbWUgYW5kIGdldCBjbG9zZXIgdGhhbiBldmVyJyk7XG5cdFx0XHRtdi5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7IFxuXHRcdFx0XHRpZiAoIW12LmNhbkFjdGl2YXRlQVIpIHsgXG5cdFx0XHRcdFx0bXYucGFyZW50Tm9kZS5wYXJlbnROb2RlLnBhcmVudE5vZGUucmVtb3ZlKCk7XG5cdFx0XHRcdH0gXG5cdFx0XHR9XG5cdFx0XHRlbGVtZW50LmFwcGVuZENoaWxkKG12KTtcblx0XHR9XG5cdH1cblxuXHQvLyAgQ2xvc2UgYWxsIG1vZGFsc1xuXHRtb2RhbHNDbG9zZUFsbCgpIHsgXG5cdFx0dmFyIG1vZGFscyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5tb2RhbCcpO1xuXHRcdGZvciAodmFyIGk9MDsgaTxtb2RhbHMubGVuZ3RoOyBpKyspIHtcblx0XHRcdG1vZGFsc1tpXS5jbGFzc0xpc3QucmVtb3ZlKCdvcGVuJyk7XG5cdFx0fVxuXHR9XG5cblx0Ly8gIFBob3RvIHNlbGVjdGVkXG5cdHNjYW5TZWxlY3RQaG90byhzbHVnKSB7IFxuXHRcdGNvbnNvbGUubG9nKFwic2x1ZyB0byBzZWxlY3QgcGhvdG86IFwiLCBzbHVnKTtcblx0XHR0aGlzLm1vZGFsc0Nsb3NlQWxsKCk7XG5cdFx0Y29uc3QgbW9kYWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2Nhbi1hcnR3b3JrLXN1bW1hcnktJytzbHVnKTtcblx0XHRpZiAobW9kYWwpIHsgXG5cdFx0XHRtb2RhbC5jbGFzc0xpc3QuYWRkKCdvcGVuJyk7XG5cdFx0XHR3aW5kb3cuZ2FFdmVudCgnU2NhbicsICdzZWxlY3QnLCBzbHVnKTtcblx0XHR9XG5cdH1cblxuXHQvLyAgVGhlIHVybCBmb3IgdGhlIGNvbnRlbnQgZnJvbSB0aGUgcGF0aFxuXHRjb250ZW50VVJMKHBhdGgpIHsgXG5cdFx0cmV0dXJuIHdpbmRvdy5wbHVnaW5CYXNlVVJMKydwYWdlcycrcGF0aCsnLmh0bWwnO1xuXHR9XG5cblx0Ly8gIENsZWFuIHRoZSBwYXRoIFxuXHRjbGVhblBhdGgocGF0aCkgeyBcblx0XHRpZiAocGF0aC5jaGFyQXQocGF0aC5sZW5ndGgtMSkgPT0gXCIvXCIpIHtcblx0XHRcdHBhdGggPSBwYXRoLnNsaWNlKDAsIC0xKVxuXHRcdH1cblx0XHRwYXRoID0gcGF0aC5zcGxpdChsb2NhdGlvbi5vcmlnaW4pLmpvaW4oJycpOyBcblx0XHRyZXR1cm4gcGF0aDtcblx0fVxuXG5cblxufVxuXG5cbiIsIlxuLy9pbXBvcnQgKiBhcyB0ZiBmcm9tICdAdGVuc29yZmxvdy90ZmpzJztcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSW1hZ2VEZXRlY3Qge1xuXG5cdGNvbnN0cnVjdG9yKCkgeyBcblx0XHQvL2NvbnNvbGUubG9nKCdJbWFnZURldGVjdCBpbml0Jyk7XG5cdFx0dGhpcy5hY3RpdmUgPSBmYWxzZTtcblx0XHR0aGlzLnNlbGVjdFBob3RvID0gbnVsbDtcblx0XHR0aGlzLmxpYnJhcnlMb2FkZWQgPSBmYWxzZTtcblx0XHR0aGlzLm1vZGVsTG9hZGVkID0gZmFsc2U7XG5cdFx0dGhpcy5jb250YWluZXIgPSBudWxsOyBcblx0XHR0aGlzLnBhcmVudCA9IG51bGw7XG5cdFx0dGhpcy5tb2RlbDtcblx0XHR0aGlzLndlYmNhbTtcblx0XHR0aGlzLmNhbnZhcztcblx0XHR0aGlzLnZpZGVvO1xuXHRcdHRoaXMuc3RyZWFtO1xuXHRcdHRoaXMubW9kZWxQYXRoID0gd2luZG93LnBsdWdpbkJhc2VVUkwrXCJzdGF0aWMvbW9kZWwvXCI7XG5cdFx0dGhpcy5zdGFydCA9IHRoaXMuc3RhcnQuYmluZCh0aGlzKTtcblx0XHR0aGlzLmxvb3AgPSB0aGlzLmxvb3AuYmluZCh0aGlzKTtcblx0XHR0aGlzLndlYmNhbVNpemUgPSBbNzIwLDcyMF07XG5cdFx0dGhpcy5jYW52YXNTaXplID0gMjI0O1xuXHRcdHRoaXMubGFzdFNsdWcgPSAnJztcblx0XHR0aGlzLmN1cnJlbnRQaG90byA9IG51bGw7XG5cdFx0dGhpcy5jdXJyZW50UGhvdG9Db3VudGVyID0gMDtcblx0XHRcblx0XHR0aGlzLnNsdWdPcmRlciA9IFtcblx0XHRcdCd0d28tZmFhZmFmaW5lJyxcblx0XHRcdCd0d28tZmFhZmFmaW5lLWdvaW5nLXRvLWNodXJjaCcsXG5cdFx0XHQnc3Bpcml0LW9mLXRoZS1hbmNlc3RvcnMtd2F0Y2hpbmcnLFxuXHRcdFx0J3RocmVlLWZhYWZhZmluZScsXG5cdFx0XHQnbmFmZWEtZS10ZS1mYWFpcG9pcG8nLFxuXHRcdFx0J3RoZS13aXphcmQnLFxuXHRcdFx0J3Npb3UtYWxvZmEtbWFyaWEtaGFpbC1tYXJ5Jyxcblx0XHRcdCd0d28tZmFhZmFmaW5lLW9uLXRoZS1iZWFjaCcsXG5cdFx0XHQnZmFhZmFmaW5lLXdpdGgtY2hpbGRyZW4nLFxuXHRcdFx0J2dlbmVzaXMtOS0xNicsXG5cdFx0XHQnZm9ub2Zvbm8tby1sZS1udWFudWEnLFxuXHRcdFx0J3BhdWwtZ2F1Z3Vpbi13aXRoLWEtaGF0Jyxcblx0XHRcdCdhdWNrbGFuZC1hcnQtZ2FsbGVyeS12aXNpdG9ycy1ib29rJyxcblx0XHRcdCdjYXN0LW9mLXBhcmFkaXNlLWNhbXAnLFxuXHRcdFx0J2RvY3VtZW50aW5nLWNsaW1hdGUtY2hhbmdlLWluLXNhbW9hJyxcblx0XHRcdCdmYWFmYWZpbmUtYW5jZXN0b3JzJyxcblx0XHRcdCdmYWFmYWZpbmUtYXF1YXJpdW0nLFxuXHRcdFx0J2dhdWd1aW4tYW5kLXNhbW9hJyxcblx0XHRcdCdnYXVndWluLWFuZC10b3VyaXNtLWltYWdlcnktaW4tdGhlLW1vYW5hJyxcblx0XHRcdCdoZWFkbGluZXMnLFxuXHRcdFx0J25ldy16ZWFsYW5kcy1jb2xvbmlhbC1hZG1pbnN0cmF0aW9uLW9mLXNhbW9hJyxcblx0XHRcdCdwYXNpZmlrYS10aGVpcnN0b3JpZXMnLFxuXHRcdFx0J3Bhc3Nwb3J0cycsXG5cdFx0XHQnc2Ftb2FuaXNpbmctY2hyaXN0aWFuaXR5Jyxcblx0XHRcdCdzdW5kYXktc2Ftb2FuLW5ld3NwYXBlcicsXG5cdFx0XHQndGVhY2hlcnMtZ3VpZGUtdG8teWVhci0xMC1zdHVkZW50cycsXG5cdFx0XHQndmFpbHVsdXUtc2VhbW91bnQnLFxuXHRcdFx0J3ZlbmljZS1hbmQtdGhlLW90aGVyJyxcblx0XHRcdCd3b3JsZC1wZWFjZS1mYWFmYWZpbmUtYmVhdXR5LXBhZ2VhbnRzJyxcblx0XHRcdCd5dWtpLWtpaGFyYS1hdC10aGUtbWV0cm9wb2xpdGFuLW11c2V1bS1vZi1hcnQnLFxuXHRcdFx0J3l1a2kta2loYXJhLW9uLXRlbGVjb20tbW9iaWxlLWNhbXBhaWduJyxcblx0XHRcdCdmYWFmYWZpbmUtaW5kdXN0cnktdmFyaWV0eS1hd2FyZCcsIFxuXHRcdFx0J2ZhYWZhZmluZS1hbmNlc3RvcnMtMScsXG5cdFx0XHQnZmFhZmFmaW5lLWFuY2VzdG9ycy0yJyxcblx0XHRcdCdmYWFmYWZpbmUtYW5jZXN0b3JzLTMnLFxuXHRcdFx0J2ZhYWZhZmluZS1hbmNlc3RvcnMtNCcsXG5cdFx0XHQnc2Ftb2FuLXF1ZWVyLWxpdmVzJyxcblx0XHRcdCdzYW1vYW4tb3JpZ2luLXN0b3J5Jyxcblx0XHRcdCdmYWFmYWZpbmUtY2xhaW0tbXl0aC1vZmZlbnNpdmUnLFxuXHRcdFx0J3BhcmFkaXNlLWNhbXAtbWVkaWEnLFxuXHRcdFx0J2dob3N0LWZvcmVzdC11cG9sdS1pc2xhbmQnLFxuXHRcdFx0J21hdGFhZmEtbG9zZWZvLWxhbmRtYXJrLWFtYWlsZScsXG5cdFx0XHQndGFwYXMtc2lhcG8tMScsXG5cdFx0XHQndGFwYXMtc2lhcG8tMicsXG5cdFx0XHQndGFwYXMtc2lhcG8tMycsXG5cdFx0XHQncGFyYWRpc2UtY2FtcC1ib29rJyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5Jyxcblx0XHRcdCdzdGFtcHMnLFxuXHRcdFx0J2dhdWd1aW4tbGFuZHNjYXBlcycsXG5cdFx0XHQnZ2F1Z3Vpbi1sYW5kc2NhcGVzLTEnLFxuXHRcdFx0J2dhdWd1aW4tbGFuZHNjYXBlcy0yJyxcblx0XHRcdCdnYXVndWluLWxhbmRzY2FwZXMtMycsXG5cdFx0XHQnZ2F1Z3Vpbi1sYW5kc2NhcGVzLTQnLFxuXHRcdFx0J2dhdWd1aW4tbGFuZHNjYXBlcy01Jyxcblx0XHRcdCdnYXVndWluLWxhbmRzY2FwZXMtNicsXG5cdFx0XHQnZ2F1Z3Vpbi1sYW5kc2NhcGVzLTcnLFxuXHRcdFx0J2dhdWd1aW4tbGFuZHNjYXBlcy04Jyxcblx0XHRcdCdnYXVndWluLWxhbmRzY2FwZXMtOScsXG5cdFx0XHQnZ2F1Z3Vpbi1sYW5kc2NhcGVzLTEwJyxcblx0XHRcdCdnYXVndWluLWxhbmRzY2FwZXMtMTEnLFxuXHRcdFx0J2dhdWd1aW4tbGFuZHNjYXBlcy0xMicsXG5cdFx0XHQnZ2F1Z3Vpbi1sYW5kc2NhcGVzLTEzJyxcblx0XHRcdCdnYXVndWluLWxhbmRzY2FwZXMtMTQnLFxuXHRcdFx0J2dhdWd1aW4tbGFuZHNjYXBlcy0xNScsXG5cdFx0XHQnZ2F1Z3Vpbi1sYW5kc2NhcGVzLTE2Jyxcblx0XHRcdCdnYXVndWluLWxhbmRzY2FwZXMtMTcnLFxuXHRcdFx0J2dhdWd1aW4tbGFuZHNjYXBlcy0xOCcsXG5cdFx0XHQnZ2F1Z3Vpbi1sYW5kc2NhcGVzLTE5Jyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5LTEnLFxuXHRcdFx0J2NoYXJsZXMta2VycnktMicsXG5cdFx0XHQnY2hhcmxlcy1rZXJyeS0zJyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5LTQnLFxuXHRcdFx0J2NoYXJsZXMta2VycnktNScsXG5cdFx0XHQnY2hhcmxlcy1rZXJyeS02Jyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5LTcnLFxuXHRcdFx0J2NoYXJsZXMta2VycnktOCcsXG5cdFx0XHQnY2hhcmxlcy1rZXJyeS05Jyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5LTEwJyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5LTExJyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5LTEyJyxcblx0XHRcdCdjaGFybGVzLWtlcnJ5LTEzJyxcblx0XHRcdCdiZXJ0aGFkYXktMjAxNicsXG5cdFx0XHQnZGFuZ2Vyb3VzLWRlc2lyZS0xOTkxJyxcblx0XHRcdCdkb29yLWJpdGNoLTIwMDEnLFxuXHRcdFx0J2VhdGVuLWFsaXZlLTE5OTgnLFxuXHRcdFx0J2ZhYWZhZmluZXMtYXQtdGhlLXN5ZG5leS1vcGVyYS1ob3VzZS0yMDA5Jyxcblx0XHRcdCdsYXctcmVmb3JtLWdpcmwtMTk4NicsXG5cdFx0XHQnbWFkYW1lLWJ1dHRlcmZseS0xOTk1Jyxcblx0XHRcdCdvdmVyLXRoZS1yYWluYm93Jyxcblx0XHRcdCdxdWVlbnMtb2YtdGhlLXBhY2lmaWMtMTk5NCcsXG5cdFx0XHQndGFrZS1tZS10by1oZWF2ZW4tMTk5MicsXG5cdFx0XHQndGhyZWUtbWFyeXMtMjAxMCcsXG5cdFx0XTtcblxuXHRcdC8vICBcblx0XHR0aGlzLnJlc2l6ZSA9IHRoaXMucmVzaXplLmJpbmQodGhpcyk7XG5cblx0XHQvLyAgUmVzaXplXG5cdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRoaXMucmVzaXplKTtcblx0XHR0aGlzLnJlc2l6ZSgpO1xuXG5cdH1cblxuXHRyZXNpemUoZXZlbnQpIHsgXG5cdFx0Y29uc3Qgc2NhbiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzY2FuJyk7XG5cdFx0aWYgKHNjYW4pIHsgXG5cdFx0XHRzY2FuLnN0eWxlLmhlaWdodCA9ICh3aW5kb3cuaW5uZXJIZWlnaHQtNTYtNTYpKydweCc7XG5cdFx0fVxuXHR9XG5cblx0c2V0UGFyZW50KHApIHsgXG5cdFx0Ly9jb25zb2xlLmxvZygnSW1hZ2VEZXRlY3Qgc2V0UGFyZW50JywgcCk7XG5cdFx0dGhpcy5wYXJlbnQgPSBwO1xuXHR9XG5cdHNldENvbnRhaW5lcihlbGVtZW50KSB7IFxuXHRcdC8vY29uc29sZS5sb2coJ0ltYWdlRGV0ZWN0IHNldENvbnRhaW5lcicsIGVsZW1lbnQpO1xuXHRcdHRoaXMuY29udGFpbmVyID0gZWxlbWVudDtcblx0fVxuXHRzZXRDYWxsYmFjayhjYWxsYmFjaykgeyBcblx0XHQvL2NvbnNvbGUubG9nKCdJbWFnZURldGVjdCBzZXRDYWxsYmFjaycsIGNhbGxiYWNrKTtcblx0XHR0aGlzLnNlbGVjdFBob3RvID0gY2FsbGJhY2s7XG5cdH1cblxuXHRhc3luYyBzdGFydCgpIHsgXG5cdFx0Ly9jb25zb2xlLmxvZygnSW1hZ2VEZXRlY3Qgc3RhcnQnKTtcblxuXHRcdC8vICBDb25maXJtIHRoZXkgc3VwcG9ydCB3ZWJjYW1zXG5cdFx0aWYgKHdpbmRvdy5sb2NhdGlvbi5wcm90b2NvbCAhPSBcImh0dHBzOlwiKSB7XG5cdFx0XHRpZiAod2luZG93LmxvY2F0aW9uLmhvc3RuYW1lICE9ICdsb2NhbGhvc3QnKSB7IFxuXHRcdFx0XHRhbGVydCgnV2ViUlRDIG5vdCBzdXBwb3J0ZWQgb3ZlciBodHRwLiAgUGxlYXNlIGVuYWJsZSBodHRwcyBvciB1c2UgbG9jYWxob3N0LicpO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XHRcblx0XHR9XG5cdFx0aWYgKCF3aW5kb3cubmF2aWdhdG9yLm1lZGlhRGV2aWNlcyB8fCAhd2luZG93Lm5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKSB7XG5cdFx0XHRhbGVydCgnWW91ciBicm93c2VyIGRvZXMgbm90IHN1cHBvcnQgV2ViUlRDLiBQbGVhc2UgdHJ5IGFub3RoZXIgb25lLicpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLmFjdGl2ZSkgeyBcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5hY3RpdmUgPSB0cnVlO1xuXG5cdFx0Ly8gIFJlZmVyZW5jZVxuXHRcdGNvbnN0IHNlbGYgPSB0aGlzO1xuXG5cdFx0Ly8gIExvYWQgdGhlIFRlbnNvcmZsb3cgTGliYXJ5IG9ubHkgYXMgaXQncyBuZWVkZWQsIGFuZCBvbmx5IGxvYWQgaXQgb25jZS5cdFx0XG5cdFx0aWYgKHRoaXMubGlicmFyeUxvYWRlZCA9PSBmYWxzZSkge1xuXHRcdFx0dGhpcy5hY3RpdmUgPSBmYWxzZTtcblx0XHRcdC8vY29uc29sZS5sb2coJ0ltYWdlRGV0ZWN0LCBsb2FkaW5nIGxpYnJhcnkuLi4nKTtcblx0XHRcdHZhciBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic2NyaXB0XCIpO1xuXHRcdFx0c2NyaXB0LnR5cGUgPSAndGV4dC9qYXZhc2NyaXB0Jztcblx0XHRcdHNjcmlwdC5zcmMgPSB3aW5kb3cucGx1Z2luQmFzZVVSTCsnc3RhdGljL2pzL3RlbnNvcmZsb3cubWluLmpzJztcblx0XHRcdHNjcmlwdC5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7IFxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdJbWFnZURldGVjdCwgbG9hZGVkIGxpYnJhcnkuJyk7XG5cdFx0XHRcdHNlbGYubGlicmFyeUxvYWRlZCA9IHRydWU7XG5cdFx0XHRcdHNlbGYuc3RhcnQoKTtcblx0XHRcdH07XG5cdFx0XHRkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gIExvYWQgdGhlIG1vZGVsXG5cdFx0aWYgKHRoaXMubW9kZWxMb2FkZWQgPT0gZmFsc2UpIHsgXG5cdFx0XHR0aGlzLm1vZGVsTG9hZGVkID0gdHJ1ZTtcblx0XHRcdC8vY29uc29sZS5sb2coJ0ltYWdlRGV0ZWN0LCBsb2FkaW5nIG1vZGVsLi4uJyk7XG5cdFx0XHR0aGlzLm1vZGVsID0gYXdhaXQgdGYubG9hZExheWVyc01vZGVsKHRoaXMubW9kZWxQYXRoKydtb2RlbC5qc29uJyk7XG5cdFx0XHQvL2NvbnNvbGUubG9nKCdJbWFnZURldGVjdCwgbG9hZGVkIG1vZGVsLicpO1xuXHRcdH1cblxuXHRcdC8vICBWZXJzaW9uIGNoZWNrXG5cdFx0Ly9jb25zb2xlLmxvZygnVGVuc29yZmxvdycsIHRmLnZlcnNpb24udGZqcywgdGYuZ2V0QmFja2VuZCgpKTtcblxuXHRcdC8vICBDcmVhdGUgdGhlIGNhbnZhc1xuXHRcdHRoaXMuY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG5cdFx0dGhpcy5jYW52YXMud2lkdGggPSB0aGlzLmNhbnZhc1NpemU7XG5cdFx0dGhpcy5jYW52YXMuaGVpZ2h0ID0gdGhpcy5jYW52YXNTaXplO1xuXG5cdFx0Ly8gIENyZWF0ZSB0aGUgdmlkZW8gb2JqZWN0XG5cdFx0Ly9jb25zb2xlLmxvZygnSW1hZ2VEZXRlY3QsIGNyZWF0ZSB2aWRlby4nKTtcblx0XHRjb25zdCB2aWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3ZpZGVvJyk7XG5cdFx0dGhpcy52aWRlbyA9IG51bGw7XG5cdFx0dGhpcy52aWRlbyA9IHZpZGVvO1xuXG5cdFx0Ly8gIFdlYmNhbSBjb25zdHJhaW50c1xuXHRcdGNvbnN0IGNvbnN0cmFpbnRzID0geyBcblx0XHRcdGF1ZGlvOiBmYWxzZSwgXG5cdFx0XHR2aWRlbzogeyBcblx0XHRcdFx0d2lkdGg6IDEyODAsXG5cdFx0XHRcdGhlaWdodDogNzIwLCBcblx0XHRcdFx0ZmFjaW5nTW9kZTonZW52aXJvbm1lbnQnIFxuXHRcdFx0fSBcblx0XHR9O1xuXG5cdFx0Ly8gIFN0YXJ0IHRoZSB3ZWJjYW1cblx0XHR0aGlzLndlYmNhbSA9IHdpbmRvdy5uYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYShjb25zdHJhaW50cylcblx0XHQudGhlbigoc3RyZWFtKSA9PiB7XG5cdFx0XHR2aWRlby5zcmNPYmplY3QgPSBzdHJlYW07XG5cdFx0XHRzZWxmLnN0cmVhbSA9IHN0cmVhbTtcblx0XHRcdC8qXG5cdFx0XHR2aWRlby5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWRtZXRhZGF0YScsIGZ1bmN0aW9uIChldmVudCkgIHtcblx0XHRcdFx0aWYgKHZpZGVvLnZpZGVvV2lkdGggIT0gMCAmJiB2aWRlby52aWRlb0hlaWdodCAhPSAwKSB7IFxuXHRcdFx0XHRcdGNvbnNvbGUubG9nKCdJbWFnZURldGVjdCwgdmlkZW8gbWV0YWRhdGEgbG9hZGVkLCAnLCB2aWRlby52aWRlb1dpZHRoLCB2aWRlby52aWRlb0hlaWdodCk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdFx0Ki9cblxuXHRcdFx0Ly8gIEhpZGUgdGhlIHNwaW5uZXJcblx0XHRcdGNvbnN0IHNwaW5uZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2Nhbi1zcGlubmVyJyk7XG5cdFx0XHRpZiAoc3Bpbm5lcikgeyBcblx0XHRcdFx0c3Bpbm5lci5zdHlsZS5vcGFjaXR5ID0gMDtcblx0XHRcdH1cblxuXHRcdFx0Ly8gIFNob3cgdGhlIHRhcmdldFxuXHRcdFx0Y29uc3QgdGFyZ2V0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3NjYW4tdGFyZ2V0Jyk7XG5cdFx0XHRpZiAodGFyZ2V0KSB7IFxuXHRcdFx0XHR0YXJnZXQuc3R5bGUub3BhY2l0eSA9IDE7XG5cdFx0XHR9XG5cblx0XHR9KVxuXHRcdC5jYXRjaCgoZXJyKSA9PiB7XG5cdFx0XHR0aGlzLnBhcmVudC5saW5rQ2xpY2soJy9leHBsb3JlL3Ryb3VibGVzaG9vdCcpO1xuXHRcdH0pO1xuXG5cdFx0Ly8gIEFkZCB0aGUgdmlkZW8gdG8gdGhlIHNjcmVlblxuXHRcdHRoaXMuY29udGFpbmVyLmFwcGVuZENoaWxkKHZpZGVvKTsgXG5cdFx0Ly9jb25zb2xlLmxvZygnSW1hZ2VEZXRlY3QsIGFwcGVuZCB2aWRlby4nLCB2aWRlbyk7XG5cdFx0Ly90aGlzLmNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLmNhbnZhcyk7XG5cblx0XHQvLyAgV3JpdHRlbiB3aXRoIFwic2V0QXR0cmlidXRlXCIgYmMuIGlPUyBidWdncyBvdGhlcndpc2UgOi0pXG5cdFx0dmlkZW8uc2V0QXR0cmlidXRlKFwicGxheXNpbmxpbmVcIiwgdHJ1ZSk7IFxuXHRcdHZpZGVvLndpZHRoID0gdGhpcy53ZWJjYW1TaXplWzBdO1xuXHRcdHZpZGVvLmhlaWdodCA9IHRoaXMud2ViY2FtU2l6ZVsxXTtcblx0XHR2aWRlby5tdXRlZCA9IFwidHJ1ZVwiXG5cdFx0dmlkZW8uaWQgPSBcIndlYmNhbVZpZGVvXCI7XG5cdFxuXHRcdC8vICBQbGF5XHRcdFxuXHRcdHZpZGVvLnBsYXkoKTtcblx0XHRcdFxuXHRcdC8vICBMb29wXG5cdFx0d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSh0aGlzLmxvb3ApO1xuXG5cdH1cblxuXHRhc3luYyBzdG9wKCkgeyBcblx0XHQvL2NvbnNvbGUubG9nKCdJbWFnZURldGVjdCBzdG9wJyk7XG5cdFx0dGhpcy5hY3RpdmUgPSBmYWxzZTtcblx0XHRpZiAodGhpcy5zdHJlYW0pIHsgXG5cdFx0XHR0aGlzLnN0cmVhbS5nZXRUcmFja3MoKVswXS5zdG9wKCk7XG5cdFx0fVxuXHRcdGlmICh0aGlzLnZpZGVvKSB7IFxuXHRcdFx0dGhpcy52aWRlby5wYXVzZSgpO1xuXHRcdFx0dGhpcy52aWRlby5yZW1vdmUoKTtcblx0XHRcdHRoaXMudmlkZW8gPSBudWxsO1xuXHRcdH1cblx0XHR0aGlzLmNhbnZhcyA9IG51bGw7XG5cdFx0Ly90aGlzLm1vZGVsID0gbnVsbDtcblx0XHR0aGlzLndlYmNhbSA9IG51bGw7XG5cdH1cblxuXHRhc3luYyBsb29wKCkge1xuXHRcdGlmICh0aGlzLmNhbnZhcyAmJiB0aGlzLndlYmNhbSkgeyBcblx0XHRcdFxuXHRcdFx0Ly8gIFRoZSBzaXplIG9mIHRoZSB3ZWJjYW0gdmlkZW9cblx0XHRcdHZhciB3ID0gdGhpcy53ZWJjYW1TaXplWzBdO1xuXHRcdFx0dmFyIGggPSB0aGlzLndlYmNhbVNpemVbMV07XG5cdFx0XHRpZiAodGhpcy52aWRlby52aWRlb1dpZHRoICE9IDAgJiYgdGhpcy52aWRlby52aWRlb0hlaWdodCAhPSAwKSB7IFxuXHRcdFx0XHR3ID0gdGhpcy52aWRlby52aWRlb1dpZHRoXG5cdFx0XHRcdGggPSB0aGlzLnZpZGVvLnZpZGVvSGVpZ2h0O1xuXHRcdFx0fVxuXG5cdFx0XHQvLyAgQ2VudGVyIHNxdWFyZSBpbnNldCAyMCVcblx0XHRcdHZhciBtaW4gPSBNYXRoLm1pbih3LCBoKSowLjg7XG5cdFx0XHRjb25zdCB0eCA9IE1hdGguZmxvb3IoKHctbWluKSowLjUpO1xuXHRcdFx0Y29uc3QgdHkgPSBNYXRoLmZsb29yKChoLW1pbikqMC41KTtcblxuXHRcdFx0Y29uc3QgY3R4ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblx0XHRcdGN0eC5kcmF3SW1hZ2UodGhpcy52aWRlbywgdHgsIHR5LCBtaW4sIG1pbiwgICAwLDAsdGhpcy5jYW52YXNTaXplLHRoaXMuY2FudmFzU2l6ZSk7XG5cblx0XHRcdC8vICBQcmVkaWN0XG5cdFx0XHRjb25zdCBsb2dpdHMgPSB0Zi50aWR5KCgpID0+IHtcblx0XHRcdFx0Y29uc3QgcGl4ZWxzID0gdGYuYnJvd3Nlci5mcm9tUGl4ZWxzKHRoaXMuY2FudmFzKTtcblx0XHRcdFx0Y29uc3QgcGl4ZWxzRXhwYW5kZWQgPSBwaXhlbHMuZXhwYW5kRGltcygwKTtcblx0XHRcdFx0Y29uc3QgY2FwdHVyZWQgPSBwaXhlbHNFeHBhbmRlZC50b0Zsb2F0KCkuZGl2KHRmLnNjYWxhcigxMjcpKS5zdWIodGYuc2NhbGFyKDEpKTtcblx0XHRcdFx0cmV0dXJuIHRoaXMubW9kZWwucHJlZGljdChjYXB0dXJlZCk7XG5cdFx0XHR9KTtcblxuXHRcdFx0Ly8gIFZhbHVlc1xuXHRcdFx0Y29uc3QgdmFsdWVzID0gYXdhaXQgbG9naXRzLmRhdGEoKTtcblx0XHRcdHZhciBpbmRleE1heCA9IG51bGw7XG5cdFx0XHR2YXIgdmFsdWVNYXggPSAwO1xuXG5cdFx0XHRmb3IgKHZhciBpPTA7IGk8dmFsdWVzLmxlbmd0aDsgaSsrKSB7IFxuXHRcdFx0XHR2YXIgdmFsdWUgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdGlmICh2YWx1ZU1heCA8IHZhbHVlKSB7IFxuXHRcdFx0XHRcdHZhbHVlTWF4ID0gdmFsdWU7XG5cdFx0XHRcdFx0aW5kZXhNYXggPSBpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vY29uc29sZS5sb2coXCJpbmRleE1heCAmIHZhbHVlTWF4OiBcIiwgaW5kZXhNYXgsIHZhbHVlTWF4KTtcblx0XHRcdC8vY29uc29sZS5sb2coXCJTbHVnIG9yZGVyOiBcIiwgdGhpcy5zbHVnT3JkZXIpO1xuXG5cdFx0XHRpZiAodmFsdWVNYXggPiAwLjkwKSB7IFxuXHRcdFx0XHR0aGlzLmN1cnJlbnRQaG90byA9IGluZGV4TWF4O1xuXG5cdFx0XHRcdC8vICBMb29rdXAgdGhlIHNsdWcgZm9yIHRoZSBiZXN0IHBob3RvXG5cdFx0XHRcdHZhciBzbHVnID0gdGhpcy5zbHVnT3JkZXJbaW5kZXhNYXhdO1xuXHRcdFx0XHQvL2NvbnNvbGUubG9nKFwiU2x1ZzogXCIsIHNsdWcpO1xuXHRcdFx0XHQvL2NvbnNvbGUubG9nKGluZGV4TWF4LCBzbHVnKTtcblx0XHRcdFx0aWYgKHNsdWcuaW5kZXhPZignZmFhZmFmaW5lLWFuY2VzdG9ycycpID09IDApIHNsdWcgPSAnZmFhZmFmaW5lLWFuY2VzdG9ycyc7XG5cdFx0XHRcdGlmIChzbHVnLmluZGV4T2YoJ3RhcGFzLXNpYXBvJykgPT0gMCkgc2x1ZyA9ICd0YXBhcy1zaWFwbyc7XG5cdFx0XHRcdGlmIChzbHVnLmluZGV4T2YoJ2dhdWd1aW4tbGFuZHNjYXBlcycpID09IDApIHNsdWcgPSAnZ2F1Z3Vpbi1sYW5kc2NhcGVzJztcblx0XHRcdFx0aWYgKHNsdWcuaW5kZXhPZignY2hhcmxlcy1rZXJyeScpID09IDApIHNsdWcgPSAnY2hhcmxlcy1rZXJyeSc7XG5cblx0XHRcdFx0aWYgKHNsdWcpIHsgXG5cdFx0XHRcdFx0aWYgKHRoaXMubGFzdFNsdWcgIT0gc2x1ZykgeyBcblx0XHRcdFx0XHRcdHRoaXMuc2VsZWN0UGhvdG8oc2x1Zyk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRoaXMubGFzdFNsdWcgPSBzbHVnO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly9jb25zb2xlLmxvZygnSW1hZ2VEZXRlY3QgdGhpcy5zZWxlY3RlZFBob3RvID0gJywgaW5kZXhNYXgsIHNsdWcpO1xuXG5cdFx0XHR9XG5cblx0XHRcdFxuXHRcdH1cblxuXHRcdC8vICBMb29wXG5cdFx0aWYgKHRoaXMuYWN0aXZlKSB7XG5cdFx0XHR3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMubG9vcCk7XG5cdFx0fVxuXG5cdH1cblxuXG5cbn1cblxuXG5cbiIsIlxuXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFNoYXJlWW91clZpc2l0IHtcblxuXHRjb25zdHJ1Y3RvcihlbCkgeyBcblxuXHRcdHRoaXMuc2VuZGluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5lbCA9IGVsO1xuXHRcdFxuXHRcdHRoaXMuZWwuaW5uZXJIVE1MID0gJzxkaXYgY2xhc3M9XCJpbm5lclwiPiBcXFxuXHRcdFx0PGRpdiBjbGFzcz1cImZvcm1cIiA+IFxcXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJjb250YWluZXJcIiA+XFxcblx0XHRcdFx0XHQ8aDIgY2xhc3M9XCJ1cHBlclwiID5TaGFyZSB5b3VyIHZpc2l0PC9oMj5cXFxuXHRcdFx0XHRcdDxwIGNsYXNzPVwiaW5mby1ibG9jayBpY29uLWluZm9cIiA+WW91ciBzdG9yeSB3aWxsIGJlIHNoYXJlZCB3aXRoIE5aIGF0IFZlbmljZSBhbmQgbWF5IGJlIHVzZWQgb24gc29jaWFsIG1lZGlhLjwvcD5cXFxuXHRcdFx0XHRcdDxmb3JtPlxcXG5cdFx0XHRcdFx0XHQ8bGFiZWwgZm9yPVwibWVzc2FnZVwiPk1lc3NhZ2U8L2xhYmVsPlxcXG5cdFx0XHRcdFx0XHQ8dGV4dGFyZWEgYXV0b2NvbXBsZXRlPVwib2ZmXCIgbmFtZT1cIm1lc3NhZ2VcIiBjbGFzcz1cIm1lc3NhZ2VcIiByb3dzPVwiNFwiIHBsYWNlaG9sZGVyPVwiVGVsbCB1cyBhYm91dCB5b3VyIHZpc2l0XCIgPjwvdGV4dGFyZWE+XFxcblx0XHRcdFx0XHRcdDxsYWJlbCBmb3I9XCJkZXRhaWxzXCI+Q29udGFjdCBEZXRhaWxzPC9sYWJlbD5cXFxuXHRcdFx0XHRcdFx0PGlucHV0IGF1dG9jb21wbGV0ZT1cIm9mZlwiIHR5cGU9XCJ0ZXh0XCIgbmFtZT1cImRldGFpbHNcIiBjbGFzcz1cImRldGFpbHNcIiBwbGFjZWhvbGRlcj1cIllvdXIgZW1haWxcIiAvPlxcXG5cdFx0XHRcdFx0XHQ8YnV0dG9uIGNsYXNzPVwic3VibWl0IGJ1dHRvblwiPlN1Ym1pdDwvYnV0dG9uPlxcXG5cdFx0XHRcdFx0PC9mb3JtPlxcXG5cdFx0XHRcdDwvZGl2PlxcXG5cdFx0XHQ8L2Rpdj5cXFxuXHRcdFx0PGRpdiBjbGFzcz1cInRoYW5reW91XCIgPlxcXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJjb250YWluZXJcIiA+XFxcblx0XHRcdFx0XHQ8aDIgY2xhc3M9XCJ1cHBlclwiID5UaGFuayB5b3U8L2gyPlxcXG5cdFx0XHRcdFx0PHAgY2xhc3M9XCJpbmZvLWJsb2NrIGljb24taW5mb1wiID5Zb3VyIHN0b3J5IGhhcyBiZWVuIHNoYXJlZCB3aXRoIHVzLiBUaGFuayB5b3UuPC9wPlxcXG5cdFx0XHRcdFx0PGJ1dHRvbiBjbGFzcz1cInN1Ym1pdC1hZ2FpbiBidXR0b25cIj5TVUJNSVRURUQ8L2J1dHRvbj5cXFxuXHRcdFx0XHQ8L2Rpdj5cXFxuXHRcdFx0PC9kaXY+XFxcblx0XHQ8L2Rpdj4nO1xuXG5cdFx0dGhpcy5lbElubmVyID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuaW5uZXInKVswXTtcblxuXHRcdHRoaXMuZWxGb3JtID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuZm9ybScpWzBdO1xuXHRcdHRoaXMuZWxUaGFua3lvdSA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLnRoYW5reW91JylbMF07XG5cblx0XHR0aGlzLmJ1dHRvblN1Ym1pdCA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLnN1Ym1pdCcpWzBdO1xuXHRcdHRoaXMuYnV0dG9uU3VibWl0QWdhaW4gPSB0aGlzLmVsLnF1ZXJ5U2VsZWN0b3JBbGwoJy5zdWJtaXQtYWdhaW4nKVswXTtcblxuXHRcdHRoaXMuZmllbGREZXRhaWxzID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuZGV0YWlscycpWzBdO1xuXHRcdHRoaXMuZmllbGRNZXNzYWdlID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcubWVzc2FnZScpWzBdO1xuXG5cdFx0dGhpcy5zdWJtaXQgPSB0aGlzLnN1Ym1pdC5iaW5kKHRoaXMpO1xuXHRcdHRoaXMuc3VibWl0dGVkID0gdGhpcy5zdWJtaXR0ZWQuYmluZCh0aGlzKTtcblx0XHR0aGlzLnN1Ym1pdEFnYWluID0gdGhpcy5zdWJtaXRBZ2Fpbi5iaW5kKHRoaXMpO1xuXHRcdHRoaXMuY2xvc2UgPSB0aGlzLmNsb3NlLmJpbmQodGhpcyk7XG5cblx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cblx0XHR0aGlzLmJ1dHRvblN1Ym1pdC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIHRoaXMuc3VibWl0KTtcblx0XHR0aGlzLmJ1dHRvblN1Ym1pdEFnYWluLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgdGhpcy5zdWJtaXRBZ2Fpbik7XG5cblxuXHR9XG5cblx0c3VibWl0KGV2ZW50KSB7IFxuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRpZiAodGhpcy5maWVsZERldGFpbHMudmFsdWUgPT0gJycgJiYgdGhpcy5maWVsZE1lc3NhZ2UudmFsdWUgPT0gJycpIHsgXG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuc2VuZGluZykgeyBcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5zZW5kaW5nID0gdHJ1ZTtcblxuXHRcdHdpbmRvdy5nYUV2ZW50KCdTaGFyZSB5b3VyIHZpc2l0JywgJ3N1Ym1pdCcsIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSwgMCk7XG5cblx0XHQvLyAgU2VuZCB0aGUgZmllbGQgdmFsdWVzXG5cdFx0dmFyIHVybCA9IHdpbmRvdy5wbHVnaW5CYXNlVVJMO1xuXHRcdHVybCA9IHVybCsnc2hhcmUteW91ci12aXNpdC5waHAnO1xuXHRcdHVybCA9IHVybCsnP2RldGFpbHM9JytlbmNvZGVVUklDb21wb25lbnQodGhpcy5maWVsZERldGFpbHMudmFsdWUpO1xuXHRcdHVybCA9IHVybCsnJm1lc3NhZ2U9JytlbmNvZGVVUklDb21wb25lbnQodGhpcy5maWVsZE1lc3NhZ2UudmFsdWUpO1xuXHRcdHVybCA9IHVybCsnJmNjPScrTWF0aC5yYW5kb20oKTtcblx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cdFx0ZmV0Y2godXJsKS50aGVuKGZ1bmN0aW9uKCkgeyBcblx0XHRcdHNlbGYuc2VuZGluZyA9IGZhbHNlO1xuXG5cdFx0XHQvLyAgU2xpZGUgdG8gc2hvdyB0aGFua3lvdVxuXHRcdFx0c2VsZi5lbElubmVyLnN0eWxlLnRyYW5zZm9ybSA9ICd0cmFuc2xhdGVYKC0xMDAlKSc7XG5cdFx0XHRcblx0XHR9KTtcblxuXHR9XG5cblx0c3VibWl0dGVkKCkgeyBcblx0fVxuXG5cdHN1Ym1pdEFnYWluKGV2ZW50KSB7IFxuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHR3aW5kb3cuZ2FFdmVudCgnU2hhcmUgeW91ciB2aXNpdCcsICdzdWJtaXQtYWdhaW4nLCB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUsIDApO1xuXG5cdFx0Ly8gIFNsaWRlIGJhY2sgdG8gdGhlIGZvcm1cblx0XHR0aGlzLmVsSW5uZXIuc3R5bGUudHJhbnNmb3JtID0gJ3RyYW5zbGF0ZVgoMCUpJztcblxuXHRcdC8vICBXaXBlIHRoZSBtZXNzYWdlIGZpZWxkXG5cdFx0dGhpcy5maWVsZE1lc3NhZ2UudmFsdWUgPSAnJztcblx0XHRcblx0fVxuXG5cdGNsb3NlKCkgeyBcblx0fVxuXG5cbn1cblxuXG4iLCJcblxuLy8gIFxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTb2NpYWxTaGFyZSB7XG5cblx0Y29uc3RydWN0b3IoZWwpIHsgXG5cblx0XHR0aGlzLmVsID0gZWw7XG5cblx0XHR0aGlzLmNvbmZpcm1UaW1lb3V0MSA9IG51bGw7XG5cdFx0dGhpcy5jb25maXJtVGltZW91dDIgPSBudWxsO1xuXG5cdFx0dGhpcy5vcGVuTW9kYWwgPSB0aGlzLm9wZW5Nb2RhbC5iaW5kKHRoaXMpO1xuXHRcdHRoaXMuY29weVRvQ2xpcGJvYXJkQ2xpY2sgPSB0aGlzLmNvcHlUb0NsaXBib2FyZENsaWNrLmJpbmQodGhpcyk7XG5cdFx0dGhpcy5jbGlja1R3aXR0ZXIgPSB0aGlzLmNsaWNrVHdpdHRlci5iaW5kKHRoaXMpO1xuXHRcdHRoaXMuY2xpY2tXaGF0c0FwcCA9IHRoaXMuY2xpY2tXaGF0c0FwcC5iaW5kKHRoaXMpO1xuXG5cdFx0Ly8gIFNoYXJlIHRoaXMgYXJ0d29yayBidXR0b25cblx0XHR2YXIgYnRuID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImJ1dHRvblwiKTtcblx0XHRidG4uY2xhc3NMaXN0LmFkZCgnYnV0dG9uJyk7XG5cdFx0YnRuLmlubmVySFRNTCA9ICc8c3BhbiBjbGFzcz1cImJ1dHRvbi1pY29uLWxlZnQgaWNvbi1zaGFyZVwiPjwvc3Bhbj5TaGFyZSB0aGlzIGFydHdvcmsnO1xuXHRcdGJ0bi5vbmNsaWNrID0gdGhpcy5vcGVuTW9kYWw7XG5cdFx0dGhpcy5lbC5hcHBlbmRDaGlsZChidG4pO1xuXG5cdFx0Ly8gIEJ1dHRvbnMgd2l0aGluIHRoZSBtb2RhbCBcblx0XHR2YXIgbW9kYWwgPSAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21vZGFsLXNvY2lhbC1zaGFyZScpO1xuXHRcdGlmIChtb2RhbCkgeyBcblxuXHRcdFx0Ly8gIENsb3NlIFxuXHRcdFx0dmFyIGJ0bkNsb3NlID0gbW9kYWwucXVlcnlTZWxlY3RvcignLmNsb3NlJyk7XG5cdFx0XHRpZiAoYnRuQ2xvc2UpIHsgXG5cdFx0XHRcdGJ0bkNsb3NlLm9uY2xpY2sgPSB0aGlzLmNsb3NlTW9kYWw7XG5cdFx0XHR9XG5cblx0XHRcdC8vICBDb3B5IHRvIGNsaXBib2FyZFxuXHRcdFx0dmFyIGJ0bkNvcHkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYnV0dG9uLXNvY2lhbC1zaGFyZS1jb3B5Jyk7XG5cdFx0XHQvL2J0bkNvcHkuaW5uZXJIVE1MID0gdGhpcy51cmwoKTtcblx0XHRcdGJ0bkNvcHkuaW5uZXJIVE1MID0gJ0NvcHkgVVJMIHRvIGNsaXBib2FyZCc7XG5cdFx0XHRpZiAoYnRuQ29weSkgeyBcblx0XHRcdFx0YnRuQ29weS5vbmNsaWNrID0gdGhpcy5jb3B5VG9DbGlwYm9hcmRDbGljaztcblx0XHRcdH1cblxuXHRcdFx0Ly8gIFR3aXR0ZXJcblx0XHRcdHZhciBidG5Ud2l0dGVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2J1dHRvbi1zb2NpYWwtc2hhcmUtdHdpdHRlcicpO1xuXHRcdFx0aWYgKGJ0blR3aXR0ZXIpIHsgXG5cdFx0XHRcdGJ0blR3aXR0ZXIub25jbGljayA9IHRoaXMuY2xpY2tUd2l0dGVyO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyAgV2hhdHNBcHBcblx0XHRcdHZhciBidG5XaGF0c0FwcCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdidXR0b24tc29jaWFsLXNoYXJlLXdoYXRzYXBwJyk7XG5cdFx0XHRpZiAoYnRuV2hhdHNBcHApIHsgXG5cdFx0XHRcdGJ0bldoYXRzQXBwLm9uY2xpY2sgPSB0aGlzLmNsaWNrV2hhdHNBcHA7XG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdG9wZW5Nb2RhbChldmVudCkgeyBcblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdHZhciBidG5Db3B5ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2J1dHRvbi1zb2NpYWwtc2hhcmUtY29weScpO1xuXHRcdGlmIChidG5Db3B5KSB7IFxuXHRcdFx0Ly9idG5Db3B5LmlubmVySFRNTCA9IHRoaXMudXJsKCk7XG5cdFx0XHRidG5Db3B5LmlubmVySFRNTCA9ICdDb3B5IFVSTCB0byBjbGlwYm9hcmQnO1xuXHRcdH1cblx0XHR2YXIgbW9kYWwgPSAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21vZGFsLXNvY2lhbC1zaGFyZScpO1xuXHRcdGlmIChtb2RhbCkgeyBcblx0XHRcdG1vZGFsLmNsYXNzTGlzdC5hZGQoJ29wZW4nKTtcblx0XHRcdHdpbmRvdy5nYUV2ZW50KCdTaGFyZSBBcnR3b3JrIE9wZW4nLCAnY2xpY2snLCB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUpO1xuXHRcdH1cdFxuXHR9XG5cblx0Y2xvc2VNb2RhbChldmVudCkge1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IFxuXHRcdHZhciBtb2RhbCA9ICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbW9kYWwtc29jaWFsLXNoYXJlJyk7XG5cdFx0aWYgKG1vZGFsKSB7IFxuXHRcdFx0bW9kYWwuY2xhc3NMaXN0LnJlbW92ZSgnb3BlbicpO1xuXHRcdH1cblx0fVxuXG5cdGNvcHlUb0NsaXBib2FyZENsaWNrKGV2ZW50KSB7IFxuXHRcdGlmIChuYXZpZ2F0b3IuY2xpcGJvYXJkICE9IHVuZGVmaW5lZCkgeyAvL0Nocm9tZVxuXHRcdFx0bmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQodGhpcy51cmwoKSk7XG5cdFx0fSBlbHNlIGlmKHdpbmRvdy5jbGlwYm9hcmREYXRhKSB7IC8vIEludGVybmV0IEV4cGxvcmVyXG5cdFx0XHR3aW5kb3cuY2xpcGJvYXJkRGF0YS5zZXREYXRhKFwiVGV4dFwiLCB0aGlzLnVybCgpKTtcblx0XHR9XG5cdFx0dmFyIGNvbmZpcm0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2hhcmUtY29weS1jb25maXJtJyk7XG5cdFx0aWYgKGNvbmZpcm0pIHsgXG5cdFx0XHRjbGVhclRpbWVvdXQodGhpcy5jb25maXJtVGltZW91dDEpO1xuXHRcdFx0Y2xlYXJUaW1lb3V0KHRoaXMuY29uZmlybVRpbWVvdXQyKTtcblx0XHRcdGNvbmZpcm0uc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG5cdFx0XHRjb25maXJtLnN0eWxlLm9wYWNpdHkgPSAxO1xuXHRcdFx0dGhpcy5jb25maXJtVGltZW91dDEgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsgXG5cdFx0XHRcdGNvbmZpcm0uc3R5bGUub3BhY2l0eSA9IDA7XG5cdFx0XHR9LCAzMDAwKTtcblx0XHRcdHRoaXMuY29uZmlybVRpbWVvdXQyID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7IFxuXHRcdFx0XHRjb25maXJtLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdFx0XHR9LCAzNTAwKTtcblx0XHR9XG5cdFx0d2luZG93LmdhRXZlbnQoJ1NoYXJlIEFydHdvcmsgQ29weSB0byBjbGlwYm9hcmQnLCAnY2xpY2snLCB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUpO1xuXHR9XG5cblx0Y2xpY2tUd2l0dGVyKGV2ZW50KSB7IFxuXHRcdHdpbmRvdy5nYUV2ZW50KCdTaGFyZSBBcnR3b3JrIFR3aXR0ZXInLCAnY2xpY2snLCB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUpO1xuXHRcdHdpbmRvdy5vcGVuKCdodHRwczovL3R3aXR0ZXIuY29tL2ludGVudC90d2VldC8/dGV4dD0nK2VuY29kZVVSSUNvbXBvbmVudCh0aGlzLnRpdGxlKCkpKycmdXJsPScrZW5jb2RlVVJJQ29tcG9uZW50KHRoaXMudXJsKCkpLCAnX2JsYW5rJyk7XG5cdH1cblxuXHRjbGlja1doYXRzQXBwKGV2ZW50KSB7IFxuXHRcdHdpbmRvdy5nYUV2ZW50KCdTaGFyZSBBcnR3b3JrIFdoYXRzQXBwJywgJ2NsaWNrJywgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lKTtcblx0XHR3aW5kb3cub3BlbignaHR0cHM6Ly9hcGkud2hhdHNhcHAuY29tL3NlbmQ/dGV4dD0nK2VuY29kZVVSSUNvbXBvbmVudCh0aGlzLnRpdGxlKCkpKycrJytlbmNvZGVVUklDb21wb25lbnQodGhpcy51cmwoKSksICdfYmxhbmsnKTtcblx0fVxuXG5cdHVybCgpIHsgXG5cdFx0cmV0dXJuIFN0cmluZyh3aW5kb3cubG9jYXRpb24pLnNwbGl0KCcvZXhwbG9yZS8nKS5qb2luKCcvdmlydHVhbC1leHBsb3JlLycpO1xuXHR9XG5cdHRpdGxlKCkgeyBcblx0XHRyZXR1cm4gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCJ0aXRsZVwiKVswXS5pbm5lckhUTUw7XG5cdH1cblxuXHRjbG9zZSgpIHsgXG5cdH1cblxuXG59XG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG4iLCJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRyYW5zaXRpb25XaXBlIHtcblxuXHRjb25zdHJ1Y3RvcigpIHsgXG5cdFx0dGhpcy5VUkwgPSBudWxsO1xuXHRcdHRoaXMuYWN0aXZlID0gZmFsc2U7XG5cdFx0dGhpcy5jb250ZW50TG9hZGVkID0gZmFsc2U7XG5cdFx0dGhpcy5vbkNoYW5nZUNvbnRlbnQgPSBudWxsO1xuXHRcdHRoaXMuc3RhcnRUaW1lID0gbnVsbDtcblx0XHR0aGlzLmR1cmF0aW9uID0gMC42O1xuXHRcdHRoaXMuZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndHJhbnNpdGlvbicpO1xuXHRcdHRoaXMuZHJhd09uID0gdGhpcy5kcmF3T24uYmluZCh0aGlzKTtcblx0XHR0aGlzLmRyYXdPZmYgPSB0aGlzLmRyYXdPZmYuYmluZCh0aGlzKTtcblx0XHR0aGlzLnJlc2l6ZSA9IHRoaXMucmVzaXplLmJpbmQodGhpcyk7XG5cblx0XHQvLyAgUmVzaXplXG5cdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRoaXMucmVzaXplKTtcblx0XHR0aGlzLnJlc2l6ZSgpO1xuXHRcdFxuXHR9XG5cblx0c3RhcnQodXJsLCBvbkNoYW5nZUNvbnRlbnQpIHsgXG5cdFx0aWYgKCF0aGlzLmFjdGl2ZSkgeyBcblx0XHRcdHRoaXMuVVJMID0gdXJsO1xuXHRcdFx0dGhpcy5hY3RpdmUgPSB0cnVlO1xuXHRcdFx0dGhpcy5jb250ZW50TG9hZGVkID0gZmFsc2U7XG5cdFx0XHR0aGlzLm9uQ2hhbmdlQ29udGVudCA9IG9uQ2hhbmdlQ29udGVudDtcblx0XHRcdHRoaXMuc3RhcnRUaW1lID0gdGhpcy5tcygpO1xuXHRcdFx0dGhpcy5kcmF3T24oKTtcblx0XHR9XG5cdH1cblxuXHRyZXNpemUoZXZlbnQpIHsgXG5cdFx0dGhpcy5lbC5zdHlsZS5oZWlnaHQgPSAod2luZG93LmlubmVySGVpZ2h0KSsncHgnO1xuXHR9XG5cblx0bXMoKSB7IFxuXHRcdHJldHVybiBwZXJmb3JtYW5jZS5ub3coKS8xMDAwO1xuXHR9XG5cblx0Ly8gIFRpbWUgc28gZmFyIGFzIGEgcGVyY2VudGFnZVxuXHRwKCkgeyBcblx0XHR2YXIgcCA9ICh0aGlzLm1zKCkgLSB0aGlzLnN0YXJ0VGltZSkgLyAodGhpcy5kdXJhdGlvbiowLjUpO1xuXHRcdGlmIChwIDwgMCkgeyBcblx0XHRcdHAgPSAwO1xuXHRcdH1cblx0XHRpZiAocCA+IDEpIHsgXG5cdFx0XHRwID0gMTtcblx0XHR9XG5cdFx0cmV0dXJuIHA7XG5cdH1cblxuXHRkcmF3T24oKSB7IFxuXG5cdFx0Ly8gIERyYXcgb24gXG5cdFx0dmFyIHcgPSB3aW5kb3cuaW5uZXJXaWR0aDtcblx0XHR0aGlzLmVsLnN0eWxlLmxlZnQgPSAoLXcgKyAodGhpcy5wKCkqdykpKydweCc7XG5cdFx0dGhpcy5lbC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblxuXHRcdC8vICBXYWl0IGZvciB0aGUgZHJhdyBvbiBhbmltYXRpb24gdG8gZmluaXNoIGFuZCB0aGUgY29udGVudCB0byBsb2FkXG5cdFx0aWYgKHRoaXMucCgpIDwgMSB8fCB0aGlzLmNvbnRlbnRMb2FkZWQgPT0gZmFsc2UpIHsgXG5cdFx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUodGhpcy5kcmF3T24pO1xuXHRcdH0gZWxzZSB7IFxuXG5cdFx0XHQvLyAgQ2hhbmdlIHRoZSBwYWdlIGNvbnRlbnRcblx0XHRcdHRoaXMub25DaGFuZ2VDb250ZW50KCk7XG5cblx0XHRcdC8vICBTdGFydCB0aGUgZHJhdyBvZmZcblx0XHRcdHRoaXMuc3RhcnRUaW1lID0gdGhpcy5tcygpO1xuXHRcdFx0cmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMuZHJhd09mZik7XG5cblx0XHR9XG5cdH1cblxuXHRkcmF3T2ZmKCkgeyBcblx0XHRcblx0XHQvLyAgRHJhdyBvZmYgXG5cdFx0dmFyIHcgPSB3aW5kb3cuaW5uZXJXaWR0aDtcblx0XHR0aGlzLmVsLnN0eWxlLmxlZnQgPSAodGhpcy5wKCkqdykrJ3B4JztcblxuXHRcdGlmICh0aGlzLnAoKSA8IDEpIHsgXG5cdFx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUodGhpcy5kcmF3T2ZmKTtcblx0XHR9IGVsc2UgeyBcblx0XHRcdHRoaXMuZWwuc3R5bGUuZGlzcGxheSA9ICdub25lJztcblx0XHRcdHRoaXMuYWN0aXZlID0gZmFsc2U7XG5cdFx0fVxuXG5cdH1cblxufVxuXG5cbiIsImltcG9ydCAnaGFtbWVyanMnO1xuXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFdhbGwge1xuXG5cdGNvbnN0cnVjdG9yKGVsLCBzbHVnKSB7IFxuXHRcdFxuXHRcdHRoaXMubXVsdGlwbHkgPSAwLjU7XG5cblx0XHR0aGlzLmVsID0gZWw7XG5cdFx0dGhpcy5zbHVnID0gc2x1Zztcblx0XHR0aGlzLmVsQ29udHJvbCA9IGVsO1xuXHRcdHRoaXMuZWxJbm5lciA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmlubmVyJylbMF07XG5cdFx0Y29uc29sZS5sb2coc2x1Zyk7XG5cblx0XHRpZiAodGhpcy5zbHVnID09ICdwaG90b2dyYXBocycpIHsgIFxuXHRcdFx0dGhpcy53aWR0aCA9IDEyNzA4ICogdGhpcy5tdWx0aXBseTtcblx0XHRcdHRoaXMuaGVpZ2h0ID0gMzA5MCAqIHRoaXMubXVsdGlwbHk7XG5cdFx0fSBlbHNlIGlmICh0aGlzLnNsdWcgPT0gJ2RvbGxzJykge1xuXHRcdFx0dGhpcy53aWR0aCA9IDkxNzEgKiB0aGlzLm11bHRpcGx5O1xuXHRcdFx0dGhpcy5oZWlnaHQgPSAzMjUwICogdGhpcy5tdWx0aXBseTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy53aWR0aCA9IDM5MTcxICogdGhpcy5tdWx0aXBseTtcblx0XHRcdHRoaXMuaGVpZ2h0ID0gMzI1MCAqIHRoaXMubXVsdGlwbHk7XG5cdFx0fVxuXG5cdFx0dGhpcy50cmFuc2xhdGVYID0gMDtcblx0XHR0aGlzLnRyYW5zbGF0ZVkgPSAwO1xuXG5cdFx0dGhpcy5zY2FsZU1pbiA9ICh3aW5kb3cuaW5uZXJIZWlnaHQtNTYtNTYpIC8gdGhpcy5oZWlnaHQ7XG5cdFx0dGhpcy5zY2FsZU1heCA9IDEuNTtcblx0XHRpZiAodGhpcy5zbHVnID09ICd2YXJjaGl2ZScpIHsgXG5cdFx0XHR0aGlzLnNjYWxlID0gdGhpcy5zY2FsZU1pbiArICh0aGlzLnNjYWxlTWF4IC0gdGhpcy5zY2FsZU1pbikgKiAwLjU7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuc2NhbGUgPSB0aGlzLnNjYWxlTWluO1xuXHRcdH1cblxuXHRcdGNvbnN0IHMgPSB0aGlzLmdldENvb2tpZSgnd2FsbFBvc2l0aW9uLScrdGhpcy5zbHVnKTtcblx0XHRpZiAocykgeyBcblx0XHRcdGNvbnN0IGEgPSBzLnNwbGl0KCcsJyk7XG5cdFx0XHR0aGlzLnNjYWxlID0gTnVtYmVyKGFbMF0pO1xuXHRcdFx0dGhpcy50cmFuc2xhdGVYID0gTnVtYmVyKGFbMV0pO1xuXHRcdFx0dGhpcy50cmFuc2xhdGVZID0gTnVtYmVyKGFbMl0pO1xuXHRcdH1cblxuXHRcdHZhciBzZWxmID0gdGhpcztcblxuXHRcdHRoaXMuaGFtbWVyID0gbmV3IEhhbW1lcih0aGlzLmVsQ29udHJvbCwge1xuXHRcdFx0aW5wdXRDbGFzczogSGFtbWVyLlRvdWNoTW91c2VJbnB1dCxcblx0XHRcdHRyYW5zZm9ybV9hbHdheXNfYmxvY2s6IHRydWUsIFxuXHRcdFx0dG91Y2hBY3Rpb246ICdtYW5pcHVsYXRpb24nXG5cdFx0fSk7XG5cdFx0dGhpcy5oYW1tZXIuZ2V0KCdwaW5jaCcpLnNldCh7IGVuYWJsZTogdHJ1ZSB9KTtcblxuXHRcdC8vICBQYW5cblx0XHR0aGlzLmhhbW1lci5vbigncGFuJywgZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRcdHNlbGYudHJhbnNsYXRlWCArPSBldmVudC52ZWxvY2l0eVggKiAxOC9zZWxmLnNjYWxlO1xuXHRcdFx0c2VsZi50cmFuc2xhdGVZICs9IGV2ZW50LnZlbG9jaXR5WSAqIDE4L3NlbGYuc2NhbGU7XG5cdFx0XHRzZWxmLnVwZGF0ZSgpO1xuXHRcdFx0aWYgKGV2ZW50LmlzRmluYWwpIHtcblx0XHRcdFx0d2luZG93LmdhRXZlbnQoJ1ZpcnR1YWwgRXhwbG9yZScsICdwYW4nLCBzZWxmLnNsdWcpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHRcdFxuXHRcdC8vICBQaW5jaFxuXHRcdHRoaXMuaGFtbWVyLm9uKFwicGluY2hpblwiLCBmdW5jdGlvbihldmVudCkge1xuXHRcdFx0c2VsZi5zY2FsZUJ5KGV2ZW50LmNlbnRlci54LCBldmVudC5jZW50ZXIueSwgLTAuMDgpO1xuXHRcdH0pO1xuXHRcdHRoaXMuaGFtbWVyLm9uKFwicGluY2hvdXRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRcdHNlbGYuc2NhbGVCeShldmVudC5jZW50ZXIueCwgZXZlbnQuY2VudGVyLnksIDAuMDQpO1xuXHRcdH0pO1xuXHRcdHRoaXMuaGFtbWVyLm9uKFwicGluY2hlbmRcIiwgZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRcdHdpbmRvdy5nYUV2ZW50KCdWaXJ0dWFsIEV4cGxvcmUnLCAncGluY2gtem9vbScsIHNlbGYuc2x1Zyk7XG5cdFx0fSk7XG5cblx0XHQvLyAgTW91c2V3aGVlbFxuXHRcdHRoaXMuZWxDb250cm9sLmFkZEV2ZW50TGlzdGVuZXIoJ3doZWVsJywgZnVuY3Rpb24gKGV2ZW50KSB7IFxuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdHNlbGYuc2NhbGVCeShldmVudC5wYWdlWCwgZXZlbnQucGFnZVksIGV2ZW50LndoZWVsRGVsdGFZLzUwMCk7XG5cdFx0XHR3aW5kb3cuZ2FFdmVudCgnVmlydHVhbCBFeHBsb3JlJywgJ21vdXNlLXdoZWVsJywgc2VsZi5zbHVnKTtcblx0XHR9KTtcblxuXHRcdC8vICBCdXR0b24gSW5zdHJ1Y3Rpb25zXG5cdFx0Y29uc3QgYnV0dG9uSW5zdHJ1Y3Rpb25zID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuYnV0dG9uLWluc3RydWN0aW9ucycpWzBdO1xuXHRcdGlmIChidXR0b25JbnN0cnVjdGlvbnMpIHsgXG5cdFx0XHRidXR0b25JbnN0cnVjdGlvbnMuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbiAoZXZlbnQpIHsgXG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdGNvbnN0IG1vZGFsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3dhbGwtaW5zdHJ1Y3Rpb25zJyk7XG5cdFx0XHRcdGlmIChtb2RhbCkgeyBcblx0XHRcdFx0XHRtb2RhbC5jbGFzc0xpc3QuYWRkKCdvcGVuJyk7XG5cdFx0XHRcdFx0Ly9tb2RhbC5zdHlsZS5oZWlnaHQgPSAod2luZG93LmlubmVySGVpZ2h0LTU2LTU2KSsncHgnO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHdpbmRvdy5nYUV2ZW50KCdWaXJ0dWFsIEV4cGxvcmUnLCAnY2xpY2snLCAnSW5zdHJ1Y3Rpb25zICcrc2VsZi5zbHVnKTtcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdC8vICBCdXR0b24gWm9vbSBJblxuXHRcdGNvbnN0IGJ1dHRvblpvb21JbiA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLmJ1dHRvbi16b29tLWluJylbMF07XG5cdFx0aWYgKGJ1dHRvblpvb21JbikgeyBcblx0XHRcdGJ1dHRvblpvb21Jbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uIChldmVudCkgeyBcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0c2VsZi5zY2FsZSArPSAwLjI7IFxuXHRcdFx0XHRzZWxmLnVwZGF0ZSgpO1xuXHRcdFx0XHR3aW5kb3cuZ2FFdmVudCgnVmlydHVhbCBFeHBsb3JlJywgJ3pvb20taW4nLCBzZWxmLnNsdWcpO1xuXHRcdFx0fSk7XG5cdFx0fVxuXG5cdFx0Ly8gIEJ1dHRvbiBab29tIE91dFxuXHRcdGNvbnN0IGJ1dHRvblpvb21PdXQgPSB0aGlzLmVsLnF1ZXJ5U2VsZWN0b3JBbGwoJy5idXR0b24tem9vbS1vdXQnKVswXTtcblx0XHRpZiAoYnV0dG9uWm9vbU91dCkgeyBcblx0XHRcdGJ1dHRvblpvb21PdXQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbiAoZXZlbnQpIHsgXG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHNlbGYuc2NhbGUgLT0gMC4yOyBcblx0XHRcdFx0c2VsZi51cGRhdGUoKTtcblx0XHRcdFx0d2luZG93LmdhRXZlbnQoJ1ZpcnR1YWwgRXhwbG9yZScsICd6b29tLW91dCcsIHNlbGYuc2x1Zyk7XG5cdFx0XHR9KTtcblx0XHR9XG5cblx0XHQvLyAgXG5cdFx0dGhpcy5yZXNpemUgPSB0aGlzLnJlc2l6ZS5iaW5kKHRoaXMpO1xuXHRcdHRoaXMuc2NhbGVCeSA9IHRoaXMuc2NhbGVCeS5iaW5kKHRoaXMpO1xuXHRcdHRoaXMudXBkYXRlID0gdGhpcy51cGRhdGUuYmluZCh0aGlzKTtcblx0XHR0aGlzLmNsb3NlID0gdGhpcy5jbG9zZS5iaW5kKHRoaXMpO1xuXG5cdFx0Ly8gIFJlc2l6ZVxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCB0aGlzLnJlc2l6ZSk7XG5cdFx0dGhpcy5yZXNpemUoKTtcblxuXHRcdC8vICBPbmx5IG9wZW4gdGhlIHdhbGwgaW5zdHJ1Y3Rpb25zIG9uY2UgYSBkYXlcblx0XHRpZiAodGhpcy5nZXRDb29raWUoJ3dhbGxJbnN0cnVjdGlvbnNDbG9zZWQnKSAhPSAndHJ1ZScpIHsgXG5cdFx0XHRjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3dhbGwtaW5zdHJ1Y3Rpb25zJyk7XG5cdFx0XHRpZiAoZWxlbWVudCkgeyBcblx0XHRcdFx0ZWxlbWVudC5jbGFzc0xpc3QuYWRkKCdvcGVuJyk7XG5cdFx0XHRcdHRoaXMuc2V0Q29va2llKCd3YWxsSW5zdHJ1Y3Rpb25zQ2xvc2VkJywgJ3RydWUnLCAxKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLnVwZGF0ZSgpO1xuXG5cdFx0dGhpcy5lbC5zdHlsZS5vcGFjaXR5ID0gMTtcblxuXHR9XG5cblx0cmVzaXplKGV2ZW50KSB7IFxuXHRcdHRoaXMuZWwuc3R5bGUuaGVpZ2h0ID0gKHdpbmRvdy5pbm5lckhlaWdodC01Ni01NikrJ3B4Jztcblx0XHR0aGlzLnNjYWxlTWluID0gKHdpbmRvdy5pbm5lckhlaWdodC01Ni01NikgLyB0aGlzLmhlaWdodDtcblx0XHR0aGlzLnVwZGF0ZSgpO1xuXHR9XG5cblx0c2NhbGVCeShteCwgbXksIG4pIHsgXG5cblx0XHR2YXIgYXggPSAwIC0gdGhpcy50cmFuc2xhdGVYICsgKG14IC8gdGhpcy5zY2FsZSk7XG5cdFx0dmFyIGF5ID0gMCAtIHRoaXMudHJhbnNsYXRlWSArIChteSAvIHRoaXMuc2NhbGUpO1xuXG5cdFx0dGhpcy5zY2FsZSArPSBuO1xuXG5cdFx0aWYgKHRoaXMuc2NhbGUgPCB0aGlzLnNjYWxlTWluKSB7IFxuXHRcdFx0dGhpcy5zY2FsZSA9IHRoaXMuc2NhbGVNaW47XG5cdFx0fVxuXHRcdGlmICh0aGlzLnNjYWxlID4gdGhpcy5zY2FsZU1heCkgeyBcblx0XHRcdHRoaXMuc2NhbGUgPSB0aGlzLnNjYWxlTWF4O1xuXHRcdH1cblxuXHRcdHZhciBieCA9IDAgLSB0aGlzLnRyYW5zbGF0ZVggKyAobXggLyB0aGlzLnNjYWxlKTtcblx0XHR2YXIgYnkgPSAwIC0gdGhpcy50cmFuc2xhdGVZICsgKG15IC8gdGhpcy5zY2FsZSk7XG5cblx0XHR0aGlzLnRyYW5zbGF0ZVggKz0gKGJ4IC0gYXgpO1xuXHRcdHRoaXMudHJhbnNsYXRlWSArPSAoYnkgLSBheSk7XG5cblx0XHR0aGlzLnVwZGF0ZSgpO1xuXG5cblx0fVxuXG5cdHVwZGF0ZSgpIHtcblxuXHRcdGlmICh0aGlzLnNjYWxlIDwgdGhpcy5zY2FsZU1pbikgeyBcblx0XHRcdHRoaXMuc2NhbGUgPSB0aGlzLnNjYWxlTWluO1xuXHRcdH1cblx0XHRpZiAodGhpcy5zY2FsZSA+IHRoaXMuc2NhbGVNYXgpIHsgXG5cdFx0XHR0aGlzLnNjYWxlID0gdGhpcy5zY2FsZU1heDtcblx0XHR9XG5cblx0XHRpZiAoTnVtYmVyLmlzTmFOKHRoaXMudHJhbnNsYXRlWCkpIHsgXG5cdFx0XHR0aGlzLnRyYW5zbGF0ZVggPSAwO1xuXHRcdH1cblx0XHRpZiAoTnVtYmVyLmlzTmFOKHRoaXMudHJhbnNsYXRlWSkpIHsgXG5cdFx0XHR0aGlzLnRyYW5zbGF0ZVkgPSAwO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLnRyYW5zbGF0ZVggPCAwIC0gdGhpcy53aWR0aCArIHdpbmRvdy5pbm5lcldpZHRoL3RoaXMuc2NhbGUpIHsgXG5cdFx0XHR0aGlzLnRyYW5zbGF0ZVggPSAwIC0gdGhpcy53aWR0aCArIHdpbmRvdy5pbm5lcldpZHRoL3RoaXMuc2NhbGU7XG5cdFx0fSBcblx0XHRpZiAodGhpcy50cmFuc2xhdGVYID4gMCkgeyBcblx0XHRcdHRoaXMudHJhbnNsYXRlWCA9IDA7XG5cdFx0fVxuXHRcdGlmICh0aGlzLnRyYW5zbGF0ZVkgPCAwIC0gdGhpcy5oZWlnaHQgKyAod2luZG93LmlubmVySGVpZ2h0LTU2LTU2KS90aGlzLnNjYWxlKSB7IFxuXHRcdFx0dGhpcy50cmFuc2xhdGVZID0gMCAtIHRoaXMuaGVpZ2h0ICsgKHdpbmRvdy5pbm5lckhlaWdodC01Ni01NikvdGhpcy5zY2FsZTtcblx0XHR9IFxuXHRcdGlmICh0aGlzLnRyYW5zbGF0ZVkgPiAwKSB7IFxuXHRcdFx0dGhpcy50cmFuc2xhdGVZID0gMDtcblx0XHR9XG5cblx0XHR0aGlzLmVsSW5uZXIuc3R5bGUudHJhbnNmb3JtID0gJ3NjYWxlKCcrdGhpcy5zY2FsZSsnKSB0cmFuc2xhdGUoJyt0aGlzLnRyYW5zbGF0ZVgrJ3B4LCAnK3RoaXMudHJhbnNsYXRlWSsncHgpJztcblxuXHRcdHRoaXMuc2V0Q29va2llKCd3YWxsUG9zaXRpb24tJyt0aGlzLnNsdWcsIHRoaXMuc2NhbGUrJywnK3RoaXMudHJhbnNsYXRlWCsnLCcrdGhpcy50cmFuc2xhdGVZLCA3KTtcblx0fVxuXG5cdGNsb3NlKCkgeyBcblx0XHR0aGlzLmhhbW1lci5kZXN0cm95KCk7XG5cdH1cblxuXG5cblx0Z2V0Q29va2llKG5hbWUpIHtcblx0XHR2YXIgdiA9IGRvY3VtZW50LmNvb2tpZS5tYXRjaCgnKF58OykgPycgKyBuYW1lICsgJz0oW147XSopKDt8JCknKTtcblx0XHRyZXR1cm4gdiA/IHZbMl0gOiBudWxsO1xuXHR9XG5cdHNldENvb2tpZShuYW1lLCB2YWx1ZSwgZGF5cykge1xuXHRcdHZhciBkID0gbmV3IERhdGU7XG5cdFx0ZC5zZXRUaW1lKGQuZ2V0VGltZSgpICsgMjQqNjAqNjAqMTAwMCpkYXlzKTtcblx0XHRkb2N1bWVudC5jb29raWUgPSBuYW1lICsgXCI9XCIgKyB2YWx1ZSArIFwiO3BhdGg9LztleHBpcmVzPVwiICsgZC50b0dNVFN0cmluZygpO1xuXHR9XG5cblxufVxuXG5cbiIsIi8vIFRoZSBtb2R1bGUgY2FjaGVcbnZhciBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX18gPSB7fTtcblxuLy8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbmZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG5cdHZhciBjYWNoZWRNb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdO1xuXHRpZiAoY2FjaGVkTW9kdWxlICE9PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gY2FjaGVkTW9kdWxlLmV4cG9ydHM7XG5cdH1cblx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcblx0dmFyIG1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF0gPSB7XG5cdFx0Ly8gbm8gbW9kdWxlLmlkIG5lZWRlZFxuXHRcdC8vIG5vIG1vZHVsZS5sb2FkZWQgbmVlZGVkXG5cdFx0ZXhwb3J0czoge31cblx0fTtcblxuXHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cblx0X193ZWJwYWNrX21vZHVsZXNfX1ttb2R1bGVJZF0obW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cblx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcblx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xufVxuXG4iLCIvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuX193ZWJwYWNrX3JlcXVpcmVfXy5uID0gKG1vZHVsZSkgPT4ge1xuXHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cblx0XHQoKSA9PiAobW9kdWxlWydkZWZhdWx0J10pIDpcblx0XHQoKSA9PiAobW9kdWxlKTtcblx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgeyBhOiBnZXR0ZXIgfSk7XG5cdHJldHVybiBnZXR0ZXI7XG59OyIsIi8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb25zIGZvciBoYXJtb255IGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uZCA9IChleHBvcnRzLCBkZWZpbml0aW9uKSA9PiB7XG5cdGZvcih2YXIga2V5IGluIGRlZmluaXRpb24pIHtcblx0XHRpZihfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZGVmaW5pdGlvbiwga2V5KSAmJiAhX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIGtleSkpIHtcblx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBrZXksIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBkZWZpbml0aW9uW2tleV0gfSk7XG5cdFx0fVxuXHR9XG59OyIsIl9fd2VicGFja19yZXF1aXJlX18ubyA9IChvYmosIHByb3ApID0+IChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKSkiLCJcbmltcG9ydCBDb250ZW50IGZyb20gJy4vanMvQ29udGVudC5qcyc7XG5cblxuXG5cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgZnVuY3Rpb24oZXZlbnQpIHtcblxuXHQvLyAgVGhlIEFwcFxuXHRjb250ZW50ID0gbmV3IENvbnRlbnQoKTtcblxuXG59KTtcblxuXG5cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuXG5cblxuIiwiLy8gZXh0cmFjdGVkIGJ5IG1pbmktY3NzLWV4dHJhY3QtcGx1Z2luXG5leHBvcnQge307Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9