UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

280 lines 26.1 kB
import { tgdActionCreateCameraInterpolation, tgdEasingFunctionOutQuad, } from "./../../utils/index.js"; import { tgdCalcClamp } from "./../../utils/math.js"; import { TgdEvent } from "./../../event/index.js"; import { TgdMat3, TgdQuat, TgdVec3 } from "./../../math/index.js"; export class TgdControllerCameraOrbit { constructor(context, { geo, minZoom = 1e-3, maxZoom = Infinity, speedZoom = 1, speedOrbit = 1, speedPanning = 1, inertiaZoom = 0, inertiaOrbit = 0, inertiaPanning = 0, fixedTarget = false, debug = false, onZoomRequest = alwaysTrue, } = {}) { this.context = context; this.id = `TgdControllerCameraOrbit-${TgdControllerCameraOrbit.counter++}`; this.eventChange = new TgdEvent(); this.minZoom = 1e-3; this.maxZoom = Infinity; this.speedZoom = 1; this.speedOrbit = 1; this.speedPanning = 1; this.inertiaZoom = 0; this.inertiaOrbit = 0; this.inertiaPanning = 0; /** * If `true`, pannig will only act on `camera.shift`, * not on `camera.target`. */ this.fixedTarget = false; /** * The camera will only move if `enabled === true`. */ this._enabled = true; this.animOrbit = null; /** * It can be usefull to disable to orbit controller for some time * because an animation is going on on the camera, for instance. */ this.disabledUntil = 0; this.tmpQuat = new TgdQuat(); this.handleMove = (event) => { if (!this.enabled || this.animOrbit) return; this.actualMove(event); }; this.actualMove = (event) => { const dt = event.current.t - event.previous.t; if (dt <= 0) return; const { context } = this; const { keyboard } = context.inputs; if (event.altKey || event.current.fingersCount === 2) return this.handlePan(event); if (this.geo) { const speed = keyboard.isDown("Shift") ? 0.2 : 2; const lngDelta = keyboard.isDown("x") ? 0 : speed * (event.previous.x - event.current.x); const latDelta = keyboard.isDown("y") ? 0 : speed * (event.previous.y - event.current.y); const lng = this.geo.lng + lngDelta; const lat = this.geo.lat + latDelta; this.orbitGeo(lat, lng); return; } if (keyboard.isDown("z")) return this.handleRotateAroundZ(event); this.orbit(event.current.x - event.previous.x, event.current.y - event.previous.y, event.shiftKey); }; this.handleMoveStart = () => { if (!this.enabled) return; const { animOrbit, context } = this; if (animOrbit) { context.animCancel(animOrbit); this.animOrbit = null; } }; this.handleMoveEnd = (event) => { if (!this.enabled) return; const { context, inertiaOrbit } = this; if (inertiaOrbit > 0) { const inverseDeltaTime = 1 / (event.current.t - event.previous.t); const speedX = inverseDeltaTime * (event.current.x - event.previous.x); const speedY = inverseDeltaTime * (event.current.y - event.previous.y); const currentEvent = structuredClone(event); currentEvent.current.t = Date.now(); this.animOrbit = { duration: inertiaOrbit * 1e-3, action: alpha => { currentEvent.previous.t = currentEvent.current.t; currentEvent.previous.x = currentEvent.current.x; currentEvent.previous.y = currentEvent.current.y; currentEvent.previous.fingersCount = currentEvent.current.fingersCount; currentEvent.current.t = Date.now(); const deltaTime = currentEvent.current.t - currentEvent.previous.t; const strength = 1 - alpha; const factor = strength * deltaTime; currentEvent.current.x += factor * speedX; currentEvent.current.y += factor * speedY; this.actualMove(currentEvent); }, easingFunction: tgdEasingFunctionOutQuad, }; context.animSchedule(this.animOrbit); } }; this.handleZoom = (event) => { if (!this.enabled || this.speedZoom === 0 || !this.onZoomRequest({ altKey: event.altKey, ctrlKey: event.ctrlKey, metaKey: event.metaKey, shiftKey: event.shiftKey, x: event.current.x, y: event.current.y, })) return; const { context } = this; const { camera } = context; let speed = 0.1 * this.speedZoom; if (this.context.inputs.keyboard.isDown("Shift")) speed *= 0.1; const dz = -event.direction * speed; camera.transfo.distance = Math.max(0, camera.transfo.distance + dz); // camera.zoom = tgdCalcClamp( // camera.zoom * (1 + dz), // this.minZoom, // this.maxZoom // ) event.preventDefault(); this.fireZoomChange(); }; this.geo = undefined; if (geo) { this.geo = Object.assign({ lat: 0, lng: 0, minLat: -Math.PI / 2, maxLat: +Math.PI / 2, minLng: -Number.MAX_VALUE, maxLng: +Number.MAX_VALUE }, geo); } this.cameraInitialState = context.camera.getCurrentState(); const { inputs } = context; inputs.pointer.eventMoveStart.addListener(this.handleMoveStart); inputs.pointer.eventMoveEnd.addListener(this.handleMoveEnd); inputs.pointer.eventMove.addListener(this.handleMove); inputs.pointer.eventZoom.addListener(this.handleZoom); this.speedOrbit = speedOrbit; this.speedZoom = speedZoom; this.speedPanning = speedPanning; this.inertiaOrbit = inertiaOrbit; this.inertiaZoom = inertiaZoom; this.inertiaPanning = inertiaPanning; this.fixedTarget = fixedTarget; this.minZoom = minZoom; this.maxZoom = maxZoom; this.onZoomRequest = onZoomRequest; if (this.geo) this.orbitGeo(this.geo.lat, this.geo.lng); globalThis.setTimeout(() => context.paint()); if (debug) { context.inputs.keyboard.eventKeyPress.addListener(event => { if (event.key === "?") { console.log(this.context.camera.toCode()); } }); } } get enabled() { return this.context.time > this.disabledUntil && this._enabled; } set enabled(value) { this._enabled = value; } reset(animDuration, easingFunction) { const { context } = this; this.disableForSomeTime(animDuration); context.animSchedule({ action: tgdActionCreateCameraInterpolation(context.camera, this.cameraInitialState), duration: animDuration, easingFunction, }); } disableForSomeTime(delayInMsec) { this.disabledUntil = Math.max(this.disabledUntil, this.context.time + delayInMsec); } detach() { const { inputs } = this.context; inputs.pointer.eventMove.removeListener(this.handleMove); inputs.pointer.eventZoom.removeListener(this.handleZoom); } orbit(deltaX, deltaY, slowDown) { const { context } = this; const { camera } = context; const { keyboard } = context.inputs; const speed = 3 * (slowDown ? 0.1 : 1) * this.speedOrbit; const dx = deltaX * speed; const dy = deltaY * speed; if (!keyboard.isDown("x")) camera.transfo.orbitAroundY(dx); if (!keyboard.isDown("y")) camera.transfo.orbitAroundX(-dy); this.fireOrbitChange(); } /** * Set the camera orientation from latitude/longitude * @param lat Expressed in radians * @param lng Expressed in radians */ orbitGeo(lat, lng) { const { geo } = this; if (!geo) return; lat = tgdCalcClamp(lat, geo.minLat, geo.maxLat); geo.lat = lat; lng = tgdCalcClamp(lng, geo.minLng, geo.maxLng); geo.lng = lng; const { orientation } = this.cameraInitialState; const vecZ = makeGeoVec3(lat, lng); const vecY = makeGeoVec3(lat + Math.PI / 2, lng); const vecX = new TgdVec3(vecY).cross(vecZ); const mat = new TgdMat3(); orientation.toMatrix(mat); const final = new TgdMat3(vecX, vecY, vecZ); final.multiply(mat); this.tmpQuat.fromMatrix(final); this.context.camera.transfo.orientation = this.tmpQuat; this.fireOrbitChange(); } handlePan(event) { const { fixedTarget, speedPanning, context } = this; const { camera } = context; const inverseZoom = 1 / camera.zoom; const panSpeed = 0.5 * speedPanning * inverseZoom; const dx = (event.current.x - event.previous.x) * panSpeed * camera.spaceWidthAtTarget; const dy = (event.current.y - event.previous.y) * panSpeed * camera.spaceHeightAtTarget; if (fixedTarget) { // camera.moveShift(-dx, -dy, 0) } else { camera.transfo.moveAlongAxes(-dx, -dy, 0); } this.fireOrbitChange(); return; } handleRotateAroundZ(event) { const { camera } = this.context; const x1 = event.previous.x; const y1 = event.previous.y; if (Math.abs(x1) + Math.abs(y1) === 0) return; const x2 = event.current.x; const y2 = event.current.y; if (Math.abs(x2) + Math.abs(y2) === 0) return; const x = x1 * x2 + y1 * y2; const y = x1 * y2 - y1 * x2; const ang = Math.atan2(y, x) * this.speedOrbit; camera.transfo.orbitAroundZ(ang); this.fireOrbitChange(); return; } fireOrbitChange() { this.context.paint(); this.eventChange.dispatch(this.context.camera); } fireZoomChange() { this.context.paint(); } } TgdControllerCameraOrbit.counter = 0; /** * Default function for `onZoomRequest`. */ const alwaysTrue = () => true; function makeGeoVec3(lat, lng) { const radius = Math.cos(lat); const y = Math.sin(lat); const z = radius * Math.cos(lng); const x = radius * Math.sin(lng); return new TgdVec3(x, y, z); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JiaXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29udHJvbGxlci9jYW1lcmEvb3JiaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUNILGtDQUFrQyxFQUNsQyx3QkFBd0IsR0FDM0IsTUFBTSxZQUFZLENBQUE7QUFDbkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBTTlDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFFckMsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBZ0ZyRCxNQUFNLE9BQU8sd0JBQXdCO0lBdURqQyxZQUNxQixPQU9oQixFQUNELEVBQ0ksR0FBRyxFQUNILE9BQU8sR0FBRyxJQUFJLEVBQ2QsT0FBTyxHQUFHLFFBQVEsRUFDbEIsU0FBUyxHQUFHLENBQUMsRUFDYixVQUFVLEdBQUcsQ0FBQyxFQUNkLFlBQVksR0FBRyxDQUFDLEVBQ2hCLFdBQVcsR0FBRyxDQUFDLEVBQ2YsWUFBWSxHQUFHLENBQUMsRUFDaEIsY0FBYyxHQUFHLENBQUMsRUFDbEIsV0FBVyxHQUFHLEtBQUssRUFDbkIsS0FBSyxHQUFHLEtBQUssRUFDYixhQUFhLEdBQUcsVUFBVSxNQUNnQixFQUFFO1FBckIvQixZQUFPLEdBQVAsT0FBTyxDQU92QjtRQTVEVyxPQUFFLEdBQUcsNEJBQTRCLHdCQUF3QixDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUE7UUFDckUsZ0JBQVcsR0FBRyxJQUFJLFFBQVEsRUFBYSxDQUFBO1FBQ2hELFlBQU8sR0FBRyxJQUFJLENBQUE7UUFDZCxZQUFPLEdBQUcsUUFBUSxDQUFBO1FBQ2xCLGNBQVMsR0FBRyxDQUFDLENBQUE7UUFDYixlQUFVLEdBQUcsQ0FBQyxDQUFBO1FBQ2QsaUJBQVksR0FBRyxDQUFDLENBQUE7UUFDaEIsZ0JBQVcsR0FBRyxDQUFDLENBQUE7UUFDZixpQkFBWSxHQUFHLENBQUMsQ0FBQTtRQUNoQixtQkFBYyxHQUFHLENBQUMsQ0FBQTtRQUN6Qjs7O1dBR0c7UUFDSSxnQkFBVyxHQUFHLEtBQUssQ0FBQTtRQWdCMUI7O1dBRUc7UUFDSSxhQUFRLEdBQUcsSUFBSSxDQUFBO1FBRWQsY0FBUyxHQUF3QixJQUFJLENBQUE7UUFDN0M7OztXQUdHO1FBQ0ssa0JBQWEsR0FBRyxDQUFDLENBQUE7UUFVUixZQUFPLEdBQUcsSUFBSSxPQUFPLEVBQUUsQ0FBQTtRQWtHdkIsZUFBVSxHQUFHLENBQUMsS0FBK0IsRUFBRSxFQUFFO1lBQzlELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxTQUFTO2dCQUFFLE9BQU07WUFFM0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUMxQixDQUFDLENBQUE7UUFFZ0IsZUFBVSxHQUFHLENBQUMsS0FBK0IsRUFBRSxFQUFFO1lBQzlELE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFBO1lBQzdDLElBQUksRUFBRSxJQUFJLENBQUM7Z0JBQUUsT0FBTTtZQUVuQixNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFBO1lBQ3hCLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFBO1lBQ25DLElBQUksS0FBSyxDQUFDLE1BQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFlBQVksS0FBSyxDQUFDO2dCQUNoRCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUE7WUFFaEMsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ1gsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7Z0JBQ2hELE1BQU0sUUFBUSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDO29CQUNqQyxDQUFDLENBQUMsQ0FBQztvQkFDSCxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFDbEQsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7b0JBQ2pDLENBQUMsQ0FBQyxDQUFDO29CQUNILENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFBO2dCQUNsRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxRQUFRLENBQUE7Z0JBQ25DLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxHQUFHLFFBQVEsQ0FBQTtnQkFDbkMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUE7Z0JBQ3ZCLE9BQU07WUFDVixDQUFDO1lBRUQsSUFBSSxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztnQkFBRSxPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsQ0FBQTtZQUVoRSxJQUFJLENBQUMsS0FBSyxDQUNOLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUNsQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsRUFDbEMsS0FBSyxDQUFDLFFBQVEsQ0FDakIsQ0FBQTtRQUNMLENBQUMsQ0FBQTtRQXdDZ0Isb0JBQWUsR0FBRyxHQUFHLEVBQUU7WUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPO2dCQUFFLE9BQU07WUFFekIsTUFBTSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUE7WUFDbkMsSUFBSSxTQUFTLEVBQUUsQ0FBQztnQkFDWixPQUFPLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFBO2dCQUM3QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQTtZQUN6QixDQUFDO1FBQ0wsQ0FBQyxDQUFBO1FBRWdCLGtCQUFhLEdBQUcsQ0FBQyxLQUErQixFQUFFLEVBQUU7WUFDakUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPO2dCQUFFLE9BQU07WUFFekIsTUFBTSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsR0FBRyxJQUFJLENBQUE7WUFDdEMsSUFBSSxZQUFZLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ25CLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFDakUsTUFBTSxNQUFNLEdBQ1IsZ0JBQWdCLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFBO2dCQUMzRCxNQUFNLE1BQU0sR0FDUixnQkFBZ0IsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUE7Z0JBQzNELE1BQU0sWUFBWSxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQTtnQkFDM0MsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFBO2dCQUNuQyxJQUFJLENBQUMsU0FBUyxHQUFHO29CQUNiLFFBQVEsRUFBRSxZQUFZLEdBQUcsSUFBSTtvQkFDN0IsTUFBTSxFQUFFLEtBQUssQ0FBQyxFQUFFO3dCQUNaLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQyxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFBO3dCQUNoRCxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQTt3QkFDaEQsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUE7d0JBQ2hELFlBQVksQ0FBQyxRQUFRLENBQUMsWUFBWTs0QkFDOUIsWUFBWSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUE7d0JBQ3JDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQTt3QkFDbkMsTUFBTSxTQUFTLEdBQ1gsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUE7d0JBQ3BELE1BQU0sUUFBUSxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUE7d0JBQzFCLE1BQU0sTUFBTSxHQUFHLFFBQVEsR0FBRyxTQUFTLENBQUE7d0JBQ25DLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLE1BQU0sR0FBRyxNQUFNLENBQUE7d0JBQ3pDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLE1BQU0sR0FBRyxNQUFNLENBQUE7d0JBQ3pDLElBQUksQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDLENBQUE7b0JBQ2pDLENBQUM7b0JBQ0QsY0FBYyxFQUFFLHdCQUF3QjtpQkFDM0MsQ0FBQTtnQkFDRCxPQUFPLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQTtZQUN4QyxDQUFDO1FBQ0wsQ0FBQyxDQUFBO1FBK0NnQixlQUFVLEdBQUcsQ0FBQyxLQUErQixFQUFFLEVBQUU7WUFDOUQsSUFDSSxDQUFDLElBQUksQ0FBQyxPQUFPO2dCQUNiLElBQUksQ0FBQyxTQUFTLEtBQUssQ0FBQztnQkFDcEIsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO29CQUNoQixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07b0JBQ3BCLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTztvQkFDdEIsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO29CQUN0QixRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7b0JBQ3hCLENBQUMsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQ2xCLENBQUMsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7aUJBQ3JCLENBQUM7Z0JBRUYsT0FBTTtZQUVWLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUE7WUFDeEIsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQTtZQUMxQixJQUFJLEtBQUssR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQTtZQUNoQyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO2dCQUFFLEtBQUssSUFBSSxHQUFHLENBQUE7WUFDOUQsTUFBTSxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQTtZQUNuQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsR0FBRyxFQUFFLENBQUMsQ0FBQTtZQUNuRSw4QkFBOEI7WUFDOUIsOEJBQThCO1lBQzlCLG9CQUFvQjtZQUNwQixtQkFBbUI7WUFDbkIsSUFBSTtZQUNKLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQTtZQUN0QixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUE7UUFDekIsQ0FBQyxDQUFBO1FBMVFHLElBQUksQ0FBQyxHQUFHLEdBQUcsU0FBUyxDQUFBO1FBQ3BCLElBQUksR0FBRyxFQUFFLENBQUM7WUFDTixJQUFJLENBQUMsR0FBRyxtQkFDSixHQUFHLEVBQUUsQ0FBQyxFQUNOLEdBQUcsRUFBRSxDQUFDLEVBQ04sTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLEVBQ3BCLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUNwQixNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUN6QixNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsU0FBUyxJQUN0QixHQUFHLENBQ1QsQ0FBQTtRQUNMLENBQUM7UUFDRCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQTtRQUMxRCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFBO1FBQzFCLE1BQU0sQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUE7UUFDL0QsTUFBTSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQTtRQUMzRCxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQ3JELE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDckQsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUE7UUFDNUIsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUE7UUFDMUIsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUE7UUFDaEMsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUE7UUFDaEMsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUE7UUFDOUIsSUFBSSxDQUFDLGNBQWMsR0FBRyxjQUFjLENBQUE7UUFDcEMsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUE7UUFDOUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUE7UUFDdEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUE7UUFDdEIsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUE7UUFDbEMsSUFBSSxJQUFJLENBQUMsR0FBRztZQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUN2RCxVQUFVLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFBO1FBQzVDLElBQUksS0FBSyxFQUFFLENBQUM7WUFDUixPQUFPLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUN0RCxJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssR0FBRyxFQUFFLENBQUM7b0JBQ3BCLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQTtnQkFDN0MsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFBO1FBQ04sQ0FBQztJQUNMLENBQUM7SUFFRCxJQUFJLE9BQU87UUFDUCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxhQUFhLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQTtJQUNsRSxDQUFDO0lBQ0QsSUFBSSxPQUFPLENBQUMsS0FBYztRQUN0QixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQTtJQUN6QixDQUFDO0lBRUQsS0FBSyxDQUFDLFlBQW9CLEVBQUUsY0FBc0M7UUFDOUQsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQTtRQUN4QixJQUFJLENBQUMsa0JBQWtCLENBQUMsWUFBWSxDQUFDLENBQUE7UUFDckMsT0FBTyxDQUFDLFlBQVksQ0FBQztZQUNqQixNQUFNLEVBQUUsa0NBQWtDLENBQ3RDLE9BQU8sQ0FBQyxNQUFNLEVBQ2QsSUFBSSxDQUFDLGtCQUFrQixDQUMxQjtZQUNELFFBQVEsRUFBRSxZQUFZO1lBQ3RCLGNBQWM7U0FDakIsQ0FBQyxDQUFBO0lBQ04sQ0FBQztJQUVELGtCQUFrQixDQUFDLFdBQW1CO1FBQ2xDLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FDekIsSUFBSSxDQUFDLGFBQWEsRUFDbEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsV0FBVyxDQUNsQyxDQUFBO0lBQ0wsQ0FBQztJQUVELE1BQU07UUFDRixNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQTtRQUMvQixNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQ3hELE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDNUQsQ0FBQztJQXdDTyxLQUFLLENBQUMsTUFBYyxFQUFFLE1BQWMsRUFBRSxRQUFpQjtRQUMzRCxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ3hCLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUE7UUFDMUIsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUE7UUFDbkMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUE7UUFDeEQsTUFBTSxFQUFFLEdBQUcsTUFBTSxHQUFHLEtBQUssQ0FBQTtRQUN6QixNQUFNLEVBQUUsR0FBRyxNQUFNLEdBQUcsS0FBSyxDQUFBO1FBQ3pCLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztZQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1FBQzFELElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztZQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUE7UUFDM0QsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFBO0lBQzFCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksUUFBUSxDQUFDLEdBQVcsRUFBRSxHQUFXO1FBQ3BDLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDcEIsSUFBSSxDQUFDLEdBQUc7WUFBRSxPQUFNO1FBRWhCLEdBQUcsR0FBRyxZQUFZLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQy9DLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFBO1FBQ2IsR0FBRyxHQUFHLFlBQVksQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDL0MsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUE7UUFDYixNQUFNLEVBQUUsV0FBVyxFQUFFLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFBO1FBQy9DLE1BQU0sSUFBSSxHQUFHLFdBQVcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFDbEMsTUFBTSxJQUFJLEdBQUcsV0FBVyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtRQUNoRCxNQUFNLElBQUksR0FBRyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDMUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxPQUFPLEVBQUUsQ0FBQTtRQUN6QixXQUFXLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ3pCLE1BQU0sS0FBSyxHQUFHLElBQUksT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDM0MsS0FBSyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNuQixJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUE7UUFDdEQsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFBO0lBQzFCLENBQUM7SUErQ08sU0FBUyxDQUFDLEtBQStCO1FBQzdDLE1BQU0sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuRCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFBO1FBQzFCLE1BQU0sV0FBVyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFBO1FBQ25DLE1BQU0sUUFBUSxHQUFHLEdBQUcsR0FBRyxZQUFZLEdBQUcsV0FBVyxDQUFBO1FBQ2pELE1BQU0sRUFBRSxHQUNKLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDcEMsUUFBUTtZQUNSLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQTtRQUM3QixNQUFNLEVBQUUsR0FDSixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1lBQ3BDLFFBQVE7WUFDUixNQUFNLENBQUMsbUJBQW1CLENBQUE7UUFDOUIsSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNkLGdDQUFnQztRQUNwQyxDQUFDO2FBQU0sQ0FBQztZQUNKLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFBO1FBQzdDLENBQUM7UUFDRCxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUE7UUFDdEIsT0FBTTtJQUNWLENBQUM7SUFFTyxtQkFBbUIsQ0FBQyxLQUErQjtRQUN2RCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQTtRQUMvQixNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQTtRQUMzQixNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQTtRQUMzQixJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDO1lBQUUsT0FBTTtRQUU3QyxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQTtRQUMxQixNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQTtRQUMxQixJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDO1lBQUUsT0FBTTtRQUU3QyxNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUE7UUFDM0IsTUFBTSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFBO1FBQzNCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUE7UUFDOUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDaEMsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFBO1FBQ3RCLE9BQU07SUFDVixDQUFDO0lBRU8sZUFBZTtRQUNuQixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQ3BCLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDbEQsQ0FBQztJQWdDTyxjQUFjO1FBQ2xCLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUE7SUFDeEIsQ0FBQzs7QUE1VmMsZ0NBQU8sR0FBRyxDQUFDLEFBQUosQ0FBSTtBQStWOUI7O0dBRUc7QUFDSCxNQUFNLFVBQVUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUE7QUFFN0IsU0FBUyxXQUFXLENBQUMsR0FBVyxFQUFFLEdBQVc7SUFDekMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUM1QixNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQ3ZCLE1BQU0sQ0FBQyxHQUFHLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQ2hDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQ2hDLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtBQUMvQixDQUFDIn0=