angular-grid-layout-ngx13
Version:
Grid Layout with draggable and resizable items for Angular
72 lines • 14.7 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
};
}
/**
* 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.
*/
export 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.
*/
export 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.
*/
export function ktdMouseOrTouchEnd(element, touchNumber = 1) {
return iif(() => ktdIsMobileOrTablet(), ktdTouchEnd(element, touchNumber), fromEvent(element, 'mouseup'));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9pbnRlci51dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItZ3JpZC1sYXlvdXQvc3JjL2xpYi91dGlscy9wb2ludGVyLnV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBYyxNQUFNLE1BQU0sQ0FBQztBQUN6RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFekUsaUVBQWlFO0FBQ2pFLE1BQU0sMkJBQTJCLEdBQUcsa0NBQWtDLENBQUMsRUFBQyxPQUFPLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQztBQUV4RixpRUFBaUU7QUFDakUsTUFBTSwwQkFBMEIsR0FBRyxrQ0FBa0MsQ0FBQyxFQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFDO0FBRXhGLElBQUksUUFBUSxHQUFtQixJQUFJLENBQUM7QUFFcEMsTUFBTSxVQUFVLG1CQUFtQjtJQUUvQixJQUFJLFFBQVEsSUFBSSxJQUFJLEVBQUU7UUFDbEIsT0FBTyxRQUFRLENBQUM7S0FDbkI7SUFFRCw2REFBNkQ7SUFDN0QsTUFBTSxjQUFjLEdBQUcsMERBQTBELENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUU1RyxvTUFBb007SUFDcE0sTUFBTSxpQkFBaUIsR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsS0FBSyxVQUFVLElBQUksU0FBUyxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUU3SSxRQUFRLEdBQUcsY0FBYyxJQUFJLGlCQUFpQixDQUFDO0lBRS9DLE9BQU8sUUFBUSxDQUFDO0FBQ3BCLENBQUM7QUFFRCxNQUFNLFVBQVUsZUFBZSxDQUFDLEtBQVU7SUFDdEMsT0FBUSxLQUFvQixDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUM7QUFDakQsQ0FBQztBQUVELE1BQU0sVUFBVSxlQUFlLENBQUMsS0FBVTtJQUN0QyxPQUFRLEtBQW9CLENBQUMsT0FBTyxJQUFJLElBQUksSUFBSyxLQUFvQixDQUFDLE9BQU8sQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDO0FBQ2pHLENBQUM7QUFFRCxNQUFNLFVBQVUsaUJBQWlCLENBQUMsS0FBOEI7SUFDNUQsT0FBTyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO0FBQzdFLENBQUM7QUFFRCxNQUFNLFVBQVUsaUJBQWlCLENBQUMsS0FBOEI7SUFDNUQsT0FBTyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO0FBQzdFLENBQUM7QUFFRCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsS0FBOEI7SUFDM0QsT0FBUTtRQUNKLE9BQU8sRUFBRSxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTztRQUMxRSxPQUFPLEVBQUUsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU87S0FDN0UsQ0FBQztBQUNOLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxXQUFXLEdBQUcsQ0FBQztJQUN4RCxPQUFPLEdBQUcsQ0FDTixHQUFHLEVBQUUsQ0FBQyxtQkFBbUIsRUFBRSxFQUMzQixTQUFTLENBQWEsT0FBTyxFQUFFLFlBQVksRUFBRSwyQkFBc0QsQ0FBQyxDQUFDLElBQUksQ0FDckcsTUFBTSxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxXQUFXLENBQUMsQ0FDcEUsRUFDRCxTQUFTLENBQWEsT0FBTyxFQUFFLFdBQVcsRUFBRSwwQkFBcUQsQ0FBQyxDQUFDLElBQUksQ0FDbkcsTUFBTSxDQUFDLENBQUMsVUFBc0IsRUFBRSxFQUFFO1FBQzlCOzs7O1dBSUc7UUFDSCxPQUFPLFVBQVUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsK0NBQStDO0lBQ25GLENBQUMsQ0FBQyxDQUNMLENBQ0osQ0FBQztBQUNOLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxXQUFXLEdBQUcsQ0FBQztJQUN4RCxPQUFPLEdBQUcsQ0FDTixHQUFHLEVBQUUsQ0FBQyxtQkFBbUIsRUFBRSxFQUMzQixTQUFTLENBQWEsT0FBTyxFQUFFLFdBQVcsRUFBRSwwQkFBcUQsQ0FBQyxDQUFDLElBQUksQ0FDbkcsTUFBTSxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxXQUFXLENBQUMsQ0FDcEUsRUFDRCxTQUFTLENBQWEsT0FBTyxFQUFFLFdBQVcsRUFBRSwwQkFBcUQsQ0FBQyxDQUNyRyxDQUFDO0FBQ04sQ0FBQztBQUVELE1BQU0sVUFBVSxXQUFXLENBQUMsT0FBTyxFQUFFLFdBQVcsR0FBRyxDQUFDO0lBQ2hELE9BQU8sS0FBSyxDQUNSLFNBQVMsQ0FBYSxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUMzQyxNQUFNLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsTUFBTSxLQUFLLFdBQVcsR0FBRyxDQUFDLENBQUMsQ0FDeEUsRUFDRCxTQUFTLENBQWEsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFDLElBQUksQ0FDOUMsTUFBTSxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQ3hFLENBQ0osQ0FBQztBQUNOLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGtCQUFrQixDQUFDLE9BQU8sRUFBRSxXQUFXLEdBQUcsQ0FBQztJQUN2RCxPQUFPLEdBQUcsQ0FDTixHQUFHLEVBQUUsQ0FBQyxtQkFBbUIsRUFBRSxFQUMzQixXQUFXLENBQUMsT0FBTyxFQUFFLFdBQVcsQ0FBQyxFQUNqQyxTQUFTLENBQWEsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUM1QyxDQUFDO0FBQ04sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGZyb21FdmVudCwgaWlmLCBtZXJnZSwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmlsdGVyIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsga3RkTm9ybWFsaXplUGFzc2l2ZUxpc3RlbmVyT3B0aW9ucyB9IGZyb20gJy4vcGFzc2l2ZS1saXN0ZW5lcnMnO1xuXG4vKiogT3B0aW9ucyB0aGF0IGNhbiBiZSB1c2VkIHRvIGJpbmQgYSBwYXNzaXZlIGV2ZW50IGxpc3RlbmVyLiAqL1xuY29uc3QgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zID0ga3RkTm9ybWFsaXplUGFzc2l2ZUxpc3RlbmVyT3B0aW9ucyh7cGFzc2l2ZTogdHJ1ZX0pO1xuXG4vKiogT3B0aW9ucyB0aGF0IGNhbiBiZSB1c2VkIHRvIGJpbmQgYW4gYWN0aXZlIGV2ZW50IGxpc3RlbmVyLiAqL1xuY29uc3QgYWN0aXZlRXZlbnRMaXN0ZW5lck9wdGlvbnMgPSBrdGROb3JtYWxpemVQYXNzaXZlTGlzdGVuZXJPcHRpb25zKHtwYXNzaXZlOiBmYWxzZX0pO1xuXG5sZXQgaXNNb2JpbGU6IGJvb2xlYW4gfCBudWxsID0gbnVsbDtcblxuZXhwb3J0IGZ1bmN0aW9uIGt0ZElzTW9iaWxlT3JUYWJsZXQoKTogYm9vbGVhbiB7XG5cbiAgICBpZiAoaXNNb2JpbGUgIT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gaXNNb2JpbGU7XG4gICAgfVxuXG4gICAgLy8gR2VuZXJpYyBtYXRjaCBwYXR0ZXJuIHRvIGlkZW50aWZ5IG1vYmlsZSBvciB0YWJsZXQgZGV2aWNlc1xuICAgIGNvbnN0IGlzTW9iaWxlRGV2aWNlID0gL0FuZHJvaWR8d2ViT1N8QmxhY2tCZXJyeXxXaW5kb3dzIFBob25lfGlQYWR8aVBob25lfGlQb2QvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuXG4gICAgLy8gU2luY2UgSU9TIDEzIGlzIG5vdCBzYWZlIHRvIGp1c3QgY2hlY2sgZm9yIHRoZSBnZW5lcmljIHNvbHV0aW9uLiBTZWU6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU4MDE5NDYzL2hvdy10by1kZXRlY3QtZGV2aWNlLW5hbWUtaW4tc2FmYXJpLW9uLWlvcy0xMy13aGlsZS1pdC1kb2VzbnQtc2hvdy10aGUtY29ycmVjdFxuICAgIGNvbnN0IGlzSU9TTW9iaWxlRGV2aWNlID0gL2lQYWR8aVBob25lfGlQb2QvLnRlc3QobmF2aWdhdG9yLnBsYXRmb3JtKSB8fCAobmF2aWdhdG9yLnBsYXRmb3JtID09PSAnTWFjSW50ZWwnICYmIG5hdmlnYXRvci5tYXhUb3VjaFBvaW50cyA+IDEpO1xuXG4gICAgaXNNb2JpbGUgPSBpc01vYmlsZURldmljZSB8fCBpc0lPU01vYmlsZURldmljZTtcblxuICAgIHJldHVybiBpc01vYmlsZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGt0ZElzTW91c2VFdmVudChldmVudDogYW55KTogZXZlbnQgaXMgTW91c2VFdmVudCB7XG4gICAgcmV0dXJuIChldmVudCBhcyBNb3VzZUV2ZW50KS5jbGllbnRYICE9IG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBrdGRJc1RvdWNoRXZlbnQoZXZlbnQ6IGFueSk6IGV2ZW50IGlzIFRvdWNoRXZlbnQge1xuICAgIHJldHVybiAoZXZlbnQgYXMgVG91Y2hFdmVudCkudG91Y2hlcyAhPSBudWxsICYmIChldmVudCBhcyBUb3VjaEV2ZW50KS50b3VjaGVzLmxlbmd0aCAhPSBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24ga3RkUG9pbnRlckNsaWVudFgoZXZlbnQ6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KTogbnVtYmVyIHtcbiAgICByZXR1cm4ga3RkSXNNb3VzZUV2ZW50KGV2ZW50KSA/IGV2ZW50LmNsaWVudFggOiBldmVudC50b3VjaGVzWzBdLmNsaWVudFg7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBrdGRQb2ludGVyQ2xpZW50WShldmVudDogTW91c2VFdmVudCB8IFRvdWNoRXZlbnQpOiBudW1iZXIge1xuICAgIHJldHVybiBrdGRJc01vdXNlRXZlbnQoZXZlbnQpID8gZXZlbnQuY2xpZW50WSA6IGV2ZW50LnRvdWNoZXNbMF0uY2xpZW50WTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGt0ZFBvaW50ZXJDbGllbnQoZXZlbnQ6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KToge2NsaWVudFg6IG51bWJlciwgY2xpZW50WTogbnVtYmVyfSB7XG4gICAgcmV0dXJuICB7XG4gICAgICAgIGNsaWVudFg6IGt0ZElzTW91c2VFdmVudChldmVudCkgPyBldmVudC5jbGllbnRYIDogZXZlbnQudG91Y2hlc1swXS5jbGllbnRYLFxuICAgICAgICBjbGllbnRZOiBrdGRJc01vdXNlRXZlbnQoZXZlbnQpID8gZXZlbnQuY2xpZW50WSA6IGV2ZW50LnRvdWNoZXNbMF0uY2xpZW50WVxuICAgIH07XG59XG5cbi8qKlxuICogRW1pdHMgd2hlbiBhIG1vdXNlZG93biBvciB0b3VjaHN0YXJ0IGVtaXRzLiBBdm9pZHMgY29uZmxpY3RzIGJldHdlZW4gYm90aCBldmVudHMuXG4gKiBAcGFyYW0gZWxlbWVudCwgaHRtbCBlbGVtZW50IHdoZXJlIHRvICBsaXN0ZW4gdGhlIGV2ZW50cy5cbiAqIEBwYXJhbSB0b3VjaE51bWJlciBudW1iZXIgb2YgdGhlIHRvdWNoIHRvIHRyYWNrIHRoZSBldmVudCwgZGVmYXVsdCB0byB0aGUgZmlyc3Qgb25lLlxuICovXG5leHBvcnQgZnVuY3Rpb24ga3RkTW91c2VPclRvdWNoRG93bihlbGVtZW50LCB0b3VjaE51bWJlciA9IDEpOiBPYnNlcnZhYmxlPE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50PiB7XG4gICAgcmV0dXJuIGlpZihcbiAgICAgICAgKCkgPT4ga3RkSXNNb2JpbGVPclRhYmxldCgpLFxuICAgICAgICBmcm9tRXZlbnQ8VG91Y2hFdmVudD4oZWxlbWVudCwgJ3RvdWNoc3RhcnQnLCBwYXNzaXZlRXZlbnRMaXN0ZW5lck9wdGlvbnMgYXMgQWRkRXZlbnRMaXN0ZW5lck9wdGlvbnMpLnBpcGUoXG4gICAgICAgICAgICBmaWx0ZXIoKHRvdWNoRXZlbnQpID0+IHRvdWNoRXZlbnQudG91Y2hlcy5sZW5ndGggPT09IHRvdWNoTnVtYmVyKVxuICAgICAgICApLFxuICAgICAgICBmcm9tRXZlbnQ8TW91c2VFdmVudD4oZWxlbWVudCwgJ21vdXNlZG93bicsIGFjdGl2ZUV2ZW50TGlzdGVuZXJPcHRpb25zIGFzIEFkZEV2ZW50TGlzdGVuZXJPcHRpb25zKS5waXBlKFxuICAgICAgICAgICAgZmlsdGVyKChtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICogMCA6IExlZnQgbW91c2UgYnV0dG9uXG4gICAgICAgICAgICAgICAgICogMSA6IFdoZWVsIGJ1dHRvbiBvciBtaWRkbGUgYnV0dG9uIChpZiBwcmVzZW50KVxuICAgICAgICAgICAgICAgICAqIDIgOiBSaWdodCBtb3VzZSBidXR0b25cbiAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICByZXR1cm4gbW91c2VFdmVudC5idXR0b24gPT09IDA7IC8vIE1vdXNlIGRvd24gdG8gYmUgb25seSBmaXJlZCBpZiBpcyBsZWZ0IGNsaWNrXG4gICAgICAgICAgICB9KVxuICAgICAgICApXG4gICAgKTtcbn1cblxuLyoqXG4gKiBFbWl0cyB3aGVuIGEgJ21vdXNlbW92ZScgb3IgYSAndG91Y2htb3ZlJyBldmVudCBnZXRzIGZpcmVkLlxuICogQHBhcmFtIGVsZW1lbnQsIGh0bWwgZWxlbWVudCB3aGVyZSB0byAgbGlzdGVuIHRoZSBldmVudHMuXG4gKiBAcGFyYW0gdG91Y2hOdW1iZXIgbnVtYmVyIG9mIHRoZSB0b3VjaCB0byB0cmFjayB0aGUgZXZlbnQsIGRlZmF1bHQgdG8gdGhlIGZpcnN0IG9uZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGt0ZE1vdXNlT3JUb3VjaE1vdmUoZWxlbWVudCwgdG91Y2hOdW1iZXIgPSAxKTogT2JzZXJ2YWJsZTxNb3VzZUV2ZW50IHwgVG91Y2hFdmVudD4ge1xuICAgIHJldHVybiBpaWYoXG4gICAgICAgICgpID0+IGt0ZElzTW9iaWxlT3JUYWJsZXQoKSxcbiAgICAgICAgZnJvbUV2ZW50PFRvdWNoRXZlbnQ+KGVsZW1lbnQsICd0b3VjaG1vdmUnLCBhY3RpdmVFdmVudExpc3RlbmVyT3B0aW9ucyBhcyBBZGRFdmVudExpc3RlbmVyT3B0aW9ucykucGlwZShcbiAgICAgICAgICAgIGZpbHRlcigodG91Y2hFdmVudCkgPT4gdG91Y2hFdmVudC50b3VjaGVzLmxlbmd0aCA9PT0gdG91Y2hOdW1iZXIpLFxuICAgICAgICApLFxuICAgICAgICBmcm9tRXZlbnQ8TW91c2VFdmVudD4oZWxlbWVudCwgJ21vdXNlbW92ZScsIGFjdGl2ZUV2ZW50TGlzdGVuZXJPcHRpb25zIGFzIEFkZEV2ZW50TGlzdGVuZXJPcHRpb25zKVxuICAgICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBrdGRUb3VjaEVuZChlbGVtZW50LCB0b3VjaE51bWJlciA9IDEpOiBPYnNlcnZhYmxlPFRvdWNoRXZlbnQ+IHtcbiAgICByZXR1cm4gbWVyZ2UoXG4gICAgICAgIGZyb21FdmVudDxUb3VjaEV2ZW50PihlbGVtZW50LCAndG91Y2hlbmQnKS5waXBlKFxuICAgICAgICAgICAgZmlsdGVyKCh0b3VjaEV2ZW50KSA9PiB0b3VjaEV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSB0b3VjaE51bWJlciAtIDEpXG4gICAgICAgICksXG4gICAgICAgIGZyb21FdmVudDxUb3VjaEV2ZW50PihlbGVtZW50LCAndG91Y2hjYW5jZWwnKS5waXBlKFxuICAgICAgICAgICAgZmlsdGVyKCh0b3VjaEV2ZW50KSA9PiB0b3VjaEV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSB0b3VjaE51bWJlciAtIDEpXG4gICAgICAgIClcbiAgICApO1xufVxuXG4vKipcbiAqIEVtaXRzIHdoZW4gYSB0aGVyZSBpcyBhICdtb3VzZXVwJyBvciB0aGUgdG91Y2ggZW5kcy5cbiAqIEBwYXJhbSBlbGVtZW50LCBodG1sIGVsZW1lbnQgd2hlcmUgdG8gIGxpc3RlbiB0aGUgZXZlbnRzLlxuICogQHBhcmFtIHRvdWNoTnVtYmVyIG51bWJlciBvZiB0aGUgdG91Y2ggdG8gdHJhY2sgdGhlIGV2ZW50LCBkZWZhdWx0IHRvIHRoZSBmaXJzdCBvbmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBrdGRNb3VzZU9yVG91Y2hFbmQoZWxlbWVudCwgdG91Y2hOdW1iZXIgPSAxKTogT2JzZXJ2YWJsZTxNb3VzZUV2ZW50IHwgVG91Y2hFdmVudD4ge1xuICAgIHJldHVybiBpaWYoXG4gICAgICAgICgpID0+IGt0ZElzTW9iaWxlT3JUYWJsZXQoKSxcbiAgICAgICAga3RkVG91Y2hFbmQoZWxlbWVudCwgdG91Y2hOdW1iZXIpLFxuICAgICAgICBmcm9tRXZlbnQ8TW91c2VFdmVudD4oZWxlbWVudCwgJ21vdXNldXAnKSxcbiAgICApO1xufVxuIl19