olcs
Version:
OpenLayers Cesium integration and plugin library
631 lines • 53.9 kB
JavaScript
import { linear as linearEasing } from 'ol/easing.js';
import olLayerTile from 'ol/layer/Tile.js';
import olLayerImage from 'ol/layer/Image.js';
import { get as getProjection, transformExtent } from 'ol/proj.js';
import olSourceImageStatic from 'ol/source/ImageStatic.js';
import olSourceImageWMS from 'ol/source/ImageWMS.js';
import olSourceTileImage from 'ol/source/TileImage.js';
import olSourceTileWMS from 'ol/source/TileWMS.js';
import olSourceVectorTile from 'ol/source/VectorTile.js';
import olcsCoreOLImageryProvider from './core/OLImageryProvider.js';
import { getSourceProjection } from './util.js';
import MVTImageryProvider from './MVTImageryProvider.js';
import VectorTileLayer from 'ol/layer/VectorTile.js';
import { getCenter as getExtentCenter } from 'ol/extent.js';
/**
* Compute the pixel width and height of a point in meters using the
* camera frustum.
*/
export function computePixelSizeAtCoordinate(scene, target) {
const camera = scene.camera;
const canvas = scene.canvas;
const frustum = camera.frustum;
const distance = Cesium.Cartesian3.magnitude(Cesium.Cartesian3.subtract(camera.position, target, new Cesium.Cartesian3()));
// @ts-ignore TS2341
return frustum.getPixelDimensions(canvas.clientWidth, canvas.clientHeight, distance, scene.pixelRatio, new Cesium.Cartesian2());
}
/**
* Compute bounding box around a target point.
* @param {!Cesium.Scene} scene
* @param {!Cesium.Cartesian3} target
* @param {number} amount Half the side of the box, in pixels.
* @return {Array<Cesium.Cartographic>} bottom left and top right
* coordinates of the box
*/
export function computeBoundingBoxAtTarget(scene, target, amount) {
const pixelSize = computePixelSizeAtCoordinate(scene, target);
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(target);
const bottomLeft = Cesium.Matrix4.multiplyByPoint(transform, new Cesium.Cartesian3(-pixelSize.x * amount, -pixelSize.y * amount, 0), new Cesium.Cartesian3());
const topRight = Cesium.Matrix4.multiplyByPoint(transform, new Cesium.Cartesian3(pixelSize.x * amount, pixelSize.y * amount, 0), new Cesium.Cartesian3());
return Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray([bottomLeft, topRight]);
}
export function applyHeightOffsetToGeometry(geometry, height) {
geometry.applyTransform((input, output, stride) => {
console.assert(input === output);
if (stride !== undefined && stride >= 3) {
for (let i = 0; i < output.length; i += stride) {
output[i + 2] = output[i + 2] + height;
}
}
return output;
});
}
export function createMatrixAtCoordinates(coordinates, rotation = 0, translation = Cesium.Cartesian3.ZERO, scale = new Cesium.Cartesian3(1, 1, 1)) {
const position = ol4326CoordinateToCesiumCartesian(coordinates);
const rawMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
const quaternion = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, -rotation);
const rotationMatrix = Cesium.Matrix4.fromTranslationQuaternionRotationScale(translation, quaternion, scale);
return Cesium.Matrix4.multiply(rawMatrix, rotationMatrix, new Cesium.Matrix4());
}
export function rotateAroundAxis(camera, angle, axis, transform, opt_options) {
const clamp = Cesium.Math.clamp;
const options = opt_options;
const duration = options?.duration ?? 500; // ms
const easing = options?.easing ?? linearEasing;
const callback = options?.callback;
let lastProgress = 0;
const oldTransform = new Cesium.Matrix4();
const start = Date.now();
const step = function () {
const timestamp = Date.now();
const timeDifference = timestamp - start;
const progress = easing(clamp(timeDifference / duration, 0, 1));
console.assert(progress >= lastProgress);
camera.transform.clone(oldTransform);
const stepAngle = (progress - lastProgress) * angle;
lastProgress = progress;
camera.lookAtTransform(transform);
camera.rotate(axis, stepAngle);
camera.lookAtTransform(oldTransform);
if (progress < 1) {
window.requestAnimationFrame(step);
}
else {
if (callback) {
callback();
}
}
};
window.requestAnimationFrame(step);
}
export function setHeadingUsingBottomCenter(scene, heading, bottomCenter, options) {
const camera = scene.camera;
// Compute the camera position to zenith quaternion
const angleToZenith = computeAngleToZenith(scene, bottomCenter);
const axis = camera.right;
const quaternion = Cesium.Quaternion.fromAxisAngle(axis, angleToZenith);
const rotation = Cesium.Matrix3.fromQuaternion(quaternion);
// Get the zenith point from the rotation of the position vector
const vector = new Cesium.Cartesian3();
Cesium.Cartesian3.subtract(camera.position, bottomCenter, vector);
const zenith = new Cesium.Cartesian3();
Cesium.Matrix3.multiplyByVector(rotation, vector, zenith);
Cesium.Cartesian3.add(zenith, bottomCenter, zenith);
// Actually rotate around the zenith normal
const transform = Cesium.Matrix4.fromTranslation(zenith);
rotateAroundAxis(camera, heading, zenith, transform, options);
}
/**
* Get the 3D position of the given pixel of the canvas.
*/
export function pickOnTerrainOrEllipsoid(scene, pixel) {
const ray = scene.camera.getPickRay(pixel);
const target = scene.globe.pick(ray, scene);
return target || scene.camera.pickEllipsoid(pixel);
}
/**
* Get the 3D position of the point at the bottom-center of the screen.
*/
export function pickBottomPoint(scene) {
const canvas = scene.canvas;
const bottom = new Cesium.Cartesian2(canvas.clientWidth / 2, canvas.clientHeight);
return pickOnTerrainOrEllipsoid(scene, bottom);
}
/**
* Get the 3D position of the point at the center of the screen.
*/
export function pickCenterPoint(scene) {
const canvas = scene.canvas;
const center = new Cesium.Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
return pickOnTerrainOrEllipsoid(scene, center);
}
/**
* Compute the signed tilt angle on globe, between the opposite of the
* camera direction and the target normal. Return undefined if there is no
*/
export function computeSignedTiltAngleOnGlobe(scene) {
const camera = scene.camera;
const ray = new Cesium.Ray(camera.position, camera.direction);
let target = scene.globe.pick(ray, scene);
if (!target) {
// no tiles in the area were loaded?
const ellipsoid = Cesium.Ellipsoid.WGS84;
const obj = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid);
if (obj) {
target = Cesium.Ray.getPoint(ray, obj.start);
}
}
if (!target) {
return undefined;
}
const normal = new Cesium.Cartesian3();
Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(target, normal);
const angleBetween = signedAngleBetween;
const angle = angleBetween(camera.direction, normal, camera.right) - Math.PI;
return Cesium.Math.convertLongitudeRange(angle);
}
/**
* Compute the ray from the camera to the bottom-center of the screen.
*/
export function bottomFovRay(scene) {
const camera = scene.camera;
// @ts-ignore TS2341
const fovy2 = camera.frustum.fovy / 2;
const direction = camera.direction;
const rotation = Cesium.Quaternion.fromAxisAngle(camera.right, fovy2);
const matrix = Cesium.Matrix3.fromQuaternion(rotation);
const vector = new Cesium.Cartesian3();
Cesium.Matrix3.multiplyByVector(matrix, direction, vector);
return new Cesium.Ray(camera.position, vector);
}
/**
* Compute the angle between two Cartesian3.
*/
export function signedAngleBetween(first, second, normal) {
// We are using the dot for the angle.
// Then the cross and the dot for the sign.
const a = new Cesium.Cartesian3();
const b = new Cesium.Cartesian3();
const c = new Cesium.Cartesian3();
Cesium.Cartesian3.normalize(first, a);
Cesium.Cartesian3.normalize(second, b);
Cesium.Cartesian3.cross(a, b, c);
const cosine = Cesium.Cartesian3.dot(a, b);
const sine = Cesium.Cartesian3.magnitude(c);
// Sign of the vector product and the orientation normal
const sign = Cesium.Cartesian3.dot(normal, c);
const angle = Math.atan2(sine, cosine);
return sign >= 0 ? angle : -angle;
}
/**
* Compute the rotation angle around a given point, needed to reach the
* zenith position.
* At a zenith position, the camera direction is going througth the earth
* center and the frustrum bottom ray is going through the chosen pivot
* point.
* The bottom-center of the screen is a good candidate for the pivot point.
*/
export function computeAngleToZenith(scene, pivot) {
// This angle is the sum of the angles 'fy' and 'a', which are defined
// using the pivot point and its surface normal.
// Zenith | camera
// \ | /
// \fy| /
// \ |a/
// \|/pivot
const camera = scene.camera;
// @ts-ignore TS2341
const fy = camera.frustum.fovy / 2;
const ray = bottomFovRay(scene);
const direction = Cesium.Cartesian3.clone(ray.direction);
Cesium.Cartesian3.negate(direction, direction);
const normal = new Cesium.Cartesian3();
Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(pivot, normal);
const left = new Cesium.Cartesian3();
Cesium.Cartesian3.negate(camera.right, left);
const a = signedAngleBetween(normal, direction, left);
return a + fy;
}
/**
* Convert an OpenLayers extent to a Cesium rectangle.
* @param {ol.Extent} extent Extent.
* @param {ol.ProjectionLike} projection Extent projection.
* @return {Cesium.Rectangle} The corresponding Cesium rectangle.
*/
export function extentToRectangle(extent, projection) {
if (extent && projection) {
const ext = transformExtent(extent, projection, 'EPSG:4326');
return Cesium.Rectangle.fromDegrees(ext[0], ext[1], ext[2], ext[3]);
}
else {
return null;
}
}
export function sourceToImageryProvider(olMap, source, viewProj, olLayer) {
const skip = source.get('olcs_skip');
if (skip) {
return null;
}
let provider = null;
// Convert ImageWMS to TileWMS
if (source instanceof olSourceImageWMS && source.getUrl()) {
const sourceProps = {
'olcs_proxy': source.get('olcs_proxy'),
'olcs_extent': source.get('olcs_extent'),
'olcs_projection': source.get('olcs_projection'),
'olcs.imagesource': source
};
const imageLoadFunction = source.getImageLoadFunction();
const tileLoadFunction = source.get('olcs_tileLoadFunction') || function tileLoadFunction(tile, src) {
// An imageLoadFunction takes an ImageWrapperm which has a getImage method.
// A tile also has a getImage method.
// We incorrectly passe a tile as an ImageWrapper and hopes for the best.
imageLoadFunction(tile, src);
};
source = new olSourceTileWMS({
url: source.getUrl(),
attributions: source.getAttributions(),
projection: source.getProjection(),
tileLoadFunction,
params: source.getParams()
});
source.setProperties(sourceProps);
}
if (source instanceof olSourceTileImage) {
let projection = getSourceProjection(source);
if (!projection) {
// if not explicit, assume the same projection as view
projection = viewProj;
}
if (isCesiumProjection(projection)) {
provider = new olcsCoreOLImageryProvider(olMap, source, viewProj);
}
// Projection not supported by Cesium
else {
return null;
}
}
else if (source instanceof olSourceImageStatic) {
let projection = getSourceProjection(source);
if (!projection) {
projection = viewProj;
}
if (isCesiumProjection(projection)) {
const rectangle = Cesium.Rectangle.fromDegrees(source.getImageExtent()[0], source.getImageExtent()[1], source.getImageExtent()[2], source.getImageExtent()[3], new Cesium.Rectangle());
provider = new Cesium.SingleTileImageryProvider({
url: source.getUrl(),
rectangle
});
}
// Projection not supported by Cesium
else {
return null;
}
}
else if (source instanceof olSourceVectorTile && olLayer instanceof VectorTileLayer) {
let projection = getSourceProjection(source);
if (!projection) {
projection = viewProj;
}
if (skip === false) {
// MVT is experimental, it should be whitelisted to be synchronized
const fromCode = projection.getCode().split(':')[1];
// @ts-ignore TS2341
const urls = source.urls.map(u => u.replace(fromCode, '3857'));
const extent = olLayer.getExtent();
const rectangle = extentToRectangle(extent, projection);
const minimumLevel = source.get('olcs_minimumLevel');
const attributionsFunction = source.getAttributions();
const styleFunction = olLayer.getStyleFunction();
let credit;
if (extent && attributionsFunction) {
const center = getExtentCenter(extent);
credit = attributionsFunctionToCredits(attributionsFunction, 0, center, extent)[0];
}
provider = new MVTImageryProvider({
credit,
rectangle,
minimumLevel,
styleFunction,
urls
});
return provider;
}
return null; // FIXME: it is disabled by default right now
}
else {
// sources other than TileImage|Imageexport function are currently not supported
return null;
}
return provider;
}
/**
* Creates Cesium.ImageryLayer best corresponding to the given ol.layer.Layer.
* Only supports raster layers and export function images
*/
export function tileLayerToImageryLayer(olMap, olLayer, viewProj) {
if (!(olLayer instanceof olLayerTile) && !(olLayer instanceof olLayerImage) &&
!(olLayer instanceof VectorTileLayer)) {
return null;
}
const source = olLayer.getSource();
if (!source) {
return null;
}
let provider = source.get('olcs_provider');
if (!provider) {
provider = sourceToImageryProvider(olMap, source, viewProj, olLayer);
}
if (!provider) {
return null;
}
const layerOptions = {};
const forcedExtent = (olLayer.get('olcs_extent'));
const ext = forcedExtent || olLayer.getExtent();
if (ext) {
layerOptions.rectangle = extentToRectangle(ext, viewProj);
}
const cesiumLayer = new Cesium.ImageryLayer(provider, layerOptions);
return cesiumLayer;
}
/**
* Synchronizes the layer rendering properties (opacity, visible)
* to the given Cesium ImageryLayer.
*/
export function updateCesiumLayerProperties(olLayerWithParents, csLayer) {
let opacity = 1;
let visible = true;
[olLayerWithParents.layer].concat(olLayerWithParents.parents).forEach((olLayer) => {
const layerOpacity = olLayer.getOpacity();
if (layerOpacity !== undefined) {
opacity *= layerOpacity;
}
const layerVisible = olLayer.getVisible();
if (layerVisible !== undefined) {
visible = visible && layerVisible;
}
});
csLayer.alpha = opacity;
csLayer.show = visible;
}
/**
* Convert a 2D or 3D OpenLayers coordinate to Cesium.
*/
export function ol4326CoordinateToCesiumCartesian(coordinate) {
const coo = coordinate;
return coo.length > 2 ?
Cesium.Cartesian3.fromDegrees(coo[0], coo[1], coo[2]) :
Cesium.Cartesian3.fromDegrees(coo[0], coo[1]);
}
/**
* Convert an array of 2D or 3D OpenLayers coordinates to Cesium.
*/
export function ol4326CoordinateArrayToCsCartesians(coordinates) {
console.assert(coordinates !== null);
const toCartesian = ol4326CoordinateToCesiumCartesian;
const cartesians = [];
for (let i = 0; i < coordinates.length; ++i) {
cartesians.push(toCartesian(coordinates[i]));
}
return cartesians;
}
/**
* Reproject an OpenLayers geometry to EPSG:4326 if needed.
* The geometry will be cloned only when original projection is not EPSG:4326
* and the properties will be shallow copied.
*/
export function olGeometryCloneTo4326(geometry, projection) {
console.assert(!!projection);
const proj4326 = getProjection('EPSG:4326');
const proj = getProjection(projection);
if (proj.getCode() !== proj4326.getCode()) {
const properties = geometry.getProperties();
geometry = geometry.clone();
geometry.transform(proj, proj4326);
geometry.setProperties(properties);
}
return geometry;
}
/**
* Convert an OpenLayers color to Cesium.
*/
export function convertColorToCesium(olColor) {
olColor = olColor || 'black';
if (Array.isArray(olColor)) {
return new Cesium.Color(Cesium.Color.byteToFloat(olColor[0]), Cesium.Color.byteToFloat(olColor[1]), Cesium.Color.byteToFloat(olColor[2]), olColor[3]);
}
else if (typeof olColor == 'string') {
return Cesium.Color.fromCssColorString(olColor);
}
else if (olColor instanceof CanvasPattern || olColor instanceof CanvasGradient) {
// Render the CanvasPattern/CanvasGradient into a canvas that will be sent to Cesium as material
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = canvas.height = 256;
ctx.fillStyle = olColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
return new Cesium.ImageMaterialProperty({
image: canvas
});
}
console.assert(false, 'impossible');
}
/**
* Convert an OpenLayers url to Cesium.
*/
export function convertUrlToCesium(url) {
let subdomains = '';
const re = /\{(\d|[a-z])-(\d|[a-z])\}/;
const match = re.exec(url);
if (match) {
url = url.replace(re, '{s}');
const startCharCode = match[1].charCodeAt(0);
const stopCharCode = match[2].charCodeAt(0);
let charCode;
for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {
subdomains += String.fromCharCode(charCode);
}
}
return {
url,
subdomains
};
}
/**
* Animate the return to a top-down view from the zenith.
* The camera is rotated to orient to the North.
*/
export function resetToNorthZenith(map, scene) {
return new Promise((resolve, reject) => {
const camera = scene.camera;
const pivot = pickBottomPoint(scene);
if (!pivot) {
reject('Could not get bottom pivot');
return;
}
const currentHeading = map.getView().getRotation();
if (currentHeading === undefined) {
reject('The view is not initialized');
return;
}
const angle = computeAngleToZenith(scene, pivot);
// Point to North
setHeadingUsingBottomCenter(scene, currentHeading, pivot);
// Go to zenith
const transform = Cesium.Matrix4.fromTranslation(pivot);
const axis = camera.right;
const options = {
callback: () => {
const view = map.getView();
normalizeView(view);
resolve(undefined);
}
};
rotateAroundAxis(camera, -angle, axis, transform, options);
});
}
/**
* @param {!Cesium.Scene} scene
* @param {number} angle in radian
* @return {Promise<undefined>}
* @api
*/
export function rotateAroundBottomCenter(scene, angle) {
return new Promise((resolve, reject) => {
const camera = scene.camera;
const pivot = pickBottomPoint(scene);
if (!pivot) {
reject('could not get bottom pivot');
return;
}
const options = { callback: () => resolve(undefined) };
const transform = Cesium.Matrix4.fromTranslation(pivot);
const axis = camera.right;
rotateAroundAxis(camera, -angle, axis, transform, options);
});
}
/**
* Set the OpenLayers view to a specific rotation and
* the nearest resolution.
*/
export function normalizeView(view, angle = 0) {
const resolution = view.getResolution();
view.setRotation(angle);
// @ts-ignore TS2341
if (view.constrainResolution) {
// @ts-ignore TS2341
view.setResolution(view.constrainResolution(resolution));
}
else {
view.setResolution(view.getConstrainedResolution(resolution));
}
}
/**
* Check if the given projection is managed by Cesium (WGS84 or Mercator Spheric)
*/
export function isCesiumProjection(projection) {
const is3857 = projection.getCode() === 'EPSG:3857';
const is4326 = projection.getCode() === 'EPSG:4326';
return is3857 || is4326;
}
export function attributionsFunctionToCredits(attributionsFunction, zoom, center, extent) {
if (!attributionsFunction) {
return [];
}
let attributions = attributionsFunction({
viewState: { zoom, center, projection: undefined, resolution: undefined, rotation: undefined },
extent,
});
if (!Array.isArray(attributions)) {
attributions = [attributions];
}
return attributions.map(html => new Cesium.Credit(html, true));
}
/**
* calculate the distance between camera and centerpoint based on the resolution and latitude value
*/
export function calcDistanceForResolution(resolution, latitude, scene, projection) {
const canvas = scene.canvas;
const camera = scene.camera;
// @ts-ignore TS2341
const fovy = camera.frustum.fovy; // vertical field of view
console.assert(!isNaN(fovy));
const metersPerUnit = projection.getMetersPerUnit();
// number of "map units" visible in 2D (vertically)
const visibleMapUnits = resolution * canvas.clientHeight;
// The metersPerUnit does not take latitude into account, but it should
// be lower with increasing latitude -- we have to compensate.
// In 3D it is not possible to maintain the resolution at more than one point,
// so it only makes sense to use the latitude of the "target" point.
const relativeCircumference = Math.cos(Math.abs(latitude));
// how many meters should be visible in 3D
const visibleMeters = visibleMapUnits * metersPerUnit * relativeCircumference;
// distance required to view the calculated length in meters
//
// fovy/2
// |\
// x | \
// |--\
// visibleMeters/2
const requiredDistance = (visibleMeters / 2) / Math.tan(fovy / 2);
// NOTE: This calculation is not absolutely precise, because metersPerUnit
// is a great simplification. It does not take ellipsoid/terrain into account.
return requiredDistance;
}
/**
* calculate the resolution based on a distance(camera to position) and latitude value
*/
export function calcResolutionForDistance(distance, latitude, scene, projection) {
// See the reverse calculation (calcDistanceForResolution) for details
const canvas = scene.canvas;
const camera = scene.camera;
// @ts-ignore TS2341
const fovy = camera.frustum.fovy; // vertical field of view
console.assert(!isNaN(fovy));
const metersPerUnit = projection.getMetersPerUnit();
const visibleMeters = 2 * distance * Math.tan(fovy / 2);
const relativeCircumference = Math.cos(Math.abs(latitude));
const visibleMapUnits = visibleMeters / metersPerUnit / relativeCircumference;
const resolution = visibleMapUnits / canvas.clientHeight;
return resolution;
}
/**
* Constrain the camera so that it stays close to the bounding sphere of the map extent.
* Near the ground the allowed distance is shorter.
*/
export function limitCameraToBoundingSphere(camera, boundingSphere, ratio) {
let blockLimiter = false;
return function () {
if (!blockLimiter) {
const position = camera.position;
const carto = Cesium.Cartographic.fromCartesian(position);
if (Cesium.Cartesian3.distance(boundingSphere.center, position) > boundingSphere.radius * ratio(carto.height)) {
// @ts-ignore TS2339: FIXME, there is no flying property in Camera
const currentlyFlying = camera.flying;
if (currentlyFlying === true) {
// There is a flying property and its value is true
return;
}
else {
blockLimiter = true;
const unblockLimiter = () => (blockLimiter = false);
camera.flyToBoundingSphere(boundingSphere, {
complete: unblockLimiter,
cancel: unblockLimiter,
});
}
}
}
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9vbGNzL2NvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLE1BQU0sSUFBSSxZQUFZLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFDcEQsT0FBTyxXQUFXLE1BQU0sa0JBQWtCLENBQUM7QUFDM0MsT0FBTyxZQUFZLE1BQU0sbUJBQW1CLENBQUM7QUFDN0MsT0FBTyxFQUFDLEdBQUcsSUFBSSxhQUFhLEVBQXVCLGVBQWUsRUFBQyxNQUFNLFlBQVksQ0FBQztBQUN0RixPQUFPLG1CQUFtQixNQUFNLDBCQUEwQixDQUFDO0FBQzNELE9BQU8sZ0JBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFDckQsT0FBTyxpQkFBaUIsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLGVBQWUsTUFBTSxzQkFBc0IsQ0FBQztBQUNuRCxPQUFPLGtCQUFrQixNQUFNLHlCQUF5QixDQUFDO0FBRXpELE9BQU8seUJBQXlCLE1BQU0sNkJBQTZCLENBQUM7QUFDcEUsT0FBTyxFQUFDLG1CQUFtQixFQUFDLE1BQU0sV0FBVyxDQUFDO0FBQzlDLE9BQU8sa0JBQWtCLE1BQU0seUJBQXlCLENBQUM7QUFDekQsT0FBTyxlQUFlLE1BQU0sd0JBQXdCLENBQUM7QUFDckQsT0FBTyxFQUFjLFNBQVMsSUFBSSxlQUFlLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFtRHZFOzs7R0FHRztBQUNILE1BQU0sVUFBVSw0QkFBNEIsQ0FBQyxLQUFZLEVBQUUsTUFBa0I7SUFDM0UsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUM1QixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQzVCLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUM7SUFDL0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLFVB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