ol-cesium
Version:
OpenLayers Cesium integration library
274 lines • 19 kB
JavaScript
import { getSourceProjection } from '../util';
import { Tile as TileSource } from 'ol/source.js';
import { attributionsFunctionToCredits } from '../core';
export function createEmptyCanvas() {
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
return canvas;
}
const olUseNewCoordinates = (function () {
const tileSource = new TileSource({
projection: 'EPSG:3857',
wrapX: true
});
const tileCoord = tileSource.getTileCoordForTileUrlFunction([6, -31, 22]);
return tileCoord && tileCoord[1] === 33 && tileCoord[2] === 22;
// See b/test/spec/ol/source/tile.test.js
// of e9a30c5cb7e3721d9370025fbe5472c322847b35 in OpenLayers repository
})();
export default class OLImageryProvider {
source_;
projection_;
fallbackProj_;
map_;
shouldRequestNextLevel;
emptyCanvas_ = createEmptyCanvas();
emptyCanvasPromise_ = Promise.resolve(this.emptyCanvas_);
tilingScheme_;
ready_;
rectangle_;
/**
* When <code>true</code>, this model is ready to render, i.e., the external binary, image,
* and shader files were downloaded and the WebGL resources were created.
*/
get ready() {
return this.ready_;
}
/**
* Gets the rectangle, in radians, of the imagery provided by the instance.
*/
get rectangle() {
return this.rectangle_;
}
/**
* Gets the tiling scheme used by the provider.
*/
get tilingScheme() {
return this.tilingScheme_;
}
/**
* Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
* to the event, you will be notified of the error and can potentially recover from it. Event listeners
* are passed an instance of {@link Cesium.TileProviderError}.
*/
errorEvent = new Cesium.Event();
/**
* Gets the credit to display when this imagery provider is active. Typically this is used to credit
* the source of the imagery.
*/
credit;
/**
* Gets the proxy used by this provider.
*/
proxy;
get _ready() {
return this.ready_;
}
/**
* Gets the width of each tile, in pixels.
*/
get tileWidth() {
const tileGrid = this.source_.getTileGrid();
if (tileGrid) {
const tileSizeAtZoom0 = tileGrid.getTileSize(0);
if (Array.isArray(tileSizeAtZoom0)) {
return tileSizeAtZoom0[0];
}
else {
return tileSizeAtZoom0; // same width and height
}
}
return 256;
}
/**
* Gets the height of each tile, in pixels.
*/
get tileHeight() {
const tileGrid = this.source_.getTileGrid();
if (tileGrid) {
const tileSizeAtZoom0 = tileGrid.getTileSize(0);
if (Array.isArray(tileSizeAtZoom0)) {
return tileSizeAtZoom0[1];
}
else {
return tileSizeAtZoom0; // same width and height
}
}
return 256;
}
/**
* Gets the maximum level-of-detail that can be requested.
*/
get maximumLevel() {
const tileGrid = this.source_.getTileGrid();
if (tileGrid) {
return tileGrid.getMaxZoom();
}
else {
return 18; // some arbitrary value
}
}
// FIXME: to implement, we could check the number of tiles at minzoom (for this rectangle) and return 0 if too big
/**
* Gets the minimum level-of-detail that can be requested. Generally,
* a minimum level should only be used when the rectangle of the imagery is small
* enough that the number of tiles at the minimum level is small. An imagery
* provider with more than a few tiles at the minimum level will lead to
* rendering problems.
*/
get minimumLevel() {
// WARNING: Do not use the minimum level (at least until the extent is
// properly set). Cesium assumes the minimumLevel to contain only
// a few tiles and tries to load them all at once -- this can
// freeze and/or crash the browser !
return 0;
//var tg = this.source_.getTileGrid();
//return tg ? tg.getMinZoom() : 0;
}
/**
* Gets the tile discard policy. If not undefined, the discard policy is responsible
* for filtering out "missing" tiles via its shouldDiscardImage function. If this function
* returns undefined, no tiles are filtered.
*/
get tileDiscardPolicy() {
return undefined;
}
// FIXME: this might be exposed
/**
* Gets a value indicating whether or not the images provided by this imagery provider
* include an alpha channel. If this property is false, an alpha channel, if present, will
* be ignored. If this property is true, any images without an alpha channel will be treated
* as if their alpha is 1.0 everywhere. When this property is false, memory usage
* and texture upload time are reduced.
*/
get hasAlphaChannel() {
return true;
}
// FIXME: this could be implemented by proxying to OL
/**
* Asynchronously determines what features, if any, are located at a given longitude and latitude within
* a tile.
* This function is optional, so it may not exist on all ImageryProviders.
* @param x - The tile X coordinate.
* @param y - The tile Y coordinate.
* @param level - The tile level.
* @param longitude - The longitude at which to pick features.
* @param latitude - The latitude at which to pick features.
* @return A promise for the picked features that will resolve when the asynchronous
* picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
* instances. The array may be empty if no features are found at the given location.
* It may also be undefined if picking is not supported.
*/
pickFeatures(x, y, level, longitude, latitude) {
return undefined;
}
/**
* Special class derived from Cesium.ImageryProvider
* that is connected to the given ol.source.TileImage.
* @param olMap OL map
* @param source Tile image source
* @param [opt_fallbackProj] Projection to assume if source has no projection
*/
constructor(olMap, source, opt_fallbackProj) {
this.source_ = source;
this.projection_ = null;
this.ready_ = false;
this.fallbackProj_ = opt_fallbackProj || null;
// cesium v107+ don't wait for ready anymore so we put somehing here while it loads
this.tilingScheme_ = new Cesium.WebMercatorTilingScheme();
this.rectangle_ = null;
this.map_ = olMap;
this.shouldRequestNextLevel = false;
const proxy = this.source_.get('olcs.proxy');
if (proxy) {
if (typeof proxy === 'function') {
// Duck typing a proxy
this.proxy = {
'getURL': proxy
};
}
else if (typeof proxy === 'string') {
this.proxy = new Cesium.DefaultProxy(proxy);
}
}
this.source_.on('change', (e) => {
this.handleSourceChanged_();
});
this.handleSourceChanged_();
}
/**
* Checks if the underlying source is ready and cached required data.
*/
handleSourceChanged_() {
if (!this.ready_ && this.source_.getState() == 'ready') {
this.projection_ = getSourceProjection(this.source_) || this.fallbackProj_;
const options = { numberOfLevelZeroTilesX: 1, numberOfLevelZeroTilesY: 1 };
if (this.source_.tileGrid !== null) {
// Get the number of tiles at level 0 if it is defined
this.source_.tileGrid.forEachTileCoord(this.projection_.getExtent(), 0, ([zoom, xIndex, yIndex]) => {
options.numberOfLevelZeroTilesX = xIndex + 1;
options.numberOfLevelZeroTilesY = yIndex + 1;
});
}
if (this.projection_.getCode() === 'EPSG:4326') {
// Cesium zoom level 0 is OpenLayers zoom level 1 for layer in EPSG:4326 with a single tile on level 0
this.shouldRequestNextLevel = options.numberOfLevelZeroTilesX === 1 && options.numberOfLevelZeroTilesY === 1;
this.tilingScheme_ = new Cesium.GeographicTilingScheme(options);
}
else if (this.projection_.getCode() === 'EPSG:3857') {
this.shouldRequestNextLevel = false;
this.tilingScheme_ = new Cesium.WebMercatorTilingScheme(options);
}
else {
return;
}
this.rectangle_ = this.tilingScheme_.rectangle;
this.ready_ = true;
}
}
/**
* Generates the proper attributions for a given position and zoom
* level.
* @implements
*/
getTileCredits(x, y, level) {
const attributionsFunction = this.source_.getAttributions();
if (!attributionsFunction) {
return [];
}
const extent = this.map_.getView().calculateExtent(this.map_.getSize());
const center = this.map_.getView().getCenter();
const zoom = this.shouldRequestNextLevel ? level + 1 : level;
return attributionsFunctionToCredits(attributionsFunction, zoom, center, extent);
}
/**
* @implements
*/
requestImage(x, y, level, request) {
const tileUrlFunction = this.source_.getTileUrlFunction();
if (tileUrlFunction && this.projection_) {
const z_ = this.shouldRequestNextLevel ? level + 1 : level;
let y_ = y;
if (!olUseNewCoordinates) {
// LEGACY
// OpenLayers version 3 to 5 tile coordinates increase from bottom to top
y_ = -y - 1;
}
let url = tileUrlFunction.call(this.source_, [z_, x, y_], 1, this.projection_);
if (this.proxy) {
url = this.proxy.getURL(url);
}
if (url) {
// It is probably safe to cast here
return Cesium.ImageryProvider.loadImage(this, url);
}
return this.emptyCanvasPromise_;
}
else {
// return empty canvas to stop Cesium from retrying later
return this.emptyCanvasPromise_;
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT0xJbWFnZXJ5UHJvdmlkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvb2xjcy9jb3JlL09MSW1hZ2VyeVByb3ZpZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxtQkFBbUIsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUM1QyxPQUFPLEVBQUMsSUFBSSxJQUFJLFVBQVUsRUFBaUIsTUFBTSxjQUFjLENBQUM7QUFDaEUsT0FBTyxFQUFDLDZCQUE2QixFQUFDLE1BQU0sU0FBUyxDQUFDO0FBTXRELE1BQU0sVUFBVSxpQkFBaUI7SUFDL0IsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNoRCxNQUFNLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNqQixNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUNsQixPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQsTUFBTSxtQkFBbUIsR0FBRyxDQUFDO0lBQzNCLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDO1FBQ2hDLFVBQVUsRUFBRSxXQUFXO1FBQ3ZCLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQyxDQUFDO0lBQ0gsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLDhCQUE4QixDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDMUUsT0FBTyxTQUFTLElBQUksU0FBUyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQy9ELHlDQUF5QztJQUN6Qyx1RUFBdUU7QUFDekUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUdMLE1BQU0sQ0FBQyxPQUFPLE9BQU8saUJBQWlCO0lBQzVCLE9BQU8sQ0FBWTtJQUNuQixXQUFXLENBQXlCO0lBQ3BDLGFBQWEsQ0FBeUI7SUFDdEMsSUFBSSxDQUFNO0lBQ1Ysc0JBQXNCLENBQVU7SUFDaEMsWUFBWSxHQUFzQixpQkFBaUIsRUFBRSxDQUFDO0lBQ3RELG1CQUFtQixHQUErQixPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUNyRixhQUFhLENBQWU7SUFDNUIsTUFBTSxDQUFVO0lBQ2hCLFVBQVUsQ0FBWTtJQUU5Qjs7O0tBR0M7SUFDRCxJQUFJLEtBQUs7UUFDUCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDckIsQ0FBQztJQUVEOztLQUVDO0lBQ0QsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksWUFBWTtRQUNkLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQztJQUM1QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNNLFVBQVUsR0FBVSxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUVoRDs7O09BR0c7SUFDTSxNQUFNLENBQVM7SUFFeEI7O09BRUc7SUFDTSxLQUFLLENBQVE7SUFFdEIsSUFBSSxNQUFNO1FBQ1IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksU0FBUztRQUNYLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDNUMsSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUNiLE1BQU0sZUFBZSxHQUFHLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDaEQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7Z0JBQ25DLE9BQU8sZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVCLENBQUM7aUJBQU0sQ0FBQztnQkFDTixPQUFPLGVBQWUsQ0FBQyxDQUFDLHdCQUF3QjtZQUNsRCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxVQUFVO1FBQ1osTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUM1QyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQ2IsTUFBTSxlQUFlLEdBQUcsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNoRCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztnQkFDbkMsT0FBTyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDNUIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE9BQU8sZUFBZSxDQUFDLENBQUMsd0JBQXdCO1lBQ2xELENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJLFlBQVk7UUFDZCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzVDLElBQUksUUFBUSxFQUFFLENBQUM7WUFDYixPQUFPLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUMvQixDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sRUFBRSxDQUFDLENBQUMsdUJBQXVCO1FBQ3BDLENBQUM7SUFDSCxDQUFDO0lBRUQsa0hBQWtIO0lBQ2xIOzs7Ozs7T0FNRztJQUNILElBQUksWUFBWTtRQUNkLHNFQUFzRTtRQUN0RSxpRUFBaUU7UUFDakUsNkRBQTZEO1FBQzdELG9DQUFvQztRQUNwQyxPQUFPLENBQUMsQ0FBQztRQUNULHNDQUFzQztRQUN0QyxrQ0FBa0M7SUFDcEMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxJQUFJLGlCQUFpQjtRQUNuQixPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQsK0JBQStCO0lBQy9COzs7Ozs7T0FNRztJQUNILElBQUksZUFBZTtRQUNqQixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxxREFBcUQ7SUFDckQ7Ozs7Ozs7Ozs7Ozs7T0FhRztJQUNILFlBQVksQ0FBQyxDQUFTLEVBQUUsQ0FBUyxFQUFFLEtBQWEsRUFBRSxTQUFpQixFQUFFLFFBQWdCO1FBQ25GLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxZQUFZLEtBQVUsRUFBRSxNQUFpQixFQUFFLGdCQUE0QjtRQUNyRSxJQUFJLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztRQUV0QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUV4QixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUVwQixJQUFJLENBQUMsYUFBYSxHQUFHLGdCQUFnQixJQUFJLElBQUksQ0FBQztRQUU5QyxtRkFBbUY7UUFDbkYsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLE1BQU0sQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBRTFELElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1FBRXZCLElBQUksQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDO1FBRWxCLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxLQUFLLENBQUM7UUFFcEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDN0MsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNWLElBQUksT0FBTyxLQUFLLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQ2hDLHNCQUFzQjtnQkFDdEIsSUFBSSxDQUFDLEtBQUssR0FBRztvQkFDWCxRQUFRLEVBQUUsS0FBSztpQkFDUCxDQUFDO1lBQ2IsQ0FBQztpQkFBTSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUNyQyxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM5QyxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFO1lBQzlCLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzlCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssb0JBQW9CO1FBQzFCLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLElBQUksT0FBTyxFQUFFLENBQUM7WUFDdkQsSUFBSSxDQUFDLFdBQVcsR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksSUFBSSxDQUFDLGFBQWEsQ0FBQztZQUMzRSxNQUFNLE9BQU8sR0FBRyxFQUFDLHVCQUF1QixFQUFFLENBQUMsRUFBRSx1QkFBdUIsRUFBRSxDQUFDLEVBQUMsQ0FBQztZQUV6RSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUNuQyxzREFBc0Q7Z0JBQ3RELElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUFFLEVBQUU7b0JBQ2pHLE9BQU8sQ0FBQyx1QkFBdUIsR0FBRyxNQUFNLEdBQUcsQ0FBQyxDQUFDO29CQUM3QyxPQUFPLENBQUMsdUJBQXVCLEdBQUcsTUFBTSxHQUFHLENBQUMsQ0FBQztnQkFDL0MsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDO1lBRUQsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUMvQyxzR0FBc0c7Z0JBQ3RHLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxPQUFPLENBQUMsdUJBQXVCLEtBQUssQ0FBQyxJQUFJLE9BQU8sQ0FBQyx1QkFBdUIsS0FBSyxDQUFDLENBQUM7Z0JBQzdHLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxNQUFNLENBQUMsc0JBQXNCLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbEUsQ0FBQztpQkFBTSxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEtBQUssV0FBVyxFQUFFLENBQUM7Z0JBQ3RELElBQUksQ0FBQyxzQkFBc0IsR0FBRyxLQUFLLENBQUM7Z0JBQ3BDLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxNQUFNLENBQUMsdUJBQXVCLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbkUsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE9BQU87WUFDVCxDQUFDO1lBQ0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQztZQUUvQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNyQixDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxjQUFjLENBQUMsQ0FBUyxFQUFFLENBQVMsRUFBRSxLQUFhO1FBQ2hELE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUM1RCxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztZQUMxQixPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7UUFDRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDeEUsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUMvQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztRQUM3RCxPQUFPLDZCQUE2QixDQUFDLG9CQUFvQixFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDbkYsQ0FBQztJQUVEOztPQUVHO0lBQ0gsWUFBWSxDQUFDLENBQVMsRUFBRSxDQUFTLEVBQUUsS0FBYSxFQUFFLE9BQWlCO1FBQ2pFLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMxRCxJQUFJLGVBQWUsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDeEMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7WUFFM0QsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ1gsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7Z0JBQ3pCLFNBQVM7Z0JBQ1QseUVBQXlFO2dCQUN6RSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ2QsQ0FBQztZQUNELElBQUksR0FBRyxHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMvRSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDZixHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDL0IsQ0FBQztZQUNELElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ1IsbUNBQW1DO2dCQUNuQyxPQUFPLE1BQU0sQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxHQUFHLENBQTBCLENBQUM7WUFDOUUsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDO1FBQ2xDLENBQUM7YUFBTSxDQUFDO1lBQ04seURBQXlEO1lBQ3pELE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDO1FBQ2xDLENBQUM7SUFDSCxDQUFDO0NBQ0YifQ==