UNPKG

webglimpse

Version:

Webglimpse is a data visualization library for the web.

619 lines 96.1 kB
/* * 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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