ngx-pluto
Version:
858 lines • 84.7 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { ElementRef } from '@angular/core';
import { Subject } from 'rxjs';
import { moveItemInArray } from './drag-utils';
/**
* Counter used to generate unique ids for drop refs.
* @type {?}
*/
let _uniqueIdCounter = 0;
/**
* Proximity, as a ratio to width/height, at which a
* dragged item will affect the drop container.
* @type {?}
*/
const DROP_PROXIMITY_THRESHOLD = 0.05;
/**
* @ignore
* Entry in the position cache for draggable items.
* \@docs-private
* @record
*/
function CachedItemPosition() { }
if (false) {
/**
* Instance of the drag item.
* @type {?}
*/
CachedItemPosition.prototype.drag;
/**
* Dimensions of the item.
* @type {?}
*/
CachedItemPosition.prototype.clientRect;
/**
* Amount by which the item has been moved since dragging started.
* @type {?}
*/
CachedItemPosition.prototype.offset;
}
/**
* @ignore
* Internal compile-time-only representation of a `DropListRef`.
* Used to avoid circular import issues between the `DropListRef` and the `DragRef`.
* \@docs-private
* @record
*/
export function DropListRefInternal() { }
/**
* @ignore
* Reference to a drop list. Used to manipulate or dispose of the container.
* \@docs-private
* @template T
*/
export class DropListRef {
/**
* @param {?} element
* @param {?} _dragDropRegistry
* @param {?} _document
*/
constructor(element, _dragDropRegistry, _document) {
this._dragDropRegistry = _dragDropRegistry;
/**
* Unique ID for the drop list.
* @deprecated No longer being used. To be removed.
* \@breaking-change 8.0.0
*/
this.id = `cdk-drop-list-ref-${_uniqueIdCounter++}`;
/**
* Whether starting a dragging sequence from this container is disabled.
*/
this.disabled = false;
/**
* Function that is used to determine whether an item
* is allowed to be moved into a drop container.
*/
this.enterPredicate = (/**
* @return {?}
*/
() => true);
/**
* Emits right before dragging has started.
*/
this.beforeStarted = new Subject();
/**
* Emits when the user has moved a new drag item into this container.
*/
this.entered = new Subject();
/**
* Emits when the user removes an item from the container
* by dragging it into another container.
*/
this.exited = new Subject();
/**
* Emits when the user drops an item inside the container.
*/
this.dropped = new Subject();
/**
* Emits as the user is swapping items while actively dragging.
*/
this.sorted = new Subject();
/**
* Whether an item in the list is being dragged.
*/
this._isDragging = false;
/**
* Cache of the dimensions of all the items inside the container.
*/
this._itemPositions = [];
/**
* Keeps track of the item that was last swapped with the dragged item, as
* well as what direction the pointer was moving in when the swap occured.
*/
this._previousSwap = { drag: (/** @type {?} */ (null)), delta: 0 };
/**
* Drop lists that are connected to the current one.
*/
this._siblings = [];
/**
* Direction in which the list is oriented.
*/
this._orientation = 'vertical';
/**
* Connected siblings that currently have a dragged item.
*/
this._activeSiblings = new Set();
/**
* Layout direction of the drop list.
*/
this._direction = 'ltr';
_dragDropRegistry.registerDropContainer(this);
this._document = _document;
this.element = element instanceof ElementRef ? element.nativeElement : element;
}
/**
* Removes the drop list functionality from the DOM element.
* @return {?}
*/
dispose() {
this.beforeStarted.complete();
this.entered.complete();
this.exited.complete();
this.dropped.complete();
this.sorted.complete();
this._activeSiblings.clear();
this._dragDropRegistry.removeDropContainer(this);
}
/**
* Whether an item from this list is currently being dragged.
* @return {?}
*/
isDragging() {
return this._isDragging;
}
/**
* Starts dragging an item.
* @return {?}
*/
start() {
this.beforeStarted.next();
this._isDragging = true;
this._activeDraggables = this._draggables.slice();
this._cacheOwnPosition();
this._cacheItemPositions();
this._siblings.forEach((/**
* @param {?} sibling
* @return {?}
*/
sibling => sibling._startReceiving(this)));
}
/**
* Emits an event to indicate that the user moved an item into the container.
* @param {?} item Item that was moved into the container.
* @param {?} pointerX Position of the item along the X axis.
* @param {?} pointerY Position of the item along the Y axis.
* @return {?}
*/
enter(item, pointerX, pointerY) {
this.entered.next({ item, container: this });
this.start();
// We use the coordinates of where the item entered the drop
// zone to figure out at which index it should be inserted.
/** @type {?} */
const newIndex = this._getItemIndexFromPointerPosition(item, pointerX, pointerY);
/** @type {?} */
const currentIndex = this._activeDraggables.indexOf(item);
/** @type {?} */
const newPositionReference = this._activeDraggables[newIndex];
/** @type {?} */
const placeholder = item.getPlaceholderElement();
// Since the item may be in the `activeDraggables` already (e.g. if the user dragged it
// into another container and back again), we have to ensure that it isn't duplicated.
if (currentIndex > -1) {
this._activeDraggables.splice(currentIndex, 1);
}
// Don't use items that are being dragged as a reference, because
// their element has been moved down to the bottom of the body.
if (newPositionReference && !this._dragDropRegistry.isDragging(newPositionReference)) {
/** @type {?} */
const element = newPositionReference.getRootElement();
(/** @type {?} */ (element.parentElement)).insertBefore(placeholder, element);
this._activeDraggables.splice(newIndex, 0, item);
}
else {
this.element.appendChild(placeholder);
this._activeDraggables.push(item);
}
// The transform needs to be cleared so it doesn't throw off the measurements.
placeholder.style.transform = '';
// Note that the positions were already cached when we called `start` above,
// but we need to refresh them since the amount of items has changed.
this._cacheItemPositions();
}
/**
* Removes an item from the container after it was dragged into another container by the user.
* @param {?} item Item that was dragged out.
* @return {?}
*/
exit(item) {
this._reset();
this.exited.next({ item, container: this });
}
/**
* Drops an item into this container.
* @param {?} item Item being dropped into the container.
* @param {?} currentIndex Index at which the item should be inserted.
* @param {?} previousContainer Container from which the item got dragged in.
* @param {?} isPointerOverContainer Whether the user's pointer was over the
* container when the item was dropped.
* @return {?}
*/
drop(item, currentIndex, previousContainer, isPointerOverContainer) {
this._reset();
this.dropped.next({
item,
currentIndex,
previousIndex: previousContainer.getItemIndex(item),
container: this,
previousContainer,
isPointerOverContainer
});
}
/**
* Sets the draggable items that are a part of this list.
* @template THIS
* @this {THIS}
* @param {?} items Items that are a part of this list.
* @return {THIS}
*/
withItems(items) {
(/** @type {?} */ (this))._draggables = items;
items.forEach((/**
* @param {?} item
* @return {?}
*/
item => item._withDropContainer((/** @type {?} */ (this)))));
return (/** @type {?} */ (this));
}
/**
* Sets the layout direction of the drop list.
* @template THIS
* @this {THIS}
* @param {?} direction
* @return {THIS}
*/
withDirection(direction) {
(/** @type {?} */ (this))._direction = direction;
return (/** @type {?} */ (this));
}
/**
* Sets the containers that are connected to this one. When two or more containers are
* connected, the user will be allowed to transfer items between them.
* @template THIS
* @this {THIS}
* @param {?} connectedTo Other containers that the current containers should be connected to.
* @return {THIS}
*/
connectedTo(connectedTo) {
(/** @type {?} */ (this))._siblings = connectedTo.slice();
return (/** @type {?} */ (this));
}
/**
* Sets the orientation of the container.
* @template THIS
* @this {THIS}
* @param {?} orientation New orientation for the container.
* @return {THIS}
*/
withOrientation(orientation) {
(/** @type {?} */ (this))._orientation = orientation;
return (/** @type {?} */ (this));
}
/**
* Figures out the index of an item in the container.
* @param {?} item Item whose index should be determined.
* @return {?}
*/
getItemIndex(item) {
if (!this._isDragging) {
return this._draggables.indexOf(item);
}
// Items are sorted always by top/left in the cache, however they flow differently in RTL.
// The rest of the logic still stands no matter what orientation we're in, however
// we need to invert the array when determining the index.
/** @type {?} */
const items = this._orientation === 'horizontal' && this._direction === 'rtl' ?
this._itemPositions.slice().reverse() : this._itemPositions;
return findIndex(items, (/**
* @param {?} currentItem
* @return {?}
*/
currentItem => currentItem.drag === item));
}
/**
* Whether the list is able to receive the item that
* is currently being dragged inside a connected drop list.
* @return {?}
*/
isReceiving() {
return this._activeSiblings.size > 0;
}
/**
* Sorts an item inside the container based on its position.
* @param {?} item Item to be sorted.
* @param {?} pointerX Position of the item along the X axis.
* @param {?} pointerY Position of the item along the Y axis.
* @param {?} pointerDelta Direction in which the pointer is moving along each axis.
* @return {?}
*/
_sortItem(item, pointerX, pointerY, pointerDelta) {
// Don't sort the item if it's out of range.
if (!this._isPointerNearDropContainer(pointerX, pointerY)) {
return;
}
/** @type {?} */
const siblings = this._itemPositions;
/** @type {?} */
const newIndex = this._getItemIndexFromPointerPosition(item, pointerX, pointerY, pointerDelta);
if (newIndex === -1 && siblings.length > 0) {
return;
}
/** @type {?} */
const isHorizontal = this._orientation === 'horizontal';
/** @type {?} */
const currentIndex = findIndex(siblings, (/**
* @param {?} currentItem
* @return {?}
*/
currentItem => currentItem.drag === item));
/** @type {?} */
const siblingAtNewPosition = siblings[newIndex];
/** @type {?} */
const currentPosition = siblings[currentIndex].clientRect;
/** @type {?} */
const newPosition = siblingAtNewPosition.clientRect;
/** @type {?} */
const delta = currentIndex > newIndex ? 1 : -1;
this._previousSwap.drag = siblingAtNewPosition.drag;
this._previousSwap.delta = isHorizontal ? pointerDelta.x : pointerDelta.y;
// How many pixels the item's placeholder should be offset.
/** @type {?} */
const itemOffset = this._getItemOffsetPx(currentPosition, newPosition, delta);
// How many pixels all the other items should be offset.
/** @type {?} */
const siblingOffset = this._getSiblingOffsetPx(currentIndex, siblings, delta);
// Save the previous order of the items before moving the item to its new index.
// We use this to check whether an item has been moved as a result of the sorting.
/** @type {?} */
const oldOrder = siblings.slice();
// Shuffle the array in place.
moveItemInArray(siblings, currentIndex, newIndex);
this.sorted.next({
previousIndex: currentIndex,
currentIndex: newIndex,
container: this,
item
});
siblings.forEach((/**
* @param {?} sibling
* @param {?} index
* @return {?}
*/
(sibling, index) => {
// Don't do anything if the position hasn't changed.
if (oldOrder[index] === sibling) {
return;
}
/** @type {?} */
const isDraggedItem = sibling.drag === item;
/** @type {?} */
const offset = isDraggedItem ? itemOffset : siblingOffset;
/** @type {?} */
const elementToOffset = isDraggedItem ? item.getPlaceholderElement() :
sibling.drag.getRootElement();
// Update the offset to reflect the new position.
sibling.offset += offset;
// Since we're moving the items with a `transform`, we need to adjust their cached
// client rects to reflect their new position, as well as swap their positions in the cache.
// Note that we shouldn't use `getBoundingClientRect` here to update the cache, because the
// elements may be mid-animation which will give us a wrong result.
if (isHorizontal) {
// Round the transforms since some browsers will
// blur the elements, for sub-pixel transforms.
elementToOffset.style.transform = `translate3d(${Math.round(sibling.offset)}px, 0, 0)`;
adjustClientRect(sibling.clientRect, 0, offset);
}
else {
elementToOffset.style.transform = `translate3d(0, ${Math.round(sibling.offset)}px, 0)`;
adjustClientRect(sibling.clientRect, offset, 0);
}
}));
}
/**
* Caches the position of the drop list.
* @private
* @return {?}
*/
_cacheOwnPosition() {
this._clientRect = this.element.getBoundingClientRect();
}
/**
* Refreshes the position cache of the items and sibling containers.
* @private
* @return {?}
*/
_cacheItemPositions() {
/** @type {?} */
const isHorizontal = this._orientation === 'horizontal';
this._itemPositions = this._activeDraggables.map((/**
* @param {?} drag
* @return {?}
*/
drag => {
/** @type {?} */
const elementToMeasure = this._dragDropRegistry.isDragging(drag) ?
// If the element is being dragged, we have to measure the
// placeholder, because the element is hidden.
drag.getPlaceholderElement() :
drag.getRootElement();
/** @type {?} */
const clientRect = elementToMeasure.getBoundingClientRect();
return {
drag,
offset: 0,
// We need to clone the `clientRect` here, because all the values on it are readonly
// and we need to be able to update them. Also we can't use a spread here, because
// the values on a `ClientRect` aren't own properties. See:
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#Notes
clientRect: {
top: clientRect.top,
right: clientRect.right,
bottom: clientRect.bottom,
left: clientRect.left,
width: clientRect.width,
height: clientRect.height
}
};
})).sort((/**
* @param {?} a
* @param {?} b
* @return {?}
*/
(a, b) => {
return isHorizontal ? a.clientRect.left - b.clientRect.left :
a.clientRect.top - b.clientRect.top;
}));
}
/**
* Resets the container to its initial state.
* @private
* @return {?}
*/
_reset() {
this._isDragging = false;
// TODO(crisbeto): may have to wait for the animations to finish.
this._activeDraggables.forEach((/**
* @param {?} item
* @return {?}
*/
item => item.getRootElement().style.transform = ''));
this._siblings.forEach((/**
* @param {?} sibling
* @return {?}
*/
sibling => sibling._stopReceiving(this)));
this._activeDraggables = [];
this._itemPositions = [];
this._previousSwap.drag = null;
this._previousSwap.delta = 0;
}
/**
* Gets the offset in pixels by which the items that aren't being dragged should be moved.
* @private
* @param {?} currentIndex Index of the item currently being dragged.
* @param {?} siblings All of the items in the list.
* @param {?} delta Direction in which the user is moving.
* @return {?}
*/
_getSiblingOffsetPx(currentIndex, siblings, delta) {
/** @type {?} */
const isHorizontal = this._orientation === 'horizontal';
/** @type {?} */
const currentPosition = siblings[currentIndex].clientRect;
/** @type {?} */
const immediateSibling = siblings[currentIndex + delta * -1];
/** @type {?} */
let siblingOffset = currentPosition[isHorizontal ? 'width' : 'height'] * delta;
if (immediateSibling) {
/** @type {?} */
const start = isHorizontal ? 'left' : 'top';
/** @type {?} */
const end = isHorizontal ? 'right' : 'bottom';
// Get the spacing between the start of the current item and the end of the one immediately
// after it in the direction in which the user is dragging, or vice versa. We add it to the
// offset in order to push the element to where it will be when it's inline and is influenced
// by the `margin` of its siblings.
if (delta === -1) {
siblingOffset -= immediateSibling.clientRect[start] - currentPosition[end];
}
else {
siblingOffset += currentPosition[start] - immediateSibling.clientRect[end];
}
}
return siblingOffset;
}
/**
* Checks whether the pointer coordinates are close to the drop container.
* @private
* @param {?} pointerX Coordinates along the X axis.
* @param {?} pointerY Coordinates along the Y axis.
* @return {?}
*/
_isPointerNearDropContainer(pointerX, pointerY) {
const { top, right, bottom, left, width, height } = this._clientRect;
/** @type {?} */
const xThreshold = width * DROP_PROXIMITY_THRESHOLD;
/** @type {?} */
const yThreshold = height * DROP_PROXIMITY_THRESHOLD;
return pointerY > top - yThreshold && pointerY < bottom + yThreshold &&
pointerX > left - xThreshold && pointerX < right + xThreshold;
}
/**
* Gets the offset in pixels by which the item that is being dragged should be moved.
* @private
* @param {?} currentPosition Current position of the item.
* @param {?} newPosition Position of the item where the current item should be moved.
* @param {?} delta Direction in which the user is moving.
* @return {?}
*/
_getItemOffsetPx(currentPosition, newPosition, delta) {
/** @type {?} */
const isHorizontal = this._orientation === 'horizontal';
/** @type {?} */
let itemOffset = isHorizontal ? newPosition.left - currentPosition.left :
newPosition.top - currentPosition.top;
// Account for differences in the item width/height.
if (delta === -1) {
itemOffset += isHorizontal ? newPosition.width - currentPosition.width :
newPosition.height - currentPosition.height;
}
return itemOffset;
}
/**
* Gets the index of an item in the drop container, based on the position of the user's pointer.
* @private
* @param {?} item Item that is being sorted.
* @param {?} pointerX Position of the user's pointer along the X axis.
* @param {?} pointerY Position of the user's pointer along the Y axis.
* @param {?=} delta Direction in which the user is moving their pointer.
* @return {?}
*/
_getItemIndexFromPointerPosition(item, pointerX, pointerY, delta) {
/** @type {?} */
const isHorizontal = this._orientation === 'horizontal';
return findIndex(this._itemPositions, (/**
* @param {?} __0
* @param {?} _
* @param {?} array
* @return {?}
*/
({ drag, clientRect }, _, array) => {
if (drag === item) {
// If there's only one item left in the container, it must be
// the dragged item itself so we use it as a reference.
return array.length < 2;
}
if (delta) {
/** @type {?} */
const direction = isHorizontal ? delta.x : delta.y;
// If the user is still hovering over the same item as last time, and they didn't change
// the direction in which they're dragging, we don't consider it a direction swap.
if (drag === this._previousSwap.drag && direction === this._previousSwap.delta) {
return false;
}
}
return isHorizontal ?
// Round these down since most browsers report client rects with
// sub-pixel precision, whereas the pointer coordinates are rounded to pixels.
pointerX >= Math.floor(clientRect.left) && pointerX <= Math.floor(clientRect.right) :
pointerY >= Math.floor(clientRect.top) && pointerY <= Math.floor(clientRect.bottom);
}));
}
/**
* Checks whether the user's pointer is positioned over the container.
* @param {?} x Pointer position along the X axis.
* @param {?} y Pointer position along the Y axis.
* @return {?}
*/
_isOverContainer(x, y) {
return isInsideClientRect(this._clientRect, x, y);
}
/**
* Figures out whether an item should be moved into a sibling
* drop container, based on its current position.
* @param {?} item Drag item that is being moved.
* @param {?} x Position of the item along the X axis.
* @param {?} y Position of the item along the Y axis.
* @return {?}
*/
_getSiblingContainerFromPosition(item, x, y) {
return this._siblings.find((/**
* @param {?} sibling
* @return {?}
*/
sibling => sibling._canReceive(item, x, y)));
}
/**
* Checks whether the drop list can receive the passed-in item.
* @param {?} item Item that is being dragged into the list.
* @param {?} x Position of the item along the X axis.
* @param {?} y Position of the item along the Y axis.
* @return {?}
*/
_canReceive(item, x, y) {
if (!this.enterPredicate(item, this) || !isInsideClientRect(this._clientRect, x, y)) {
return false;
}
/** @type {?} */
const elementFromPoint = this._document.elementFromPoint(x, y);
// If there's no element at the pointer position, then
// the client rect is probably scrolled out of the view.
if (!elementFromPoint) {
return false;
}
// The `ClientRect`, that we're using to find the container over which the user is
// hovering, doesn't give us any information on whether the element has been scrolled
// out of the view or whether it's overlapping with other containers. This means that
// we could end up transferring the item into a container that's invisible or is positioned
// below another one. We use the result from `elementFromPoint` to get the top-most element
// at the pointer position and to find whether it's one of the intersecting drop containers.
return elementFromPoint === this.element || this.element.contains(elementFromPoint);
}
/**
* Called by one of the connected drop lists when a dragging sequence has started.
* @param {?} sibling Sibling in which dragging has started.
* @return {?}
*/
_startReceiving(sibling) {
/** @type {?} */
const activeSiblings = this._activeSiblings;
if (!activeSiblings.has(sibling)) {
activeSiblings.add(sibling);
this._cacheOwnPosition();
}
}
/**
* Called by a connected drop list when dragging has stopped.
* @param {?} sibling Sibling whose dragging has stopped.
* @return {?}
*/
_stopReceiving(sibling) {
this._activeSiblings.delete(sibling);
}
}
if (false) {
/**
* @type {?}
* @private
*/
DropListRef.prototype._document;
/**
* Element that the drop list is attached to.
* @type {?}
*/
DropListRef.prototype.element;
/**
* Unique ID for the drop list.
* @deprecated No longer being used. To be removed.
* \@breaking-change 8.0.0
* @type {?}
*/
DropListRef.prototype.id;
/**
* Whether starting a dragging sequence from this container is disabled.
* @type {?}
*/
DropListRef.prototype.disabled;
/**
* Locks the position of the draggable elements inside the container along the specified axis.
* @type {?}
*/
DropListRef.prototype.lockAxis;
/**
* Function that is used to determine whether an item
* is allowed to be moved into a drop container.
* @type {?}
*/
DropListRef.prototype.enterPredicate;
/**
* Emits right before dragging has started.
* @type {?}
*/
DropListRef.prototype.beforeStarted;
/**
* Emits when the user has moved a new drag item into this container.
* @type {?}
*/
DropListRef.prototype.entered;
/**
* Emits when the user removes an item from the container
* by dragging it into another container.
* @type {?}
*/
DropListRef.prototype.exited;
/**
* Emits when the user drops an item inside the container.
* @type {?}
*/
DropListRef.prototype.dropped;
/**
* Emits as the user is swapping items while actively dragging.
* @type {?}
*/
DropListRef.prototype.sorted;
/**
* Arbitrary data that can be attached to the drop list.
* @type {?}
*/
DropListRef.prototype.data;
/**
* Whether an item in the list is being dragged.
* @type {?}
* @private
*/
DropListRef.prototype._isDragging;
/**
* Cache of the dimensions of all the items inside the container.
* @type {?}
* @private
*/
DropListRef.prototype._itemPositions;
/**
* Cached `ClientRect` of the drop list.
* @type {?}
* @private
*/
DropListRef.prototype._clientRect;
/**
* Draggable items that are currently active inside the container. Includes the items
* from `_draggables`, as well as any items that have been dragged in, but haven't
* been dropped yet.
* @type {?}
* @private
*/
DropListRef.prototype._activeDraggables;
/**
* Keeps track of the item that was last swapped with the dragged item, as
* well as what direction the pointer was moving in when the swap occured.
* @type {?}
* @private
*/
DropListRef.prototype._previousSwap;
/**
* Draggable items in the container.
* @type {?}
* @private
*/
DropListRef.prototype._draggables;
/**
* Drop lists that are connected to the current one.
* @type {?}
* @private
*/
DropListRef.prototype._siblings;
/**
* Direction in which the list is oriented.
* @type {?}
* @private
*/
DropListRef.prototype._orientation;
/**
* Connected siblings that currently have a dragged item.
* @type {?}
* @private
*/
DropListRef.prototype._activeSiblings;
/**
* Layout direction of the drop list.
* @type {?}
* @private
*/
DropListRef.prototype._direction;
/**
* @type {?}
* @private
*/
DropListRef.prototype._dragDropRegistry;
}
/**
* Updates the top/left positions of a `ClientRect`, as well as their bottom/right counterparts.
* @param {?} clientRect `ClientRect` that should be updated.
* @param {?} top Amount to add to the `top` position.
* @param {?} left Amount to add to the `left` position.
* @return {?}
*/
function adjustClientRect(clientRect, top, left) {
clientRect.top += top;
clientRect.bottom = clientRect.top + clientRect.height;
clientRect.left += left;
clientRect.right = clientRect.left + clientRect.width;
}
/**
* Finds the index of an item that matches a predicate function. Used as an equivalent
* of `Array.prototype.find` which isn't part of the standard Google typings.
* @template T
* @param {?} array Array in which to look for matches.
* @param {?} predicate Function used to determine whether an item is a match.
* @return {?}
*/
function findIndex(array, predicate) {
for (let i = 0; i < array.length; i++) {
if (predicate(array[i], i, array)) {
return i;
}
}
return -1;
}
/**
* Checks whether some coordinates are within a `ClientRect`.
* @param {?} clientRect ClientRect that is being checked.
* @param {?} x Coordinates along the X axis.
* @param {?} y Coordinates along the Y axis.
* @return {?}
*/
function isInsideClientRect(clientRect, x, y) {
const { top, bottom, left, right } = clientRect;
return y >= top && y <= bottom && x >= left && x <= right;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJvcC1saXN0LXJlZi5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1wbHV0by8iLCJzb3VyY2VzIjpbImxpYi9kcmFnLWRyb3AvZHJvcC1saXN0LXJlZi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFHekMsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sY0FBYyxDQUFDOzs7OztJQUt6QyxnQkFBZ0IsR0FBRyxDQUFDOzs7Ozs7TUFNbEIsd0JBQXdCLEdBQUcsSUFBSTs7Ozs7OztBQU9yQyxpQ0FPQzs7Ozs7O0lBTEMsa0NBQWM7Ozs7O0lBRWQsd0NBQXVCOzs7OztJQUV2QixvQ0FBZTs7Ozs7Ozs7O0FBU2pCLHlDQUEyRDs7Ozs7OztBQU8zRCxNQUFNLE9BQU8sV0FBVzs7Ozs7O0lBaUd0QixZQUNFLE9BQThDLEVBQ3RDLGlCQUF5RCxFQUNqRSxTQUFjO1FBRE4sc0JBQWlCLEdBQWpCLGlCQUFpQixDQUF3Qzs7Ozs7O1FBeEZuRSxPQUFFLEdBQUcscUJBQXFCLGdCQUFnQixFQUFFLEVBQUUsQ0FBQzs7OztRQUcvQyxhQUFRLEdBQVksS0FBSyxDQUFDOzs7OztRQVMxQixtQkFBYzs7O1FBQWtELEdBQUcsRUFBRSxDQUFDLElBQUksRUFBQzs7OztRQUczRSxrQkFBYSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7Ozs7UUFLcEMsWUFBTyxHQUFHLElBQUksT0FBTyxFQUEyQyxDQUFDOzs7OztRQU1qRSxXQUFNLEdBQUcsSUFBSSxPQUFPLEVBQTJDLENBQUM7Ozs7UUFHaEUsWUFBTyxHQUFHLElBQUksT0FBTyxFQU9qQixDQUFDOzs7O1FBR0wsV0FBTSxHQUFHLElBQUksT0FBTyxFQUtoQixDQUFDOzs7O1FBTUcsZ0JBQVcsR0FBRyxLQUFLLENBQUM7Ozs7UUFHcEIsbUJBQWMsR0FBeUIsRUFB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VTtJQUM3QyxPQUFPLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLE1BQU0sSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUM7QUFDNUQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxyXG4gKiBAbGljZW5zZVxyXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxyXG4gKlxyXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxyXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtFbGVtZW50UmVmfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtEcmFnRHJvcFJlZ2lzdHJ5fSBmcm9tICcuL2RyYWctZHJvcC1yZWdpc3RyeSc7XHJcbmltcG9ydCB7RGlyZWN0aW9ufSBmcm9tICdAYW5ndWxhci9jZGsvYmlkaSc7XHJcbmltcG9ydCB7U3ViamVjdH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7bW92ZUl0ZW1JbkFycmF5fSBmcm9tICcuL2RyYWctdXRpbHMnO1xyXG5pbXBvcnQge0RyYWdSZWZJbnRlcm5hbCBhcyBEcmFnUmVmfSBmcm9tICcuL2RyYWctcmVmJztcclxuXHJcblxyXG4vKiogQ291bnRlciB1c2VkIHRvIGdlbmVyYXRlIHVuaXF1ZSBpZHMgZm9yIGRyb3AgcmVmcy4gKi9cclxubGV0IF91bmlxdWVJZENvdW50ZXIgPSAwO1xyXG5cclxuLyoqXHJcbiAqIFByb3hpbWl0eSwgYXMgYSByYXRpbyB0byB3aWR0aC9oZWlnaHQsIGF0IHdoaWNoIGFcclxuICogZHJhZ2dlZCBpdGVtIHdpbGwgYWZmZWN0IHRoZSBkcm9wIGNvbnRhaW5lci5cclxuICovXHJcbmNvbnN0IERST1BfUFJPWElNSVRZX1RIUkVTSE9MRCA9IDAuMDU7XHJcblxyXG4vKipcclxuICogQGlnbm9yZVxyXG4gKiBFbnRyeSBpbiB0aGUgcG9zaXRpb24gY2FjaGUgZm9yIGRyYWdnYWJsZSBpdGVtcy5cclxuICogQGRvY3MtcHJpdmF0ZVxyXG4gKi9cclxuaW50ZXJmYWNlIENhY2hlZEl0ZW1Qb3NpdGlvbiB7XHJcbiAgLyoqIEluc3RhbmNlIG9mIHRoZSBkcmFnIGl0ZW0uICovXHJcbiAgZHJhZzogRHJhZ1JlZjtcclxuICAvKiogRGltZW5zaW9ucyBvZiB0aGUgaXRlbS4gKi9cclxuICBjbGllbnRSZWN0OiBDbGllbnRSZWN0O1xyXG4gIC8qKiBBbW91bnQgYnkgd2hpY2ggdGhlIGl0ZW0gaGFzIGJlZW4gbW92ZWQgc2luY2UgZHJhZ2dpbmcgc3RhcnRlZC4gKi9cclxuICBvZmZzZXQ6IG51bWJlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIEBpZ25vcmVcclxuICogSW50ZXJuYWwgY29tcGlsZS10aW1lLW9ubHkgcmVwcmVzZW50YXRpb24gb2YgYSBgRHJvcExpc3RSZWZgLlxyXG4gKiBVc2VkIHRvIGF2b2lkIGNpcmN1bGFyIGltcG9ydCBpc3N1ZXMgYmV0d2VlbiB0aGUgYERyb3BMaXN0UmVmYCBhbmQgdGhlIGBEcmFnUmVmYC5cclxuICogQGRvY3MtcHJpdmF0ZVxyXG4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBEcm9wTGlzdFJlZkludGVybmFsIGV4dGVuZHMgRHJvcExpc3RSZWYge31cclxuXHJcbi8qKlxyXG4gKiBAaWdub3JlXHJcbiAqIFJlZmVyZW5jZSB0byBhIGRyb3AgbGlzdC4gVXNlZCB0byBtYW5pcHVsYXRlIG9yIGRpc3Bvc2Ugb2YgdGhlIGNvbnRhaW5lci5cclxuICogQGRvY3MtcHJpdmF0ZVxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIERyb3BMaXN0UmVmPFQgPSBhbnk+IHtcclxuICBwcml2YXRlIF9kb2N1bWVudDogRG9jdW1lbnQ7XHJcblxyXG4gIC8qKiBFbGVtZW50IHRoYXQgdGhlIGRyb3AgbGlzdCBpcyBhdHRhY2hlZCB0by4gKi9cclxuICByZWFkb25seSBlbGVtZW50OiBIVE1MRWxlbWVudDtcclxuXHJcbiAgLyoqXHJcbiAgICogVW5pcXVlIElEIGZvciB0aGUgZHJvcCBsaXN0LlxyXG4gICAqIEBkZXByZWNhdGVkIE5vIGxvbmdlciBiZWluZyB1c2VkLiBUbyBiZSByZW1vdmVkLlxyXG4gICAqIEBicmVha2luZy1jaGFuZ2UgOC4wLjBcclxuICAgKi9cclxuICBpZCA9IGBjZGstZHJvcC1saXN0LXJlZi0ke191bmlxdWVJZENvdW50ZXIrK31gO1xyXG5cclxuICAvKiogV2hldGhlciBzdGFydGluZyBhIGRyYWdnaW5nIHNlcXVlbmNlIGZyb20gdGhpcyBjb250YWluZXIgaXMgZGlzYWJsZWQuICovXHJcbiAgZGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHJcbiAgLyoqIExvY2tzIHRoZSBwb3NpdGlvbiBvZiB0aGUgZHJhZ2dhYmxlIGVsZW1lbnRzIGluc2lkZSB0aGUgY29udGFpbmVyIGFsb25nIHRoZSBzcGVjaWZpZWQgYXhpcy4gKi9cclxuICBsb2NrQXhpczogJ3gnIHwgJ3knO1xyXG5cclxuICAvKipcclxuICAgKiBGdW5jdGlvbiB0aGF0IGlzIHVzZWQgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgYW4gaXRlbVxyXG4gICAqIGlzIGFsbG93ZWQgdG8gYmUgbW92ZWQgaW50byBhIGRyb3AgY29udGFpbmVyLlxyXG4gICAqL1xyXG4gIGVudGVyUHJlZGljYXRlOiAoZHJhZzogRHJhZ1JlZiwgZHJvcDogRHJvcExpc3RSZWYpID0+IGJvb2xlYW4gPSAoKSA9PiB0cnVlO1xyXG5cclxuICAvKiogRW1pdHMgcmlnaHQgYmVmb3JlIGRyYWdnaW5nIGhhcyBzdGFydGVkLiAqL1xyXG4gIGJlZm9yZVN0YXJ0ZWQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xyXG5cclxuICAvKipcclxuICAgKiBFbWl0cyB3aGVuIHRoZSB1c2VyIGhhcyBtb3ZlZCBhIG5ldyBkcmFnIGl0ZW0gaW50byB0aGlzIGNvbnRhaW5lci5cclxuICAgKi9cclxuICBlbnRlcmVkID0gbmV3IFN1YmplY3Q8e2l0ZW06IERyYWdSZWYsIGNvbnRhaW5lcjogRHJvcExpc3RSZWZ9PigpO1xyXG5cclxuICAvKipcclxuICAgKiBFbWl0cyB3aGVuIHRoZSB1c2VyIHJlbW92ZXMgYW4gaXRlbSBmcm9tIHRoZSBjb250YWluZXJcclxuICAgKiBieSBkcmFnZ2luZyBpdCBpbnRvIGFub3RoZXIgY29udGFpbmVyLlxyXG4gICAqL1xyXG4gIGV4aXRlZCA9IG5ldyBTdWJqZWN0PHtpdGVtOiBEcmFnUmVmLCBjb250YWluZXI6IERyb3BMaXN0UmVmfT4oKTtcclxuXHJcbiAgLyoqIEVtaXRzIHdoZW4gdGhlIHVzZXIgZHJvcHMgYW4gaXRlbSBpbnNpZGUgdGhlIGNvbnRhaW5lci4gKi9cclxuICBkcm9wcGVkID0gbmV3IFN1YmplY3Q8e1xyXG4gICAgaXRlbTogRHJhZ1JlZixcclxuICAgIGN1cnJlbnRJbmRleDogbnVtYmVyLFxyXG4gICAgcHJldmlvdXNJbmRleDogbnVtYmVyLFxyXG4gICAgY29udGFpbmVyOiBEcm9wTGlzdFJlZixcclxuICAgIHByZXZpb3VzQ29udGFpbmVyOiBEcm9wTGlzdFJlZixcclxuICAgIGlzUG9pbnRlck92ZXJDb250YWluZXI6IGJvb2xlYW5cclxuICB9PigpO1xyXG5cclxuICAvKiogRW1pdHMgYXMgdGhlIHVzZXIgaXMgc3dhcHBpbmcgaXRlbXMgd2hpbGUgYWN0aXZlbHkgZHJhZ2dpbmcuICovXHJcbiAgc29ydGVkID0gbmV3IFN1YmplY3Q8e1xyXG4gICAgcHJldmlvdXNJbmRleDogbnVtYmVyLFxyXG4gICAgY3VycmVudEluZGV4OiBudW1iZXIsXHJcbiAgICBjb250YWluZXI6IERyb3BMaXN0UmVmLFxyXG4gICAgaXRlbTogRHJhZ1JlZlxyXG4gIH0+KCk7XHJcblxyXG4gIC8qKiBBcmJpdHJhcnkgZGF0YSB0aGF0IGNhbiBiZSBhdHRhY2hlZCB0byB0aGUgZHJvcCBsaXN0LiAqL1xyXG4gIGRhdGE6IFQ7XHJcblxyXG4gIC8qKiBXaGV0aGVyIGFuIGl0ZW0gaW4gdGhlIGxpc3QgaXMgYmVpbmcgZHJhZ2dlZC4gKi9cclxuICBwcml2YXRlIF9pc0RyYWdnaW5nID0gZmFsc2U7XHJcblxyXG4gIC8qKiBDYWNoZSBvZiB0aGUgZGltZW5zaW9ucyBvZiBhbGwgdGhlIGl0ZW1zIGluc2lkZSB0aGUgY29udGFpbmVyLiAqL1xyXG4gIHByaXZhdGUgX2l0ZW1Qb3NpdGlvbnM6IENhY2hlZEl0ZW1Qb3NpdGlvbltdID0gW107XHJcblxyXG4gIC8qKiBDYWNoZWQgYENsaWVudFJlY3RgIG9mIHRoZSBkcm9wIGxpc3QuICovXHJcbiAgcHJpdmF0ZSBfY2xpZW50UmVjdDogQ2xpZW50UmVjdDtcclxuXHJcbiAgLyoqXHJcbiAgICogRHJhZ2dhYmxlIGl0ZW1zIHRoYXQgYXJlIGN1cnJlbnRseSBhY3RpdmUgaW5zaWRlIHRoZSBjb250YWluZXIuIEluY2x1ZGVzIHRoZSBpdGVtc1xyXG4gICAqIGZyb20gYF9kcmFnZ2FibGVzYCwgYXMgd2VsbCBhcyBhbnkgaXRlbXMgdGhhdCBoYXZlIGJlZW4gZHJhZ2dlZCBpbiwgYnV0IGhhdmVuJ3RcclxuICAgKiBiZWVuIGRyb3BwZWQgeWV0LlxyXG4gICAqL1xyXG4gIHByaXZhdGUgX2FjdGl2ZURyYWdnYWJsZXM6IERyYWdSZWZbXTtcclxuXHJcbiAgLyoqXHJcbiAgICogS2VlcHMgdHJhY2sgb2YgdGhlIGl0ZW0gdGhhdCB3YXMgbGFzdCBzd2FwcGVkIHdpdGggdGhlIGRyYWdnZWQgaXRlbSwgYXNcclxuICAgKiB3ZWxsIGFzIHdoYXQgZGlyZWN0aW9uIHRoZSBwb2ludGVyIHdhcyBtb3ZpbmcgaW4gd2hlbiB0aGUgc3dhcCBvY2N1cmVkLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgX3ByZXZpb3VzU3dhcCA9IHtkcmFnOiBudWxsIGFzIERyYWdSZWYgfCBudWxsLCBkZWx0YTogMH07XHJcblxyXG4gIC8qKiBEcmFnZ2FibGUgaXRlbXMgaW4gdGhlIGNvbnRhaW5lci4gKi9cclxuICBwcml2YXRlIF9kcmFnZ2FibGVzOiBSZWFkb25seUFycmF5PERyYWdSZWY+O1xyXG5cclxuICAvKiogRHJvcCBsaXN0cyB0aGF0IGFyZSBjb25uZWN0ZWQgdG8gdGhlIGN1cnJlbnQgb25lLiAqL1xyXG4gIHByaXZhdGUgX3NpYmxpbmdzOiBSZWFkb25seUFycmF5PERyb3BMaXN0UmVmPiA9IFtdO1xyXG5cclxuICAvKiogRGlyZWN0aW9uIGluIHdoaWNoIHRoZSBsaXN0IGlzIG9yaWVudGVkLiAqL1xyXG4gIHByaXZhdGUgX29yaWVudGF0aW9uOiAnaG9yaXpvbnRhbCcgfCAndmVydGljYWwnID0gJ3ZlcnRpY2FsJztcclxuXHJcbiAgLyoqIENvbm5lY3RlZCBzaWJsaW5ncyB0aGF0IGN1cnJlbnRseSBoYXZlIGEgZHJhZ2dlZCBpdGVtLiAqL1xyXG4gIHByaXZhdGUgX2FjdGl2ZVNpYmxpbmdzID0gbmV3IFNldDxEcm9wTGlzdFJlZj4oKTtcclxuXHJcbiAgLyoqIExheW91dCBkaXJlY3Rpb24gb2YgdGhlIGRyb3AgbGlzdC4gKi9cclxuICBwcml2YXRlIF9kaXJlY3Rpb246IERpcmVjdGlvbiA9ICdsdHInO1xyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIGVsZW1lbnQ6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+IHwgSFRNTEVsZW1lbnQsXHJcbiAgICBwcml2YXRlIF9kcmFnRHJvcFJlZ2lzdHJ5OiBEcmFnRHJvcFJlZ2lzdHJ5PERyYWdSZWYsIERyb3BMaXN0UmVmPixcclxuICAgIF9kb2N1bWVudDogYW55KSB7XHJcbiAgICBfZHJhZ0Ryb3BSZWdpc3RyeS5yZWdpc3RlckRyb3BDb250YWluZXIodGhpcyk7XHJcbiAgICB0aGlzLl9kb2N1bWVudCA9IF9kb2N1bWVudDtcclxuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQgaW5zdGFuY2VvZiBFbGVtZW50UmVmID8gZWxlbWVudC5uYXRpdmVFbGVtZW50IDogZWxlbWVudDtcclxuICB9XHJcblxyXG4gIC8qKiBSZW1vdmVzIHRoZSBkcm9wIGxpc3QgZnVuY3Rpb25hbGl0eSBmcm9tIHRoZSBET00gZWxlbWVudC4gKi9cclxuICBkaXNwb3NlKCkge1xyXG4gICAgdGhpcy5iZWZvcmVTdGFydGVkLmNvbXBsZXRlKCk7XHJcbiAgICB0aGlzLmVudGVyZWQuY29tcGxldGUoKTtcclxuICAgIHRoaXMuZXhpdGVkLmNvbXBsZXRlKCk7XHJcbiAgICB0aGlzLmRyb3BwZWQuY29tcGxldGUoKTtcclxuICAgIHRoaXMuc29ydGVkLmNvbXBsZXRlKCk7XHJcbiAgICB0aGlzLl9hY3RpdmVTaWJsaW5ncy5jbGVhcigpO1xyXG4gICAgdGhpcy5fZHJhZ0Ryb3BSZWdpc3RyeS5yZW1vdmVEcm9wQ29udGFpbmVyKHRoaXMpO1xyXG4gIH1cclxuXHJcbiAgLyoqIFdoZXRoZXIgYW4gaXRlbSBmcm9tIHRoaXMgbGlzdCBpcyBjdXJyZW50bHkgYmVpbmcgZHJhZ2dlZC4gKi9cclxuICBpc0RyYWdnaW5nKCkge1xyXG4gICAgcmV0dXJuIHRoaXMuX2lzRHJhZ2dpbmc7XHJcbiAgfVxyXG5cclxuICAvKiogU3RhcnRzIGRyYWdnaW5nIGFuIGl0ZW0uICovXHJcbiAgc3RhcnQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmJlZm9yZVN0YXJ0ZWQubmV4dCgpO1xyXG4gICAgdGhpcy5faXNEcmFnZ2luZyA9IHRydWU7XHJcbiAgICB0aGlzLl9hY3RpdmVEcmFnZ2FibGVzID0gdGhpcy5fZHJhZ2dhYmxlcy5zbGljZSgpO1xyXG4gICAgdGhpcy5fY2FjaGVPd25Qb3NpdGlvbigpO1xyXG4gICAgdGhpcy5fY2FjaGVJdGVtUG9zaXRpb25zKCk7XHJcbiAgICB0aGlzLl9zaWJsaW5ncy5mb3JFYWNoKHNpYmxpbmcgPT4gc2libGluZy5fc3RhcnRSZWNlaXZpbmcodGhpcykpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRW1pdHMgYW4gZXZlbnQgdG8gaW5kaWNhdGUgdGhhdCB0aGUgdXNlciBtb3ZlZCBhbiBpdGVtIGludG8gdGhlIGNvbnRhaW5lci5cclxuICAgKiBAcGFyYW0gaXRlbSBJdGVtIHRoYXQgd2FzIG1vdmVkIGludG8gdGhlIGNvbnRhaW5lci5cclxuICAgKiBAcGFyYW0gcG9pbnRlclggUG9zaXRpb24gb2YgdGhlIGl0ZW0gYWxvbmcgdGhlIFggYXhpcy5cclxuICAgKiBAcGFyYW0gcG9pbnRlclkgUG9zaXRpb24gb2YgdGhlIGl0ZW0gYWxvbmcgdGhlIFkgYXhpcy5cclxuICAgKi9cclxuICBlbnRlcihpdGVtOiBEcmFnUmVmLCBwb2ludGVyWDogbnVtYmVyLCBwb2ludGVyWTogbnVtYmVyKTogdm9pZCB7XHJcbiAgICB0aGlzLmVudGVyZWQubmV4dCh7aXRlbSwgY29udGFpbmVyOiB0aGlzfSk7XHJcbiAgICB0aGlzLnN0YXJ0KCk7XHJcblxyXG4gICAgLy8gV2UgdXNlIHRoZSBjb29yZGluYXRlcyBvZiB3aGVyZSB0aGUgaXRlbSBlbnRlcmVkIHRoZSBkcm9wXHJcbiAgICAvLyB6b25lIHRvIGZpZ3VyZSBvdXQgYXQgd2hpY2ggaW5kZXggaXQgc2hvdWxkIGJlIGluc2VydGVkLlxyXG4gICAgY29uc3QgbmV3SW5kZXggPSB0aGlzLl9nZXRJdGVtSW5kZXhGcm9tUG9pbnRlclBvc2l0aW9uKGl0ZW0sIHBvaW50ZXJYLCBwb2ludGVyWSk7XHJcbiAgICBjb25zdCBjdXJyZW50SW5kZXggPSB0aGlzLl9hY3RpdmVEcmFnZ2FibGVzLmluZGV4T2YoaXRlbSk7XHJcbiAgICBjb25zdCBuZXdQb3NpdGlvblJlZmVyZW5jZSA9IHRoaXMuX2FjdGl2ZURyYWdnYWJsZXNbbmV3SW5kZXhdO1xyXG4gICAgY29uc3QgcGxhY2Vob2xkZXIgPSBpdGVtLmdldFBsYWNlaG9sZGVyRWxlbWVudCgpO1xyXG5cclxuICAgIC8vIFNpbmNlIHRoZSBpdGVtIG1heSBiZSBpbiB0aGUgYGFjdGl2ZURyYWdnYWJsZXNgIGFscmVhZHkgKGUuZy4gaWYgdGhlIHVzZXIgZHJhZ2dlZCBpdFxyXG4gICAgLy8gaW50byBhbm90aGVyIGNvbnRhaW5lciBhbmQgYmFjayBhZ2FpbiksIHdlIGhhdmUgdG8gZW5zdXJlIHRoYXQgaXQgaXNuJ3QgZHVwbGljYXRlZC5cclxuICAgIGlmIChjdXJyZW50SW5kZXggPiAtMSkge1xyXG4gICAgICB0aGlzLl9hY3RpdmVEcmFnZ2FibGVzLnNwbGljZShjdXJyZW50SW5kZXgsIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERvbid0IHVzZSBpdGVtcyB0aGF0IGFyZSBiZWluZyBkcmFnZ2VkIGFzIGEgcmVmZXJlbmNlLCBiZWNhdXNlXHJcbiAgICAvLyB0aGVpciBlbGVtZW50IGhhcyBiZWVuIG1vdmVkIGRvd24gdG8gdGhlIGJvdHRvbSBvZiB0aGUgYm9keS5cclxuICAgIGlmIChuZXdQb3NpdGlvblJlZmVyZW5jZSAmJiAhdGhpcy5fZHJhZ0Ryb3BSZWdpc3RyeS5pc0RyYWdnaW5nKG5ld1Bvc2l0aW9uUmVmZXJlbmNlKSkge1xyXG4gICAgICBjb25zdCBlbGVtZW50ID0gbmV3UG9zaXRpb25SZWZlcmVuY2UuZ2V0Um9vdEVsZW1lbnQoKTtcclxuICAgICAgZWxlbWVudC5wYXJlbnRFbGVtZW50IS5pbnNlcnRCZWZvcmUocGxhY2Vob2xkZXIsIGVsZW1lbnQpO1xyXG4gICAgICB0aGlzLl9hY3RpdmVEcmFnZ2FibGVzLnNwbGljZShuZXdJbmRleCwgMCwgaXRlbSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmVsZW1lbnQuYXBwZW5kQ2hpbGQocGxhY2Vob2xkZXIpO1xyXG4gICAgICB0aGlzLl9hY3RpdmVEcmFnZ2FibGVzLnB1c2goaXRlbSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIHRyYW5zZm9ybSBuZWVkcyB0byBiZSBjbGVhcmVkIHNvIGl0IGRvZXNuJ3QgdGhyb3cgb2ZmIHRoZSBtZWFzdXJlbWVudHMuXHJcbiAgICBwbGFjZWhvbGRlci5zdHlsZS50cmFuc2Zvcm0gPSAnJztcclxuXHJcbiAgICAvLyBOb3RlIHRoYXQgdGhlIHBvc2l0aW9ucyB3ZXJlIGFscmVhZHkgY2FjaGVkIHdoZW4gd2UgY2FsbGVkIGBzdGFydGAgYWJvdmUsXHJcbiAgICAvLyBidXQgd2UgbmVlZCB0byByZWZyZXNoIHRoZW0gc2luY2UgdGhlIGFtb3VudCBvZiBpdGVtcyBoYXMgY2hhbmdlZC5cclxuICAgIHRoaXMuX2NhY2hlSXRlbVBvc2l0aW9ucygpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVtb3ZlcyBhbiBpdGVtIGZyb20gdGhlIGNvbnRhaW5lciBhZnRlciBpdCB3YXMgZHJhZ2dlZCBpbnRvIGFub3RoZXIgY29udGFpbmVyIGJ5IHRoZSB1c2VyLlxyXG4gICAqIEBwYXJhbSBpdGVtIEl0ZW0gdGhhdCB3YXMgZHJhZ2dlZCBvdXQuXHJcbiAgICovXHJcbiAgZXhpdChpdGVtOiBEcmFnUmVmKTogdm9pZCB7XHJcbiAgICB0aGlzLl9yZXNldCgpO1xyXG4gICAgdGhpcy5leGl0ZWQubmV4dCh7aXRlbSwgY29udGFpbmVyOiB0aGlzfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEcm9wcyBhbiBpdGVtIGludG8gdGhpcyBjb250YWluZXIuXHJcbiAgICogQHBhcmFtIGl0ZW0gSXRlbSBiZWluZyBkcm9wcGVkIGludG8gdGhlIGNvbnRhaW5lci5cclxuICAgKiBAcGFyYW0gY3VycmVudEluZGV4IEluZGV4IGF0IHdoaWNoIHRoZSBpdGVtIHNob3VsZCBiZSBpbnNlcnRlZC5cclxuICAgKiBAcGFyYW0gcHJldmlvdXNDb250YWluZXIgQ29udGFpbmVyIGZyb20gd2hpY2ggdGhlIGl0ZW0gZ290IGRyYWdnZWQgaW4uXHJcbiAgICogQHBhcmFtIGlzUG9pbnRlck92ZXJDb250YWluZXIgV2hldGhlciB0aGUgdXNlcidzIHBvaW50ZXIgd2FzIG92ZXIgdGhlXHJcbiAgICogICAgY29udGFpbmVyIHdoZW4gdGhlIGl0ZW0gd2FzIGRyb3BwZWQuXHJcbiAgICovXHJcbiAgZHJvcChpdGVtOiBEcmFnUmVmLCBjdXJyZW50SW5kZXg6IG51bWJlciwgcHJldmlvdXNDb250YWluZXI6IERyb3BMaXN0UmVmLFxyXG4gICAgaXNQb2ludGVyT3ZlckNvbnRhaW5lcjogYm9vbGVhbik6IHZvaWQge1xyXG4gICAgdGhpcy5fcmVzZXQoKTtcclxuICAgIHRoaXMuZHJvcHBlZC5uZXh0KHtcclxuICAgICAgaXRlbSxcclxuICAgICAgY3VycmVudEluZGV4LFxyXG4gICAgICBwcmV2aW91c0luZGV4OiBwcmV2aW91c0NvbnRhaW5lci5nZXRJdGVtSW5kZXgoaXRlbSksXHJcbiAgICAgIGNvbnRhaW5lcjogdGhpcyxcclxuICAgICAgcHJldmlvdXNDb250YWluZXIsXHJcbiAgICAgIGlzUG9pbnRlck92ZXJDb250YWluZXJcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyB0aGUgZHJhZ2dhYmxlIGl0ZW1zIHRoYXQgYXJlIGEgcGFydCBvZiB0aGlzIGxpc3QuXHJcbiAgICogQHBhcmFtIGl0ZW1zIEl0ZW1zIHRoYXQgYXJlIGEgcGFydCBvZiB0aGlzIGxpc3QuXHJcbiAgICovXHJcbiAgd2l0aEl0ZW1zKGl0ZW1zOiBEcmFnUmVmW10pOiB0aGlzIHtcclxuICAgIHRoaXMuX2RyYWdnYWJsZXMgPSBpdGVtcztcclxuICAgIGl0ZW1zLmZvckVhY2goaXRlbSA9PiBpdGVtLl93aXRoRHJvcENvbnRhaW5lcih0aGlzKSk7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcblxyXG4gIC8qKiBTZXRzIHRoZSBsYXlvdXQgZGlyZWN0aW9uIG9mIHRoZSBkcm9wIGxpc3QuICovXHJcbiAgd2l0aERpcmVjdGlvbihkaXJlY3Rpb246IERpcmVjdGlvbik6IHRoaXMge1xyXG4gICAgdGhpcy5fZGlyZWN0aW9uID0gZGlyZWN0aW9uO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIHRoZSBjb250YWluZXJzIHRoYXQgYXJlIGNvbm5lY3RlZCB0byB0aGlzIG9uZS4gV2hlbiB0d28gb3IgbW9yZSBjb250YWluZXJzIGFyZVxyXG4gICAqIGNvbm5lY3RlZCwgdGhlIHVzZXIgd2lsbCBiZSBhbGxvd2VkIHRvIHRyYW5zZmVyIGl0ZW1zIGJldHdlZW4gdGhlbS5cclxuICAgKiBAcGFyYW0gY29ubmVjdGVkVG8gT3RoZXIgY29udGFpbmVycyB0aGF0IHRoZSBjdXJyZW50IGNvbnRhaW5lcnMgc2hvdWxkIGJlIGNvbm5lY3RlZCB0by5cclxuICAgKi9cclxuICBjb25uZWN0ZWRUbyhjb25uZWN0ZWRUbzogRHJvcExpc3RSZWZbXSk6IHRoaXMge1xyXG4gICAgdGhpcy5fc2libGluZ3MgPSBjb25uZWN0ZWRUby5zbGljZSgpO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIHRoZSBvcmllbnRhdGlvbiBvZiB0aGUgY29udGFpbmVyLlxyXG4gICAqIEBwYXJhbSBvcmllbnRhdGlvbiBOZXcgb3JpZW50YXRpb24gZm9yIHRoZSBjb250YWluZXIuXHJcbiAgICovXHJcbiAgd2l0aE9yaWVudGF0aW9uKG9yaWVudGF0aW9uOiAndmVydGljYWwnIHwgJ2hvcml6b250YWwnKTogdGhpcyB7XHJcbiAgICB0aGlzLl9vcmllbnRhdGlvbiA9IG9yaWVudGF0aW9uO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGaWd1cmVzIG91dCB0aGUgaW5kZXggb2YgYW4gaXRlbSBpbiB0aGUgY29udGFpbmVyLlxyXG4gICAqIEBwYXJhbSBpdGVtIEl0ZW0gd2hvc2UgaW5kZXggc2hvdWxkIGJlIGRldGVybWluZWQuXHJcbiAgICovXHJcbiAgZ2V0SXRlbUluZGV4KGl0ZW06IERyYWdSZWYpOiBudW1iZXIge1xyXG4gICAgaWYgKCF0aGlzLl9pc0RyYWdnaW5nKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLl9kcmFnZ2FibGVzLmluZGV4T2YoaXRlbSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSXRlbXMgYXJlIHNvcnRlZCBhbHdheXMgYnkgdG9wL2xlZnQgaW4gdGhlIGNhY2hlLCBob3dldmVyIHRoZXkgZmxvdyBkaWZmZXJlbnRseSBpbiBSVEwuXHJcbiAgICAvLyBUaGUgcmVzdCBvZiB0aGUgbG9naWMgc3RpbGwgc3RhbmRzIG5vIG1hdHRlciB3aGF0IG9yaWVudGF0aW9uIHdlJ3JlIGluLCBob3dldmVyXHJcbiAgICAvLyB3ZSBuZWVkIHRvIGludmVydCB0aGUgYXJyYXkgd2hlbiBkZXRlcm1pbmluZyB0aGUgaW5kZXguXHJcbiAgICBjb25zdCBpdGVtcyA9IHRoaXMuX29yaWVudGF0aW9uID09PSAnaG9yaXpvbnRhbCcgJiYgdGhpcy5fZGlyZWN0aW9uID09PSAncnRsJyA/XHJcbiAgICAgICAgdGhpcy5faXRlbVBvc2l0aW9ucy5zbGljZSgpLnJldmVyc2UoKSA6IHRoaXMuX2l0ZW1Qb3NpdGlvbnM7XHJcblxyXG4gICAgcmV0dXJuIGZpbmRJbmRleChpdGVtcywgY3VycmVudEl0ZW0gPT4gY3VycmVudEl0ZW0uZHJhZyA9PT0gaXRlbSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBXaGV0aGVyIHRoZSBsaXN0IGlzIGFibGUgdG8gcmVjZWl2ZSB0aGUgaXRlbSB0aGF0XHJcbiAgICogaXMgY3VycmVudGx5IGJlaW5nIGRyYWdnZWQgaW5zaWRlIGEgY29ubmVjdGVkIGRyb3AgbGlzdC5cclxuICAgKi9cclxuICBpc1JlY2VpdmluZygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLl9hY3RpdmVTaWJsaW5ncy5zaXplID4gMDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNvcnRzIGFuIGl0ZW0gaW5zaWRlIHRoZSBjb250YWluZXIgYmFzZWQgb24gaXRzIHBvc2l0aW9uLlxyXG4gICAqIEBwYXJhbSBpdGVtIEl0ZW0gdG8gYmUgc29ydGVkLlxyXG4gICAqIEBwYXJhbSBwb2ludGVyWCBQb3NpdGlvbiBvZiB0aGUgaXRlbSBhbG9uZyB0aGUgWCBheGlzLlxyXG4gICAqIEBwYXJhbSBwb2ludGVyWSBQb3NpdGlvbiBvZiB0aGUgaXRlbSBhbG9uZyB0aGUgWSBheGlzLlxyXG4gICAqIEBwYXJhbSBwb2ludGVyRGVsdGEgRGlyZWN0aW9uIGluIHdoaWNoIHRoZSBwb2ludGVyIGlzIG1vdmluZyBhbG9uZyBlYWNoIGF4aXMuXHJcbiAgICovXHJcbiAgX3NvcnRJdGVtKGl0ZW06IERyYWdSZWYsIHBvaW50ZXJYOiBudW1iZXIsIHBvaW50ZXJZOiBudW1iZXIsXHJcbiAgICAgICAgICAgIHBvaW50ZXJEZWx0YToge3g6IG51bWJlciwgeTogbnVtYmVyfSk6IHZvaWQge1xyXG4gICAgLy8gRG9uJ3Qgc29ydCB0aGUgaXRlbSBpZiBpdCdzIG91dCBvZiByYW5nZS5cclxuICAgIGlmICghdGhpcy5faXNQb2ludGVyTmVhckRyb3BDb250YWluZXIocG9pbnRlclgsIHBvaW50ZXJZKSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3Qgc2libGluZ3MgPSB0aGlzLl9pdGVtUG9zaXRpb25zO1xyXG4gICAgY29uc3QgbmV3SW5kZXggPSB0aGlzLl9nZXRJdGVtSW5kZXhGcm9tUG9pbnRlclBvc2l0aW9uKGl0ZW0sIHBvaW50ZXJYLCBwb2ludGVyWSwgcG9pbnRlckRlbHRhKTtcclxuXHJcbiAgICBpZiAobmV3SW5kZXggPT09IC0xICYmIHNpYmxpbmdzLmxlbmd0aCA+IDApIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGlzSG9yaXpvbnRhbCA9IHRoaXMuX29yaWVudGF0aW9uID09PSAnaG9yaXpvbnRhbCc7XHJcbiAgICBjb25zdCBjdXJyZW50SW5kZXggPSBmaW5kSW5kZXgoc2libGluZ3MsIGN1cnJlbnRJdGVtID0+IGN1cnJlbnRJdGVtLmRyYWcgPT09IGl0ZW0pO1xyXG4gICAgY29uc3Qgc2libGluZ0F0TmV3UG9zaXRpb24gPSBzaWJsaW5nc1tuZXdJbmRleF07XHJcbiAgICBjb25zdCBjdXJyZW50UG9zaXRpb24gPSBzaWJsaW5nc1tjdXJyZW50SW5kZXhdLmNsaWVudFJlY3Q7XHJcbiAgICBjb25zdCBuZXdQb3NpdGlvbiA9IHNpYmxpbmdBdE5ld1Bvc2l0aW9uLmNsaWVudFJlY3Q7XHJcbiAgICBjb25zdCBkZWx0YSA9IGN1cnJlbnRJbmRleCA+IG5ld0luZGV4ID8gMSA6IC0xO1xyXG5cclxuICAgIHRoaXMuX3ByZXZpb3VzU3dhcC5kcmFnID0gc2libGluZ0F0TmV3UG9zaXRpb24uZHJhZztcclxuICAgIHRoaXMuX3ByZXZpb3VzU3dhcC5kZWx0YSA9IGlzSG9yaXpvbnRhbCA/IHBvaW50ZXJEZWx0YS54IDogcG9pbnRlckRlbHRhLnk7XHJcblxyXG4gICAgLy8gSG93IG1hbnkgcGl4ZWxzIHRoZSBpdGVtJ3MgcGxhY2Vob2xkZXIgc2hvdWxkIGJlIG9mZnNldC5cclxuICAgIGNvbnN0IGl0ZW1PZmZzZXQgPSB0aGlzLl9nZXRJdGVtT2Zmc2V0UHgoY3VycmVudFBvc2l0aW9uLCBuZXdQb3NpdGlvbiwgZGVsdGEpO1xyXG5cclxuICAgIC8vIEhvdyBtYW55IHBpeGVscyBhbGwgdGhlIG90aGVyIGl0ZW1zIHNob3VsZCBiZSBvZmZzZXQuXHJcbiAgICBjb25zdCBzaWJsaW5nT2Zmc2V0ID0gdGhpcy5fZ2V0U2libGluZ09mZnNldFB4KGN1cnJlbnRJbmRleCwgc2libGluZ3MsIGRlbHRhKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBwcmV2aW91cyBvcmRlciBvZiB0aGUgaXRlbXMgYmVmb3JlIG1vdmluZyB0aGUgaXRlbSB0byBpdHMgbmV3IGluZGV4LlxyXG4gICAgLy8gV2UgdXNlIHRoaXMgdG8gY2hlY2sgd2hldGhlciBhbiBpdGVtIGhhcyBiZWVuIG1vdmVkIGFzIGEgcmVzdWx0IG9mIHRoZSBzb3J0aW5nLlxyXG4gICAgY29uc3Qgb2xkT3JkZXIgPSBzaWJsaW5ncy5zbGljZSgpO1xyXG5cclxuICAgIC8vIFNodWZmbGUgdGhlIGFycmF5IGluIHBsYWNlLlxyXG4gICAgbW92ZUl0ZW1JbkFycmF5KHNpYmxpbmdzLCBjdXJyZW50SW5kZXgsIG5ld0luZGV4KTtcclxuXHJcbiAgICB0aGlzLnNvcnRlZC5uZXh0KHtcclxuICAgICAgcHJldmlvdXNJbmRleDogY3VycmVudEluZGV4LFxyXG4gICAgICBjdXJyZW50SW5kZXg6IG5ld0luZGV4LFxyXG4gICAgICBjb250YWluZXI6IHRoaXMsXHJcbiAgICAgIGl0ZW1cclxuICAgIH0pO1xyXG5cclxuICAgIHNpYmxpbmdzLmZvckVhY2goKHNpYmxpbmcsIGluZGV4KSA9PiB7XHJcbiAgICAgIC8vIERvbid0IGRvIGFueXRoaW5nIGlmIHRoZSBwb3NpdGlvbiBoYXNuJ3QgY2hhbmdlZC5cclxuICAgICAgaWYgKG9sZE9yZGVyW2luZGV4XSA9PT0gc2libGluZykge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgY29uc3QgaXNEcmFnZ2VkSXRlbSA9IHNpYmxpbmcuZHJhZyA9PT0gaXRlbTtcclxuICAgICAgY29uc3Qgb2Zmc2V0ID0gaXNEcmFnZ2VkSXRlbSA/IGl0ZW1PZmZzZXQgOiBzaWJsaW5nT2Zmc2V0O1xyXG4gICAgICBjb25zdCBlbGVtZW50VG9PZmZzZXQgPSBpc0RyYWdnZWRJdGVtID8gaXRlbS5nZXRQbGFjZWhvbGRlckVsZW1lbnQoKSA6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWJsaW5nLmRyYWcuZ2V0Um9vdEVsZW1lbnQoKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSB0aGUgb2Zmc2V0IHRvIHJlZmxlY3QgdGhlIG5ldyBwb3NpdGlvbi5cclxuICAgICAgc2libGluZy5vZmZzZXQgKz0gb2Zmc2V0O1xyXG5cclxuICAgICAgLy8gU2luY2Ugd2UncmUgbW92aW5nIHRoZSBpdGVtcyB3aXRoIGEgYHRyYW5zZm9ybWAsIHdlIG5lZWQgdG8gYWRqdXN0IHRoZWlyIGNhY2hlZFxyXG4gICAgICAvLyBjbGllbnQgcmVjdHMgdG8gcmVmbGVjdCB0aGVpciBuZXcgcG9zaXRpb24sIGFzIHdlbGwgYXMgc3dhcCB0aGVpciBwb3NpdGlvbnMgaW4gdGhlIGNhY2hlLlxyXG4gICAgICAvLyBOb3RlIHRoYXQgd2Ugc2hvdWxkbid0IHVzZSBgZ2V0Qm91bmRpbmdDbGllbnRSZWN0YCBoZXJlIHRvIHVwZGF0ZSB0aGUgY2FjaGUsIGJlY2F1c2UgdGhlXHJcbiAgICAgIC8vIGVsZW1lbnRzIG1heSBiZSBtaWQtYW5pbWF0aW9uIHdoaWNoIHdpbGwgZ2l2ZSB1cyBhIHdyb25nIHJlc3VsdC5cclxuICAgICAgaWYgKGlzSG9yaXpvbnRhbCkge1xyXG4gICAgICAgIC8vIFJvdW5kIHRoZSB0cmFuc2Zvcm1zIHNpbmNlIHNvbWUgYnJvd3NlcnMgd2lsbFxyXG4gICAgICAgIC8vIGJsdXIgdGhlIGVsZW1lbnRzLCBmb3Igc3ViLXBpeGVsIHRyYW5zZm9ybXMuXHJcbiAgICAgICAgZWxlbWVudFRvT2Zmc2V0LnN0eWxlLnRyYW5zZm9ybSA9IGB0cmFuc2xhdGUzZCgke01hdGgucm91bmQoc2libGluZy5vZmZzZXQpfXB4LCAwLCAwKWA7XHJcbiAgICAgICAgYWRqdXN0Q2xpZW50UmVjdChzaWJsaW5nLmNsaWVudFJlY3QsIDAsIG9mZnNldCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZWxlbWVudFRvT2Zmc2V0LnN0eWxlLnRyYW5zZm9ybSA9IGB0cmFuc2xhdGUzZCgwLCAke01hdGgucm91bmQoc2libGluZy5vZmZzZXQpfXB4LCAwKWA7XHJcbiAgICAgICAgYWRqdXN0Q2xpZW50UmVjdChzaWJsaW5nLmNsaWVudFJlY3QsIG9mZnNldCwgMCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqIENhY2hlcyB0aGUgcG9zaXRpb24gb2YgdGhlIGRyb3AgbGlzdC4gKi9cclxuICBwcml2YXRlIF9jYWNoZU93blBvc2l0aW9uKCkge1xyXG4gICAgdGhpcy5fY2xpZW50UmVjdCA9IHRoaXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICB9XHJcblxyXG4gIC8qKiBSZWZyZXNoZXMgdGhlIHBvc2l0aW9uIGNhY2hlIG9mIHRoZSBpdGVtcyBhbmQgc2libGluZyBjb250YWluZXJzLiAqL1xyXG4gIHByaXZhdGUgX2NhY2hlSXRlbVBvc2l0aW9ucygpIHtcclxuICAgIGNvbnN0IGlzSG9yaXpvbnRhbCA9IHRoaXMuX29yaWVudGF0aW9uID09PSAnaG9yaXpvbnRhbCc7XHJcblxyXG4gICAgdGhpcy5faXRlbVBvc2l0aW9ucyA9IHRoaXMuX2FjdGl2ZURyYWdnYWJsZXMubWFwKGRyYWcgPT4ge1xyXG4gICAgICBjb25zdCBlbGVtZW50VG9NZWFzdXJlID0gdGhpcy5fZHJhZ0Ryb3BSZWdpc3RyeS5pc0RyYWdnaW5nKGRyYWcpID9cclxuICAgICAgICAgIC8vIElmIHRoZSBlbGVtZW50IGlzIGJlaW5nIGRyYWdnZWQsIHdlIGhhdmUgdG8gbWVhc3VyZSB0aGVcclxuICAgICAgICAgIC8vIHBsYWNlaG9sZGVyLCBiZWNhdXNlIHRoZSBlbGVtZW50IGlzIGhpZGRlbi5cclxuICAgICAgICAgIGRyYWcuZ2V0UGxhY2Vob2xkZXJFbGVtZW50KCkgOlxyXG4gICAgICAgICAgZHJhZy5nZXRSb290RWxlbWVudCgpO1xyXG4gICAgICBjb25zdCBjbGllbnRSZWN0ID0gZWxlbWVudFRvTWVhc3VyZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuXHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgZHJhZyxcclxuICAgICAgICBvZmZzZXQ6IDAsXHJcbiAgICAgICAgLy8gV2UgbmVlZCB0byBjbG9uZSB0aGUgYGNsaWVudFJlY3RgIGhlcmUsIGJlY2F1c2UgYWxsIHRoZSB2YWx1ZXMgb24gaXQgYXJlIHJlYWRvbmx5XHJcbiAgICAgICAgLy8gYW5kIHdlIG5lZWQgdG8gYmUgYWJsZSB0byB1cGRhdGUgdGhlbS4gQWxzbyB3ZSBjYW4ndCB1c2UgYSBzcHJlYWQgaGVyZSwgYmVjYXVzZVxyXG4gICAgICAgIC8vIHRoZSB2YWx1ZXMgb24gYSBgQ2xpZW50UmVjdGAgYXJlbid0IG93biBwcm9wZXJ0aWVzLiBTZWU6XHJcbiAgICAgICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0VsZW1lbnQvZ2V0Qm91bmRpbmdDbGllbnRSZWN0I05vdGVzXHJcbiAgICAgICAgY2xpZW50UmVjdDoge1xyXG4gICAgICAgICAgdG9wOiBjbGllbnRSZWN0LnRvcCxcclxuICAgICAgICAgIHJpZ2h0OiBjbGllbnRSZWN0LnJpZ2h0LFxyXG4gICAgICAgICAgYm90dG9tOiBjbGllbnRSZWN0LmJvdHRvbSxcclxuICAgICAgICAgIGxlZnQ6IGNsaWVudFJlY3QubGVmdCxcclxuICAgICAgICAgIHdpZHRoOiBjbGllbnRSZWN0LndpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiBjbGllbnRSZWN0LmhlaWdodFxyXG4gICAgICAgIH1cclxuICAgICAgfTtcclxuICAgIH0pLnNvcnQoKGEsIGIpID0+IHtcclxuICAgICAgcmV0dXJuIGlzSG9yaXpvbnRhbCA/IGEuY2xpZW50UmVjdC5sZWZ0IC0gYi5jbGllbnRSZWN0LmxlZnQgOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYS5jbGllbnRSZWN0LnRvcCAtIGIuY2xpZW50UmVjdC50b3A7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKiBSZXNldHMgdGhlIGNvbnRhaW5lciB0byBpdHMgaW5pdGlhbCBzdGF0ZS4gKi9cclxuICBwcml2YXRlIF9yZXNldCgpIHtcclxuICAgIHRoaXMuX2lzRHJhZ2dpbmcgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBUT0RPKGNyaXNiZXRvKTogbWF5IGhhdmUgdG8gd2FpdCBmb3IgdGhlIGFuaW1hdGlvbnMgdG8gZmluaXNoLlxyXG4gICAgdGhpcy5fYWN0aXZlRHJhZ2dhYmxlcy5mb3JFYWNoKGl0ZW0gPT4gaXRlbS5nZXRSb290RWxlbWVudCgpLnN0eWxlLnRyYW5zZm9ybSA9ICcnKTtcclxuICAgIHRoaXMuX3NpYmxpbmdzLmZvckVhY2goc2libGluZyA9PiBzaWJsaW5nLl9zdG9wUmVjZWl2aW5nKHRoaXMpKTtcclxuICAgIHRoaXMuX2FjdGl2ZURyYWdnYWJsZXMgPSBbXTtcclxuICAgIHRoaXMuX2l0ZW1Qb3NpdGlvbnMgPSBbXTtcclxuICAgIHRoaXMuX3ByZXZpb3VzU3dhcC5kcmFnID0gbnVsbDtcclxuICAgIHRoaXMuX3ByZXZpb3VzU3dhcC5kZWx0YSA9IDA7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXRzIHRoZSBvZmZzZXQgaW4gcGl4ZWxzIGJ5IHdoaWNoIHRoZSBpdGVtcyB0aGF0IGFyZW4ndCBiZWluZyBkcmFnZ2VkIHNob3VsZCBiZSBtb3ZlZC5cclxuICAgKiBAcGFyYW0gY3VycmVudEluZGV4IEluZGV4IG9mIHRoZSBpdGVtIGN1cnJlbnRseSBiZWluZyBkcmFnZ2VkLlxyXG4gICAqIEBwYXJhbSBzaWJsaW5ncyBBbGwgb2YgdGhlIGl0ZW1zIGluIHRoZSBsaXN0LlxyXG4gICAqIEBwYXJhbSBkZWx0YSBEaXJlY3Rpb24gaW4gd2hpY2ggdGhlIHVzZXIgaXMgbW92aW5nLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgX2dldFNpYmxpbmdPZmZzZXRQeChjdXJyZW50SW5kZXg6IG51bWJlcixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2libGluZ3M6IENhY2hlZEl0ZW1Qb3NpdGlvbltdLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWx0YTogMSB8IC0xKSB7XHJcblxyXG4gICAgY29uc3QgaXNIb3Jpem9udGFsID0gdGhpcy5fb3JpZW50YXRpb24gPT09ICdob3Jpem9udGFsJztcclxuICAgIGNvbnN0IGN1cnJlbnRQb3NpdGlvbiA9IHNpYmxpbmdzW2N1cnJlbnRJbmRleF0uY2xpZW50UmVjdDtcclxuICAgIGNvbnN0IGltbWVkaWF0ZVNpYmxpbmcgPSBzaWJsaW5nc1tjdXJyZW50SW5kZXggKyBkZWx0YSAqIC0xXTtcclxuICAgIGxldCBzaWJsaW5nT2Zmc2V0ID0gY3VycmVudFBvc2l0aW9uW2lzSG9yaXpvbnRhbCA/ICd3aWR0aCcgOiAnaGVpZ2h0J10gKiBkZWx0YTtcclxuXHJcbiAgICBpZiAoaW1tZWRpYXRlU2libGluZykge1xyXG4gICAgICBjb25zdCBzdGFydCA9IGlzSG9yaXpvbnRhbCA/ICdsZWZ0JyA6ICd0b3AnO1xyXG4gICAgICBjb25zdCBlbmQgPSBpc0hvcml6b250YWwgPyAncmlnaHQnIDogJ2JvdHRvbSc7XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHNwYWNpbmcgYmV0d2VlbiB0aGUgc3RhcnQgb2YgdGhlIGN1cnJlbnQgaXRlbSBhbmQgdGhlIGVuZCBvZiB0aGUgb25lIGltbWVkaWF0ZWx5XHJcbiAgICAgIC8vIGFmdGVyIGl0IGluIHRoZSBkaXJlY3Rpb24gaW4gd2hpY2ggdGhlIHVzZXIgaXMgZHJhZ2dpbmcsIG9yIHZpY2UgdmVyc2EuIFdlIGFkZCBpdCB0byB0aGVcclxuICAgICAgLy8gb2Zmc2V0IGluIG9yZGVyIHRvIHB1c2ggdGhlIGVsZW1lbnQgdG8gd2hlcmUgaXQgd2lsbCBiZSB3aGVuIGl0J3MgaW5saW5lIGFuZCBpcyBpbmZsdWVuY2VkXHJcbiAgICAgIC8vIGJ5IHRoZSBgbWFyZ2luYCBvZiBpdHMgc2libGluZ3MuXHJcbiAgICAgIGlmIChkZWx0YSA9PT0gLTEpIHtcclxuICAgICAgICBzaWJsaW5nT2Zmc2V0IC09IGltbWVkaWF0ZVNpYmxpbmcuY2xpZW50UmVjdFtzdGFydF0gLSBjdXJyZW50UG9zaXRpb25bZW5kXTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzaWJsaW5nT2Zmc2V0ICs9IGN1cnJlbnRQb3NpdGlvbltzdGFydF0gLSBpbW1lZGlhdGVTaWJsaW5nLmNsaWVudFJlY3RbZW5kXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBzaWJsaW5nT2Zmc2V0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2hlY2tzIHdoZXRoZXIgdGhlIHBvaW50ZXIgY29vcmRpbmF0ZXMgYXJlIGNsb3NlIHRvIHRoZSBkcm9wIGNvbnRhaW5lci5cclxuICAgKiBAcGFyYW0gcG9pbnRlclggQ29vcmRpbmF0ZXMgYWxvbmcgdGhlIFggYXhpcy5cclxuICAgKiBAcGFyYW0gcG9pbnRlclkgQ29vcmRpbmF0ZXMgYWxvbmcgdGhlIFkgYXhpcy5cclxuICAgKi9cclxuICBwcml2YXRlIF9pc1BvaW50ZXJOZWFyRHJvcENvbnRhaW5lcihwb2ludGVyWDogbnVtYmVyLCBwb2ludGVyWTogbnVtYmVyKTogYm9vbGVhbiB7XHJcbiAgICBjb25zdCB7dG9wLCByaWdodCwgYm90dG9tLCBsZWZ0LCB3aWR0aCwgaGVpZ2h0fSA9IHRoaXMuX2NsaWVudFJlY3Q7XHJcbiAgICBjb25zdCB4VGhyZXNob2xkID0gd2lkdGggKiBEUk9QX1BST1hJTUlUWV9USFJFU0hPTEQ7XHJcbiAgICBjb25zdCB5VGhyZXNob2xkID0gaGVpZ2h0ICogRFJPUF9QUk9YSU1JVFlfVEhSRVNIT0xEO1xyXG5cclxuICAgIHJldHVybiBwb2ludGVyWSA+IHRvcCAtIHlUaHJlc2hvbGQgJiYgcG9pbnRlclkgPCBib3R0b20gKyB5VGhyZXNob2xkICYmXHJcbiAgICAgICAgICAgcG9pbnRlclggPiBsZWZ0IC0geFRocmVzaG9sZCAmJiBwb2ludGVyWCA8IHJpZ2h0ICsgeFRocmVzaG9sZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgdGhlIG9mZnNldCBpbiBwaXhlbHMgYnkgd2hpY2ggdGhlIGl0ZW0gdGhhdCBpcyBiZWluZyBkcmFnZ2VkIHNob3VsZCBiZSBtb3ZlZC5cclxuICAgKiBAcGFyYW0gY3VycmVudFBvc2l0aW9uIEN1cnJlbnQgcG9zaXRpb24gb2YgdGhlIGl0ZW0uXHJcbiAgICogQHBhcmFtIG5ld1Bvc2l0aW9uIFBvc2l0aW9uIG9mIHRoZSBpdGVtIHdoZXJlIHRoZSBjdXJyZW50IGl0ZW0gc2hvdWxkIGJlIG1vdmVkLlxyXG4gICAqIEBwYXJhbSBkZWx0YSBEaXJlY3Rpb24gaW4gd2hpY2ggdGhlIHVzZXIgaXMgbW92aW5nLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgX2dldEl0ZW1PZmZzZXRQeChjdXJyZW50UG9zaXRpb246IENsaWVudFJlY3QsIG5ld1Bvc2l0aW9uOiBDbGllbnRSZWN0LCBkZWx0YTogMSB8IC0xKSB7XHJcbiAgICBjb25zdCBpc0hvcml6b250YWwgPSB0aGlzLl9vcmllbnRhdGlvbiA9PT0gJ2hvcml6b250YWwnO1xyXG4gICAgbGV0IGl0ZW1PZmZzZXQgPSBpc0hvcml6b250YWwgPyBuZXdQb3NpdGlvbi5sZWZ0IC0gY3VycmVudFBvc2l0aW9uLmxlZnQgOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdQb3NpdGlvbi50b3AgLSBjdXJyZW50UG9zaXRpb24udG9wO1xyXG5cclxuICAgIC8vIEFjY291bnQgZm9yIGRpZmZlcmVuY2VzIGluIHRoZSBpdGVtIHdpZHRoL2hlaWdodC5cclxuICAgIGlmIChkZWx0YSA9PT0gLTEpIHtcclxuICAgICAgaXRlbU9mZnNldCArPSBpc0hvcml6b250YWwgPyBuZXdQb3NpdGlvbi53aWR0aCAtIGN1cnJlbnRQb3NpdGlvbi53aWR0aCA6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3UG9zaXRpb24uaGVpZ2h0IC0gY3VycmVudFBvc2l0aW9uLmhlaWdodDtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gaXRlbU9mZnNldDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgdGhlIGluZGV4IG9mIGFuIGl0ZW0gaW4gdGhlIGRyb3AgY29udGFpbmVyLCBiYXNlZCBvbiB0aGUgcG9zaXRpb24gb2YgdGhlIHVzZXIncyBwb2ludGVyLlxyXG4gICAqIEBwYXJhbSBpdGVtIEl0ZW0gdGhhdCBpcyBiZWluZyBzb3J0ZWQuXHJcbiAgICogQHBhcmFtIHBvaW50ZXJYIFBvc2l0aW9uIG9mIHRoZSB1c2VyJ3MgcG9pbnRlciBhbG9uZyB0aGUgWCBheGlzLlxyXG4gICAqIEBwYXJhbSBwb2ludGVyWSBQb3NpdGlvbiBvZiB0aGUgdXNlcidzIHBvaW50ZXIgYWxvbmcgdGhlIFkgYXhpcy5cclxuICAgKiBAcGFyYW0gZGVsdGEgRGlyZWN0aW9uIGluIHdoaWNoIHRoZSB1c2VyIGlzIG1vdmluZyB0aGVpciBwb2ludGVyLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgX2dldEl0ZW1JbmRleEZyb21Qb2ludGVyUG9zaXRpb24oaXRlbTogRHJhZ1JlZiwgcG9pbnRlclg6IG51bWJlciwgcG9pbnRlclk6IG51bWJlcixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhPzoge3g6IG51bWJlciwgeTogbnVtYmVyfSkge1xyXG4gICAgY29uc3QgaXNIb3Jpem9udGFsID0gdGhpcy5fb3JpZW50YXRpb24gPT09ICdob3Jpem9udGFsJztcclxuXHJcbiAgICByZXR1cm4gZmluZEluZGV4KHRoaXMuX2l0ZW1Qb3NpdGlvbnMsICh7ZHJhZywgY2xpZW50UmVjdH0sIF8sIGFycmF5KSA9PiB7XHJcbiAgICAgIGlmIChkcmFnID09PSBpdGVtKSB7XHJcbiAgICAgICAgLy8gSWYgdGhlcmUncyBvbmx5IG9uZSBpdGVtIGxlZnQgaW4gdGhlIGNvbnRhaW5lciwgaXQgbXVzdCBiZVxyXG4gICAgICAgIC8vIHRoZSBkcmFnZ2VkIGl0ZW0gaXRzZWxmIHNvIHdlIHVzZSBpdCBhcyBhIHJlZmVyZW5jZS5cclxuICAgICAgICByZXR1cm4gYXJyYXkubGVuZ3RoIDwgMjtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGRlbHRhKSB7XHJcbiAgICAgICAgY29uc3QgZGlyZWN0aW9uID0gaXNIb3Jpem9udGFsID8gZGVsdGEueCA6IGRlbHRhLnk7XHJcblxyXG4gICAgICAgIC8vIElmIHRoZSB1c2VyIGlzIHN0aWxsIGhvdmVyaW5nIG92ZXIgdGhlIHNhbWUgaXRlbSBhcyBsYXN0IHRpbWUsIGFuZCB0aGV5IGRpZG4ndCBjaGFuZ2VcclxuICAgICAgICAvLyB0aGUgZGlyZWN0aW9uIGluIHdoaWNoIHRoZXkncmUgZHJhZ2dpbmcsIHdlIGRvbid0IGNvbnNpZGVyIGl0IGEgZGlyZWN0aW9uIHN3YXAuXHJcbiAgICAgICAgaWYgKGRyYWcgPT09IHRoaXMuX3ByZXZpb3VzU3dhcC5kcmFnICYmIGRpcmVjdGlvbiA9PT0gdGhpcy5fcHJldmlvdXNTd2FwLmRlbHRhKSB7XHJcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gaXNIb3Jpem9udGFsID9cclxuICAgICAgICAgIC8vIFJvdW5kIHRoZXNlIGRvd24gc2luY2UgbW9zdCBicm93c2VycyByZXBvcnQgY2xpZW50IHJlY3RzIHdpdGhcclxuICAgICAgICAgIC8vIHN1Yi1waXhlbCBwcmVjaXNpb24sIHdoZXJlYXMgdGhlIHBvaW50ZXIgY29vcmRpbmF0ZXMgYXJlIHJvdW5kZWQgdG8gcGl4ZWxzLlxyXG4gICAgICAgICAgcG9pbnRlclggPj0gTWF0aC5mbG9vcihjbGllbnRSZWN0LmxlZnQpICYmIHBvaW50ZXJYIDw9IE1hdGguZmxvb3IoY2xpZW50UmVjdC5yaWdodCkgOlxyXG4gICAgICAgICAgcG9pbnRlclkgPj0gTWF0aC5mbG9vcihjbGllbnRSZWN0LnRvcCkgJiYgcG9pbnRlclkgPD0gTWF0aC5mbG9vcihjbGllbnRSZWN0LmJvdHRvbSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrcyB3aGV0aGVyIHRoZSB1c2VyJ3MgcG9pbnRlciBpcyBwb3NpdGlvbmVkIG92ZXIgdGhlIGNvbnRhaW5lci5cclxuICAgKiBAcGFyYW0geCBQb2ludGVyIHBvc2l0aW9uIGFsb25nIHRoZSBYIGF4aXMuXHJcbiAgICogQHBhcmFtIHkgUG9pbnRlciBwb3NpdGlvbiBhbG9uZyB0aGUgWSBheGlzLlxyXG4gICAqL1xyXG4gIF9pc092ZXJDb250YWluZXIoeDogbnVtYmVyLCB5OiBudW1iZXIpOiBib29sZWFuIHtcclxuICAgIHJldHVybiBpc0luc2lkZUNsaWVudFJlY3QodGhpcy5fY2xpZW50UmVjdCwgeCwgeSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGaWd1cmVzIG91dCB3aGV0aGVyIGFuIGl0ZW0gc2hvdWxkIGJlIG1vdmVkIGludG8gYSBzaWJsaW5nXHJcbiAgICogZHJvcCBjb250YWluZXIsIGJhc2VkIG9uIGl0cyBjdXJyZW50IHBvc2l0aW9uLlxyXG4gICAqIEBwYXJhbSBpdGVtIERyYWcgaXRlbSB0aGF0IGlzIGJlaW5nIG1vdmVkLlxyXG4gICAqIEBwYXJhbSB4IFBvc2l0aW9uIG9mIHRoZSBpdGVtIGFsb25nIHRoZSBYIGF4aXMuXHJcbiAgICogQHBhcmFtIHkgUG9zaXRpb24gb2YgdGhlIGl0ZW0gYWxvbmcgdGhlIFkgYXhpcy5cclxuICAgKi9cclxuICBfZ2V0U2libGluZ0NvbnRhaW5lckZyb21Qb3NpdGlvbihpdGVtOiBEcmFnUmVmLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IERyb3BMaXN0UmVmIHwgdW5kZWZpbmVkIHtcclxuICAgIHJldHVybiB0aGlzLl9zaWJsaW5ncy5maW5kKHNpYmxpbmcgPT4gc2libGluZy5fY2FuUmVjZWl2ZShpdGVtLCB4LCB5KSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDaGVja3Mgd2hldGhlciB0aGUgZHJvcCBsaXN0IGNhbiByZWNlaXZlIHRoZSBwYXNzZWQtaW4gaXRlbS5cclxuICAgKiBAcGFyYW0gaXRlbSBJdGVtIHRoYXQgaXMgYmVpbmcgZHJhZ2dlZCBpbnRvIHRoZSBsaXN0LlxyXG4gICAqIEBwYXJhbSB4IFBvc2l0aW9uIG9mIHRoZSBpdGVtIGFsb25nIHRoZSBYIGF4aXMuXHJcbiAgICogQHBhcmFtIHkgUG9zaXRpb24gb2YgdGhlIGl0ZW0gYWxvbmcgdGhlIFkgYXhpcy5cclxuICAgKi9cclxuICBfY2FuUmVjZWl2ZShpdGVtOiBEcmFnUmVmLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgaWYgKCF0aGlzLmVudGVyUHJlZGljYXRlKGl0ZW0sIHRoaXMpIHx8ICFpc0luc2lkZUNsaWVudFJlY3QodGhpcy5fY2xpZW50UmVjdCwgeCwgeSkpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGVsZW1lbnRGcm9tUG9pbnQgPSB0aGlzLl9kb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KHgsIHkpO1xyXG5cclxuICAgIC8vIElmIHRoZXJlJ3Mgbm8gZWxlbWVudCBhdCB0aGUgcG9pbnRlciBwb3NpdGlvbiwgdGhlblxyXG4gICAgLy8gdGhlIGNsaWVudCByZWN0IGlzIHByb2JhYmx5IHNjcm9sbGVkIG91dCBvZiB0aGUgdmlldy5cclxuICAgIGlmICghZWxlbWVudEZyb21Qb2ludCkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGBDbGllbnRSZWN0YCwgdGhhdCB3ZSdyZSB1c2luZyB0byBmaW5kIHRoZSBjb250YWluZXIgb3ZlciB3aGljaCB0aGUgdXNlciBpc1xyXG4gICAgLy8gaG92ZXJpbmcsIGRvZXNuJ3QgZ2l2ZSB1cyBhbnkgaW5mb3JtYXRpb24gb24gd2hldGhlciB0aGUgZWxlbWVudCBoYXMgYmVlbiBzY3JvbGxlZFxyXG4gICAgLy8gb3V0IG9mIHRoZSB2aWV3IG9yIHdoZXRoZXIgaXQncyBvdmVybGFwcGluZyB3aXRoIG90aGVyIGNvbnRhaW5lcnMuIFRoaXMgbWVhbnMgdGhhdFxyXG4gICAgLy8gd2UgY291bGQgZW5kIHVwIHRyYW5zZmVycmluZyB0aGUgaXRlbSBpbnRvIGEgY29udGFpbmVyIHRoYXQncyBpbnZpc2libGUgb3IgaXMgcG9zaXRpb25lZFxyXG4gICAgLy8gYmVsb3cgYW5vdGhlciBvbmUuIFdlIHVzZSB0aGUgcmVzdWx0IGZyb20gYGVsZW1lbnRGcm9tUG9pbnRgIHRvIGdldCB0aGUgdG9wLW1vc3QgZWxlbWVudFxyXG4gICAgLy8gYXQgdGhlIHBvaW50ZXIgcG9zaXRpb24gYW5kIHRvIGZpbmQgd2hldGhlciBpdCdzIG9uZSBvZiB0aGUgaW50ZXJzZWN0aW5nIGRyb3AgY29udGFpbmVycy5cclxuICAgIHJldHVybiBlbGVtZW50RnJvbVBvaW50ID09PSB0aGlzLmVsZW1lbnQgfHwgdGhpcy5lbGVtZW50LmNvbnRhaW5zKGVsZW1lbnRGcm9tUG9pbnQpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2FsbGVkIGJ5IG9uZSBvZiB0aGUgY29ubmVjdGVkIGRyb3AgbGlzdHMgd2hlbiBhIGRyYWdnaW5nIHNlcXVlbmNlIGhhcyBzdGFydGVkLlxyXG4gICAqIEBwYXJhbSBzaWJsaW5nIFNpYmxpbmcgaW4gd2hpY2ggZHJhZ2dpbmcgaGFzIHN0YXJ0ZWQuXHJcbiAgICovXHJcbiAgX3N0YXJ0UmVjZWl2aW5nKHNpYmxpbmc6IERyb3BMaXN0UmVmKSB7XHJcbiAgICBjb25zdCBhY3RpdmVTaWJsaW5ncyA9IHRoaXMuX2FjdGl2ZVNpYmxpbmdzO1xyXG5cclxuICAgIGlmICghYWN0aXZlU2libGluZ3MuaGFzKHNpYmxpbmcpKSB7XHJcbiAgICAgIGFjdGl2ZVNpYmxpbmdzLmFkZChzaWJsaW5nKTtcclxuICAgICAgdGhpcy5fY2FjaGVPd25Qb3NpdGlvbigpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2FsbGVkIGJ5IGEgY29ubmVjdGVkIGRyb3AgbGlzdCB3aGVuIGRyYWdnaW5nIGhhcyBzdG9wcGVkLlxyXG4gICAqIEBwYXJhbSBzaWJsaW5nIFNpYmxpbmcgd2hvc2UgZHJhZ2dpbmcgaGFzIHN0b3BwZWQuXHJcbiAgICovXHJcbiAgX3N0b3BSZWNlaXZpbmcoc2libGluZzogRHJvcExpc3RSZWYpIHtcclxuICAgIHRoaXMuX2FjdGl2ZVNpYmxpbmdzLmRlbGV0ZShzaWJsaW5nKTtcclxuICB9XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgdG9wL2xlZnQgcG9zaXRpb25zIG9mIGEgYENsaWVudFJlY3RgLCBhcyB3ZWxsIGFzIHRoZWlyIGJvdHRvbS9yaWdodCBjb3VudGVycGFydHMuXHJcbiAqIEBwYXJhbSBjbGllbnRSZWN0IGBDbGllbnRSZWN0YCB0aGF0IHNob3VsZCBiZSB1cGRhdGVkLlxyXG4gKiBAcGFyYW0gdG9wIEFtb3VudCB0byBhZGQgdG8gdGhlIGB0b3BgIHBvc2l0aW9uLlxyXG4gKiBAcGFyYW0gbGVmdCBBbW91bnQgdG8gYWRkIHRvIHRoZSBgbGVmdGAgcG9zaXRpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiBhZGp1c3RDbGllbnRSZWN0KGNsaWVudFJlY3Q6IENsaWVudFJlY3QsIHRvcDogbnVtYmVyLCBsZWZ0OiBudW1iZXIpIHtcclxuICBjbGllbnRSZWN0LnRvcCArPSB0b3A7XHJcbiAgY2xpZW50UmVjdC5ib3R0b20gPSBjbGllbnRSZWN0LnRvcCArIGNsaWVudFJlY3QuaGVpZ2h0O1xyXG5cclxuICBjbGllbnRSZWN0LmxlZnQgKz0gbGVmdDtcclxuICBjbGllbnRSZWN0LnJpZ2h0ID0gY2xpZW50UmVjdC5sZWZ0ICsgY2xpZW50UmVjdC53aWR0aDtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBGaW5kcyB0aGUgaW5kZXggb2YgYW4gaXRlbSB0aGF0IG1hdGNoZXMgYSBwcmVkaWNhdGUgZnVuY3Rpb24uIFVzZWQgYXMgYW4gZXF1aXZhbGVudFxyXG4gKiBvZiBgQXJyYXkucHJvdG90eXBlLmZpbmRgIHdoaWNoIGlzbid0IHBhcnQgb2YgdGhlIHN0YW5kYXJkIEdvb2dsZSB0eXBpbmdzLlxyXG4gKiBAcGFyYW0gYXJyYXkgQXJyYXkgaW4gd2hpY2ggdG8gbG9vayBmb3IgbWF0Y2hlcy5cclxuICogQHBhcmFtIHByZWRpY2F0ZSBGdW5jdGlvbiB1c2VkIHRvIGRldGVybWluZSB3aGV0aGVyIGFuIGl0ZW0gaXMgYSBtYXRjaC5cclxuICovXHJcbmZ1bmN0aW9uIGZpbmRJbmRleDxUPihhcnJheTogVFtdLFxyXG4gICAgICAgICAgICAgICAgICAgICAgcHJlZGljYXRlOiAodmFsdWU6IFQsIGluZGV4OiBudW1iZXIsIG9iajogVFtdKSA9PiBib29sZWFuKTogbnVtYmVyIHtcclxuXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKykge1xyXG4gICAgaWYgKHByZWRpY2F0ZShhcnJheVtpXSwgaSwgYXJyYXkpKSB7XHJcbiAgICAgIHJldHVybiBpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIC0xO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB3aGV0aGVyIHNvbWUgY29vcmRpbmF0ZXMgYXJlIHdpdGhpbiBhIGBDbGllbnRSZWN0YC5cclxuICogQHBhcmFtIGNsaWVudFJlY3QgQ2xpZW50UmVjdCB0aGF0IGlzIGJlaW5nIGNoZWNrZWQuXHJcbiAqIEBwYXJhbSB4IENvb3JkaW5hdGVzIGFsb25nIHRoZSBYIGF4aXMuXHJcbiAqIEBwYXJhbSB5IENvb3JkaW5hdGVzIGFsb25nIHRoZSBZIGF4aXMuXHJcbiAqL1xyXG5mdW5jdGlvbiBpc0luc2lkZUNsaWVudFJlY3QoY2xpZW50UmVjdDogQ2xpZW50UmVjdCwgeDogbnVtYmVyLCB5OiBudW1iZXIpIHtcclxuICBjb25zdCB7dG9wLCBib3R0b20sIGxlZnQsIHJpZ2h0fSA9IGNsaWVudFJlY3Q7XHJcbiAgcmV0dXJuIHkgPj0gdG9wICYmIHkgPD0gYm90dG9tICYmIHggPj0gbGVmdCAmJiB4IDw9IHJpZ2h0O1xyXG59XHJcbiJdfQ==