@@ -155,22 +155,21 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
||||
tilesToDrawByZ, getTileIfLoaded);
|
||||
|
||||
var allTilesLoaded = true;
|
||||
var tile, tileCoord, tileState, x, y;
|
||||
var tile, tileState, x, y;
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
|
||||
tileCoord = new ol.TileCoord(z, x, y);
|
||||
tile = tileSource.getTile(tileCoord, tileGrid, projection);
|
||||
tile = tileSource.getTile(z, x, y, tileGrid, projection);
|
||||
tileState = tile.getState();
|
||||
if (tileState == ol.TileState.LOADED || tileState == ol.TileState.EMPTY) {
|
||||
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
||||
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
|
||||
continue;
|
||||
} else if (tileState == ol.TileState.ERROR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
allTilesLoaded = false;
|
||||
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
|
||||
tileGrid.forEachTileCoordParentTileRange(tile.tileCoord, findLoadedTiles);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -191,9 +190,8 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
||||
if (currentZ == z) {
|
||||
for (tileCoordKey in tilesToDraw) {
|
||||
tile = tilesToDraw[tileCoordKey];
|
||||
tileCoord = tile.tileCoord;
|
||||
index = (tileCoord.y - tileRange.minY) * tileRangeWidth +
|
||||
(tileCoord.x - tileRange.minX);
|
||||
index = (tile.tileCoord.y - tileRange.minY) * tileRangeWidth +
|
||||
(tile.tileCoord.x - tileRange.minX);
|
||||
if (this.renderedTiles_[index] != tile) {
|
||||
x = tileSize.width * (tile.tileCoord.x - tileRange.minX);
|
||||
y = tileSize.height * (tileRange.maxY - tile.tileCoord.y);
|
||||
|
||||
@@ -112,15 +112,14 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
||||
tilesToDrawByZ, getTileIfLoaded);
|
||||
|
||||
var allTilesLoaded = true;
|
||||
var tile, tileCoord, tileState, x, y;
|
||||
var tile, tileState, x, y;
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
|
||||
tileCoord = new ol.TileCoord(z, x, y);
|
||||
tile = tileSource.getTile(tileCoord, tileGrid, projection);
|
||||
tile = tileSource.getTile(z, x, y, tileGrid, projection);
|
||||
tileState = tile.getState();
|
||||
if (tileState == ol.TileState.LOADED) {
|
||||
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
||||
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
|
||||
continue;
|
||||
} else if (tileState == ol.TileState.ERROR ||
|
||||
tileState == ol.TileState.EMPTY) {
|
||||
@@ -128,7 +127,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
||||
}
|
||||
|
||||
allTilesLoaded = false;
|
||||
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
|
||||
tileGrid.forEachTileCoordParentTileRange(tile.tileCoord, findLoadedTiles);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ goog.require('ol.Image');
|
||||
goog.require('ol.ImageState');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileRange');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.layer.Layer');
|
||||
@@ -258,12 +257,13 @@ ol.renderer.Layer.prototype.updateUsedTiles =
|
||||
* @param {ol.source.TileSource} tileSource Tile source.
|
||||
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
|
||||
* @param {ol.Projection} projection Projection.
|
||||
* @return {function(ol.TileCoord): ol.Tile} Returns a tile if it is loaded.
|
||||
* @return {function(number, number, number): ol.Tile} Returns a tile if it is
|
||||
* loaded.
|
||||
*/
|
||||
ol.renderer.Layer.prototype.createGetTileIfLoadedFunction =
|
||||
function(isLoadedFunction, tileSource, tileGrid, projection) {
|
||||
return function(tileCoord) {
|
||||
var tile = tileSource.getTile(tileCoord, tileGrid, projection);
|
||||
return function(z, x, y) {
|
||||
var tile = tileSource.getTile(z, x, y, tileGrid, projection);
|
||||
return isLoadedFunction(tile) ? tile : null;
|
||||
};
|
||||
};
|
||||
@@ -307,7 +307,7 @@ ol.renderer.Layer.prototype.manageTilePyramid =
|
||||
}
|
||||
var wantedTiles = frameState.wantedTiles[tileSourceKey];
|
||||
var tileQueue = frameState.tileQueue;
|
||||
var tile, tileCenter, tileCoord, tileRange, tileResolution, x, y, z;
|
||||
var tile, tileCenter, tileRange, tileResolution, x, y, z;
|
||||
// FIXME this should loop up to tileGrid's minZ when implemented
|
||||
for (z = currentZ; z >= 0; --z) {
|
||||
tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
|
||||
@@ -315,15 +315,14 @@ ol.renderer.Layer.prototype.manageTilePyramid =
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
if (ol.PREEMPTIVELY_LOAD_LOW_RESOLUTION_TILES || z == currentZ) {
|
||||
tileCoord = new ol.TileCoord(z, x, y);
|
||||
tile = tileSource.getTile(tileCoord, tileGrid, projection);
|
||||
tile = tileSource.getTile(z, x, y, tileGrid, projection);
|
||||
if (tile.getState() == ol.TileState.IDLE) {
|
||||
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
||||
wantedTiles[tileCoord.toString()] = true;
|
||||
tileCenter = tileGrid.getTileCoordCenter(tile.tileCoord);
|
||||
wantedTiles[tile.tileCoord.toString()] = true;
|
||||
tileQueue.enqueue(tile, tileSourceKey, tileCenter, tileResolution);
|
||||
}
|
||||
} else {
|
||||
tileSource.useTile(z + '/' + x + '/' + y);
|
||||
tileSource.useTile(z, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ goog.require('goog.webgl');
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Size');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileRange');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.layer.TileLayer');
|
||||
@@ -214,19 +213,18 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
||||
var tilesToLoad = new goog.structs.PriorityQueue();
|
||||
|
||||
var allTilesLoaded = true;
|
||||
var deltaX, deltaY, priority, tile, tileCenter, tileCoord, tileState, x, y;
|
||||
var deltaX, deltaY, priority, tile, tileCenter, tileState, x, y;
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
|
||||
tileCoord = new ol.TileCoord(z, x, y);
|
||||
tile = tileSource.getTile(tileCoord, tileGrid, projection);
|
||||
tile = tileSource.getTile(z, x, y, tileGrid, projection);
|
||||
tileState = tile.getState();
|
||||
if (tileState == ol.TileState.LOADED) {
|
||||
if (mapRenderer.isTileTextureLoaded(tile)) {
|
||||
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
||||
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
|
||||
continue;
|
||||
} else {
|
||||
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
||||
tileCenter = tileGrid.getTileCoordCenter(tile.tileCoord);
|
||||
deltaX = tileCenter.x - center.x;
|
||||
deltaY = tileCenter.y - center.y;
|
||||
priority = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
@@ -238,7 +236,8 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
||||
}
|
||||
|
||||
allTilesLoaded = false;
|
||||
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
|
||||
tileGrid.forEachTileCoordParentTileRange(
|
||||
tile.tileCoord, findLoadedTiles);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -122,13 +122,13 @@ ol.source.DebugTileSource.prototype.expireCache = function(usedTiles) {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.source.DebugTileSource.prototype.getTile = function(tileCoord) {
|
||||
var key = tileCoord.toString();
|
||||
if (this.tileCache_.containsKey(key)) {
|
||||
return /** @type {!ol.DebugTile_} */ (this.tileCache_.get(key));
|
||||
ol.source.DebugTileSource.prototype.getTile = function(z, x, y) {
|
||||
var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
|
||||
if (this.tileCache_.containsKey(tileCoordKey)) {
|
||||
return /** @type {!ol.DebugTile_} */ (this.tileCache_.get(tileCoordKey));
|
||||
} else {
|
||||
var tile = new ol.DebugTile_(tileCoord, this.tileGrid);
|
||||
this.tileCache_.set(key, tile);
|
||||
var tile = new ol.DebugTile_(new ol.TileCoord(z, x, y), this.tileGrid);
|
||||
this.tileCache_.set(tileCoordKey, tile);
|
||||
return tile;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ goog.require('ol.ImageTile');
|
||||
goog.require('ol.Projection');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileCache');
|
||||
goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.TileUrlFunction');
|
||||
goog.require('ol.TileUrlFunctionType');
|
||||
@@ -87,20 +88,21 @@ ol.source.ImageTileSource.prototype.expireCache = function(usedTiles) {
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.source.ImageTileSource.prototype.getTile =
|
||||
function(tileCoord, tileGrid, projection) {
|
||||
var key = tileCoord.toString();
|
||||
if (this.tileCache_.containsKey(key)) {
|
||||
return /** @type {!ol.Tile} */ (this.tileCache_.get(key));
|
||||
function(z, x, y, tileGrid, projection) {
|
||||
var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
|
||||
if (this.tileCache_.containsKey(tileCoordKey)) {
|
||||
return /** @type {!ol.Tile} */ (this.tileCache_.get(tileCoordKey));
|
||||
} else {
|
||||
goog.asserts.assert(tileGrid);
|
||||
goog.asserts.assert(projection);
|
||||
var tileCoord = new ol.TileCoord(z, x, y);
|
||||
var tileUrl = this.tileUrlFunction(tileCoord, tileGrid, projection);
|
||||
var tile = new ol.ImageTile(
|
||||
tileCoord,
|
||||
goog.isDef(tileUrl) ? ol.TileState.IDLE : ol.TileState.EMPTY,
|
||||
goog.isDef(tileUrl) ? tileUrl : '',
|
||||
this.crossOrigin_);
|
||||
this.tileCache_.set(key, tile);
|
||||
this.tileCache_.set(tileCoordKey, tile);
|
||||
return tile;
|
||||
}
|
||||
};
|
||||
@@ -109,7 +111,8 @@ ol.source.ImageTileSource.prototype.getTile =
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.source.ImageTileSource.prototype.useTile = function(tileCoordKey) {
|
||||
ol.source.ImageTileSource.prototype.useTile = function(z, x, y) {
|
||||
var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
|
||||
if (this.tileCache_.containsKey(tileCoordKey)) {
|
||||
this.tileCache_.get(tileCoordKey);
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ ol.source.TileSource.prototype.expireCache = goog.abstractMethod;
|
||||
*
|
||||
* @param {Object.<number, Object.<string, ol.Tile>>} loadedTilesByZ A lookup of
|
||||
* loaded tiles by zoom level.
|
||||
* @param {function(ol.TileCoord): ol.Tile} getTileIfLoaded A function that
|
||||
* returns the tile only if it is fully loaded.
|
||||
* @param {function(number, number, number): ol.Tile} getTileIfLoaded A function
|
||||
* that returns the tile only if it is fully loaded.
|
||||
* @param {number} z Zoom level.
|
||||
* @param {ol.TileRange} tileRange Tile range.
|
||||
* @return {boolean} The tile range is fully covered with loaded tiles.
|
||||
@@ -82,15 +82,14 @@ ol.source.TileSource.prototype.findLoadedTiles = function(loadedTilesByZ,
|
||||
getTileIfLoaded, z, tileRange) {
|
||||
// FIXME this could be more efficient about filling partial holes
|
||||
var fullyCovered = true;
|
||||
var tile, tileCoord, tileCoordKey, x, y;
|
||||
var tile, tileCoordKey, x, y;
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
tileCoord = new ol.TileCoord(z, x, y);
|
||||
tileCoordKey = tileCoord.toString();
|
||||
tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
|
||||
if (loadedTilesByZ[z] && loadedTilesByZ[z][tileCoordKey]) {
|
||||
continue;
|
||||
}
|
||||
tile = getTileIfLoaded(tileCoord);
|
||||
tile = getTileIfLoaded(z, x, y);
|
||||
if (!goog.isNull(tile)) {
|
||||
if (!loadedTilesByZ[z]) {
|
||||
loadedTilesByZ[z] = {};
|
||||
@@ -122,7 +121,9 @@ ol.source.TileSource.prototype.getResolutions = function() {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.TileCoord} tileCoord Tile coordinate.
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @param {ol.tilegrid.TileGrid=} opt_tileGrid Tile grid.
|
||||
* @param {ol.Projection=} opt_projection Projection.
|
||||
* @return {!ol.Tile} Tile.
|
||||
@@ -140,6 +141,8 @@ ol.source.TileSource.prototype.getTileGrid = function() {
|
||||
|
||||
/**
|
||||
* Marks a tile coord as being used, without triggering a load.
|
||||
* @param {string} tileCoordKey Tile coordinate key.
|
||||
* @param {number} z Tile coordinate z.
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
*/
|
||||
ol.source.TileSource.prototype.useTile = goog.nullFunction;
|
||||
|
||||
@@ -78,6 +78,17 @@ ol.TileCoord.createFromString = function(str) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} z Z.
|
||||
* @param {number} x X.
|
||||
* @param {number} y Y.
|
||||
* @return {string} Key.
|
||||
*/
|
||||
ol.TileCoord.getKeyZXY = function(z, x, y) {
|
||||
return [z, x, y].join('/');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Hash.
|
||||
*/
|
||||
@@ -112,5 +123,5 @@ ol.TileCoord.prototype.quadKey = function() {
|
||||
* @return {string} String.
|
||||
*/
|
||||
ol.TileCoord.prototype.toString = function() {
|
||||
return [this.z, this.x, this.y].join('/');
|
||||
return ol.TileCoord.getKeyZXY(this.z, this.x, this.y);
|
||||
};
|
||||
|
||||
@@ -137,13 +137,12 @@ ol.tilegrid.TileGrid.prototype.getPixelBoundsForTileCoordAndResolution =
|
||||
function(tileCoord, resolution) {
|
||||
var scale = resolution / this.getResolution(tileCoord.z);
|
||||
var tileSize = this.getTileSize(tileCoord.z);
|
||||
tileSize = new ol.Size(tileSize.width / scale,
|
||||
tileSize.height / scale);
|
||||
var minX, maxX, minY, maxY;
|
||||
minX = Math.round(tileCoord.x * tileSize.width);
|
||||
maxX = Math.round((tileCoord.x + 1) * tileSize.width);
|
||||
minY = Math.round(tileCoord.y * tileSize.height);
|
||||
maxY = Math.round((tileCoord.y + 1) * tileSize.height);
|
||||
var tileWidth = tileSize.width / scale;
|
||||
var tileHeight = tileSize.height / scale;
|
||||
var minX = Math.round(tileCoord.x * tileWidth);
|
||||
var minY = Math.round(tileCoord.y * tileHeight);
|
||||
var maxX = Math.round((tileCoord.x + 1) * tileWidth);
|
||||
var maxY = Math.round((tileCoord.y + 1) * tileHeight);
|
||||
return new ol.PixelBounds(minX, minY, maxX, maxY);
|
||||
};
|
||||
|
||||
@@ -190,10 +189,10 @@ ol.tilegrid.TileGrid.prototype.getTileRangeExtent = function(z, tileRange) {
|
||||
*/
|
||||
ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = function(
|
||||
extent, resolution) {
|
||||
var min = this.getTileCoordForCoordAndResolution_(
|
||||
new ol.Coordinate(extent.minX, extent.minY), resolution);
|
||||
var max = this.getTileCoordForCoordAndResolution_(
|
||||
new ol.Coordinate(extent.maxX, extent.maxY), resolution, true);
|
||||
var min = this.getTileCoordForXYAndResolution_(
|
||||
extent.minX, extent.minY, resolution, false);
|
||||
var max = this.getTileCoordForXYAndResolution_(
|
||||
extent.maxX, extent.maxY, resolution, true);
|
||||
return new ol.TileRange(min.x, min.y, max.x, max.y);
|
||||
};
|
||||
|
||||
@@ -250,38 +249,40 @@ ol.tilegrid.TileGrid.prototype.getTileCoordExtent = function(tileCoord) {
|
||||
*/
|
||||
ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution = function(
|
||||
coordinate, resolution) {
|
||||
return this.getTileCoordForCoordAndResolution_(coordinate, resolution);
|
||||
return this.getTileCoordForXYAndResolution_(
|
||||
coordinate.x, coordinate.y, resolution, false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @param {number} x X.
|
||||
* @param {number} y Y.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {boolean=} opt_reverseIntersectionPolicy Instead of letting edge
|
||||
* @param {boolean} reverseIntersectionPolicy Instead of letting edge
|
||||
* intersections go to the higher tile coordinate, let edge intersections
|
||||
* go to the lower tile coordinate.
|
||||
* @return {ol.TileCoord} Tile coordinate.
|
||||
* @private
|
||||
*/
|
||||
ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution_ = function(
|
||||
coordinate, resolution, opt_reverseIntersectionPolicy) {
|
||||
ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function(
|
||||
x, y, resolution, reverseIntersectionPolicy) {
|
||||
var z = this.getZForResolution(resolution);
|
||||
var scale = resolution / this.getResolution(z);
|
||||
var origin = this.getOrigin(z);
|
||||
var tileSize = this.getTileSize(z);
|
||||
|
||||
var x = scale * (coordinate.x - origin.x) / (resolution * tileSize.width);
|
||||
var y = scale * (coordinate.y - origin.y) / (resolution * tileSize.height);
|
||||
var tileCoordX = scale * (x - origin.x) / (resolution * tileSize.width);
|
||||
var tileCoordY = scale * (y - origin.y) / (resolution * tileSize.height);
|
||||
|
||||
if (!opt_reverseIntersectionPolicy) {
|
||||
x = Math.floor(x);
|
||||
y = Math.floor(y);
|
||||
if (reverseIntersectionPolicy) {
|
||||
tileCoordX = Math.ceil(tileCoordX) - 1;
|
||||
tileCoordY = Math.ceil(tileCoordY) - 1;
|
||||
} else {
|
||||
x = Math.ceil(x) - 1;
|
||||
y = Math.ceil(y) - 1;
|
||||
tileCoordX = Math.floor(tileCoordX);
|
||||
tileCoordY = Math.floor(tileCoordY);
|
||||
}
|
||||
|
||||
return new ol.TileCoord(z, x, y);
|
||||
return new ol.TileCoord(z, tileCoordX, tileCoordY);
|
||||
};
|
||||
|
||||
|
||||
@@ -293,7 +294,8 @@ ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution_ = function(
|
||||
ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ =
|
||||
function(coordinate, z) {
|
||||
var resolution = this.getResolution(z);
|
||||
return this.getTileCoordForCoordAndResolution_(coordinate, resolution);
|
||||
return this.getTileCoordForXYAndResolution_(
|
||||
coordinate.x, coordinate.y, resolution, false);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -39,18 +39,11 @@ goog.inherits(ol.tilegrid.XYZ, ol.tilegrid.TileGrid);
|
||||
*/
|
||||
ol.tilegrid.XYZ.prototype.forEachTileCoordParentTileRange =
|
||||
function(tileCoord, callback, opt_obj) {
|
||||
var x = tileCoord.x;
|
||||
var y = tileCoord.y;
|
||||
var z = tileCoord.z;
|
||||
var tileRange;
|
||||
while (true) {
|
||||
z -= 1;
|
||||
if (z < 0) {
|
||||
break;
|
||||
}
|
||||
x >>= 1;
|
||||
y >>= 1;
|
||||
tileRange = new ol.TileRange(x, y, x, y);
|
||||
var tileRange = new ol.TileRange(0, 0, tileCoord.x, tileCoord.y);
|
||||
var z;
|
||||
for (z = tileCoord.z - 1; z >= 0; --z) {
|
||||
tileRange.minX = tileRange.maxX >>= 1;
|
||||
tileRange.minY = tileRange.maxY >>= 1;
|
||||
if (callback.call(opt_obj, z, tileRange)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user