@katoid/angular-grid-layout
Version:
Grid Layout with draggable and resizable items for Angular
110 lines • 21.1 kB
JavaScript
import { fromEvent, iif, merge } from 'rxjs';
import { filter } from 'rxjs/operators';
import { ktdNormalizePassiveListenerOptions } from './passive-listeners';
/** Options that can be used to bind a passive event listener. */
const passiveEventListenerOptions = ktdNormalizePassiveListenerOptions({ passive: true });
/** Options that can be used to bind an active event listener. */
const activeEventListenerOptions = ktdNormalizePassiveListenerOptions({ passive: false });
let isMobile = null;
export function ktdIsMobileOrTablet() {
if (isMobile != null) {
return isMobile;
}
// Generic match pattern to identify mobile or tablet devices
const isMobileDevice = /Android|webOS|BlackBerry|Windows Phone|iPad|iPhone|iPod/i.test(navigator.userAgent);
// Since IOS 13 is not safe to just check for the generic solution. See: https://stackoverflow.com/questions/58019463/how-to-detect-device-name-in-safari-on-ios-13-while-it-doesnt-show-the-correct
const isIOSMobileDevice = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
isMobile = isMobileDevice || isIOSMobileDevice;
return isMobile;
}
export function ktdIsMouseEvent(event) {
return event.clientX != null;
}
export function ktdIsTouchEvent(event) {
return event.touches != null && event.touches.length != null;
}
export function ktdPointerClientX(event) {
return ktdIsMouseEvent(event) ? event.clientX : event.touches[0].clientX;
}
export function ktdPointerClientY(event) {
return ktdIsMouseEvent(event) ? event.clientY : event.touches[0].clientY;
}
export function ktdPointerClient(event) {
return {
clientX: ktdIsMouseEvent(event) ? event.clientX : event.touches[0].clientX,
clientY: ktdIsMouseEvent(event) ? event.clientY : event.touches[0].clientY
};
}
export function ktdIsMouseEventOrMousePointerEvent(event) {
return event.type === 'mousedown'
|| (event.type === 'pointerdown' && event.pointerType === 'mouse');
}
/** Returns true if browser supports pointer events */
export function ktdSupportsPointerEvents() {
return !!window.PointerEvent;
}
/**
* Emits when a mousedown or touchstart emits. Avoids conflicts between both events.
* @param element, html element where to listen the events.
* @param touchNumber number of the touch to track the event, default to the first one.
*/
function ktdMouseOrTouchDown(element, touchNumber = 1) {
return iif(() => ktdIsMobileOrTablet(), fromEvent(element, 'touchstart', passiveEventListenerOptions).pipe(filter((touchEvent) => touchEvent.touches.length === touchNumber)), fromEvent(element, 'mousedown', activeEventListenerOptions).pipe(filter((mouseEvent) => {
/**
* 0 : Left mouse button
* 1 : Wheel button or middle button (if present)
* 2 : Right mouse button
*/
return mouseEvent.button === 0; // Mouse down to be only fired if is left click
})));
}
/**
* Emits when a 'mousemove' or a 'touchmove' event gets fired.
* @param element, html element where to listen the events.
* @param touchNumber number of the touch to track the event, default to the first one.
*/
function ktdMouseOrTouchMove(element, touchNumber = 1) {
return iif(() => ktdIsMobileOrTablet(), fromEvent(element, 'touchmove', activeEventListenerOptions).pipe(filter((touchEvent) => touchEvent.touches.length === touchNumber)), fromEvent(element, 'mousemove', activeEventListenerOptions));
}
export function ktdTouchEnd(element, touchNumber = 1) {
return merge(fromEvent(element, 'touchend').pipe(filter((touchEvent) => touchEvent.touches.length === touchNumber - 1)), fromEvent(element, 'touchcancel').pipe(filter((touchEvent) => touchEvent.touches.length === touchNumber - 1)));
}
/**
* Emits when a there is a 'mouseup' or the touch ends.
* @param element, html element where to listen the events.
* @param touchNumber number of the touch to track the event, default to the first one.
*/
function ktdMouserOrTouchEnd(element, touchNumber = 1) {
return iif(() => ktdIsMobileOrTablet(), ktdTouchEnd(element, touchNumber), fromEvent(element, 'mouseup'));
}
/**
* Emits when a 'pointerdown' event occurs (only for the primary pointer). Fallbacks to 'mousemove' or a 'touchmove' if pointer events are not supported.
* @param element, html element where to listen the events.
*/
export function ktdPointerDown(element) {
if (!ktdSupportsPointerEvents()) {
return ktdMouseOrTouchDown(element);
}
return fromEvent(element, 'pointerdown', activeEventListenerOptions).pipe(filter((pointerEvent) => pointerEvent.isPrimary));
}
/**
* Emits when a 'pointermove' event occurs (only for the primary pointer). Fallbacks to 'mousemove' or a 'touchmove' if pointer events are not supported.
* @param element, html element where to listen the events.
*/
export function ktdPointerMove(element) {
if (!ktdSupportsPointerEvents()) {
return ktdMouseOrTouchMove(element);
}
return fromEvent(element, 'pointermove', activeEventListenerOptions).pipe(filter((pointerEvent) => pointerEvent.isPrimary));
}
/**
* Emits when a 'pointerup' event occurs (only for the primary pointer). Fallbacks to 'mousemove' or a 'touchmove' if pointer events are not supported.
* @param element, html element where to listen the events.
*/
export function ktdPointerUp(element) {
if (!ktdSupportsPointerEvents()) {
return ktdMouserOrTouchEnd(element);
}
return fromEvent(element, 'pointerup').pipe(filter(pointerEvent => pointerEvent.isPrimary));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9pbnRlci51dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItZ3JpZC1sYXlvdXQvc3JjL2xpYi91dGlscy9wb2ludGVyLnV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBYyxNQUFNLE1BQU0sQ0FBQztBQUN6RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFekUsaUVBQWlFO0FBQ2pFLE1BQU0sMkJBQTJCLEdBQUcsa0NBQWtDLENBQUMsRUFBQyxPQUFPLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQztBQUV4RixpRUFBaUU7QUFDakUsTUFBTSwwQkFBMEIsR0FBRyxrQ0FBa0MsQ0FBQyxFQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFDO0FBRXhGLElBQUksUUFBUSxHQUFtQixJQUFJLENBQUM7QUFFcEMsTUFBTSxVQUFVLG1CQUFtQjtJQUUvQixJQUFJLFFBQVEsSUFBSSxJQUFJLEVBQUU7UUFDbEIsT0FBTyxRQUFRLENBQUM7S0FDbkI7SUFFRCw2REFBNkQ7SUFDN0QsTUFBTSxjQUFjLEdBQUcsMERBQTBELENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUU1RyxvTUFBb007SUFDcE0sTUFBTSxpQkFBaUIsR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsS0FBSyxVQUFVLElBQUksU0FBUyxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUU3SSxRQUFRLEdBQUcsY0FBYyxJQUFJLGlCQUFpQixDQUFDO0lBRS9DLE9BQU8sUUFBUSxDQUFDO0FBQ3BCLENBQUM7QUFF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OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxPQUFPO0lBQ2xDLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxFQUFFO1FBQzdCLE9BQU8sbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7S0FDdkM7SUFDRCxPQUFPLFNBQVMsQ0FBZSxPQUFPLEVBQUUsYUFBYSxFQUFFLDBCQUFxRCxDQUFDLENBQUMsSUFBSSxDQUM5RyxNQUFNLENBQUMsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FDbkQsQ0FBQztBQUNOLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUFDLE9BQU87SUFDaEMsSUFBSSxDQUFDLHdCQUF3QixFQUFFLEVBQUU7UUFDN0IsT0FBTyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztLQUN2QztJQUNELE9BQU8sU0FBUyxDQUFlLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7QUFDOUcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGZyb21FdmVudCwgaWlmLCBtZXJnZSwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBmaWx0ZXIgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XHJcbmltcG9ydCB7IGt0ZE5vcm1hbGl6ZVBhc3NpdmVMaXN0ZW5lck9wdGlvbnMgfSBmcm9tICcuL3Bhc3NpdmUtbGlzdGVuZXJzJztcclxuXHJcbi8qKiBPcHRpb25zIHRoYXQgY2FuIGJlIHVzZWQgdG8gYmluZCBhIHBhc3NpdmUgZXZlbnQgbGlzdGVuZXIuICovXHJcbmNvbnN0IHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9ucyA9IGt0ZE5vcm1hbGl6ZVBhc3NpdmVMaXN0ZW5lck9wdGlvbnMoe3Bhc3NpdmU6IHRydWV9KTtcclxuXHJcbi8qKiBPcHRpb25zIHRoYXQgY2FuIGJlIHVzZWQgdG8gYmluZCBhbiBhY3RpdmUgZXZlbnQgbGlzdGVuZXIuICovXHJcbmNvbnN0IGFjdGl2ZUV2ZW50TGlzdGVuZXJPcHRpb25zID0ga3RkTm9ybWFsaXplUGFzc2l2ZUxpc3RlbmVyT3B0aW9ucyh7cGFzc2l2ZTogZmFsc2V9KTtcclxuXHJcbmxldCBpc01vYmlsZTogYm9vbGVhbiB8IG51bGwgPSBudWxsO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGt0ZElzTW9iaWxlT3JUYWJsZXQoKTogYm9vbGVhbiB7XHJcblxyXG4gICAgaWYgKGlzTW9iaWxlICE9IG51bGwpIHtcclxuICAgICAgICByZXR1cm4gaXNNb2JpbGU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2VuZXJpYyBtYXRjaCBwYXR0ZXJuIHRvIGlkZW50aWZ5IG1vYmlsZSBvciB0YWJsZXQgZGV2aWNlc1xyXG4gICAgY29uc3QgaXNNb2JpbGVEZXZpY2UgPSAvQW5kcm9pZHx3ZWJPU3xCbGFja0JlcnJ5fFdpbmRvd3MgUGhvbmV8aVBhZHxpUGhvbmV8aVBvZC9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCk7XHJcblxyXG4gICAgLy8gU2luY2UgSU9TIDEzIGlzIG5vdCBzYWZlIHRvIGp1c3QgY2hlY2sgZm9yIHRoZSBnZW5lcmljIHNvbHV0aW9uLiBTZWU6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU4MDE5NDYzL2hvdy10by1kZXRlY3QtZGV2aWNlLW5hbWUtaW4tc2FmYXJpLW9uLWlvcy0xMy13aGlsZS1pdC1kb2VzbnQtc2hvdy10aGUtY29ycmVjdFxyXG4gICAgY29uc3QgaXNJT1NNb2JpbGVEZXZpY2UgPSAvaVBhZHxpUGhvbmV8aVBvZC8udGVzdChuYXZpZ2F0b3IucGxhdGZvcm0pIHx8IChuYXZpZ2F0b3IucGxhdGZvcm0gPT09ICdNYWNJbnRlbCcgJiYgbmF2aWdhdG9yLm1heFRvdWNoUG9pbnRzID4gMSk7XHJcblxyXG4gICAgaXNNb2JpbGUgPSBpc01vYmlsZURldmljZSB8fCBpc0lPU01vYmlsZURldmljZTtcclxuXHJcbiAgICByZXR1cm4gaXNNb2JpbGU7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBrdGRJc01vdXNlRXZlbnQoZXZlbnQ6IGFueSk6IGV2ZW50IGlzIE1vdXNlRXZlbnQge1xyXG4gICAgcmV0dXJuIChldmVudCBhcyBNb3VzZUV2ZW50KS5jbGllbnRYICE9IG51bGw7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBrdGRJc1RvdWNoRXZlbnQoZXZlbnQ6IGFueSk6IGV2ZW50IGlzIFRvdWNoRXZlbnQge1xyXG4gICAgcmV0dXJuIChldmVudCBhcyBUb3VjaEV2ZW50KS50b3VjaGVzICE9IG51bGwgJiYgKGV2ZW50IGFzIFRvdWNoRXZlbnQpLnRvdWNoZXMubGVuZ3RoICE9IG51bGw7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBrdGRQb2ludGVyQ2xpZW50WChldmVudDogTW91c2VFdmVudCB8IFRvdWNoRXZlbnQpOiBudW1iZXIge1xyXG4gICAgcmV0dXJuIGt0ZElzTW91c2VFdmVudChldmVudCkgPyBldmVudC5jbGllbnRYIDogZXZlbnQudG91Y2hlc1swXS5jbGllbnRYO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24ga3RkUG9pbnRlckNsaWVudFkoZXZlbnQ6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KTogbnVtYmVyIHtcclxuICAgIHJldHVybiBrdGRJc01vdXNlRXZlbnQoZXZlbnQpID8gZXZlbnQuY2xpZW50WSA6IGV2ZW50LnRvdWNoZXNbMF0uY2xpZW50WTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGt0ZFBvaW50ZXJDbGllbnQoZXZlbnQ6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KTogeyBjbGllbnRYOiBudW1iZXIsIGNsaWVudFk6IG51bWJlciB9IHtcclxuICAgIHJldHVybiB7XHJcbiAgICAgICAgY2xpZW50WDoga3RkSXNNb3VzZUV2ZW50KGV2ZW50KSA/IGV2ZW50LmNsaWVudFggOiBldmVudC50b3VjaGVzWzBdLmNsaWVudFgsXHJcbiAgICAgICAgY2xpZW50WToga3RkSXNNb3VzZUV2ZW50KGV2ZW50KSA/IGV2ZW50LmNsaWVudFkgOiBldmVudC50b3VjaGVzWzBdLmNsaWVudFlcclxuICAgIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBrdGRJc01vdXNlRXZlbnRPck1vdXNlUG9pbnRlckV2ZW50KGV2ZW50OiBNb3VzZUV2ZW50IHwgVG91Y2hFdmVudCB8IFBvaW50ZXJFdmVudCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIGV2ZW50LnR5cGUgPT09ICdtb3VzZWRvd24nXHJcbiAgICAgICAgfHwgKGV2ZW50LnR5cGUgPT09ICdwb2ludGVyZG93bicgJiYgKGV2ZW50IGFzIFBvaW50ZXJFdmVudCkucG9pbnRlclR5cGUgPT09ICdtb3VzZScpO1xyXG59XHJcblxyXG4vKiogUmV0dXJucyB0cnVlIGlmIGJyb3dzZXIgc3VwcG9ydHMgcG9pbnRlciBldmVudHMgKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGt0ZFN1cHBvcnRzUG9pbnRlckV2ZW50cygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAhIXdpbmRvdy5Qb2ludGVyRXZlbnQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbWl0cyB3aGVuIGEgbW91c2Vkb3duIG9yIHRvdWNoc3RhcnQgZW1pdHMuIEF2b2lkcyBjb25mbGljdHMgYmV0d2VlbiBib3RoIGV2ZW50cy5cclxuICogQHBhcmFtIGVsZW1lbnQsIGh0bWwgZWxlbWVudCB3aGVyZSB0byAgbGlzdGVuIHRoZSBldmVudHMuXHJcbiAqIEBwYXJhbSB0b3VjaE51bWJlciBudW1iZXIgb2YgdGhlIHRvdWNoIHRvIHRyYWNrIHRoZSBldmVudCwgZGVmYXVsdCB0byB0aGUgZmlyc3Qgb25lLlxyXG4gKi9cclxuZnVuY3Rpb24ga3RkTW91c2VPclRvdWNoRG93bihlbGVtZW50LCB0b3VjaE51bWJlciA9IDEpOiBPYnNlcnZhYmxlPE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50PiB7XHJcbiAgICByZXR1cm4gaWlmKFxyXG4gICAgICAgICgpID0+IGt0ZElzTW9iaWxlT3JUYWJsZXQoKSxcclxuICAgICAgICBmcm9tRXZlbnQ8VG91Y2hFdmVudD4oZWxlbWVudCwgJ3RvdWNoc3RhcnQnLCBwYXNzaXZlRXZlbnRMaXN0ZW5lck9wdGlvbnMgYXMgQWRkRXZlbnRMaXN0ZW5lck9wdGlvbnMpLnBpcGUoXHJcbiAgICAgICAgICAgIGZpbHRlcigodG91Y2hFdmVudCkgPT4gdG91Y2hFdmVudC50b3VjaGVzLmxlbmd0aCA9PT0gdG91Y2hOdW1iZXIpXHJcbiAgICAgICAgKSxcclxuICAgICAgICBmcm9tRXZlbnQ8TW91c2VFdmVudD4oZWxlbWVudCwgJ21vdXNlZG93bicsIGFjdGl2ZUV2ZW50TGlzdGVuZXJPcHRpb25zIGFzIEFkZEV2ZW50TGlzdGVuZXJPcHRpb25zKS5waXBlKFxyXG4gICAgICAgICAgICBmaWx0ZXIoKG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgICAgIC8qKlxyXG4gICAgICAgICAgICAgICAgICogMCA6IExlZnQgbW91c2UgYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAgKiAxIDogV2hlZWwgYnV0dG9uIG9yIG1pZGRsZSBidXR0b24gKGlmIHByZXNlbnQpXHJcbiAgICAgICAgICAgICAgICAgKiAyIDogUmlnaHQgbW91c2UgYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAgKi9cclxuICAgICAgICAgICAgICAgIHJldHVybiBtb3VzZUV2ZW50LmJ1dHRvbiA9PT0gMDsgLy8gTW91c2UgZG93biB0byBiZSBvbmx5IGZpcmVkIGlmIGlzIGxlZnQgY2xpY2tcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICApXHJcbiAgICApO1xyXG59XHJcblxyXG4vKipcclxuICogRW1pdHMgd2hlbiBhICdtb3VzZW1vdmUnIG9yIGEgJ3RvdWNobW92ZScgZXZlbnQgZ2V0cyBmaXJlZC5cclxuICogQHBhcmFtIGVsZW1lbnQsIGh0bWwgZWxlbWVudCB3aGVyZSB0byAgbGlzdGVuIHRoZSBldmVudHMuXHJcbiAqIEBwYXJhbSB0b3VjaE51bWJlciBudW1iZXIgb2YgdGhlIHRvdWNoIHRvIHRyYWNrIHRoZSBldmVudCwgZGVmYXVsdCB0byB0aGUgZmlyc3Qgb25lLlxyXG4gKi9cclxuZnVuY3Rpb24ga3RkTW91c2VPclRvdWNoTW92ZShlbGVtZW50OiBIVE1MRWxlbWVudCwgdG91Y2hOdW1iZXIgPSAxKTogT2JzZXJ2YWJsZTxNb3VzZUV2ZW50IHwgVG91Y2hFdmVudD4ge1xyXG4gICAgcmV0dXJuIGlpZihcclxuICAgICAgICAoKSA9PiBrdGRJc01vYmlsZU9yVGFibGV0KCksXHJcbiAgICAgICAgZnJvbUV2ZW50PFRvdWNoRXZlbnQ+KGVsZW1lbnQsICd0b3VjaG1vdmUnLCBhY3RpdmVFdmVudExpc3RlbmVyT3B0aW9ucyBhcyBBZGRFdmVudExpc3RlbmVyT3B0aW9ucykucGlwZShcclxuICAgICAgICAgICAgZmlsdGVyKCh0b3VjaEV2ZW50KSA9PiB0b3VjaEV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSB0b3VjaE51bWJlciksXHJcbiAgICAgICAgKSxcclxuICAgICAgICBmcm9tRXZlbnQ8TW91c2VFdmVudD4oZWxlbWVudCwgJ21vdXNlbW92ZScsIGFjdGl2ZUV2ZW50TGlzdGVuZXJPcHRpb25zIGFzIEFkZEV2ZW50TGlzdGVuZXJPcHRpb25zKVxyXG4gICAgKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGt0ZFRvdWNoRW5kKGVsZW1lbnQsIHRvdWNoTnVtYmVyID0gMSk6IE9ic2VydmFibGU8VG91Y2hFdmVudD4ge1xyXG4gICAgcmV0dXJuIG1lcmdlKFxyXG4gICAgICAgIGZyb21FdmVudDxUb3VjaEV2ZW50PihlbGVtZW50LCAndG91Y2hlbmQnKS5waXBlKFxyXG4gICAgICAgICAgICBmaWx0ZXIoKHRvdWNoRXZlbnQpID0+IHRvdWNoRXZlbnQudG91Y2hlcy5sZW5ndGggPT09IHRvdWNoTnVtYmVyIC0gMSlcclxuICAgICAgICApLFxyXG4gICAgICAgIGZyb21FdmVudDxUb3VjaEV2ZW50PihlbGVtZW50LCAndG91Y2hjYW5jZWwnKS5waXBlKFxyXG4gICAgICAgICAgICBmaWx0ZXIoKHRvdWNoRXZlbnQpID0+IHRvdWNoRXZlbnQudG91Y2hlcy5sZW5ndGggPT09IHRvdWNoTnVtYmVyIC0gMSlcclxuICAgICAgICApXHJcbiAgICApO1xyXG59XHJcblxyXG4vKipcclxuICogRW1pdHMgd2hlbiBhIHRoZXJlIGlzIGEgJ21vdXNldXAnIG9yIHRoZSB0b3VjaCBlbmRzLlxyXG4gKiBAcGFyYW0gZWxlbWVudCwgaHRtbCBlbGVtZW50IHdoZXJlIHRvICBsaXN0ZW4gdGhlIGV2ZW50cy5cclxuICogQHBhcmFtIHRvdWNoTnVtYmVyIG51bWJlciBvZiB0aGUgdG91Y2ggdG8gdHJhY2sgdGhlIGV2ZW50LCBkZWZhdWx0IHRvIHRoZSBmaXJzdCBvbmUuXHJcbiAqL1xyXG5mdW5jdGlvbiBrdGRNb3VzZXJPclRvdWNoRW5kKGVsZW1lbnQ6IEhUTUxFbGVtZW50LCB0b3VjaE51bWJlciA9IDEpOiBPYnNlcnZhYmxlPE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50PiB7XHJcbiAgICByZXR1cm4gaWlmKFxyXG4gICAgICAgICgpID0+IGt0ZElzTW9iaWxlT3JUYWJsZXQoKSxcclxuICAgICAgICBrdGRUb3VjaEVuZChlbGVtZW50LCB0b3VjaE51bWJlciksXHJcbiAgICAgICAgZnJvbUV2ZW50PE1vdXNlRXZlbnQ+KGVsZW1lbnQsICdtb3VzZXVwJyksXHJcbiAgICApO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIEVtaXRzIHdoZW4gYSAncG9pbnRlcmRvd24nIGV2ZW50IG9jY3VycyAob25seSBmb3IgdGhlIHByaW1hcnkgcG9pbnRlcikuIEZhbGxiYWNrcyB0byAnbW91c2Vtb3ZlJyBvciBhICd0b3VjaG1vdmUnIGlmIHBvaW50ZXIgZXZlbnRzIGFyZSBub3Qgc3VwcG9ydGVkLlxyXG4gKiBAcGFyYW0gZWxlbWVudCwgaHRtbCBlbGVtZW50IHdoZXJlIHRvIGxpc3RlbiB0aGUgZXZlbnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGt0ZFBvaW50ZXJEb3duKGVsZW1lbnQpOiBPYnNlcnZhYmxlPE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50IHwgUG9pbnRlckV2ZW50PiB7XHJcbiAgICBpZiAoIWt0ZFN1cHBvcnRzUG9pbnRlckV2ZW50cygpKSB7XHJcbiAgICAgICAgcmV0dXJuIGt0ZE1vdXNlT3JUb3VjaERvd24oZWxlbWVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGZyb21FdmVudDxQb2ludGVyRXZlbnQ+KGVsZW1lbnQsICdwb2ludGVyZG93bicsIGFjdGl2ZUV2ZW50TGlzdGVuZXJPcHRpb25zIGFzIEFkZEV2ZW50TGlzdGVuZXJPcHRpb25zKS5waXBlKFxyXG4gICAgICAgIGZpbHRlcigocG9pbnRlckV2ZW50KSA9PiBwb2ludGVyRXZlbnQuaXNQcmltYXJ5KVxyXG4gICAgKVxyXG59XHJcblxyXG4vKipcclxuICogRW1pdHMgd2hlbiBhICdwb2ludGVybW92ZScgZXZlbnQgb2NjdXJzIChvbmx5IGZvciB0aGUgcHJpbWFyeSBwb2ludGVyKS4gRmFsbGJhY2tzIHRvICdtb3VzZW1vdmUnIG9yIGEgJ3RvdWNobW92ZScgaWYgcG9pbnRlciBldmVudHMgYXJlIG5vdCBzdXBwb3J0ZWQuXHJcbiAqIEBwYXJhbSBlbGVtZW50LCBodG1sIGVsZW1lbnQgd2hlcmUgdG8gbGlzdGVuIHRoZSBldmVudHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24ga3RkUG9pbnRlck1vdmUoZWxlbWVudCk6IE9ic2VydmFibGU8TW91c2VFdmVudCB8IFRvdWNoRXZlbnQgfCBQb2ludGVyRXZlbnQ+IHtcclxuICAgIGlmICgha3RkU3VwcG9ydHNQb2ludGVyRXZlbnRzKCkpIHtcclxuICAgICAgICByZXR1cm4ga3RkTW91c2VPclRvdWNoTW92ZShlbGVtZW50KTtcclxuICAgIH1cclxuICAgIHJldHVybiBmcm9tRXZlbnQ8UG9pbnRlckV2ZW50PihlbGVtZW50LCAncG9pbnRlcm1vdmUnLCBhY3RpdmVFdmVudExpc3RlbmVyT3B0aW9ucyBhcyBBZGRFdmVudExpc3RlbmVyT3B0aW9ucykucGlwZShcclxuICAgICAgICBmaWx0ZXIoKHBvaW50ZXJFdmVudCkgPT4gcG9pbnRlckV2ZW50LmlzUHJpbWFyeSksXHJcbiAgICApO1xyXG59XHJcblxyXG4vKipcclxuICogRW1pdHMgd2hlbiBhICdwb2ludGVydXAnIGV2ZW50IG9jY3VycyAob25seSBmb3IgdGhlIHByaW1hcnkgcG9pbnRlcikuIEZhbGxiYWNrcyB0byAnbW91c2Vtb3ZlJyBvciBhICd0b3VjaG1vdmUnIGlmIHBvaW50ZXIgZXZlbnRzIGFyZSBub3Qgc3VwcG9ydGVkLlxyXG4gKiBAcGFyYW0gZWxlbWVudCwgaHRtbCBlbGVtZW50IHdoZXJlIHRvIGxpc3RlbiB0aGUgZXZlbnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGt0ZFBvaW50ZXJVcChlbGVtZW50KTogT2JzZXJ2YWJsZTxNb3VzZUV2ZW50IHwgVG91Y2hFdmVudCB8IFBvaW50ZXJFdmVudD4ge1xyXG4gICAgaWYgKCFrdGRTdXBwb3J0c1BvaW50ZXJFdmVudHMoKSkge1xyXG4gICAgICAgIHJldHVybiBrdGRNb3VzZXJPclRvdWNoRW5kKGVsZW1lbnQpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGZyb21FdmVudDxQb2ludGVyRXZlbnQ+KGVsZW1lbnQsICdwb2ludGVydXAnKS5waXBlKGZpbHRlcihwb2ludGVyRXZlbnQgPT4gcG9pbnRlckV2ZW50LmlzUHJpbWFyeSkpO1xyXG59XHJcbiJdfQ==