webglimpse
Version:
Webglimpse is a data visualization library for the web.
619 lines • 96.1 kB
JavaScript
/*
* Copyright (c) 2014, Metron, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import { newBoundsFromRect } from './bounds';
import { Notification, Notification1 } from './util/notification';
import { OrderedSet } from './util/ordered_set';
import { alwaysTrue, GL, getObjectId, hasval } from './util/util';
export function xFrac(ev) {
return ev.paneViewport.xFrac(ev.i);
}
export function yFrac(ev) {
return ev.paneViewport.yFrac(ev.j);
}
class PaneChild {
constructor(pane, layoutArg, layoutOptions) {
this.pane = pane;
this.layoutArg = layoutArg;
this.layoutOptions = layoutOptions;
this.viewport = newBoundsFromRect(0, 0, 0, 0);
this.scissor = newBoundsFromRect(0, 0, 0, 0);
this.prefSize = { w: 0, h: 0 };
}
}
export class Pane {
constructor(layout, consumesInputEvents = true, isInside = alwaysTrue) {
// Input Handling
//
this._mouseUp = new Notification1();
this._mouseDown = new Notification1();
this._mouseMove = new Notification1();
this._mouseWheel = new Notification1();
this._mouseEnter = new Notification1();
this._mouseExit = new Notification1();
this._contextMenu = new Notification1();
this.painters = [];
this.consumesInputEvents = consumesInputEvents;
this.isInside = isInside;
this._mouseCursor = (consumesInputEvents ? 'default' : null);
this._mouseCursorChanged = new Notification();
this._childMouseCursorListener = (() => this._mouseCursorChanged.fire());
this.children = new OrderedSet([], (paneChild) => getObjectId(paneChild.pane), false);
this._layout = layout;
this._viewport = newBoundsFromRect(0, 0, 0, 0);
this._scissor = newBoundsFromRect(0, 0, 0, 0);
this._viewportChanged = new Notification();
this._dispose = new Notification();
this._dispose.on(() => {
this._mouseUp.dispose();
this._mouseDown.dispose();
this._mouseMove.dispose();
this._mouseWheel.dispose();
this._mouseEnter.dispose();
this._mouseExit.dispose();
this._contextMenu.dispose();
// recursively dispose all child panes
for (let i = 0; i < this.children.length; i++) {
this.children.valueAt(i).pane.dispose.fire();
}
});
}
get layout() {
return this._layout;
}
set layout(layout) {
this._layout = layout;
}
get mouseCursor() {
return this._mouseCursor;
}
set mouseCursor(mouseCursor) {
if (mouseCursor !== this._mouseCursor) {
this._mouseCursor = mouseCursor;
this._mouseCursorChanged.fire();
}
}
get mouseCursorChanged() {
return this._mouseCursorChanged;
}
addPainter(painter) {
this.painters.push(painter);
}
addPane(pane, layoutArg = null, layoutOptions = {}) {
this.children.add(new PaneChild(pane, layoutArg, layoutOptions));
pane.mouseCursorChanged.on(this._childMouseCursorListener);
}
removePane(pane) {
this.children.removeValue(this._childFor(pane));
pane.mouseCursorChanged.off(this._childMouseCursorListener);
}
layoutArg(pane) {
return this._childFor(pane).layoutArg;
}
setLayoutArg(pane, layoutArg) {
this._childFor(pane).layoutArg = layoutArg;
}
updateLayoutArgs(updateFn) {
for (let c = 0; c < this.children.length; c++) {
const child = this.children.valueAt(c);
child.layoutArg = updateFn(child.layoutArg, child.layoutOptions);
}
}
layoutOptions(pane) {
return this._childFor(pane).layoutOptions;
}
_childFor(pane) {
return this.children.valueFor(getObjectId(pane));
}
// Layout & Paint
//
updatePrefSizes(result) {
// Child panes
for (let c = 0; c < this.children.length; c++) {
const child = this.children.valueAt(c);
child.pane.updatePrefSizes(child.prefSize);
}
// This pane
if (hasval(this._layout) && hasval(this._layout.updatePrefSize)) {
this._layout.updatePrefSize(result, this.children.toArray());
}
else {
result.w = null;
result.h = null;
}
}
updateBounds(viewport, scissor) {
// This pane
const viewportChanged = (viewport.iStart !== this._viewport.iStart || viewport.iEnd !== this._viewport.iEnd || viewport.jStart !== this._viewport.jStart || viewport.jEnd !== this._viewport.jEnd);
this._viewport.setBounds(viewport);
this._scissor.setBounds(scissor);
// Child panes
if (hasval(this._layout) && hasval(this._layout.updateChildViewports)) {
this._layout.updateChildViewports(this.children.toArray(), viewport);
for (let c = 0; c < this.children.length; c++) {
const child = this.children.valueAt(c);
child.scissor.setBounds(child.viewport.unmod);
child.scissor.cropToBounds(scissor);
child.pane.updateBounds(child.viewport.unmod, child.scissor.unmod);
}
}
else if (this.children.length > 0) {
throw new Error('Pane has ' + this.children.length + ' ' + (this.children.length === 1 ? 'child' : 'children') + ', but its layout is ' + this.layout);
}
// Notify
if (viewportChanged) {
this._viewportChanged.fire();
}
}
paint(gl) {
const viewport = this._viewport.unmod;
const scissor = this._scissor.unmod;
if (scissor.w > 0 && scissor.h > 0) {
// This pane
gl.viewport(viewport.i, viewport.j, viewport.w, viewport.h);
gl.enable(GL.SCISSOR_TEST);
gl.scissor(scissor.i, scissor.j, scissor.w, scissor.h);
for (let p = 0; p < this.painters.length; p++) {
this.painters[p](gl, viewport);
}
// Child panes
for (let c = 0; c < this.children.length; c++) {
this.children.valueAt(c).pane.paint(gl);
}
}
}
get viewport() {
return this._viewport.unmod;
}
get scissor() {
return this._scissor.unmod;
}
get viewportChanged() {
return this._viewportChanged;
}
panesAt(i, j) {
const result = [];
this._panesAt(i, j, result);
return result;
}
_panesAt(i, j, result) {
if (this._scissor.contains(i, j)) {
for (let c = this.children.length - 1; c >= 0; c--) {
const consumed = this.children.valueAt(c).pane._panesAt(i, j, result);
if (consumed) {
return true;
}
}
if (this.isInside(this._viewport.unmod, i, j)) {
result.push(this);
return this.consumesInputEvents;
}
}
return false;
}
get mouseUp() { return this._mouseUp; }
get mouseDown() { return this._mouseDown; }
get mouseMove() { return this._mouseMove; }
get mouseWheel() { return this._mouseWheel; }
get mouseEnter() { return this._mouseEnter; }
get mouseExit() { return this._mouseExit; }
get contextMenu() { return this._contextMenu; }
fireMouseUp(i, j, clickCount, mouseEvent) {
return this._mouseUp.fire({ paneViewport: this._viewport.unmod, i: i, j: j, clickCount: clickCount, mouseEvent: mouseEvent });
}
fireMouseDown(i, j, clickCount, mouseEvent) {
return this._mouseDown.fire({ paneViewport: this._viewport.unmod, i: i, j: j, clickCount: clickCount, mouseEvent: mouseEvent });
}
fireMouseMove(i, j, mouseEvent) {
return this._mouseMove.fire({ paneViewport: this._viewport.unmod, i: i, j: j, mouseEvent: mouseEvent });
}
fireMouseWheel(i, j, wheelSteps, mouseEvent) {
return this._mouseWheel.fire({ paneViewport: this._viewport.unmod, i: i, j: j, wheelSteps: wheelSteps, mouseEvent: mouseEvent });
}
fireMouseEnter(i, j, mouseEvent) {
return this._mouseEnter.fire({ paneViewport: this._viewport.unmod, i: i, j: j, mouseEvent: mouseEvent });
}
fireMouseExit(i, j, mouseEvent) {
return this._mouseExit.fire({ paneViewport: this._viewport.unmod, i: i, j: j, mouseEvent: mouseEvent });
}
fireContextMenu(i, j, mouseEvent) {
return this._contextMenu.fire({ paneViewport: this._viewport.unmod, i: i, j: j, mouseEvent: mouseEvent });
}
// Disposal
//
get dispose() {
return this._dispose;
}
}
export function requireGL(canvasElement) {
// Wrapping the getContext calls in try-catch blocks may lose information. However,
// there are two reasons to do so:
//
// 1. We want to try 'experimental-webgl' even if 'webgl' throws an error
// 2. Throwing a custom error should make it easy to show a helpful message
//
// Reason 2 is particularly important on Firefox, where the error thrown by getContext
// has a completely uninformative message.
//
try {
const glA = canvasElement.getContext('webgl');
if (glA) {
return glA;
}
}
catch (e) { }
try {
const glB = canvasElement.getContext('experimental-webgl');
if (glB) {
return glB;
}
}
catch (e) { }
throw new Error('WebGLContextCreationError');
}
function iMouse(element, ev) {
return (ev.clientX - element.getBoundingClientRect().left);
}
function jMouse(element, ev) {
return (element.clientHeight - (ev.clientY - element.getBoundingClientRect().top));
}
function mouseWheelSteps(ev) {
// MouseWheelEvent.wheelDelta is deprecated, use WheelEvent.deltaY instead.
// Firefox uses positive values for a downward scroll; everybody else uses positive for upward
const raw = (ev.deltaY !== undefined ? ev.deltaY : -ev.detail);
if (raw > 0) {
return -1;
}
if (raw < 0) {
return +1;
}
return 0;
}
// Button presses for mouse events are reported differently in different browsers:
// The results below are for the following browser versions:
// Chrome Version 40.0.2214.94 (64-bit)
// Firefox 35.0.1
// IE 11.0.9600.17501
//
// ‘mousemove’ event with left mouse button down:
//
// Chrome Firefox IE
// MouseEvent.button 0 0 0
// MouseEvent.buttons 1 1 1
// MouseEvent.which 1 1 1
//
// ‘mousemove’ event with no mouse button down:
//
// Chrome Firefox IE
// MouseEvent.button 0 0 0
// MouseEvent.buttons undefined 0 0
// MouseEvent.which 0 1 1
//
//
// For more info see: http://stackoverflow.com/questions/3944122/detect-left-mouse-button-press
//
export function isLeftMouseDown(ev) {
// it appears that ev.buttons works across the board now, so ev.buttons === 1 is probably all that is necessary
if (ev.buttons !== undefined) {
return ev.buttons === 1;
}
else {
return ev.which === 1;
}
}
// detects whether any mouse button is down
export function isMouseDown(ev) {
return ev.buttons !== 0;
}
function attachEventListeners(element, contentPane) {
function detectEntersAndExits(oldPanes, newPanes, i, j, mouseEvent) {
for (let n = 0; n < oldPanes.length; n++) {
oldPanes[n]['isHovered'] = false;
}
for (let n = 0; n < newPanes.length; n++) {
newPanes[n]['isHovered'] = true;
}
for (let n = 0; n < oldPanes.length; n++) {
const oldPane = oldPanes[n];
if (!oldPane['isHovered']) {
oldPane.fireMouseExit(i, j, mouseEvent);
}
}
for (let n = 0; n < newPanes.length; n++) {
newPanes[n]['wasHovered'] = false;
}
for (let n = 0; n < oldPanes.length; n++) {
oldPanes[n]['wasHovered'] = true;
}
for (let n = 0; n < newPanes.length; n++) {
const newPane = newPanes[n];
if (!newPane['wasHovered']) {
newPane.fireMouseEnter(i, j, mouseEvent);
}
}
}
// Support for reporting click count. Browsers handle reporting single/double
// clicks differently, so it's generally not a good idea to use both listeners
// at one. That's why it's done this way instead of using the 'dblclick' event.
const multiPressTimeout_MILLIS = 250;
let prevPress_PMILLIS = 0;
let clickCount = 1;
let currentPanes = [];
let currentMouseCursor = null;
let dragging = false;
let pendingExit = false;
function refreshMouseCursor() {
let newMouseCursor = null;
for (let n = 0; n < currentPanes.length; n++) {
newMouseCursor = currentPanes[n].mouseCursor;
if (hasval(newMouseCursor)) {
break;
}
}
if (!hasval(newMouseCursor)) {
newMouseCursor = 'default';
}
if (newMouseCursor !== currentMouseCursor) {
element.style.cursor = newMouseCursor;
currentMouseCursor = newMouseCursor;
}
}
refreshMouseCursor();
contentPane.mouseCursorChanged.on(refreshMouseCursor);
element.addEventListener('mousedown', function (ev) {
const press_PMILLIS = (new Date()).getTime();
const i = iMouse(element, ev);
const j = jMouse(element, ev);
if (press_PMILLIS - prevPress_PMILLIS < multiPressTimeout_MILLIS) {
clickCount++;
}
else {
clickCount = 1;
}
prevPress_PMILLIS = press_PMILLIS;
const newPanes = contentPane.panesAt(i, j);
detectEntersAndExits(currentPanes, newPanes, i, j, ev);
currentPanes = newPanes;
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseDown(i, j, clickCount, ev);
}
refreshMouseCursor();
dragging = true;
// Disable browser-default double-click action, which selects text and messes up subsequent drags
ev.preventDefault();
});
// Only want NON-DRAG moves from the canvas (e.g. we don't want moves that occur in an overlay div) -- so subscribe to CANVAS's mousemove
element.addEventListener('mousemove', function (ev) {
if (!dragging) {
const i = iMouse(element, ev);
const j = jMouse(element, ev);
const newPanes = contentPane.panesAt(i, j);
detectEntersAndExits(currentPanes, newPanes, i, j, ev);
currentPanes = newPanes;
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
refreshMouseCursor();
}
});
// During a DRAG we want all move events, even ones that occur outside the canvas -- so subscribe to WINDOW's mousemove
window.addEventListener('mousemove', function (ev) {
if (dragging) {
const i = iMouse(element, ev);
const j = jMouse(element, ev);
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
}
});
element.addEventListener('mouseout', function (ev) {
const i = iMouse(element, ev);
const j = jMouse(element, ev);
if (dragging) {
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
pendingExit = true;
}
else {
detectEntersAndExits(currentPanes, [], i, j, ev);
currentPanes = [];
refreshMouseCursor();
}
});
element.addEventListener('mouseover', function (ev) {
const i = iMouse(element, ev);
const j = jMouse(element, ev);
if (dragging) {
pendingExit = false;
}
else {
const newPanes = contentPane.panesAt(i, j);
detectEntersAndExits(currentPanes, newPanes, i, j, ev);
currentPanes = newPanes;
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
refreshMouseCursor();
}
});
const endDrag = function (ev) {
const i = iMouse(element, ev);
const j = jMouse(element, ev);
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseUp(i, j, clickCount, ev);
}
dragging = false;
if (pendingExit) {
detectEntersAndExits(currentPanes, [], i, j, ev);
currentPanes = [];
pendingExit = false;
refreshMouseCursor();
}
else {
const newPanes = contentPane.panesAt(i, j);
detectEntersAndExits(currentPanes, newPanes, i, j, ev);
currentPanes = newPanes;
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
refreshMouseCursor();
}
};
// The window always gets the mouse-up event at the end of a drag -- even if it occurs outside the browser window
window.addEventListener('mouseup', function (ev) {
if (dragging) {
endDrag(ev);
}
});
// We don't receive mouse events that happen over another iframe -- even during a drag. If we miss a mouseup that
// should terminate a drag, we end up stuck in dragging mode, which makes for a really lousy user experience. To
// avoid that, whenever the mouse moves, check whether the button is down. If we're still in dragging mode, but
// the button is now up, end the drag.
// If we're dragging, and we see a mousemove with no buttons down, end the drag
let recentDrag = null;
const handleMissedMouseUp = function (ev) {
if (dragging) {
if (!isMouseDown(ev) && recentDrag) {
const mouseUp = document.createEvent('MouseEvents');
mouseUp.initMouseEvent('mouseup', true, true, window, 0, recentDrag.screenX, recentDrag.screenY, ev.screenX - window.screenX, ev.screenY - window.screenY, recentDrag.ctrlKey, recentDrag.altKey, recentDrag.shiftKey, recentDrag.metaKey, 0, null);
endDrag(mouseUp);
}
recentDrag = ev;
}
};
window.addEventListener('mousemove', handleMissedMouseUp);
let w = window;
while (w.parent !== w) {
try {
w.parent.addEventListener('mousemove', handleMissedMouseUp);
w = w.parent;
}
catch (e) {
// Cross-origin security may prevent us from adding a listener to a window other than our own -- in that case,
// the least bad option is to terminate drags on exit from the highest accessible window
w.addEventListener('mouseout', function (ev) {
if (dragging) {
const mouseUp = document.createEvent('MouseEvents');
mouseUp.initMouseEvent('mouseup', true, true, window, 0, ev.screenX, ev.screenY, ev.screenX - window.screenX, ev.screenY - window.screenY, ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey, 0, null);
endDrag(mouseUp);
}
});
break;
}
}
const handleMouseWheel = function (ev) {
const i = iMouse(element, ev);
const j = jMouse(element, ev);
if (dragging) {
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
}
else {
const newPanes = contentPane.panesAt(i, j);
detectEntersAndExits(currentPanes, newPanes, i, j, ev);
currentPanes = newPanes;
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
}
const wheelSteps = mouseWheelSteps(ev);
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseWheel(i, j, wheelSteps, ev);
}
};
element.addEventListener('wheel', handleMouseWheel);
element.addEventListener('contextmenu', function (ev) {
const i = iMouse(element, ev);
const j = jMouse(element, ev);
if (dragging) {
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
}
else {
const newPanes = contentPane.panesAt(i, j);
detectEntersAndExits(currentPanes, newPanes, i, j, ev);
currentPanes = newPanes;
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireMouseMove(i, j, ev);
}
refreshMouseCursor();
}
for (let n = 0; n < currentPanes.length; n++) {
currentPanes[n].fireContextMenu(i, j, ev);
}
// Disable browser-default context menu
ev.preventDefault();
});
}
export function newDrawable(canvas) {
let contentPane = null;
const contentPrefSizeNotification = new Notification1();
const contentPrefSize = { w: null, h: null };
const contentViewport = newBoundsFromRect(0, 0, 0, 0);
const gl = requireGL(canvas);
let pendingRequestId = null;
return {
setContentPane: function (pane) {
if (hasval(contentPane)) {
// XXX: Detach listeners from old contentPane
}
contentPane = pane;
attachEventListeners(canvas, contentPane);
},
redraw: function () {
if (!hasval(pendingRequestId)) {
pendingRequestId = window.requestAnimationFrame(function () {
let oldPrefSize = { w: null, h: null };
if (hasval(contentPane)) {
oldPrefSize = { w: contentPrefSize.w, h: contentPrefSize.h };
contentPane.updatePrefSizes(contentPrefSize);
contentViewport.setRect(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
contentPane.updateBounds(contentViewport.unmod, contentViewport.unmod);
contentPane.paint(gl);
// XXX: Trigger an enter/exit check somehow (fake a mouse-event?)
}
pendingRequestId = null;
if (oldPrefSize.w !== contentPrefSize.w || oldPrefSize.h !== contentPrefSize.h) {
contentPrefSizeNotification.fire({ w: contentPrefSize.w, h: contentPrefSize.h });
}
});
}
},
getPrefSize: function () {
return { w: contentPrefSize.w, h: contentPrefSize.h };
},
prefSizeChanged: function () {
return contentPrefSizeNotification;
}
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy93ZWJnbGltcHNlL2NvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0Qkc7QUFDSCxPQUFPLEVBQW9DLGlCQUFpQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQy9FLE9BQU8sRUFBRSxZQUFZLEVBQVksYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDNUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFlbEUsTUFBTSxVQUFVLEtBQUssQ0FBQyxFQUFnQjtJQUNsQyxPQUFPLEVBQUUsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUN2QyxDQUFDO0FBR0QsTUFBTSxVQUFVLEtBQUssQ0FBQyxFQUFnQjtJQUNsQyxPQUFPLEVBQUUsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUN2QyxDQUFDO0FBMEJELE1BQU0sU0FBUztJQVFYLFlBQVksSUFBVSxFQUFFLFNBQWMsRUFBRSxhQUFrQjtRQUN0RCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUNuQyxJQUFJLENBQUMsUUFBUSxHQUFHLGlCQUFpQixDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzlDLElBQUksQ0FBQyxPQUFPLEdBQUcsaUJBQWlCLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFD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QUcsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN0QyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsS0FBSyxDQUFDO1NBQ3BDO1FBQ0QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDdEMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxHQUFHLElBQUksQ0FBQztTQUNuQztRQUNELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3RDLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxFQUFFO2dCQUN2QixPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUM7YUFDM0M7U0FDSjtRQUVELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3RDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsR0FBRyxLQUFLLENBQUM7U0FDckM7UUFDRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN0QyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLEdBQUcsSUFBSSxDQUFDO1NBQ3BDO1FBQ0QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDdEMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVCLElB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