From 630b290cab6a12d120d12edda3246c7bfe59f2d8 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Fri, 19 Apr 2024 14:22:28 +0300 Subject: [PATCH 01/14] chore(TileMerger): return resulted tile after merge --- MergerLogic/Batching/Tile.cs | 4 ++++ MergerLogic/ImageProcessing/ITileMerger.cs | 2 +- MergerLogic/ImageProcessing/TileMerger.cs | 16 +++++++++++----- .../ImageProcessing/TileMergerTest.cs | 2 +- MergerService/Runners/TaskExecutor.cs | 8 ++++---- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index 52ee5e12..3955aef5 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -72,6 +72,10 @@ public virtual byte[] GetImageBytes() return this._data; } + public int Size() { + return this._data.Length; + } + public void ConvertToFormat(TileFormat format) { if (this.Format == format) { diff --git a/MergerLogic/ImageProcessing/ITileMerger.cs b/MergerLogic/ImageProcessing/ITileMerger.cs index acc82b70..d2dd89a5 100644 --- a/MergerLogic/ImageProcessing/ITileMerger.cs +++ b/MergerLogic/ImageProcessing/ITileMerger.cs @@ -5,6 +5,6 @@ namespace MergerLogic.ImageProcessing { public interface ITileMerger { - byte[]? MergeTiles(List tiles, Coord targetCoords, TileFormat format); + Tile? MergeTiles(List tiles, Coord targetCoords, TileFormat format); } } diff --git a/MergerLogic/ImageProcessing/TileMerger.cs b/MergerLogic/ImageProcessing/TileMerger.cs index a1295a68..85dbe478 100644 --- a/MergerLogic/ImageProcessing/TileMerger.cs +++ b/MergerLogic/ImageProcessing/TileMerger.cs @@ -18,10 +18,12 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) this._tileScaler = tileScaler; } - public byte[]? MergeTiles(List tiles, Coord targetCoords, TileFormat format) + public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormat format) { var images = this.GetImageList(tiles, targetCoords); byte[] data; + Tile tile; + switch (images.Count) { case 0: @@ -29,12 +31,14 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] No images where found return null"); return null; case 1: - ImageFormatter.ConvertToFormat(images[0], format); ImageFormatter.RemoveImageDateAttributes(images[0]); data = images[0].ToByteArray(); images[0].Dispose(); this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] 1 image found"); - return data; + + tile = new Tile(targetCoords, data); + tile.ConvertToFormat(format); + return tile; default: using (var imageCollection = new MagickImageCollection()) { @@ -50,10 +54,12 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) mergedImage.ColorSpace = ColorSpace.sRGB; mergedImage.ColorType = mergedImage.HasAlpha ? ColorType.TrueColorAlpha : ColorType.TrueColor; - ImageFormatter.ConvertToFormat(mergedImage, format); var mergedImageBytes = mergedImage.ToByteArray(); this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] 'imageMagic' merging finished"); - return mergedImageBytes; + + tile = new Tile(targetCoords, mergedImageBytes); + tile.ConvertToFormat(format); + return tile; } } } diff --git a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs index 829564e0..9953070a 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs @@ -98,7 +98,7 @@ public void MergeTiles(Tile[] tiles, Coord targetCoord, TileFormat tileFormat, b var result = this._testTileMerger.MergeTiles(tileBuilders, targetCoord, tileFormat); Assert.IsNotNull(result); - CollectionAssert.AreEqual(expectedTileBytes, result); + CollectionAssert.AreEqual(expectedTileBytes, result.GetImageBytes()); } #endregion diff --git a/MergerService/Runners/TaskExecutor.cs b/MergerService/Runners/TaskExecutor.cs index d5376959..351d9630 100644 --- a/MergerService/Runners/TaskExecutor.cs +++ b/MergerService/Runners/TaskExecutor.cs @@ -168,15 +168,15 @@ public void ExecuteTask(MergeTask task, ITaskUtils taskUtils, string? managerCal correspondingTileBuilders.Add(() => source.GetCorrespondingTile(coord, false)); } var tileMergeStopwatch = Stopwatch.StartNew(); - byte[]? blob = this._tileMerger.MergeTiles(correspondingTileBuilders, coord, + Tile? tile = this._tileMerger.MergeTiles(correspondingTileBuilders, coord, metadata.TargetFormat); tileMergeStopwatch.Stop(); this._metricsProvider.MergeTimePerTileHistogram(tileMergeStopwatch.Elapsed.TotalSeconds, metadata.TargetFormat); - if (blob != null) + if (tile != null) { - tiles.Add(new Tile(coord, blob)); - currentBatchBytes += blob.Length; + tiles.Add(tile); + currentBatchBytes += tile.Size(); // Flushes the "tiles" list if it reached the batch size or the batch max bytes // This is done to prevent memory overflow From 2de58d0907b310d1e90a90902068f2c633b2116a Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Fri, 19 Apr 2024 19:08:05 +0300 Subject: [PATCH 02/14] feat: support mixed image format --- MergerCli/IProcess.cs | 3 +- MergerCli/ISourceParser.cs | 3 +- MergerCli/Process.cs | 28 +++++++---- MergerCli/Program.cs | 7 ++- MergerCli/SourceParser.cs | 9 +--- MergerCli/appsettings.json | 4 ++ MergerLogic/Batching/Tile.cs | 4 -- MergerLogic/ImageProcessing/ITileMerger.cs | 2 +- MergerLogic/ImageProcessing/ImageFormatter.cs | 26 +++++++++- MergerLogic/ImageProcessing/TileMerger.cs | 21 ++++---- MergerLogic/Utils/ImageUtils.cs | 11 +++- .../TestImages/2_1_merged.jpeg | Bin 0 -> 8359 bytes .../ImageProcessing/TileMergerTest.cs | 47 +++++++++++++++--- MergerService/Models/Tasks/Task.cs | 6 ++- MergerService/Runners/TaskExecutor.cs | 7 +-- .../Runners/TaskExecutorTest.cs | 8 +-- 16 files changed, 125 insertions(+), 61 deletions(-) create mode 100644 MergerLogicUnitTests/ImageProcessing/TestImages/2_1_merged.jpeg diff --git a/MergerCli/IProcess.cs b/MergerCli/IProcess.cs index 08885f77..ec2eb8e9 100644 --- a/MergerCli/IProcess.cs +++ b/MergerCli/IProcess.cs @@ -1,12 +1,11 @@ using MergerCli.Utils; using MergerLogic.DataTypes; -using MergerLogic.ImageProcessing; namespace MergerCli { internal interface IProcess { - void Start(TileFormat targetFormat, IData baseData, IData newData, BatchStatusManager batchStatusManager); + void Start(IData baseData, IData newData, BatchStatusManager batchStatusManager); void Validate(IData baseData, IData newData, string? incompleteBatchIdentifier = null); } diff --git a/MergerCli/ISourceParser.cs b/MergerCli/ISourceParser.cs index b2d584fb..2f2a379f 100644 --- a/MergerCli/ISourceParser.cs +++ b/MergerCli/ISourceParser.cs @@ -1,10 +1,9 @@ using MergerLogic.DataTypes; -using MergerLogic.ImageProcessing; namespace MergerCli { internal interface ISourceParser { - List ParseSources(string[] args, int batchSize, out TileFormat format); + List ParseSources(string[] args, int batchSize); } } diff --git a/MergerCli/Process.cs b/MergerCli/Process.cs index 2e778cf5..fec4be8f 100644 --- a/MergerCli/Process.cs +++ b/MergerCli/Process.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using System.Collections.Concurrent; using System.Reflection; +using static MergerLogic.ImageProcessing.TileFormatStrategy; namespace MergerCli { @@ -15,6 +16,7 @@ internal class Process : IProcess private readonly IConfigurationManager _configManager; private readonly ITileMerger _tileMerger; private readonly ILogger _logger; + private TileFormatStrategy _tileFormatStrategy; static readonly object _locker = new object(); public Process(IConfigurationManager configuration, ITileMerger tileMerger, ILogger logger) @@ -22,9 +24,13 @@ public Process(IConfigurationManager configuration, ITileMerger tileMerger, ILog this._configManager = configuration; this._tileMerger = tileMerger; this._logger = logger; + + FormatStrategy outputFormatStrategy = this._configManager.GetConfiguration("TILE", "outputFormatStrategy"); + TileFormat outputFormat = this._configManager.GetConfiguration("TILE", "outputFormat"); + this._tileFormatStrategy = new TileFormatStrategy(outputFormat, outputFormatStrategy); } - public void Start(TileFormat targetFormat, IData baseData, IData newData, BatchStatusManager batchStatusManager) + public void Start(IData baseData, IData newData, BatchStatusManager batchStatusManager) { long totalTileCount = newData.TileCount(); batchStatusManager.InitializeLayer(newData.Path); @@ -47,13 +53,14 @@ public void Start(TileFormat targetFormat, IData baseData, IData newData, BatchS this._logger.LogInformation($"[{MethodBase.GetCurrentMethod().Name}] Total amount of tiles to merge: {totalTileCount - tileProgressCount}"); var uploadOnly = this._configManager.GetConfiguration("GENERAL", "uploadOnly"); - bool shouldUpscale = !(uploadOnly || baseData.IsNew); - _getTileByCoord = uploadOnly || baseData.IsNew ? + uploadOnly = uploadOnly || baseData.IsNew; + bool shouldUpscale = !uploadOnly; + _getTileByCoord = uploadOnly ? (_) => null : (targetCoords) => baseData.GetCorrespondingTile(targetCoords, shouldUpscale); - ParallelRun(targetFormat, baseData, newData, batchStatusManager, + ParallelRun(baseData, newData, batchStatusManager, tileProgressCount, totalTileCount, resumeBatchIdentifier, resumeMode, pollForBatch); batchStatusManager.CompleteLayer(newData.Path); @@ -97,7 +104,7 @@ public void Start(TileFormat targetFormat, IData baseData, IData newData, BatchS } } - private void ProcessBatch(TileFormat targetFormat, IData baseData, List newTiles, ref long tileProgressCount, long totalTileCount,ref bool pollForBatch) + private void ProcessBatch(IData baseData, List newTiles, ref long tileProgressCount, long totalTileCount,ref bool pollForBatch) { ConcurrentBag tiles = new ConcurrentBag(); @@ -116,12 +123,11 @@ private void ProcessBatch(TileFormat targetFormat, IData baseData, List ne () => _getTileByCoord(targetCoords), () => newTile }; - byte[]? image = this._tileMerger.MergeTiles(correspondingTileBuilders, targetCoords, targetFormat); + Tile? tile = this._tileMerger.MergeTiles(correspondingTileBuilders, targetCoords, this._tileFormatStrategy); - if (image != null) + if (tile != null) { - newTile = new Tile(newTile.Z, newTile.X, newTile.Y, image); - tiles.Add(newTile); + tiles.Add(tile); } } @@ -131,7 +137,7 @@ private void ProcessBatch(TileFormat targetFormat, IData baseData, List ne this._logger.LogInformation($"[{MethodBase.GetCurrentMethod().Name}] Tile Count: {tileProgressCount} / {totalTileCount}"); } - private void ParallelRun(TileFormat targetFormat, IData baseData, IData newData, + private void ParallelRun(IData baseData, IData newData, BatchStatusManager batchStatusManager, long tileProgressCount, long totalTileCount, string? resumeBatchIdentifier, bool resumeMode,bool pollForBatch) { var numOfThreads = this._configManager.GetConfiguration("GENERAL", "parallel", "numOfThreads"); @@ -140,7 +146,7 @@ private void ParallelRun(TileFormat targetFormat, IData baseData, IData newData, while (tileProgressCount != totalTileCount && pollForBatch) { var batchResult = ManageBatchIdentifier(batchStatusManager, newData, resumeBatchIdentifier, totalTileCount, ref resumeMode); - ProcessBatch(targetFormat, baseData, batchResult.newTiles, ref tileProgressCount, + ProcessBatch(baseData, batchResult.newTiles, ref tileProgressCount, totalTileCount, ref pollForBatch); batchStatusManager.CompleteBatch(newData.Path, batchResult.currentBatchIdentifier, tileProgressCount); } diff --git a/MergerCli/Program.cs b/MergerCli/Program.cs index 7393575c..37db2662 100644 --- a/MergerCli/Program.cs +++ b/MergerCli/Program.cs @@ -53,12 +53,11 @@ private static void Main(string[] args) PrepareStatusManger(); int batchSize = int.Parse(args[1]); - TileFormat format; List sources; try { var parser = container.GetRequiredService(); - sources = parser.ParseSources(args, batchSize, out format); + sources = parser.ParseSources(args, batchSize); } catch (Exception ex) { @@ -101,7 +100,7 @@ private static void Main(string[] args) continue; } - process.Start(format, baseData, sources[i], _batchStatusManager); + process.Start(baseData, sources[i], _batchStatusManager); baseData.IsNew = false; stopWatch.Stop(); @@ -161,7 +160,7 @@ web sources (cant be base source): gpkg [bbox - in format 'minX,minY,maxX,maxY' - required base] [--1x1] [--UL / --LL] **** please note all layers must be 2X1 EPSG:4326 layers **** - merge sources: {programName} [...] + merge sources: {programName} [...] Examples: {programName} 1000 gpkg area1.gpkg gpkg area2.gpkg {programName} 1000 s3 /path1/on/s3 s3 /path2/on/s3 diff --git a/MergerCli/SourceParser.cs b/MergerCli/SourceParser.cs index a380dc26..708e842d 100644 --- a/MergerCli/SourceParser.cs +++ b/MergerCli/SourceParser.cs @@ -26,16 +26,11 @@ private void LogDataErrorAndExit(bool isBase, Exception e) { Environment.Exit(1); } - public List ParseSources(string[] args, int batchSize, out TileFormat format) + public List ParseSources(string[] args, int batchSize) { List sources = new List(); - if (!TileFormat.TryParse(args[2], true, out format)) - { - this._logger.LogError($"invalid target tile format: {args[2]}"); - Environment.Exit(1); - } - int idx = 3; + int idx = 2; bool isBase = true; while (idx < args.Length) { diff --git a/MergerCli/appsettings.json b/MergerCli/appsettings.json index 0826e828..bcf7f3ec 100644 --- a/MergerCli/appsettings.json +++ b/MergerCli/appsettings.json @@ -7,6 +7,10 @@ "numOfThreads": 1 } }, + "TILE": { + "outputFormatStrategy": "fixed", + "outputFormat": "jpeg" + }, "GPKG": { "vacuum": false }, diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index 3955aef5..18cb4f31 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -78,10 +78,6 @@ public int Size() { public void ConvertToFormat(TileFormat format) { - if (this.Format == format) { - return; - } - this._data = ImageFormatter.ConvertToFormat(this._data, format); this.Format = format; } diff --git a/MergerLogic/ImageProcessing/ITileMerger.cs b/MergerLogic/ImageProcessing/ITileMerger.cs index d2dd89a5..e7428cc5 100644 --- a/MergerLogic/ImageProcessing/ITileMerger.cs +++ b/MergerLogic/ImageProcessing/ITileMerger.cs @@ -5,6 +5,6 @@ namespace MergerLogic.ImageProcessing { public interface ITileMerger { - Tile? MergeTiles(List tiles, Coord targetCoords, TileFormat format); + Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy); } } diff --git a/MergerLogic/ImageProcessing/ImageFormatter.cs b/MergerLogic/ImageProcessing/ImageFormatter.cs index 92f3a083..d07268f7 100644 --- a/MergerLogic/ImageProcessing/ImageFormatter.cs +++ b/MergerLogic/ImageProcessing/ImageFormatter.cs @@ -9,11 +9,35 @@ public enum TileFormat [EnumMember(Value = "jpeg")] Jpeg, } + public class TileFormatStrategy { + public enum FormatStrategy { + [EnumMember(Value = "fixed")] Fixed, + [EnumMember(Value = "mixed")] Mixed, + } + + private FormatStrategy _strategy; + private TileFormat _format; + + public TileFormatStrategy(TileFormat format, FormatStrategy strategy = FormatStrategy.Fixed) + { + this._strategy = strategy; + this._format = format; + } + + public TileFormat ApplyStrategy(TileFormat format) { + if (this._strategy == FormatStrategy.Fixed) { + return this._format; + } + + return format; + } + } + public class ImageFormatter { public static byte[] ConvertToFormat(byte[] tile, TileFormat format) { - var currentFormat = GetTileFormat(tile); + TileFormat? currentFormat = GetTileFormat(tile); if (currentFormat != format) { using (var image = new MagickImage(tile)) diff --git a/MergerLogic/ImageProcessing/TileMerger.cs b/MergerLogic/ImageProcessing/TileMerger.cs index 85dbe478..18cac00c 100644 --- a/MergerLogic/ImageProcessing/TileMerger.cs +++ b/MergerLogic/ImageProcessing/TileMerger.cs @@ -18,12 +18,11 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) this._tileScaler = tileScaler; } - public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormat format) + public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy) { var images = this.GetImageList(tiles, targetCoords); byte[] data; - Tile tile; - + switch (images.Count) { case 0: @@ -35,10 +34,7 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) data = images[0].ToByteArray(); images[0].Dispose(); this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] 1 image found"); - - tile = new Tile(targetCoords, data); - tile.ConvertToFormat(format); - return tile; + break; default: using (var imageCollection = new MagickImageCollection()) { @@ -54,15 +50,16 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) mergedImage.ColorSpace = ColorSpace.sRGB; mergedImage.ColorType = mergedImage.HasAlpha ? ColorType.TrueColorAlpha : ColorType.TrueColor; - var mergedImageBytes = mergedImage.ToByteArray(); + data = mergedImage.ToByteArray(); this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] 'imageMagic' merging finished"); - - tile = new Tile(targetCoords, mergedImageBytes); - tile.ConvertToFormat(format); - return tile; } } + break; } + + Tile tile = new Tile(targetCoords, data); + tile.ConvertToFormat(strategy.ApplyStrategy(tile.Format)); + return tile; } private List GetImageList(List tiles, Coord targetCoords) diff --git a/MergerLogic/Utils/ImageUtils.cs b/MergerLogic/Utils/ImageUtils.cs index 5d19c9a0..8d11a8d5 100644 --- a/MergerLogic/Utils/ImageUtils.cs +++ b/MergerLogic/Utils/ImageUtils.cs @@ -12,8 +12,15 @@ public static bool IsTransparent(MagickImage image) } using var pixels = image.GetPixels(); - // Check pixels to see if at least one of them is transparent (or partially transparent) - return pixels.Select(pixel => pixel.ToColor()).Any(color => color?.A != 255); + + foreach (var pixel in pixels) + { + if (pixel.ToColor()?.A != 255) { + return true; + } + } + + return false; } public static bool IsFullyTransparent(MagickImage image) diff --git a/MergerLogicUnitTests/ImageProcessing/TestImages/2_1_merged.jpeg b/MergerLogicUnitTests/ImageProcessing/TestImages/2_1_merged.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..670365b928d557883682ce832885701f4206f923 GIT binary patch literal 8359 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 GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, TileFormat.Png, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + File.ReadAllBytes("2_1_merged.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png), TileFormat.Png, File.ReadAllBytes("2_1_merged.png"), }; + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Png, File.ReadAllBytes("2_1_merged.png"), + }; + yield return new object[] { new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Jpeg, File.ReadAllBytes("3_1_merged.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, File.ReadAllBytes("3_1_merged.jpeg"), }; @@ -68,15 +92,23 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) - }, targetCoordHighZoom, TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, File.ReadAllBytes("3_4_merged.jpeg"), }; + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Jpeg, File.ReadAllBytes("3_4_merged.jpeg"), + }; + yield return new object[] { new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordLowZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, File.ReadAllBytes("3_1_merged_upscaled_5_15.jpeg"), }; @@ -84,7 +116,7 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordMediumZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, File.ReadAllBytes("3_1_merged_upscaled_14_15.jpeg"), }; } @@ -92,12 +124,13 @@ public static IEnumerable GetMergeTilesTestParameters() [TestMethod] [TestCategory("MergeTiles")] [DynamicData(nameof(GetMergeTilesTestParameters), DynamicDataSourceType.Method)] - public void MergeTiles(Tile[] tiles, Coord targetCoord, TileFormat tileFormat, byte[] expectedTileBytes) + public void MergeTiles(Tile[] tiles, Coord targetCoord, TileFormatStrategy strategy, TileFormat expectedForamt, byte[] expectedTileBytes) { var tileBuilders = tiles.Select(tile => () => tile).ToList(); - var result = this._testTileMerger.MergeTiles(tileBuilders, targetCoord, tileFormat); + var result = this._testTileMerger.MergeTiles(tileBuilders, targetCoord, strategy); Assert.IsNotNull(result); + Assert.AreEqual(expectedForamt, result.Format); CollectionAssert.AreEqual(expectedTileBytes, result.GetImageBytes()); } diff --git a/MergerService/Models/Tasks/Task.cs b/MergerService/Models/Tasks/Task.cs index 901568e4..fb8d410f 100644 --- a/MergerService/Models/Tasks/Task.cs +++ b/MergerService/Models/Tasks/Task.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Runtime.Serialization; using System.Text.Json.Serialization; +using static MergerLogic.ImageProcessing.TileFormatStrategy; namespace MergerService.Models.Tasks { @@ -22,6 +23,8 @@ public enum Status public class MergeMetadata { [JsonInclude] public TileFormat TargetFormat { get; } + + [JsonInclude] public FormatStrategy OutputFormatStrategy { get; } [JsonInclude] public bool IsNewTarget { get; } @@ -32,9 +35,10 @@ public class MergeMetadata [System.Text.Json.Serialization.JsonIgnore] private JsonSerializerSettings _jsonSerializerSettings; - public MergeMetadata(TileFormat targetFormat, bool isNewTarget, TileBounds[] batches, Source[] sources) + public MergeMetadata(TileFormat targetFormat, bool isNewTarget, TileBounds[] batches, Source[] sources, FormatStrategy outputFormatStrategy = FormatStrategy.Fixed) { this.TargetFormat = targetFormat; + this.OutputFormatStrategy = outputFormatStrategy; this.IsNewTarget = isNewTarget; this.Batches = batches; this.Sources = sources; diff --git a/MergerService/Runners/TaskExecutor.cs b/MergerService/Runners/TaskExecutor.cs index 351d9630..23e43bea 100644 --- a/MergerService/Runners/TaskExecutor.cs +++ b/MergerService/Runners/TaskExecutor.cs @@ -30,7 +30,7 @@ public class TaskExecutor : ITaskExecutor private readonly bool _shouldValidate; private static readonly int DEFAULT_BATCH_SIZE = 1000; - public TaskExecutor(IDataFactory dataFactory, ITileMerger tileMerger, ITimeUtils timeUtils, MergerLogic.Utils.IConfigurationManager configurationManager, + public TaskExecutor(IDataFactory dataFactory, ITileMerger tileMerger, ITimeUtils timeUtils, IConfigurationManager configurationManager, ILogger logger, ActivitySource activitySource, IFileSystem fileSystem, IMetricsProvider metricsProvider) { @@ -86,6 +86,8 @@ public void ExecuteTask(MergeTask task, ITaskUtils taskUtils, string? managerCal Stopwatch mergeRunTimeStopwatch = new Stopwatch(); TimeSpan ts; + TileFormatStrategy strategy = new TileFormatStrategy(metadata.TargetFormat, metadata.OutputFormatStrategy); + bool shouldUpscale = !metadata.IsNewTarget; Func getTileByCoord = metadata.IsNewTarget ? (_, _) => null @@ -168,8 +170,7 @@ public void ExecuteTask(MergeTask task, ITaskUtils taskUtils, string? managerCal correspondingTileBuilders.Add(() => source.GetCorrespondingTile(coord, false)); } var tileMergeStopwatch = Stopwatch.StartNew(); - Tile? tile = this._tileMerger.MergeTiles(correspondingTileBuilders, coord, - metadata.TargetFormat); + Tile? tile = this._tileMerger.MergeTiles(correspondingTileBuilders, coord, strategy); tileMergeStopwatch.Stop(); this._metricsProvider.MergeTimePerTileHistogram(tileMergeStopwatch.Elapsed.TotalSeconds, metadata.TargetFormat); diff --git a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs index 74ca69a0..dd104637 100644 --- a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs +++ b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs @@ -116,16 +116,16 @@ public static IEnumerable GetBatchLimitTestParameters() // When the limit is 2, and there are total 5 tiles, we expect 3 flushes // We set the bytes limit to a high value to avoid it being reached by the test yield return new object[] { - true, 2, 1024 * 1024 * 80, 3, 5 - }; + true, 2, 1024 * 1024 * 80, 3, 5 + }; // Tests that given a batch bytes limit, it flushes every time it reaches the limit // When the limit is one byte more then twice the size of the tile, and there are total 7 tiles, we expect 3 flushes // (Flush every 3rd tile, and additional flush at the end) // We disable the size limit to avoid it being used in the test yield return new object[] { - false, 1, (File.ReadAllBytes("tile.jpeg").Length * 2) + 1, 3, 7 - }; + false, 1, (File.ReadAllBytes("tile.jpeg").Length * 2) + 1, 3, 7 + }; } [TestMethod] From fb588865d0600d04c6d29c94b935983a33bf76cc Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sat, 20 Apr 2024 21:02:06 +0300 Subject: [PATCH 03/14] test(Task): add cases for malformed and correct json of tasks - WIP --- MergerServiceUnitTests/Utils/TaskUtilsTest.cs | 38 +++++++++++++++++-- .../Utils/TestData/invalidTask.json | 18 +++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 MergerServiceUnitTests/Utils/TestData/invalidTask.json diff --git a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs index b08834ab..b97e9197 100644 --- a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs +++ b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs @@ -6,7 +6,10 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Newtonsoft.Json; +using System; +using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Net.Http; namespace MergerLogicUnitTests.Utils @@ -14,6 +17,7 @@ namespace MergerLogicUnitTests.Utils [TestClass] [TestCategory("unit")] [TestCategory("utils")] + [DeploymentItem(@"../../../Utils/TestData")] public class TaskUtilsTest { #region mocks @@ -59,11 +63,17 @@ public void WhenGettingTaskByType_ShouldUseCorrectHttpUri() this._httpClientMock.Verify(httpClient => httpClient.PostData(expectedUrl, null, false), Times.Once); } + public static IEnumerable GetBadJsonTestParameters() + { + yield return new object[] { "bad json" }; + yield return new object[] { File.ReadAllText("invalidTask.json") }; + } + [TestMethod] - public void WhenGettingMalformedJsonTask_ShouldReturnNull() + [DynamicData(nameof(GetBadJsonTestParameters), DynamicDataSourceType.Method)] + public void WhenGettingMalformedJsonTask_ShouldReturnNull(string json) { - var malformedJsonString = "bad json"; - this._httpClientMock.Setup(httpClient => httpClient.PostData(It.IsAny(), It.IsAny(), It.IsAny())).Returns(malformedJsonString); + this._httpClientMock.Setup(httpClient => httpClient.PostData(It.IsAny(), It.IsAny(), It.IsAny())).Returns(json); var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, _testActivitySource); @@ -73,6 +83,28 @@ public void WhenGettingMalformedJsonTask_ShouldReturnNull() Assert.IsNull(resultTask); } + // [TestMethod] + // public void WhenGettingJsonTask_ShouldReturnTaskObject() + // { + // int maxAttempts = this._configurationManagerMock.Object.GetConfiguration("TASK", "maxAttempts"); + + // string json = File.ReadAllText("validTask.json"); + // this._httpClientMock.Setup(httpClient => httpClient.PostData(It.IsAny(), It.IsAny(), It.IsAny())).Returns(json); + + // var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, + // _testActivitySource); + + // var resultTask = testTaskUtils.GetTask("testJobType", "testTaskType"); + + // Assert.IsNotNull(resultTask); + // Assert.IsTrue(Guid.TryParse(resultTask.Id, out _)); + // Assert.IsTrue(Guid.TryParse(resultTask.JobId, out _)); + + // Assert.IsNotNull(resultTask.Parameters); + // Assert.IsTrue(resultTask.Percentage >= 0); + // Assert.IsTrue(resultTask.Attempts >= 0 && resultTask.Attempts <= maxAttempts); + // } + [TestMethod] public void WhenUpdatingTaskCompleted_ShouldSendCorrectStatusAndPercentage() { diff --git a/MergerServiceUnitTests/Utils/TestData/invalidTask.json b/MergerServiceUnitTests/Utils/TestData/invalidTask.json new file mode 100644 index 00000000..066a187e --- /dev/null +++ b/MergerServiceUnitTests/Utils/TestData/invalidTask.json @@ -0,0 +1,18 @@ +{ + "id": "", + "type": "", + "description": "", + "parameters": { + "tileFormat": "", + "outputFormatStrategy": "", + "isNewTarget": "" + }, + "status": "", + "percentage": "", + "reason": "", + "attempts": 0, + "jobId": "", + "resettable": false, + "created": "", + "updated": "" +} \ No newline at end of file From a45fa373fff4f7c652a330b3d6242d26d20fc85b Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 21 Apr 2024 12:58:34 +0300 Subject: [PATCH 04/14] test(Task): add test for valid json task --- MergerServiceUnitTests/Utils/TaskUtilsTest.cs | 43 +- .../Utils/TestData/validTask.json | 5776 +++++++++++++++++ 2 files changed, 5803 insertions(+), 16 deletions(-) create mode 100644 MergerServiceUnitTests/Utils/TestData/validTask.json diff --git a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs index b97e9197..3daeac29 100644 --- a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs +++ b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs @@ -1,4 +1,5 @@ using MergerLogic.Clients; +using MergerLogic.ImageProcessing; using MergerLogic.Utils; using MergerService.Models.Tasks; using MergerService.Utils; @@ -83,27 +84,37 @@ public void WhenGettingMalformedJsonTask_ShouldReturnNull(string json) Assert.IsNull(resultTask); } - // [TestMethod] - // public void WhenGettingJsonTask_ShouldReturnTaskObject() - // { - // int maxAttempts = this._configurationManagerMock.Object.GetConfiguration("TASK", "maxAttempts"); + [TestMethod] + public void WhenGettingJsonTask_ShouldReturnTaskObject() + { + int maxAttempts = this._configurationManagerMock.Object.GetConfiguration("TASK", "maxAttempts"); - // string json = File.ReadAllText("validTask.json"); - // this._httpClientMock.Setup(httpClient => httpClient.PostData(It.IsAny(), It.IsAny(), It.IsAny())).Returns(json); + string json = File.ReadAllText("validTask.json"); + this._httpClientMock.Setup(httpClient => httpClient.PostData(It.IsAny(), It.IsAny(), It.IsAny())).Returns(json); - // var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, - // _testActivitySource); + var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, + _testActivitySource); - // var resultTask = testTaskUtils.GetTask("testJobType", "testTaskType"); + var resultTask = testTaskUtils.GetTask("testJobType", "testTaskType"); + + Assert.IsNotNull(resultTask); + + // Validate GUIDs + Assert.IsTrue(Guid.TryParse(resultTask.Id, out _)); + Assert.IsTrue(Guid.TryParse(resultTask.JobId, out _)); - // Assert.IsNotNull(resultTask); - // Assert.IsTrue(Guid.TryParse(resultTask.Id, out _)); - // Assert.IsTrue(Guid.TryParse(resultTask.JobId, out _)); + // Validate dates + Assert.IsTrue(DateTime.TryParse(resultTask.Created.ToString(), out _)); + Assert.IsTrue(DateTime.TryParse(resultTask.Updated.ToString(), out _)); - // Assert.IsNotNull(resultTask.Parameters); - // Assert.IsTrue(resultTask.Percentage >= 0); - // Assert.IsTrue(resultTask.Attempts >= 0 && resultTask.Attempts <= maxAttempts); - // } + Assert.IsNotNull(resultTask.Parameters); + Assert.IsTrue(resultTask.Parameters.Sources?.Length > 0); + Assert.IsTrue(resultTask.Parameters.Batches?.Length > 0); + Assert.IsInstanceOfType(resultTask.Parameters.TargetFormat, typeof(TileFormat)); + + Assert.IsTrue(resultTask.Percentage >= 0 && resultTask.Percentage <= 100); + Assert.IsTrue(resultTask.Attempts >= 0 && resultTask.Attempts <= maxAttempts); + } [TestMethod] public void WhenUpdatingTaskCompleted_ShouldSendCorrectStatusAndPercentage() diff --git a/MergerServiceUnitTests/Utils/TestData/validTask.json b/MergerServiceUnitTests/Utils/TestData/validTask.json new file mode 100644 index 00000000..0a91b38c --- /dev/null +++ b/MergerServiceUnitTests/Utils/TestData/validTask.json @@ -0,0 +1,5776 @@ +{ + "id": "3a59ce9f-9279-43e2-936c-868ee5d0b244", + "type": "tilesMerging", + "description": "", + "parameters": { + "batches": [ + { + "maxX": 156220, + "maxY": 88402, + "minX": 156219, + "minY": 88401, + "zoom": 17 + }, + { + "maxX": 156219, + "maxY": 88403, + "minX": 156218, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88403, + "minX": 156219, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156219, + "maxY": 88404, + "minX": 156218, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88404, + "minX": 156219, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156221, + "maxY": 88402, + "minX": 156220, + "minY": 88401, + "zoom": 17 + }, + { + "maxX": 156222, + "maxY": 88402, + "minX": 156221, + "minY": 88401, + "zoom": 17 + }, + { + "maxX": 156223, + "maxY": 88402, + "minX": 156222, + "minY": 88401, + "zoom": 17 + }, + { + "maxX": 156222, + "maxY": 88404, + "minX": 156220, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156223, + "maxY": 88403, + "minX": 156222, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88403, + "minX": 156223, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156223, + "maxY": 88404, + "minX": 156222, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88404, + "minX": 156223, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88405, + "minX": 156217, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88406, + "minX": 156217, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156219, + "maxY": 88405, + "minX": 156218, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88405, + "minX": 156219, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156219, + "maxY": 88406, + "minX": 156218, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88406, + "minX": 156219, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156217, + "maxY": 88407, + "minX": 156216, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88407, + "minX": 156217, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156217, + "maxY": 88408, + "minX": 156216, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88408, + "minX": 156217, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88408, + "minX": 156218, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88408, + "minX": 156220, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88410, + "minX": 156215, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88411, + "minX": 156215, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156215, + "maxY": 88412, + "minX": 156214, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88412, + "minX": 156215, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88414, + "minX": 156213, + "minY": 88413, + "zoom": 17 + }, + { + "maxX": 156215, + "maxY": 88413, + "minX": 156214, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88413, + "minX": 156215, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156215, + "maxY": 88414, + "minX": 156214, + "minY": 88413, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88414, + "minX": 156215, + "minY": 88413, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88415, + "minX": 156213, + "minY": 88414, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88416, + "minX": 156213, + "minY": 88415, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88416, + "minX": 156214, + "minY": 88414, + "zoom": 17 + }, + { + "maxX": 156217, + "maxY": 88409, + "minX": 156216, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88409, + "minX": 156217, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156217, + "maxY": 88410, + "minX": 156216, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88410, + "minX": 156217, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88410, + "minX": 156218, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88412, + "minX": 156216, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88412, + "minX": 156218, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88412, + "minX": 156220, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88416, + "minX": 156216, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88416, + "minX": 156220, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88428, + "minX": 156207, + "minY": 88427, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88429, + "minX": 156207, + "minY": 88428, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88430, + "minX": 156206, + "minY": 88429, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88430, + "minX": 156207, + "minY": 88429, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88431, + "minX": 156206, + "minY": 88430, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88431, + "minX": 156207, + "minY": 88430, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88432, + "minX": 156206, + "minY": 88431, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88432, + "minX": 156207, + "minY": 88431, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88419, + "minX": 156211, + "minY": 88418, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88420, + "minX": 156211, + "minY": 88419, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88417, + "minX": 156212, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88417, + "minX": 156213, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88418, + "minX": 156212, + "minY": 88417, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88418, + "minX": 156213, + "minY": 88417, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88418, + "minX": 156214, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88419, + "minX": 156212, + "minY": 88418, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88419, + "minX": 156213, + "minY": 88418, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88420, + "minX": 156212, + "minY": 88419, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88420, + "minX": 156213, + "minY": 88419, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88420, + "minX": 156214, + "minY": 88418, + "zoom": 17 + }, + { + "maxX": 156211, + "maxY": 88421, + "minX": 156210, + "minY": 88420, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88421, + "minX": 156211, + "minY": 88420, + "zoom": 17 + }, + { + "maxX": 156211, + "maxY": 88422, + "minX": 156210, + "minY": 88421, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88422, + "minX": 156211, + "minY": 88421, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88424, + "minX": 156209, + "minY": 88423, + "zoom": 17 + }, + { + "maxX": 156211, + "maxY": 88423, + "minX": 156210, + "minY": 88422, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88423, + "minX": 156211, + "minY": 88422, + "zoom": 17 + }, + { + "maxX": 156211, + "maxY": 88424, + "minX": 156210, + "minY": 88423, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88424, + "minX": 156211, + "minY": 88423, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88424, + "minX": 156212, + "minY": 88420, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88424, + "minX": 156216, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88425, + "minX": 156209, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156209, + "maxY": 88426, + "minX": 156208, + "minY": 88425, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88426, + "minX": 156209, + "minY": 88425, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88426, + "minX": 156210, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156209, + "maxY": 88427, + "minX": 156208, + "minY": 88426, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88427, + "minX": 156209, + "minY": 88426, + "zoom": 17 + }, + { + "maxX": 156209, + "maxY": 88428, + "minX": 156208, + "minY": 88427, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88428, + "minX": 156209, + "minY": 88427, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88428, + "minX": 156210, + "minY": 88426, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88428, + "minX": 156212, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88432, + "minX": 156208, + "minY": 88428, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88432, + "minX": 156212, + "minY": 88428, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88432, + "minX": 156216, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88433, + "minX": 156205, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88434, + "minX": 156205, + "minY": 88433, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88433, + "minX": 156206, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88433, + "minX": 156207, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88434, + "minX": 156206, + "minY": 88433, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88434, + "minX": 156207, + "minY": 88433, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88435, + "minX": 156204, + "minY": 88434, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88435, + "minX": 156205, + "minY": 88434, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88436, + "minX": 156204, + "minY": 88435, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88436, + "minX": 156205, + "minY": 88435, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88436, + "minX": 156206, + "minY": 88434, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88437, + "minX": 156203, + "minY": 88436, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88438, + "minX": 156203, + "minY": 88437, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88439, + "minX": 156203, + "minY": 88438, + "zoom": 17 + }, + { + "maxX": 156203, + "maxY": 88440, + "minX": 156202, + "minY": 88439, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88440, + "minX": 156203, + "minY": 88439, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88437, + "minX": 156204, + "minY": 88436, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88437, + "minX": 156205, + "minY": 88436, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88438, + "minX": 156204, + "minY": 88437, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88438, + "minX": 156205, + "minY": 88437, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88438, + "minX": 156206, + "minY": 88436, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88440, + "minX": 156204, + "minY": 88438, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88440, + "minX": 156206, + "minY": 88438, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88446, + "minX": 156199, + "minY": 88445, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88447, + "minX": 156199, + "minY": 88446, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88448, + "minX": 156199, + "minY": 88447, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88442, + "minX": 156201, + "minY": 88441, + "zoom": 17 + }, + { + "maxX": 156203, + "maxY": 88441, + "minX": 156202, + "minY": 88440, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88441, + "minX": 156203, + "minY": 88440, + "zoom": 17 + }, + { + "maxX": 156203, + "maxY": 88442, + "minX": 156202, + "minY": 88441, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88442, + "minX": 156203, + "minY": 88441, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88443, + "minX": 156201, + "minY": 88442, + "zoom": 17 + }, + { + "maxX": 156201, + "maxY": 88444, + "minX": 156200, + "minY": 88443, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88444, + "minX": 156201, + "minY": 88443, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88444, + "minX": 156202, + "minY": 88442, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88444, + "minX": 156204, + "minY": 88440, + "zoom": 17 + }, + { + "maxX": 156201, + "maxY": 88445, + "minX": 156200, + "minY": 88444, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88445, + "minX": 156201, + "minY": 88444, + "zoom": 17 + }, + { + "maxX": 156201, + "maxY": 88446, + "minX": 156200, + "minY": 88445, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88446, + "minX": 156201, + "minY": 88445, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88446, + "minX": 156202, + "minY": 88444, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88448, + "minX": 156200, + "minY": 88446, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88448, + "minX": 156202, + "minY": 88446, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88448, + "minX": 156204, + "minY": 88444, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88448, + "minX": 156208, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156225, + "maxY": 88403, + "minX": 156224, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156226, + "maxY": 88403, + "minX": 156225, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156225, + "maxY": 88404, + "minX": 156224, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156226, + "maxY": 88404, + "minX": 156225, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156227, + "maxY": 88403, + "minX": 156226, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156228, + "maxY": 88403, + "minX": 156227, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156227, + "maxY": 88404, + "minX": 156226, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156228, + "maxY": 88404, + "minX": 156227, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156229, + "maxY": 88403, + "minX": 156228, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156230, + "maxY": 88403, + "minX": 156229, + "minY": 88402, + "zoom": 17 + }, + { + "maxX": 156229, + "maxY": 88404, + "minX": 156228, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156230, + "maxY": 88404, + "minX": 156229, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156231, + "maxY": 88404, + "minX": 156230, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156232, + "maxY": 88404, + "minX": 156231, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156228, + "maxY": 88408, + "minX": 156224, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156232, + "maxY": 88408, + "minX": 156228, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156233, + "maxY": 88404, + "minX": 156232, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156234, + "maxY": 88404, + "minX": 156233, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156235, + "maxY": 88404, + "minX": 156234, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156236, + "maxY": 88404, + "minX": 156235, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156237, + "maxY": 88404, + "minX": 156236, + "minY": 88403, + "zoom": 17 + }, + { + "maxX": 156236, + "maxY": 88408, + "minX": 156232, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156237, + "maxY": 88405, + "minX": 156236, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156238, + "maxY": 88405, + "minX": 156237, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156237, + "maxY": 88406, + "minX": 156236, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156238, + "maxY": 88406, + "minX": 156237, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156239, + "maxY": 88405, + "minX": 156238, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88405, + "minX": 156239, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156239, + "maxY": 88406, + "minX": 156238, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88406, + "minX": 156239, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156238, + "maxY": 88408, + "minX": 156236, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88408, + "minX": 156238, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156232, + "maxY": 88416, + "minX": 156224, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88416, + "minX": 156232, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156241, + "maxY": 88405, + "minX": 156240, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156242, + "maxY": 88405, + "minX": 156241, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156241, + "maxY": 88406, + "minX": 156240, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156242, + "maxY": 88406, + "minX": 156241, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156243, + "maxY": 88405, + "minX": 156242, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156244, + "maxY": 88405, + "minX": 156243, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156243, + "maxY": 88406, + "minX": 156242, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156244, + "maxY": 88406, + "minX": 156243, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156242, + "maxY": 88408, + "minX": 156240, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156244, + "maxY": 88408, + "minX": 156242, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156245, + "maxY": 88405, + "minX": 156244, + "minY": 88404, + "zoom": 17 + }, + { + "maxX": 156245, + "maxY": 88406, + "minX": 156244, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156246, + "maxY": 88406, + "minX": 156245, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156247, + "maxY": 88406, + "minX": 156246, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156248, + "maxY": 88406, + "minX": 156247, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156246, + "maxY": 88408, + "minX": 156244, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156248, + "maxY": 88408, + "minX": 156246, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156249, + "maxY": 88406, + "minX": 156248, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156250, + "maxY": 88406, + "minX": 156249, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156251, + "maxY": 88406, + "minX": 156250, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156252, + "maxY": 88406, + "minX": 156251, + "minY": 88405, + "zoom": 17 + }, + { + "maxX": 156250, + "maxY": 88408, + "minX": 156248, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156251, + "maxY": 88407, + "minX": 156250, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156252, + "maxY": 88407, + "minX": 156251, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156251, + "maxY": 88408, + "minX": 156250, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156252, + "maxY": 88408, + "minX": 156251, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156253, + "maxY": 88407, + "minX": 156252, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156254, + "maxY": 88407, + "minX": 156253, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156253, + "maxY": 88408, + "minX": 156252, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156254, + "maxY": 88408, + "minX": 156253, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156255, + "maxY": 88407, + "minX": 156254, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88407, + "minX": 156255, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156255, + "maxY": 88408, + "minX": 156254, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88408, + "minX": 156255, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156248, + "maxY": 88416, + "minX": 156240, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88416, + "minX": 156248, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156257, + "maxY": 88407, + "minX": 156256, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156258, + "maxY": 88407, + "minX": 156257, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156257, + "maxY": 88408, + "minX": 156256, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156258, + "maxY": 88408, + "minX": 156257, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156259, + "maxY": 88407, + "minX": 156258, + "minY": 88406, + "zoom": 17 + }, + { + "maxX": 156259, + "maxY": 88408, + "minX": 156258, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156260, + "maxY": 88408, + "minX": 156259, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156261, + "maxY": 88408, + "minX": 156260, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156262, + "maxY": 88408, + "minX": 156261, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156263, + "maxY": 88408, + "minX": 156262, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156264, + "maxY": 88408, + "minX": 156263, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156265, + "maxY": 88408, + "minX": 156264, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156266, + "maxY": 88408, + "minX": 156265, + "minY": 88407, + "zoom": 17 + }, + { + "maxX": 156264, + "maxY": 88416, + "minX": 156256, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156265, + "maxY": 88409, + "minX": 156264, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156266, + "maxY": 88409, + "minX": 156265, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156265, + "maxY": 88410, + "minX": 156264, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156266, + "maxY": 88410, + "minX": 156265, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156267, + "maxY": 88409, + "minX": 156266, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156268, + "maxY": 88409, + "minX": 156267, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156267, + "maxY": 88410, + "minX": 156266, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156268, + "maxY": 88410, + "minX": 156267, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156266, + "maxY": 88412, + "minX": 156264, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156268, + "maxY": 88412, + "minX": 156266, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156269, + "maxY": 88409, + "minX": 156268, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156270, + "maxY": 88409, + "minX": 156269, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156269, + "maxY": 88410, + "minX": 156268, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156270, + "maxY": 88410, + "minX": 156269, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156271, + "maxY": 88409, + "minX": 156270, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88409, + "minX": 156271, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156271, + "maxY": 88410, + "minX": 156270, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88410, + "minX": 156271, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156270, + "maxY": 88412, + "minX": 156268, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88412, + "minX": 156270, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156268, + "maxY": 88416, + "minX": 156264, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88416, + "minX": 156268, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156273, + "maxY": 88409, + "minX": 156272, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156274, + "maxY": 88409, + "minX": 156273, + "minY": 88408, + "zoom": 17 + }, + { + "maxX": 156273, + "maxY": 88410, + "minX": 156272, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156274, + "maxY": 88410, + "minX": 156273, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156275, + "maxY": 88410, + "minX": 156274, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156276, + "maxY": 88410, + "minX": 156275, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156274, + "maxY": 88412, + "minX": 156272, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156276, + "maxY": 88412, + "minX": 156274, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156277, + "maxY": 88410, + "minX": 156276, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156278, + "maxY": 88410, + "minX": 156277, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156279, + "maxY": 88410, + "minX": 156278, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88410, + "minX": 156279, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156278, + "maxY": 88412, + "minX": 156276, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88412, + "minX": 156278, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156276, + "maxY": 88416, + "minX": 156272, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88416, + "minX": 156276, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156281, + "maxY": 88410, + "minX": 156280, + "minY": 88409, + "zoom": 17 + }, + { + "maxX": 156281, + "maxY": 88411, + "minX": 156280, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88411, + "minX": 156281, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156281, + "maxY": 88412, + "minX": 156280, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88412, + "minX": 156281, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88411, + "minX": 156282, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88411, + "minX": 156283, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88412, + "minX": 156282, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88412, + "minX": 156283, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88411, + "minX": 156284, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88411, + "minX": 156285, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88412, + "minX": 156284, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88412, + "minX": 156285, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88411, + "minX": 156286, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88411, + "minX": 156287, + "minY": 88410, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88412, + "minX": 156286, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88412, + "minX": 156287, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88416, + "minX": 156280, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88416, + "minX": 156284, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88448, + "minX": 156224, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88432, + "minX": 156256, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88424, + "minX": 156272, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88420, + "minX": 156280, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88418, + "minX": 156284, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88417, + "minX": 156286, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88417, + "minX": 156287, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88418, + "minX": 156286, + "minY": 88417, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88418, + "minX": 156287, + "minY": 88417, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88420, + "minX": 156284, + "minY": 88418, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88419, + "minX": 156286, + "minY": 88418, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88419, + "minX": 156287, + "minY": 88418, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88420, + "minX": 156286, + "minY": 88419, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88420, + "minX": 156287, + "minY": 88419, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88424, + "minX": 156280, + "minY": 88420, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88422, + "minX": 156284, + "minY": 88420, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88421, + "minX": 156286, + "minY": 88420, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88421, + "minX": 156287, + "minY": 88420, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88422, + "minX": 156286, + "minY": 88421, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88422, + "minX": 156287, + "minY": 88421, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88424, + "minX": 156284, + "minY": 88422, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88423, + "minX": 156286, + "minY": 88422, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88423, + "minX": 156287, + "minY": 88422, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88424, + "minX": 156286, + "minY": 88423, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88424, + "minX": 156287, + "minY": 88423, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88432, + "minX": 156272, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88428, + "minX": 156280, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88426, + "minX": 156284, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88425, + "minX": 156286, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88425, + "minX": 156287, + "minY": 88424, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88426, + "minX": 156286, + "minY": 88425, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88426, + "minX": 156287, + "minY": 88425, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88428, + "minX": 156284, + "minY": 88426, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88427, + "minX": 156286, + "minY": 88426, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88427, + "minX": 156287, + "minY": 88426, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88428, + "minX": 156286, + "minY": 88427, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88428, + "minX": 156287, + "minY": 88427, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88432, + "minX": 156280, + "minY": 88428, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88430, + "minX": 156284, + "minY": 88428, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88429, + "minX": 156286, + "minY": 88428, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88429, + "minX": 156287, + "minY": 88428, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88430, + "minX": 156286, + "minY": 88429, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88430, + "minX": 156287, + "minY": 88429, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88432, + "minX": 156284, + "minY": 88430, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88431, + "minX": 156286, + "minY": 88430, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88431, + "minX": 156287, + "minY": 88430, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88432, + "minX": 156286, + "minY": 88431, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88432, + "minX": 156287, + "minY": 88431, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88448, + "minX": 156256, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88440, + "minX": 156272, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88436, + "minX": 156280, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88434, + "minX": 156284, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88433, + "minX": 156286, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88433, + "minX": 156287, + "minY": 88432, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88434, + "minX": 156286, + "minY": 88433, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88434, + "minX": 156287, + "minY": 88433, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88436, + "minX": 156284, + "minY": 88434, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88435, + "minX": 156286, + "minY": 88434, + "zoom": 17 + }, + { + "maxX": 156288, + "maxY": 88435, + "minX": 156287, + "minY": 88434, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88436, + "minX": 156286, + "minY": 88435, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88440, + "minX": 156280, + "minY": 88436, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88438, + "minX": 156284, + "minY": 88436, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88437, + "minX": 156286, + "minY": 88436, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88438, + "minX": 156286, + "minY": 88437, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88440, + "minX": 156284, + "minY": 88438, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88439, + "minX": 156286, + "minY": 88438, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88440, + "minX": 156286, + "minY": 88439, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88448, + "minX": 156272, + "minY": 88440, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88444, + "minX": 156280, + "minY": 88440, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88442, + "minX": 156284, + "minY": 88440, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88441, + "minX": 156286, + "minY": 88440, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88442, + "minX": 156286, + "minY": 88441, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88444, + "minX": 156284, + "minY": 88442, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88443, + "minX": 156286, + "minY": 88442, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88444, + "minX": 156286, + "minY": 88443, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88448, + "minX": 156280, + "minY": 88444, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88446, + "minX": 156284, + "minY": 88444, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88445, + "minX": 156286, + "minY": 88444, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88446, + "minX": 156286, + "minY": 88445, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88448, + "minX": 156284, + "minY": 88446, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88447, + "minX": 156286, + "minY": 88446, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88448, + "minX": 156286, + "minY": 88447, + "zoom": 17 + }, + { + "maxX": 156289, + "maxY": 88412, + "minX": 156288, + "minY": 88411, + "zoom": 17 + }, + { + "maxX": 156289, + "maxY": 88413, + "minX": 156288, + "minY": 88412, + "zoom": 17 + }, + { + "maxX": 156289, + "maxY": 88414, + "minX": 156288, + "minY": 88413, + "zoom": 17 + }, + { + "maxX": 156289, + "maxY": 88415, + "minX": 156288, + "minY": 88414, + "zoom": 17 + }, + { + "maxX": 156289, + "maxY": 88416, + "minX": 156288, + "minY": 88415, + "zoom": 17 + }, + { + "maxX": 156289, + "maxY": 88417, + "minX": 156288, + "minY": 88416, + "zoom": 17 + }, + { + "maxX": 156199, + "maxY": 88449, + "minX": 156198, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88449, + "minX": 156199, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156199, + "maxY": 88450, + "minX": 156198, + "minY": 88449, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88450, + "minX": 156199, + "minY": 88449, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88451, + "minX": 156197, + "minY": 88450, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88452, + "minX": 156197, + "minY": 88451, + "zoom": 17 + }, + { + "maxX": 156199, + "maxY": 88451, + "minX": 156198, + "minY": 88450, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88451, + "minX": 156199, + "minY": 88450, + "zoom": 17 + }, + { + "maxX": 156199, + "maxY": 88452, + "minX": 156198, + "minY": 88451, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88452, + "minX": 156199, + "minY": 88451, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88456, + "minX": 156195, + "minY": 88455, + "zoom": 17 + }, + { + "maxX": 156197, + "maxY": 88453, + "minX": 156196, + "minY": 88452, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88453, + "minX": 156197, + "minY": 88452, + "zoom": 17 + }, + { + "maxX": 156197, + "maxY": 88454, + "minX": 156196, + "minY": 88453, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88454, + "minX": 156197, + "minY": 88453, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88454, + "minX": 156198, + "minY": 88452, + "zoom": 17 + }, + { + "maxX": 156197, + "maxY": 88455, + "minX": 156196, + "minY": 88454, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88455, + "minX": 156197, + "minY": 88454, + "zoom": 17 + }, + { + "maxX": 156197, + "maxY": 88456, + "minX": 156196, + "minY": 88455, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88456, + "minX": 156197, + "minY": 88455, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88456, + "minX": 156198, + "minY": 88454, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88456, + "minX": 156200, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88457, + "minX": 156195, + "minY": 88456, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88458, + "minX": 156194, + "minY": 88457, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88458, + "minX": 156195, + "minY": 88457, + "zoom": 17 + }, + { + "maxX": 156194, + "maxY": 88460, + "minX": 156193, + "minY": 88459, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88459, + "minX": 156194, + "minY": 88458, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88459, + "minX": 156195, + "minY": 88458, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88460, + "minX": 156194, + "minY": 88459, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88460, + "minX": 156195, + "minY": 88459, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88460, + "minX": 156196, + "minY": 88456, + "zoom": 17 + }, + { + "maxX": 156194, + "maxY": 88461, + "minX": 156193, + "minY": 88460, + "zoom": 17 + }, + { + "maxX": 156194, + "maxY": 88462, + "minX": 156193, + "minY": 88461, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88462, + "minX": 156194, + "minY": 88460, + "zoom": 17 + }, + { + "maxX": 156193, + "maxY": 88463, + "minX": 156192, + "minY": 88462, + "zoom": 17 + }, + { + "maxX": 156194, + "maxY": 88463, + "minX": 156193, + "minY": 88462, + "zoom": 17 + }, + { + "maxX": 156193, + "maxY": 88464, + "minX": 156192, + "minY": 88463, + "zoom": 17 + }, + { + "maxX": 156194, + "maxY": 88464, + "minX": 156193, + "minY": 88463, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88464, + "minX": 156194, + "minY": 88462, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88464, + "minX": 156196, + "minY": 88460, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88464, + "minX": 156200, + "minY": 88456, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88464, + "minX": 156208, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156194, + "maxY": 88465, + "minX": 156193, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156194, + "maxY": 88466, + "minX": 156193, + "minY": 88465, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88465, + "minX": 156194, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88465, + "minX": 156195, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88466, + "minX": 156194, + "minY": 88465, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88466, + "minX": 156195, + "minY": 88465, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88467, + "minX": 156194, + "minY": 88466, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88467, + "minX": 156195, + "minY": 88466, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88468, + "minX": 156194, + "minY": 88467, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88468, + "minX": 156195, + "minY": 88467, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88468, + "minX": 156196, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156195, + "maxY": 88469, + "minX": 156194, + "minY": 88468, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88469, + "minX": 156195, + "minY": 88468, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88470, + "minX": 156195, + "minY": 88469, + "zoom": 17 + }, + { + "maxX": 156196, + "maxY": 88471, + "minX": 156195, + "minY": 88470, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88470, + "minX": 156196, + "minY": 88468, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88470, + "minX": 156198, + "minY": 88468, + "zoom": 17 + }, + { + "maxX": 156197, + "maxY": 88471, + "minX": 156196, + "minY": 88470, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88471, + "minX": 156197, + "minY": 88470, + "zoom": 17 + }, + { + "maxX": 156197, + "maxY": 88472, + "minX": 156196, + "minY": 88471, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88472, + "minX": 156197, + "minY": 88471, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88472, + "minX": 156198, + "minY": 88470, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88472, + "minX": 156200, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156197, + "maxY": 88473, + "minX": 156196, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88473, + "minX": 156197, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88474, + "minX": 156197, + "minY": 88473, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88474, + "minX": 156198, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156198, + "maxY": 88475, + "minX": 156197, + "minY": 88474, + "zoom": 17 + }, + { + "maxX": 156199, + "maxY": 88475, + "minX": 156198, + "minY": 88474, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88475, + "minX": 156199, + "minY": 88474, + "zoom": 17 + }, + { + "maxX": 156199, + "maxY": 88476, + "minX": 156198, + "minY": 88475, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88476, + "minX": 156199, + "minY": 88475, + "zoom": 17 + }, + { + "maxX": 156199, + "maxY": 88477, + "minX": 156198, + "minY": 88476, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88477, + "minX": 156199, + "minY": 88476, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88478, + "minX": 156199, + "minY": 88477, + "zoom": 17 + }, + { + "maxX": 156200, + "maxY": 88479, + "minX": 156199, + "minY": 88478, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88476, + "minX": 156200, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88476, + "minX": 156204, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88478, + "minX": 156200, + "minY": 88476, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88478, + "minX": 156202, + "minY": 88476, + "zoom": 17 + }, + { + "maxX": 156201, + "maxY": 88479, + "minX": 156200, + "minY": 88478, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88479, + "minX": 156201, + "minY": 88478, + "zoom": 17 + }, + { + "maxX": 156201, + "maxY": 88480, + "minX": 156200, + "minY": 88479, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88480, + "minX": 156201, + "minY": 88479, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88480, + "minX": 156202, + "minY": 88478, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88480, + "minX": 156204, + "minY": 88476, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88480, + "minX": 156208, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156201, + "maxY": 88481, + "minX": 156200, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88481, + "minX": 156201, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156201, + "maxY": 88482, + "minX": 156200, + "minY": 88481, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88482, + "minX": 156201, + "minY": 88481, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88482, + "minX": 156202, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88483, + "minX": 156201, + "minY": 88482, + "zoom": 17 + }, + { + "maxX": 156202, + "maxY": 88484, + "minX": 156201, + "minY": 88483, + "zoom": 17 + }, + { + "maxX": 156203, + "maxY": 88483, + "minX": 156202, + "minY": 88482, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88483, + "minX": 156203, + "minY": 88482, + "zoom": 17 + }, + { + "maxX": 156203, + "maxY": 88484, + "minX": 156202, + "minY": 88483, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88484, + "minX": 156203, + "minY": 88483, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88484, + "minX": 156204, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156203, + "maxY": 88485, + "minX": 156202, + "minY": 88484, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88485, + "minX": 156203, + "minY": 88484, + "zoom": 17 + }, + { + "maxX": 156203, + "maxY": 88486, + "minX": 156202, + "minY": 88485, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88486, + "minX": 156203, + "minY": 88485, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88487, + "minX": 156203, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156204, + "maxY": 88488, + "minX": 156203, + "minY": 88487, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88486, + "minX": 156204, + "minY": 88484, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88486, + "minX": 156206, + "minY": 88484, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88487, + "minX": 156204, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88487, + "minX": 156205, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88488, + "minX": 156204, + "minY": 88487, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88488, + "minX": 156205, + "minY": 88487, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88488, + "minX": 156206, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88489, + "minX": 156204, + "minY": 88488, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88489, + "minX": 156205, + "minY": 88488, + "zoom": 17 + }, + { + "maxX": 156205, + "maxY": 88490, + "minX": 156204, + "minY": 88489, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88490, + "minX": 156205, + "minY": 88489, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88490, + "minX": 156206, + "minY": 88488, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88491, + "minX": 156205, + "minY": 88490, + "zoom": 17 + }, + { + "maxX": 156206, + "maxY": 88492, + "minX": 156205, + "minY": 88491, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88491, + "minX": 156206, + "minY": 88490, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88491, + "minX": 156207, + "minY": 88490, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88492, + "minX": 156206, + "minY": 88491, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88492, + "minX": 156207, + "minY": 88491, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88493, + "minX": 156206, + "minY": 88492, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88493, + "minX": 156207, + "minY": 88492, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88494, + "minX": 156206, + "minY": 88493, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88494, + "minX": 156207, + "minY": 88493, + "zoom": 17 + }, + { + "maxX": 156207, + "maxY": 88495, + "minX": 156206, + "minY": 88494, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88495, + "minX": 156207, + "minY": 88494, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88496, + "minX": 156207, + "minY": 88495, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88496, + "minX": 156208, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156208, + "maxY": 88497, + "minX": 156207, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156209, + "maxY": 88497, + "minX": 156208, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88497, + "minX": 156209, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156209, + "maxY": 88498, + "minX": 156208, + "minY": 88497, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88498, + "minX": 156209, + "minY": 88497, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88498, + "minX": 156210, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156209, + "maxY": 88499, + "minX": 156208, + "minY": 88498, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88499, + "minX": 156209, + "minY": 88498, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88500, + "minX": 156209, + "minY": 88499, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88500, + "minX": 156210, + "minY": 88498, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88500, + "minX": 156212, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156210, + "maxY": 88501, + "minX": 156209, + "minY": 88500, + "zoom": 17 + }, + { + "maxX": 156211, + "maxY": 88501, + "minX": 156210, + "minY": 88500, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88501, + "minX": 156211, + "minY": 88500, + "zoom": 17 + }, + { + "maxX": 156211, + "maxY": 88502, + "minX": 156210, + "minY": 88501, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88502, + "minX": 156211, + "minY": 88501, + "zoom": 17 + }, + { + "maxX": 156211, + "maxY": 88503, + "minX": 156210, + "minY": 88502, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88503, + "minX": 156211, + "minY": 88502, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88504, + "minX": 156211, + "minY": 88503, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88504, + "minX": 156212, + "minY": 88500, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88504, + "minX": 156216, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156212, + "maxY": 88505, + "minX": 156211, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88505, + "minX": 156212, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88505, + "minX": 156213, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88506, + "minX": 156212, + "minY": 88505, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88506, + "minX": 156213, + "minY": 88505, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88506, + "minX": 156214, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88507, + "minX": 156212, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88507, + "minX": 156213, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156213, + "maxY": 88508, + "minX": 156212, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88508, + "minX": 156213, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88508, + "minX": 156214, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88509, + "minX": 156213, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156214, + "maxY": 88510, + "minX": 156213, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156215, + "maxY": 88509, + "minX": 156214, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88509, + "minX": 156215, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156215, + "maxY": 88510, + "minX": 156214, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88510, + "minX": 156215, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156215, + "maxY": 88511, + "minX": 156214, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88511, + "minX": 156215, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156215, + "maxY": 88512, + "minX": 156214, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156216, + "maxY": 88512, + "minX": 156215, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88508, + "minX": 156216, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88508, + "minX": 156220, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88510, + "minX": 156216, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88510, + "minX": 156218, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156217, + "maxY": 88511, + "minX": 156216, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88511, + "minX": 156217, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156217, + "maxY": 88512, + "minX": 156216, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156218, + "maxY": 88512, + "minX": 156217, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156219, + "maxY": 88511, + "minX": 156218, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88511, + "minX": 156219, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156219, + "maxY": 88512, + "minX": 156218, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156220, + "maxY": 88512, + "minX": 156219, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156222, + "maxY": 88510, + "minX": 156220, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88510, + "minX": 156222, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156221, + "maxY": 88511, + "minX": 156220, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156222, + "maxY": 88511, + "minX": 156221, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156221, + "maxY": 88512, + "minX": 156220, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156222, + "maxY": 88512, + "minX": 156221, + "minY": 88511, + "zoom": 17 + }, + { + "maxX": 156223, + "maxY": 88511, + "minX": 156222, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156224, + "maxY": 88511, + "minX": 156223, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88480, + "minX": 156224, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88464, + "minX": 156256, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88456, + "minX": 156272, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88452, + "minX": 156280, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88450, + "minX": 156284, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88449, + "minX": 156286, + "minY": 88448, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88450, + "minX": 156286, + "minY": 88449, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88452, + "minX": 156284, + "minY": 88450, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88451, + "minX": 156286, + "minY": 88450, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88452, + "minX": 156286, + "minY": 88451, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88456, + "minX": 156280, + "minY": 88452, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88453, + "minX": 156284, + "minY": 88452, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88453, + "minX": 156285, + "minY": 88452, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88454, + "minX": 156284, + "minY": 88453, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88454, + "minX": 156285, + "minY": 88453, + "zoom": 17 + }, + { + "maxX": 156287, + "maxY": 88453, + "minX": 156286, + "minY": 88452, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88455, + "minX": 156284, + "minY": 88454, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88455, + "minX": 156285, + "minY": 88454, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88456, + "minX": 156284, + "minY": 88455, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88456, + "minX": 156285, + "minY": 88455, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88464, + "minX": 156272, + "minY": 88456, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88460, + "minX": 156280, + "minY": 88456, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88457, + "minX": 156284, + "minY": 88456, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88457, + "minX": 156285, + "minY": 88456, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88458, + "minX": 156284, + "minY": 88457, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88458, + "minX": 156285, + "minY": 88457, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88459, + "minX": 156284, + "minY": 88458, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88459, + "minX": 156285, + "minY": 88458, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88460, + "minX": 156284, + "minY": 88459, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88460, + "minX": 156285, + "minY": 88459, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88464, + "minX": 156280, + "minY": 88460, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88461, + "minX": 156284, + "minY": 88460, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88461, + "minX": 156285, + "minY": 88460, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88462, + "minX": 156284, + "minY": 88461, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88462, + "minX": 156285, + "minY": 88461, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88463, + "minX": 156284, + "minY": 88462, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88463, + "minX": 156285, + "minY": 88462, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88464, + "minX": 156284, + "minY": 88463, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88464, + "minX": 156285, + "minY": 88463, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88480, + "minX": 156256, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88472, + "minX": 156272, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88468, + "minX": 156280, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88465, + "minX": 156284, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88465, + "minX": 156285, + "minY": 88464, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88466, + "minX": 156284, + "minY": 88465, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88466, + "minX": 156285, + "minY": 88465, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88467, + "minX": 156284, + "minY": 88466, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88467, + "minX": 156285, + "minY": 88466, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88468, + "minX": 156284, + "minY": 88467, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88468, + "minX": 156285, + "minY": 88467, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88472, + "minX": 156280, + "minY": 88468, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88469, + "minX": 156284, + "minY": 88468, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88469, + "minX": 156285, + "minY": 88468, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88470, + "minX": 156284, + "minY": 88469, + "zoom": 17 + }, + { + "maxX": 156286, + "maxY": 88470, + "minX": 156285, + "minY": 88469, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88471, + "minX": 156284, + "minY": 88470, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88472, + "minX": 156284, + "minY": 88471, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88480, + "minX": 156272, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88476, + "minX": 156280, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88473, + "minX": 156284, + "minY": 88472, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88474, + "minX": 156284, + "minY": 88473, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88475, + "minX": 156284, + "minY": 88474, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88476, + "minX": 156284, + "minY": 88475, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88480, + "minX": 156280, + "minY": 88476, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88477, + "minX": 156284, + "minY": 88476, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88478, + "minX": 156284, + "minY": 88477, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88479, + "minX": 156284, + "minY": 88478, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88480, + "minX": 156284, + "minY": 88479, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88496, + "minX": 156224, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88496, + "minX": 156240, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156232, + "maxY": 88504, + "minX": 156224, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88504, + "minX": 156232, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156228, + "maxY": 88508, + "minX": 156224, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156232, + "maxY": 88508, + "minX": 156228, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156226, + "maxY": 88510, + "minX": 156224, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156228, + "maxY": 88510, + "minX": 156226, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156225, + "maxY": 88511, + "minX": 156224, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156226, + "maxY": 88511, + "minX": 156225, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156227, + "maxY": 88511, + "minX": 156226, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156228, + "maxY": 88511, + "minX": 156227, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156230, + "maxY": 88510, + "minX": 156228, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156232, + "maxY": 88510, + "minX": 156230, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156229, + "maxY": 88511, + "minX": 156228, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156230, + "maxY": 88511, + "minX": 156229, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156231, + "maxY": 88511, + "minX": 156230, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156232, + "maxY": 88511, + "minX": 156231, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156236, + "maxY": 88508, + "minX": 156232, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88508, + "minX": 156236, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156234, + "maxY": 88510, + "minX": 156232, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156235, + "maxY": 88509, + "minX": 156234, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156236, + "maxY": 88509, + "minX": 156235, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156235, + "maxY": 88510, + "minX": 156234, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156236, + "maxY": 88510, + "minX": 156235, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156233, + "maxY": 88511, + "minX": 156232, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156234, + "maxY": 88511, + "minX": 156233, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156235, + "maxY": 88511, + "minX": 156234, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156236, + "maxY": 88511, + "minX": 156235, + "minY": 88510, + "zoom": 17 + }, + { + "maxX": 156237, + "maxY": 88509, + "minX": 156236, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156238, + "maxY": 88509, + "minX": 156237, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156237, + "maxY": 88510, + "minX": 156236, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156238, + "maxY": 88510, + "minX": 156237, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156239, + "maxY": 88509, + "minX": 156238, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88509, + "minX": 156239, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156239, + "maxY": 88510, + "minX": 156238, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156240, + "maxY": 88510, + "minX": 156239, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156248, + "maxY": 88504, + "minX": 156240, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88504, + "minX": 156248, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156244, + "maxY": 88508, + "minX": 156240, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156248, + "maxY": 88508, + "minX": 156244, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156241, + "maxY": 88509, + "minX": 156240, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156242, + "maxY": 88509, + "minX": 156241, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156241, + "maxY": 88510, + "minX": 156240, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156242, + "maxY": 88510, + "minX": 156241, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156243, + "maxY": 88509, + "minX": 156242, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156244, + "maxY": 88509, + "minX": 156243, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156243, + "maxY": 88510, + "minX": 156242, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156244, + "maxY": 88510, + "minX": 156243, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156245, + "maxY": 88509, + "minX": 156244, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156246, + "maxY": 88509, + "minX": 156245, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156245, + "maxY": 88510, + "minX": 156244, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156246, + "maxY": 88510, + "minX": 156245, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156247, + "maxY": 88509, + "minX": 156246, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156248, + "maxY": 88509, + "minX": 156247, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156247, + "maxY": 88510, + "minX": 156246, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156248, + "maxY": 88510, + "minX": 156247, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156252, + "maxY": 88508, + "minX": 156248, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88508, + "minX": 156252, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156249, + "maxY": 88509, + "minX": 156248, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156250, + "maxY": 88509, + "minX": 156249, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156249, + "maxY": 88510, + "minX": 156248, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156250, + "maxY": 88510, + "minX": 156249, + "minY": 88509, + "zoom": 17 + }, + { + "maxX": 156251, + "maxY": 88509, + "minX": 156250, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156252, + "maxY": 88509, + "minX": 156251, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156253, + "maxY": 88509, + "minX": 156252, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156254, + "maxY": 88509, + "minX": 156253, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156255, + "maxY": 88509, + "minX": 156254, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156256, + "maxY": 88509, + "minX": 156255, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88496, + "minX": 156256, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88488, + "minX": 156272, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88484, + "minX": 156280, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88481, + "minX": 156284, + "minY": 88480, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88482, + "minX": 156284, + "minY": 88481, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88483, + "minX": 156284, + "minY": 88482, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88484, + "minX": 156284, + "minY": 88483, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88486, + "minX": 156280, + "minY": 88484, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88486, + "minX": 156282, + "minY": 88484, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88488, + "minX": 156280, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88487, + "minX": 156282, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88487, + "minX": 156283, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88488, + "minX": 156282, + "minY": 88487, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88488, + "minX": 156283, + "minY": 88487, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88485, + "minX": 156284, + "minY": 88484, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88486, + "minX": 156284, + "minY": 88485, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88487, + "minX": 156284, + "minY": 88486, + "zoom": 17 + }, + { + "maxX": 156285, + "maxY": 88488, + "minX": 156284, + "minY": 88487, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88496, + "minX": 156272, + "minY": 88488, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88490, + "minX": 156280, + "minY": 88488, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88489, + "minX": 156282, + "minY": 88488, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88489, + "minX": 156283, + "minY": 88488, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88490, + "minX": 156282, + "minY": 88489, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88490, + "minX": 156283, + "minY": 88489, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88492, + "minX": 156280, + "minY": 88490, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88491, + "minX": 156282, + "minY": 88490, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88491, + "minX": 156283, + "minY": 88490, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88492, + "minX": 156282, + "minY": 88491, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88492, + "minX": 156283, + "minY": 88491, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88494, + "minX": 156280, + "minY": 88492, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88493, + "minX": 156282, + "minY": 88492, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88493, + "minX": 156283, + "minY": 88492, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88494, + "minX": 156282, + "minY": 88493, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88494, + "minX": 156283, + "minY": 88493, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88496, + "minX": 156280, + "minY": 88494, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88495, + "minX": 156282, + "minY": 88494, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88495, + "minX": 156283, + "minY": 88494, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88496, + "minX": 156282, + "minY": 88495, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88496, + "minX": 156283, + "minY": 88495, + "zoom": 17 + }, + { + "maxX": 156264, + "maxY": 88504, + "minX": 156256, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88504, + "minX": 156264, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156260, + "maxY": 88508, + "minX": 156256, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156262, + "maxY": 88506, + "minX": 156260, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156264, + "maxY": 88506, + "minX": 156262, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156262, + "maxY": 88508, + "minX": 156260, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156263, + "maxY": 88507, + "minX": 156262, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156264, + "maxY": 88507, + "minX": 156263, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156263, + "maxY": 88508, + "minX": 156262, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156264, + "maxY": 88508, + "minX": 156263, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156257, + "maxY": 88509, + "minX": 156256, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156258, + "maxY": 88509, + "minX": 156257, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156259, + "maxY": 88509, + "minX": 156258, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156260, + "maxY": 88509, + "minX": 156259, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156261, + "maxY": 88509, + "minX": 156260, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156262, + "maxY": 88509, + "minX": 156261, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156263, + "maxY": 88509, + "minX": 156262, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156264, + "maxY": 88509, + "minX": 156263, + "minY": 88508, + "zoom": 17 + }, + { + "maxX": 156266, + "maxY": 88506, + "minX": 156264, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156268, + "maxY": 88506, + "minX": 156266, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156265, + "maxY": 88507, + "minX": 156264, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156266, + "maxY": 88507, + "minX": 156265, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156265, + "maxY": 88508, + "minX": 156264, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156266, + "maxY": 88508, + "minX": 156265, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156267, + "maxY": 88507, + "minX": 156266, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156268, + "maxY": 88507, + "minX": 156267, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156267, + "maxY": 88508, + "minX": 156266, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156268, + "maxY": 88508, + "minX": 156267, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156270, + "maxY": 88506, + "minX": 156268, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88506, + "minX": 156270, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156269, + "maxY": 88507, + "minX": 156268, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156270, + "maxY": 88507, + "minX": 156269, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156269, + "maxY": 88508, + "minX": 156268, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156270, + "maxY": 88508, + "minX": 156269, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156271, + "maxY": 88507, + "minX": 156270, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88507, + "minX": 156271, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156271, + "maxY": 88508, + "minX": 156270, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156272, + "maxY": 88508, + "minX": 156271, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88504, + "minX": 156272, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88498, + "minX": 156280, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88497, + "minX": 156282, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88497, + "minX": 156283, + "minY": 88496, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88498, + "minX": 156282, + "minY": 88497, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88498, + "minX": 156283, + "minY": 88497, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88500, + "minX": 156280, + "minY": 88498, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88499, + "minX": 156282, + "minY": 88498, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88499, + "minX": 156283, + "minY": 88498, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88500, + "minX": 156282, + "minY": 88499, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88500, + "minX": 156283, + "minY": 88499, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88502, + "minX": 156280, + "minY": 88500, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88501, + "minX": 156282, + "minY": 88500, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88501, + "minX": 156283, + "minY": 88500, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88502, + "minX": 156282, + "minY": 88501, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88502, + "minX": 156283, + "minY": 88501, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88504, + "minX": 156280, + "minY": 88502, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88503, + "minX": 156282, + "minY": 88502, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88503, + "minX": 156283, + "minY": 88502, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88504, + "minX": 156282, + "minY": 88503, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88504, + "minX": 156283, + "minY": 88503, + "zoom": 17 + }, + { + "maxX": 156274, + "maxY": 88506, + "minX": 156272, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156276, + "maxY": 88506, + "minX": 156274, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156273, + "maxY": 88507, + "minX": 156272, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156274, + "maxY": 88507, + "minX": 156273, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156273, + "maxY": 88508, + "minX": 156272, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156274, + "maxY": 88508, + "minX": 156273, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156275, + "maxY": 88507, + "minX": 156274, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156276, + "maxY": 88507, + "minX": 156275, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156275, + "maxY": 88508, + "minX": 156274, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156276, + "maxY": 88508, + "minX": 156275, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156278, + "maxY": 88506, + "minX": 156276, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88506, + "minX": 156278, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156277, + "maxY": 88507, + "minX": 156276, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156278, + "maxY": 88507, + "minX": 156277, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156277, + "maxY": 88508, + "minX": 156276, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156278, + "maxY": 88508, + "minX": 156277, + "minY": 88507, + "zoom": 17 + }, + { + "maxX": 156279, + "maxY": 88507, + "minX": 156278, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156280, + "maxY": 88507, + "minX": 156279, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88506, + "minX": 156280, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88505, + "minX": 156282, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156284, + "maxY": 88505, + "minX": 156283, + "minY": 88504, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88506, + "minX": 156282, + "minY": 88505, + "zoom": 17 + }, + { + "maxX": 156281, + "maxY": 88507, + "minX": 156280, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156282, + "maxY": 88507, + "minX": 156281, + "minY": 88506, + "zoom": 17 + }, + { + "maxX": 156283, + "maxY": 88507, + "minX": 156282, + "minY": 88506, + "zoom": 17 + } + ], + "sources": [ + { + "path": "7a2ad240-c8a9-44a9-ae67-915144abec49/8c1081ab-1552-418a-87ae-b4ae25cdbf7c", + "type": "S3" + }, + { + "grid": "2X1", + "path": "getmap_test_data/aza_north/gpkg/O_ihud_w84geo_Nov04_Sep22_gpkg_19_0.gpkg", + "type": "GPKG", + "extent": { + "maxX": 34.629350139437605, + "maxY": 31.552055574098873, + "minX": 34.49793037765059, + "minY": 31.401062364453793 + } + } + ], + "isNewTarget": true, + "targetFormat": "JPEG" + }, + "status": "In-Progress", + "percentage": 0, + "reason": "", + "attempts": 0, + "jobId": "a2569d7e-2b86-43af-a6e3-e2096bbad6c5", + "resettable": false, + "created": "2024-01-25 10:29:10.429855+02", + "updated": "2024-01-25 10:42:50.70713+02" +} \ No newline at end of file From a61681772662df4e2e991d34ee7cbfd72d2105d1 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 2 May 2024 19:43:40 +0300 Subject: [PATCH 05/14] chore: add line at the end of JSON files for tests --- MergerServiceUnitTests/Utils/TestData/invalidTask.json | 2 +- MergerServiceUnitTests/Utils/TestData/validTask.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MergerServiceUnitTests/Utils/TestData/invalidTask.json b/MergerServiceUnitTests/Utils/TestData/invalidTask.json index 066a187e..64626732 100644 --- a/MergerServiceUnitTests/Utils/TestData/invalidTask.json +++ b/MergerServiceUnitTests/Utils/TestData/invalidTask.json @@ -15,4 +15,4 @@ "resettable": false, "created": "", "updated": "" -} \ No newline at end of file +} diff --git a/MergerServiceUnitTests/Utils/TestData/validTask.json b/MergerServiceUnitTests/Utils/TestData/validTask.json index 0a91b38c..02183f2c 100644 --- a/MergerServiceUnitTests/Utils/TestData/validTask.json +++ b/MergerServiceUnitTests/Utils/TestData/validTask.json @@ -5773,4 +5773,4 @@ "resettable": false, "created": "2024-01-25 10:29:10.429855+02", "updated": "2024-01-25 10:42:50.70713+02" -} \ No newline at end of file +} From f1b571d60dafd5709a15364a3839cefb56beb4ad Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 2 May 2024 19:59:56 +0300 Subject: [PATCH 06/14] chore: fix run_tests script --- TestMergerOutput/run_tests.sh | 108 +++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 28 deletions(-) diff --git a/TestMergerOutput/run_tests.sh b/TestMergerOutput/run_tests.sh index 62d04a74..44712cb6 100755 --- a/TestMergerOutput/run_tests.sh +++ b/TestMergerOutput/run_tests.sh @@ -3,6 +3,8 @@ export S3_SECRET_KEY="minio123" #"minioadmin" export S3__url="http://localhost:9000" export S3__bucket="tiles" export GENERAL__uploadOnly=false +export TILE__outputFormatStrategy="fixed" +export TILE__outputFormat="jpeg" MAXIMUM_JEPG_TILES_IN_RAM=100000 MAXIMUM_PNG_TILES_IN_RAM=30000 @@ -12,9 +14,9 @@ TEST_FOLDER='' INPUT_FOLDER="${TEST_FOLDER}/input" OUTPUT_FOLDER="${TEST_FOLDER}/output" TEST_RESULTS="${TEST_FOLDER}/correct-results" +export GENERAL__resumeOutputFolder="$TEST_FOLDER" OUTPUT_DATA_ARR=('gpkg') -OUTPUT_FORMAT_ARR=('jpeg' 'png') BATCH_SIZE_ARR=(500 1000 2000 5000 10000 15000 20000) THREAD_NUM_ARR=(1 3 5 8 10 15) @@ -28,20 +30,22 @@ TZOR=('Tzor' '35.1837230,33.22952440,35.23727232,33.2968062') MERGED=('merged' '33.8882,29.20989,36.22737,33.6244') TILE=('tile' '33.8882,29.20989,36.22737,33.6244') -DATA_TO_CHECK=('GEO[@]' 'TZOR[@]' 'JORD[@]' 'SYRIA[@]' 'AREA1[@]' 'AREA2[@]' 'AREA3[@]') +# DATA_TO_CHECK=('GEO[@]' 'TZOR[@]' 'JORD[@]' 'SYRIA[@]' 'AREA1[@]' 'AREA2[@]' 'AREA3[@]') +DATA_TO_CHECK=('GEO[@]') RESULTS=() test -z $TEST_FOLDER && echo "Please assign value to TEST_FOLDER" && exit function run_tests { - OUTPUT_FILE_TYPE=$1 - BATCH_SIZE=$2 + BATCH_SIZE=$1 echo " ########## -Output format: $OUTPUT_FILE_TYPE +Standard tests +Output strategy: $TILE__outputFormatStrategy +Output format: $TILE__outputFormat Batch size: $BATCH_SIZE Threads: $GENERAL__parallel__numOfThreads ##########" >> run.txt @@ -54,8 +58,8 @@ Threads: $GENERAL__parallel__numOfThreads STARTTIME=$(date +%s) IFS=' ' read -ra data_arr <<< "${!data}" - dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE gpkg $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg ${data_arr[1]} gpkg $INPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg >> run.txt - RESULTS+=($(python3 TestMergerOutput/run_tests.py gpkg $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg gpkg $TEST_RESULTS/gpkgs/${data_arr[0]}_${OUTPUT_FILE_TYPE}.gpkg)) + dotnet run --project MergerCli Program.cs $BATCH_SIZE gpkg $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg ${data_arr[1]} gpkg $INPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg >> run.txt + RESULTS+=($(python3 TestMergerOutput/run_tests.py gpkg $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg gpkg $TEST_RESULTS/gpkgs/${data_arr[0]}.gpkg)) rm -f $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg ENDTIME=$(date +%s) @@ -63,44 +67,92 @@ Threads: $GENERAL__parallel__numOfThreads done STARTTIME=$(date +%s) - dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE gpkg $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg ${MERGED[1]} gpkg $INPUT_FOLDER/gpkgs/${GEO[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${TZOR[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${JORD[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${SYRIA[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA1[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA2[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA3[0]}.gpkg >> run.txt - RESULTS+=($(python3 TestMergerOutput/run_tests.py gpkg $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg gpkg $TEST_RESULTS/gpkgs/${MERGED[0]}_${OUTPUT_FILE_TYPE}.gpkg)) + dotnet run --project MergerCli Program.cs $BATCH_SIZE gpkg $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg ${MERGED[1]} gpkg $INPUT_FOLDER/gpkgs/${GEO[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${TZOR[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${JORD[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${SYRIA[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA1[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA2[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA3[0]}.gpkg >> run.txt + RESULTS+=($(python3 TestMergerOutput/run_tests.py gpkg $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg gpkg $TEST_RESULTS/gpkgs/${MERGED[0]}.gpkg)) rm -f $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg ENDTIME=$(date +%s) echo "It takes $(($ENDTIME - $STARTTIME)) seconds to complete run and check for merged..." + echo "Results: ${RESULTS[@]}" ### FS target - # dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE fs $OUTPUT_FOLDER/tiles/area1 ${AREA1[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA1[0]} - # dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE fs $OUTPUT_FOLDER/tiles/area2 ${AREA2[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA2[0]} - # dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE fs $OUTPUT_FOLDER/tiles/area3 ${AREA3[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA3[0]} + # dotnet run --project MergerCli Program.cs $BATCH_SIZE fs $OUTPUT_FOLDER/tiles/area1 ${AREA1[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA1[0]} + # dotnet run --project MergerCli Program.cs $BATCH_SIZE fs $OUTPUT_FOLDER/tiles/area2 ${AREA2[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA2[0]} + # dotnet run --project MergerCli Program.cs $BATCH_SIZE fs $OUTPUT_FOLDER/tiles/area3 ${AREA3[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA3[0]} ### S3 target - # dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE s3 $OUTPUT_FOLDER/tiles/area1 ${AREA1[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA1[0]} - # dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE s3 $OUTPUT_FOLDER/tiles/area2 ${AREA2[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA2[0]} - # dotnet run --project MergerCli Program.cs $BATCH_SIZE $OUTPUT_FILE_TYPE s3 $OUTPUT_FOLDER/tiles/area3 ${AREA3[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA3[0]} + # dotnet run --project MergerCli Program.cs $BATCH_SIZE s3 $OUTPUT_FOLDER/tiles/area1 ${AREA1[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA1[0]} + # dotnet run --project MergerCli Program.cs $BATCH_SIZE s3 $OUTPUT_FOLDER/tiles/area2 ${AREA2[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA2[0]} + # dotnet run --project MergerCli Program.cs $BATCH_SIZE s3 $OUTPUT_FOLDER/tiles/area3 ${AREA3[1]} gpkg $INPUT_FOLDER/gpkgs/${AREA3[0]} +} + +function run_resume_tests { + BATCH_SIZE=$1 + + + echo " +########## +Resume tests +Output strategy: $TILE__outputFormatStrategy +Output format: $TILE__outputFormat +Batch size: $BATCH_SIZE +Threads: $GENERAL__parallel__numOfThreads +##########" >> run.txt + + ## Export to new data target + + ### GPKG target + for data in "${DATA_TO_CHECK[@]}" + do + STARTTIME=$(date +%s) + + IFS=' ' read -ra data_arr <<< "${!data}" + dotnet run --project MergerCli Program.cs $BATCH_SIZE gpkg $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg ${data_arr[1]} gpkg $INPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg >> run.txt & + + job_id=$(echo $!) + disown + sleep 3 + kill -KILL $job_id + cat $TEST_FOLDER/status.json + + # Resume stopped merge process + dotnet run --project MergerCli Program.cs >> run.txt + + RESULTS+=($(python3 TestMergerOutput/run_tests.py gpkg $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg gpkg $TEST_RESULTS/gpkgs/${data_arr[0]}.gpkg)) + rm -f $OUTPUT_FOLDER/gpkgs/${data_arr[0]}.gpkg + + ENDTIME=$(date +%s) + echo "It takes $(($ENDTIME - $STARTTIME)) seconds to complete run and check for ${data_arr[0]}..." + done + + STARTTIME=$(date +%s) + dotnet run --project MergerCli Program.cs $BATCH_SIZE gpkg $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg ${MERGED[1]} gpkg $INPUT_FOLDER/gpkgs/${GEO[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${TZOR[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${JORD[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${SYRIA[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA1[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA2[0]}.gpkg gpkg $INPUT_FOLDER/gpkgs/${AREA3[0]}.gpkg >> run.txt + RESULTS+=($(python3 TestMergerOutput/run_tests.py gpkg $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg gpkg $TEST_RESULTS/gpkgs/${MERGED[0]}.gpkg)) + rm -f $OUTPUT_FOLDER/gpkgs/${MERGED[0]}.gpkg + ENDTIME=$(date +%s) + echo "It takes $(($ENDTIME - $STARTTIME)) seconds to complete run and check for merged..." } # Run CLI tests -for format in "${OUTPUT_FORMAT_ARR[@]}" +for batch_size in "${BATCH_SIZE_ARR[@]}" do - for batch_size in "${BATCH_SIZE_ARR[@]}" + for thread_num in "${THREAD_NUM_ARR[@]}" do - for thread_num in "${THREAD_NUM_ARR[@]}" - do - # Skip batches that will be an issue because of RAM limits - if [[ $format == 'jpeg' ]] && (( $(echo "$thread_num * $batch_size > $MAXIMUM_JEPG_TILES_IN_RAM" | bc -l) )); then - echo "Skipping due to RAM limit: $format, Threads: $thread_num, Batch size: $batch_size" + # Skip batches that will be an issue because of RAM limits + if [[ $TILE__outputFormatStrategy == 'fixed' ]]; then + if [[ $TILE__outputFormat == 'jpeg' ]] && (( $(echo "$thread_num * $batch_size > $MAXIMUM_JEPG_TILES_IN_RAM" | bc -l) )); then + echo "Skipping due to RAM limit: $TILE__outputFormat, Threads: $thread_num, Batch size: $batch_size" break fi - if [[ $format == 'png' ]] && (( $(echo "$thread_num * $batch_size > $MAXIMUM_PNG_TILES_IN_RAM" | bc -l) )); then - echo "Skipping due to RAM limit: $format, Threads: $thread_num, Batch size: $batch_size" + if [[ $TILE__outputFormat == 'png' ]] && (( $(echo "$thread_num * $batch_size > $MAXIMUM_PNG_TILES_IN_RAM" | bc -l) )); then + echo "Skipping due to RAM limit: $TILE__outputFormat, Threads: $thread_num, Batch size: $batch_size" break fi + fi - export GENERAL__parallel__numOfThreads=$thread_num - # echo "Format: $format, Threads: $thread_num, Batch size: $batch_size" - run_tests "$format" $batch_size - done + export GENERAL__parallel__numOfThreads=$thread_num + # echo "Format: $format, Threads: $thread_num, Batch size: $batch_size" + run_tests $batch_size + run_resume_tests "$format" $batch_size done done From df5423e9e55b3fe380ae0f35af05aa3a22a1020d Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 2 May 2024 22:14:57 +0300 Subject: [PATCH 07/14] fix(Tile): get image format by image opaque property --- MergerLogic/Batching/Tile.cs | 10 +++++ MergerLogic/ImageProcessing/ImageFormatter.cs | 16 ++++++++ MergerLogic/ImageProcessing/TileMerger.cs | 10 ++--- .../ImageProcessing/TestImages/5.jpeg | Bin 0 -> 41969 bytes .../ImageProcessing/TileMergerTest.cs | 35 +++++++++++------- 5 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 MergerLogicUnitTests/ImageProcessing/TestImages/5.jpeg diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index 18cb4f31..a99e947a 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -1,3 +1,4 @@ +using ImageMagick; using MergerLogic.DataTypes; using MergerLogic.ImageProcessing; using System.ComponentModel.DataAnnotations; @@ -48,6 +49,15 @@ public Tile(Coord cords, byte[] data) this._data = data; } + public Tile(Coord cords, IMagickImage image) + { + this.Z = cords.Z; + this.X = cords.X; + this.Y = cords.Y; + this.Format = ImageFormatter.GetTileFormat(image) ?? throw new ValidationException($"Cannot create tile {this}, data is in invalid format"); + this._data = image.ToByteArray(); + } + public bool HasCoords(int z, int x, int y) { return z == this.Z && x == this.X && y == this.Y; diff --git a/MergerLogic/ImageProcessing/ImageFormatter.cs b/MergerLogic/ImageProcessing/ImageFormatter.cs index d07268f7..79bb55e8 100644 --- a/MergerLogic/ImageProcessing/ImageFormatter.cs +++ b/MergerLogic/ImageProcessing/ImageFormatter.cs @@ -101,6 +101,22 @@ public static void ConvertToFormat(IMagickImage image, TileFormat format) return null; } + public static TileFormat? GetTileFormat(IMagickImage image) { + if(image.IsOpaque) { + image.Format = MagickFormat.Jpeg; + } + + if (image.Format == MagickFormat.Jpg || image.Format == MagickFormat.Jpeg) { + return TileFormat.Jpeg; + } + + if (image.Format == MagickFormat.Png || image.Format == MagickFormat.Png32) { + return TileFormat.Png; + } + + return null; + } + public static void RemoveImageDateAttributes(IMagickImage? image) { if (image == null) diff --git a/MergerLogic/ImageProcessing/TileMerger.cs b/MergerLogic/ImageProcessing/TileMerger.cs index 18cac00c..69a5461c 100644 --- a/MergerLogic/ImageProcessing/TileMerger.cs +++ b/MergerLogic/ImageProcessing/TileMerger.cs @@ -21,7 +21,7 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy) { var images = this.GetImageList(tiles, targetCoords); - byte[] data; + IMagickImage image; switch (images.Count) { @@ -31,8 +31,7 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) return null; case 1: ImageFormatter.RemoveImageDateAttributes(images[0]); - data = images[0].ToByteArray(); - images[0].Dispose(); + image = images[0]; this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] 1 image found"); break; default: @@ -50,14 +49,15 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) mergedImage.ColorSpace = ColorSpace.sRGB; mergedImage.ColorType = mergedImage.HasAlpha ? ColorType.TrueColorAlpha : ColorType.TrueColor; - data = mergedImage.ToByteArray(); + image = new MagickImage(mergedImage); this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] 'imageMagic' merging finished"); } } break; } - Tile tile = new Tile(targetCoords, data); + Tile tile = new Tile(targetCoords, image); + image.Dispose(); tile.ConvertToFormat(strategy.ApplyStrategy(tile.Format)); return tile; } diff --git a/MergerLogicUnitTests/ImageProcessing/TestImages/5.jpeg b/MergerLogicUnitTests/ImageProcessing/TestImages/5.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e5a915195becb1f6c234da86c08de287cc541c6c GIT binary patch literal 41969 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 literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs index 613ef5a5..f3e34a09 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -56,6 +55,22 @@ public static IEnumerable GetMergeTilesTestParameters() File.ReadAllBytes("2_1_merged.jpeg"), }; + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + File.ReadAllBytes("3_1_merged.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + File.ReadAllBytes("3_4_merged.jpeg"), + }; + yield return new object[] { new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), @@ -80,28 +95,20 @@ public static IEnumerable GetMergeTilesTestParameters() TileFormat.Jpeg, File.ReadAllBytes("3_1_merged.jpeg"), }; - yield return new object[] { - new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, - File.ReadAllBytes("3_1_merged.jpeg"), - }; - yield return new object[] { new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, - File.ReadAllBytes("3_4_merged.jpeg"), + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Jpeg, File.ReadAllBytes("3_4_merged.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + new Tile(targetCoordHighZoom, File.ReadAllBytes("5.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("5.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), - TileFormat.Jpeg, File.ReadAllBytes("3_4_merged.jpeg"), + TileFormat.Jpeg, File.ReadAllBytes("5.jpeg"), }; yield return new object[] { From d83ade92f5a6846e7d4cc48f9992de0300a55fe9 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 5 May 2024 11:40:18 +0300 Subject: [PATCH 08/14] chore(Task): add decorators for OutputFormatStrategy --- MergerService/Models/Tasks/Task.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MergerService/Models/Tasks/Task.cs b/MergerService/Models/Tasks/Task.cs index fb8d410f..2f5fb409 100644 --- a/MergerService/Models/Tasks/Task.cs +++ b/MergerService/Models/Tasks/Task.cs @@ -24,6 +24,8 @@ public class MergeMetadata { [JsonInclude] public TileFormat TargetFormat { get; } + [DefaultValue(FormatStrategy.Fixed)] + [JsonProperty(DefaultValueHandling=DefaultValueHandling.Populate)] [JsonInclude] public FormatStrategy OutputFormatStrategy { get; } [JsonInclude] public bool IsNewTarget { get; } From 4710fbaba3677ba38566f84a0b6d108488226436 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 5 May 2024 14:26:43 +0300 Subject: [PATCH 09/14] test(TaskUtils): add tests for output strategies --- MergerServiceUnitTests/Utils/TaskUtilsTest.cs | 33 +- .../Utils/TestData/invalidTaskStrategy.json | 44 + .../Utils/TestData/validTask.json | 5776 ----------------- .../TestData/validTaskMixedStrategy.json | 44 + .../Utils/TestData/validTaskNoStrategy.json | 43 + 5 files changed, 160 insertions(+), 5780 deletions(-) create mode 100644 MergerServiceUnitTests/Utils/TestData/invalidTaskStrategy.json delete mode 100644 MergerServiceUnitTests/Utils/TestData/validTask.json create mode 100644 MergerServiceUnitTests/Utils/TestData/validTaskMixedStrategy.json create mode 100644 MergerServiceUnitTests/Utils/TestData/validTaskNoStrategy.json diff --git a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs index 3daeac29..bcbd2202 100644 --- a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs +++ b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using System.IO; using System.Net.Http; +using static MergerLogic.ImageProcessing.TileFormatStrategy; namespace MergerLogicUnitTests.Utils { @@ -68,6 +69,7 @@ public static IEnumerable GetBadJsonTestParameters() { yield return new object[] { "bad json" }; yield return new object[] { File.ReadAllText("invalidTask.json") }; + yield return new object[] { File.ReadAllText("invalidTaskStrategy.json") }; } [TestMethod] @@ -79,22 +81,28 @@ public void WhenGettingMalformedJsonTask_ShouldReturnNull(string json) var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, _testActivitySource); + Console.WriteLine(json); + var resultTask = testTaskUtils.GetTask("testJobType", "testTaskType"); Assert.IsNull(resultTask); } + public static IEnumerable GetGoodJsonTestParameters() + { + yield return new object[] { File.ReadAllText("validTaskNoStrategy.json") }; + yield return new object[] { File.ReadAllText("validTaskMixedStrategy.json") }; + } + [TestMethod] - public void WhenGettingJsonTask_ShouldReturnTaskObject() + [DynamicData(nameof(GetGoodJsonTestParameters), DynamicDataSourceType.Method)] + public void WhenGettingJsonTask_ShouldReturnTaskObject(string json) { int maxAttempts = this._configurationManagerMock.Object.GetConfiguration("TASK", "maxAttempts"); - - string json = File.ReadAllText("validTask.json"); this._httpClientMock.Setup(httpClient => httpClient.PostData(It.IsAny(), It.IsAny(), It.IsAny())).Returns(json); var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, _testActivitySource); - var resultTask = testTaskUtils.GetTask("testJobType", "testTaskType"); Assert.IsNotNull(resultTask); @@ -111,11 +119,28 @@ public void WhenGettingJsonTask_ShouldReturnTaskObject() Assert.IsTrue(resultTask.Parameters.Sources?.Length > 0); Assert.IsTrue(resultTask.Parameters.Batches?.Length > 0); Assert.IsInstanceOfType(resultTask.Parameters.TargetFormat, typeof(TileFormat)); + Assert.IsInstanceOfType(resultTask.Parameters.OutputFormatStrategy, typeof(FormatStrategy)); Assert.IsTrue(resultTask.Percentage >= 0 && resultTask.Percentage <= 100); Assert.IsTrue(resultTask.Attempts >= 0 && resultTask.Attempts <= maxAttempts); } + [TestMethod] + public void WhenGettingJsonTaskWithoutStrategy_ShouldHaveFixedDefaultStrategy() + { + string json = File.ReadAllText("validTaskNoStrategy.json"); + int maxAttempts = this._configurationManagerMock.Object.GetConfiguration("TASK", "maxAttempts"); + this._httpClientMock.Setup(httpClient => httpClient.PostData(It.IsAny(), It.IsAny(), It.IsAny())).Returns(json); + + var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, + _testActivitySource); + var resultTask = testTaskUtils.GetTask("testJobType", "testTaskType"); + + Assert.IsNotNull(resultTask); + Assert.IsInstanceOfType(resultTask.Parameters.OutputFormatStrategy, typeof(FormatStrategy)); + Assert.AreEqual(resultTask.Parameters.OutputFormatStrategy, FormatStrategy.Fixed); + } + [TestMethod] public void WhenUpdatingTaskCompleted_ShouldSendCorrectStatusAndPercentage() { diff --git a/MergerServiceUnitTests/Utils/TestData/invalidTaskStrategy.json b/MergerServiceUnitTests/Utils/TestData/invalidTaskStrategy.json new file mode 100644 index 00000000..9edc8ce2 --- /dev/null +++ b/MergerServiceUnitTests/Utils/TestData/invalidTaskStrategy.json @@ -0,0 +1,44 @@ +{ + "id": "3a59ce9f-9279-43e2-936c-868ee5d0b244", + "type": "tilesMerging", + "description": "", + "parameters": { + "batches": [ + { + "maxX": 156220, + "maxY": 88402, + "minX": 156219, + "minY": 88401, + "zoom": 17 + } + ], + "sources": [ + { + "path": "7a2ad240-c8a9-44a9-ae67-915144abec49/8c1081ab-1552-418a-87ae-b4ae25cdbf7c", + "type": "S3" + }, + { + "grid": "2X1", + "path": "getmap_test_data/aza_north/gpkg/O_ihud_w84geo_Nov04_Sep22_gpkg_19_0.gpkg", + "type": "GPKG", + "extent": { + "maxX": 34.629350139437605, + "maxY": 31.552055574098873, + "minX": 34.49793037765059, + "minY": 31.401062364453793 + } + } + ], + "isNewTarget": true, + "targetFormat": "JPEG", + "outputFormatStrategy": "bad" + }, + "status": "In-Progress", + "percentage": 0, + "reason": "", + "attempts": 0, + "jobId": "a2569d7e-2b86-43af-a6e3-e2096bbad6c5", + "resettable": false, + "created": "2024-01-25 10:29:10.429855+02", + "updated": "2024-01-25 10:42:50.70713+02" +} diff --git a/MergerServiceUnitTests/Utils/TestData/validTask.json b/MergerServiceUnitTests/Utils/TestData/validTask.json deleted file mode 100644 index 02183f2c..00000000 --- a/MergerServiceUnitTests/Utils/TestData/validTask.json +++ /dev/null @@ -1,5776 +0,0 @@ -{ - "id": "3a59ce9f-9279-43e2-936c-868ee5d0b244", - "type": "tilesMerging", - "description": "", - "parameters": { - "batches": [ - { - "maxX": 156220, - "maxY": 88402, - "minX": 156219, - "minY": 88401, - "zoom": 17 - }, - { - "maxX": 156219, - "maxY": 88403, - "minX": 156218, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88403, - "minX": 156219, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156219, - "maxY": 88404, - "minX": 156218, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88404, - "minX": 156219, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156221, - "maxY": 88402, - "minX": 156220, - "minY": 88401, - "zoom": 17 - }, - { - "maxX": 156222, - "maxY": 88402, - "minX": 156221, - "minY": 88401, - "zoom": 17 - }, - { - "maxX": 156223, - "maxY": 88402, - "minX": 156222, - "minY": 88401, - "zoom": 17 - }, - { - "maxX": 156222, - "maxY": 88404, - "minX": 156220, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156223, - "maxY": 88403, - "minX": 156222, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88403, - "minX": 156223, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156223, - "maxY": 88404, - "minX": 156222, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88404, - "minX": 156223, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88405, - "minX": 156217, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88406, - "minX": 156217, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156219, - "maxY": 88405, - "minX": 156218, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88405, - "minX": 156219, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156219, - "maxY": 88406, - "minX": 156218, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88406, - "minX": 156219, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156217, - "maxY": 88407, - "minX": 156216, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88407, - "minX": 156217, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156217, - "maxY": 88408, - "minX": 156216, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88408, - "minX": 156217, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88408, - "minX": 156218, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88408, - "minX": 156220, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88410, - "minX": 156215, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88411, - "minX": 156215, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156215, - "maxY": 88412, - "minX": 156214, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88412, - "minX": 156215, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88414, - "minX": 156213, - "minY": 88413, - "zoom": 17 - }, - { - "maxX": 156215, - "maxY": 88413, - "minX": 156214, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88413, - "minX": 156215, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156215, - "maxY": 88414, - "minX": 156214, - "minY": 88413, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88414, - "minX": 156215, - "minY": 88413, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88415, - "minX": 156213, - "minY": 88414, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88416, - "minX": 156213, - "minY": 88415, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88416, - "minX": 156214, - "minY": 88414, - "zoom": 17 - }, - { - "maxX": 156217, - "maxY": 88409, - "minX": 156216, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88409, - "minX": 156217, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156217, - "maxY": 88410, - "minX": 156216, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88410, - "minX": 156217, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88410, - "minX": 156218, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88412, - "minX": 156216, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88412, - "minX": 156218, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88412, - "minX": 156220, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88416, - "minX": 156216, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88416, - "minX": 156220, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88428, - "minX": 156207, - "minY": 88427, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88429, - "minX": 156207, - "minY": 88428, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88430, - "minX": 156206, - "minY": 88429, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88430, - "minX": 156207, - "minY": 88429, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88431, - "minX": 156206, - "minY": 88430, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88431, - "minX": 156207, - "minY": 88430, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88432, - "minX": 156206, - "minY": 88431, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88432, - "minX": 156207, - "minY": 88431, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88419, - "minX": 156211, - "minY": 88418, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88420, - "minX": 156211, - "minY": 88419, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88417, - "minX": 156212, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88417, - "minX": 156213, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88418, - "minX": 156212, - "minY": 88417, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88418, - "minX": 156213, - "minY": 88417, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88418, - "minX": 156214, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88419, - "minX": 156212, - "minY": 88418, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88419, - "minX": 156213, - "minY": 88418, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88420, - "minX": 156212, - "minY": 88419, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88420, - "minX": 156213, - "minY": 88419, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88420, - "minX": 156214, - "minY": 88418, - "zoom": 17 - }, - { - "maxX": 156211, - "maxY": 88421, - "minX": 156210, - "minY": 88420, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88421, - "minX": 156211, - "minY": 88420, - "zoom": 17 - }, - { - "maxX": 156211, - "maxY": 88422, - "minX": 156210, - "minY": 88421, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88422, - "minX": 156211, - "minY": 88421, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88424, - "minX": 156209, - "minY": 88423, - "zoom": 17 - }, - { - "maxX": 156211, - "maxY": 88423, - "minX": 156210, - "minY": 88422, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88423, - "minX": 156211, - "minY": 88422, - "zoom": 17 - }, - { - "maxX": 156211, - "maxY": 88424, - "minX": 156210, - "minY": 88423, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88424, - "minX": 156211, - "minY": 88423, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88424, - "minX": 156212, - "minY": 88420, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88424, - "minX": 156216, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88425, - "minX": 156209, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156209, - "maxY": 88426, - "minX": 156208, - "minY": 88425, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88426, - "minX": 156209, - "minY": 88425, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88426, - "minX": 156210, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156209, - "maxY": 88427, - "minX": 156208, - "minY": 88426, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88427, - "minX": 156209, - "minY": 88426, - "zoom": 17 - }, - { - "maxX": 156209, - "maxY": 88428, - "minX": 156208, - "minY": 88427, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88428, - "minX": 156209, - "minY": 88427, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88428, - "minX": 156210, - "minY": 88426, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88428, - "minX": 156212, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88432, - "minX": 156208, - "minY": 88428, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88432, - "minX": 156212, - "minY": 88428, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88432, - "minX": 156216, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88433, - "minX": 156205, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88434, - "minX": 156205, - "minY": 88433, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88433, - "minX": 156206, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88433, - "minX": 156207, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88434, - "minX": 156206, - "minY": 88433, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88434, - "minX": 156207, - "minY": 88433, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88435, - "minX": 156204, - "minY": 88434, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88435, - "minX": 156205, - "minY": 88434, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88436, - "minX": 156204, - "minY": 88435, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88436, - "minX": 156205, - "minY": 88435, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88436, - "minX": 156206, - "minY": 88434, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88437, - "minX": 156203, - "minY": 88436, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88438, - "minX": 156203, - "minY": 88437, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88439, - "minX": 156203, - "minY": 88438, - "zoom": 17 - }, - { - "maxX": 156203, - "maxY": 88440, - "minX": 156202, - "minY": 88439, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88440, - "minX": 156203, - "minY": 88439, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88437, - "minX": 156204, - "minY": 88436, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88437, - "minX": 156205, - "minY": 88436, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88438, - "minX": 156204, - "minY": 88437, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88438, - "minX": 156205, - "minY": 88437, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88438, - "minX": 156206, - "minY": 88436, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88440, - "minX": 156204, - "minY": 88438, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88440, - "minX": 156206, - "minY": 88438, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88446, - "minX": 156199, - "minY": 88445, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88447, - "minX": 156199, - "minY": 88446, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88448, - "minX": 156199, - "minY": 88447, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88442, - "minX": 156201, - "minY": 88441, - "zoom": 17 - }, - { - "maxX": 156203, - "maxY": 88441, - "minX": 156202, - "minY": 88440, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88441, - "minX": 156203, - "minY": 88440, - "zoom": 17 - }, - { - "maxX": 156203, - "maxY": 88442, - "minX": 156202, - "minY": 88441, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88442, - "minX": 156203, - "minY": 88441, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88443, - "minX": 156201, - "minY": 88442, - "zoom": 17 - }, - { - "maxX": 156201, - "maxY": 88444, - "minX": 156200, - "minY": 88443, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88444, - "minX": 156201, - "minY": 88443, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88444, - "minX": 156202, - "minY": 88442, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88444, - "minX": 156204, - "minY": 88440, - "zoom": 17 - }, - { - "maxX": 156201, - "maxY": 88445, - "minX": 156200, - "minY": 88444, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88445, - "minX": 156201, - "minY": 88444, - "zoom": 17 - }, - { - "maxX": 156201, - "maxY": 88446, - "minX": 156200, - "minY": 88445, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88446, - "minX": 156201, - "minY": 88445, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88446, - "minX": 156202, - "minY": 88444, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88448, - "minX": 156200, - "minY": 88446, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88448, - "minX": 156202, - "minY": 88446, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88448, - "minX": 156204, - "minY": 88444, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88448, - "minX": 156208, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156225, - "maxY": 88403, - "minX": 156224, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156226, - "maxY": 88403, - "minX": 156225, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156225, - "maxY": 88404, - "minX": 156224, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156226, - "maxY": 88404, - "minX": 156225, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156227, - "maxY": 88403, - "minX": 156226, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156228, - "maxY": 88403, - "minX": 156227, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156227, - "maxY": 88404, - "minX": 156226, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156228, - "maxY": 88404, - "minX": 156227, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156229, - "maxY": 88403, - "minX": 156228, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156230, - "maxY": 88403, - "minX": 156229, - "minY": 88402, - "zoom": 17 - }, - { - "maxX": 156229, - "maxY": 88404, - "minX": 156228, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156230, - "maxY": 88404, - "minX": 156229, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156231, - "maxY": 88404, - "minX": 156230, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156232, - "maxY": 88404, - "minX": 156231, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156228, - "maxY": 88408, - "minX": 156224, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156232, - "maxY": 88408, - "minX": 156228, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156233, - "maxY": 88404, - "minX": 156232, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156234, - "maxY": 88404, - "minX": 156233, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156235, - "maxY": 88404, - "minX": 156234, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156236, - "maxY": 88404, - "minX": 156235, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156237, - "maxY": 88404, - "minX": 156236, - "minY": 88403, - "zoom": 17 - }, - { - "maxX": 156236, - "maxY": 88408, - "minX": 156232, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156237, - "maxY": 88405, - "minX": 156236, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156238, - "maxY": 88405, - "minX": 156237, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156237, - "maxY": 88406, - "minX": 156236, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156238, - "maxY": 88406, - "minX": 156237, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156239, - "maxY": 88405, - "minX": 156238, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88405, - "minX": 156239, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156239, - "maxY": 88406, - "minX": 156238, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88406, - "minX": 156239, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156238, - "maxY": 88408, - "minX": 156236, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88408, - "minX": 156238, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156232, - "maxY": 88416, - "minX": 156224, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88416, - "minX": 156232, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156241, - "maxY": 88405, - "minX": 156240, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156242, - "maxY": 88405, - "minX": 156241, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156241, - "maxY": 88406, - "minX": 156240, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156242, - "maxY": 88406, - "minX": 156241, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156243, - "maxY": 88405, - "minX": 156242, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156244, - "maxY": 88405, - "minX": 156243, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156243, - "maxY": 88406, - "minX": 156242, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156244, - "maxY": 88406, - "minX": 156243, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156242, - "maxY": 88408, - "minX": 156240, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156244, - "maxY": 88408, - "minX": 156242, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156245, - "maxY": 88405, - "minX": 156244, - "minY": 88404, - "zoom": 17 - }, - { - "maxX": 156245, - "maxY": 88406, - "minX": 156244, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156246, - "maxY": 88406, - "minX": 156245, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156247, - "maxY": 88406, - "minX": 156246, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156248, - "maxY": 88406, - "minX": 156247, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156246, - "maxY": 88408, - "minX": 156244, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156248, - "maxY": 88408, - "minX": 156246, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156249, - "maxY": 88406, - "minX": 156248, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156250, - "maxY": 88406, - "minX": 156249, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156251, - "maxY": 88406, - "minX": 156250, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156252, - "maxY": 88406, - "minX": 156251, - "minY": 88405, - "zoom": 17 - }, - { - "maxX": 156250, - "maxY": 88408, - "minX": 156248, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156251, - "maxY": 88407, - "minX": 156250, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156252, - "maxY": 88407, - "minX": 156251, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156251, - "maxY": 88408, - "minX": 156250, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156252, - "maxY": 88408, - "minX": 156251, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156253, - "maxY": 88407, - "minX": 156252, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156254, - "maxY": 88407, - "minX": 156253, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156253, - "maxY": 88408, - "minX": 156252, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156254, - "maxY": 88408, - "minX": 156253, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156255, - "maxY": 88407, - "minX": 156254, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88407, - "minX": 156255, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156255, - "maxY": 88408, - "minX": 156254, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88408, - "minX": 156255, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156248, - "maxY": 88416, - "minX": 156240, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88416, - "minX": 156248, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156257, - "maxY": 88407, - "minX": 156256, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156258, - "maxY": 88407, - "minX": 156257, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156257, - "maxY": 88408, - "minX": 156256, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156258, - "maxY": 88408, - "minX": 156257, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156259, - "maxY": 88407, - "minX": 156258, - "minY": 88406, - "zoom": 17 - }, - { - "maxX": 156259, - "maxY": 88408, - "minX": 156258, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156260, - "maxY": 88408, - "minX": 156259, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156261, - "maxY": 88408, - "minX": 156260, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156262, - "maxY": 88408, - "minX": 156261, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156263, - "maxY": 88408, - "minX": 156262, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156264, - "maxY": 88408, - "minX": 156263, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156265, - "maxY": 88408, - "minX": 156264, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156266, - "maxY": 88408, - "minX": 156265, - "minY": 88407, - "zoom": 17 - }, - { - "maxX": 156264, - "maxY": 88416, - "minX": 156256, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156265, - "maxY": 88409, - "minX": 156264, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156266, - "maxY": 88409, - "minX": 156265, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156265, - "maxY": 88410, - "minX": 156264, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156266, - "maxY": 88410, - "minX": 156265, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156267, - "maxY": 88409, - "minX": 156266, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156268, - "maxY": 88409, - "minX": 156267, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156267, - "maxY": 88410, - "minX": 156266, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156268, - "maxY": 88410, - "minX": 156267, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156266, - "maxY": 88412, - "minX": 156264, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156268, - "maxY": 88412, - "minX": 156266, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156269, - "maxY": 88409, - "minX": 156268, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156270, - "maxY": 88409, - "minX": 156269, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156269, - "maxY": 88410, - "minX": 156268, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156270, - "maxY": 88410, - "minX": 156269, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156271, - "maxY": 88409, - "minX": 156270, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88409, - "minX": 156271, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156271, - "maxY": 88410, - "minX": 156270, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88410, - "minX": 156271, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156270, - "maxY": 88412, - "minX": 156268, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88412, - "minX": 156270, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156268, - "maxY": 88416, - "minX": 156264, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88416, - "minX": 156268, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156273, - "maxY": 88409, - "minX": 156272, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156274, - "maxY": 88409, - "minX": 156273, - "minY": 88408, - "zoom": 17 - }, - { - "maxX": 156273, - "maxY": 88410, - "minX": 156272, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156274, - "maxY": 88410, - "minX": 156273, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156275, - "maxY": 88410, - "minX": 156274, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156276, - "maxY": 88410, - "minX": 156275, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156274, - "maxY": 88412, - "minX": 156272, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156276, - "maxY": 88412, - "minX": 156274, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156277, - "maxY": 88410, - "minX": 156276, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156278, - "maxY": 88410, - "minX": 156277, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156279, - "maxY": 88410, - "minX": 156278, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88410, - "minX": 156279, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156278, - "maxY": 88412, - "minX": 156276, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88412, - "minX": 156278, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156276, - "maxY": 88416, - "minX": 156272, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88416, - "minX": 156276, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156281, - "maxY": 88410, - "minX": 156280, - "minY": 88409, - "zoom": 17 - }, - { - "maxX": 156281, - "maxY": 88411, - "minX": 156280, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88411, - "minX": 156281, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156281, - "maxY": 88412, - "minX": 156280, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88412, - "minX": 156281, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88411, - "minX": 156282, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88411, - "minX": 156283, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88412, - "minX": 156282, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88412, - "minX": 156283, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88411, - "minX": 156284, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88411, - "minX": 156285, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88412, - "minX": 156284, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88412, - "minX": 156285, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88411, - "minX": 156286, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88411, - "minX": 156287, - "minY": 88410, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88412, - "minX": 156286, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88412, - "minX": 156287, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88416, - "minX": 156280, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88416, - "minX": 156284, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88448, - "minX": 156224, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88432, - "minX": 156256, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88424, - "minX": 156272, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88420, - "minX": 156280, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88418, - "minX": 156284, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88417, - "minX": 156286, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88417, - "minX": 156287, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88418, - "minX": 156286, - "minY": 88417, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88418, - "minX": 156287, - "minY": 88417, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88420, - "minX": 156284, - "minY": 88418, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88419, - "minX": 156286, - "minY": 88418, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88419, - "minX": 156287, - "minY": 88418, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88420, - "minX": 156286, - "minY": 88419, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88420, - "minX": 156287, - "minY": 88419, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88424, - "minX": 156280, - "minY": 88420, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88422, - "minX": 156284, - "minY": 88420, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88421, - "minX": 156286, - "minY": 88420, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88421, - "minX": 156287, - "minY": 88420, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88422, - "minX": 156286, - "minY": 88421, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88422, - "minX": 156287, - "minY": 88421, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88424, - "minX": 156284, - "minY": 88422, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88423, - "minX": 156286, - "minY": 88422, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88423, - "minX": 156287, - "minY": 88422, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88424, - "minX": 156286, - "minY": 88423, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88424, - "minX": 156287, - "minY": 88423, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88432, - "minX": 156272, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88428, - "minX": 156280, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88426, - "minX": 156284, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88425, - "minX": 156286, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88425, - "minX": 156287, - "minY": 88424, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88426, - "minX": 156286, - "minY": 88425, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88426, - "minX": 156287, - "minY": 88425, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88428, - "minX": 156284, - "minY": 88426, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88427, - "minX": 156286, - "minY": 88426, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88427, - "minX": 156287, - "minY": 88426, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88428, - "minX": 156286, - "minY": 88427, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88428, - "minX": 156287, - "minY": 88427, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88432, - "minX": 156280, - "minY": 88428, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88430, - "minX": 156284, - "minY": 88428, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88429, - "minX": 156286, - "minY": 88428, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88429, - "minX": 156287, - "minY": 88428, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88430, - "minX": 156286, - "minY": 88429, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88430, - "minX": 156287, - "minY": 88429, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88432, - "minX": 156284, - "minY": 88430, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88431, - "minX": 156286, - "minY": 88430, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88431, - "minX": 156287, - "minY": 88430, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88432, - "minX": 156286, - "minY": 88431, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88432, - "minX": 156287, - "minY": 88431, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88448, - "minX": 156256, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88440, - "minX": 156272, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88436, - "minX": 156280, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88434, - "minX": 156284, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88433, - "minX": 156286, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88433, - "minX": 156287, - "minY": 88432, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88434, - "minX": 156286, - "minY": 88433, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88434, - "minX": 156287, - "minY": 88433, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88436, - "minX": 156284, - "minY": 88434, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88435, - "minX": 156286, - "minY": 88434, - "zoom": 17 - }, - { - "maxX": 156288, - "maxY": 88435, - "minX": 156287, - "minY": 88434, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88436, - "minX": 156286, - "minY": 88435, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88440, - "minX": 156280, - "minY": 88436, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88438, - "minX": 156284, - "minY": 88436, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88437, - "minX": 156286, - "minY": 88436, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88438, - "minX": 156286, - "minY": 88437, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88440, - "minX": 156284, - "minY": 88438, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88439, - "minX": 156286, - "minY": 88438, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88440, - "minX": 156286, - "minY": 88439, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88448, - "minX": 156272, - "minY": 88440, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88444, - "minX": 156280, - "minY": 88440, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88442, - "minX": 156284, - "minY": 88440, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88441, - "minX": 156286, - "minY": 88440, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88442, - "minX": 156286, - "minY": 88441, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88444, - "minX": 156284, - "minY": 88442, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88443, - "minX": 156286, - "minY": 88442, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88444, - "minX": 156286, - "minY": 88443, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88448, - "minX": 156280, - "minY": 88444, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88446, - "minX": 156284, - "minY": 88444, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88445, - "minX": 156286, - "minY": 88444, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88446, - "minX": 156286, - "minY": 88445, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88448, - "minX": 156284, - "minY": 88446, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88447, - "minX": 156286, - "minY": 88446, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88448, - "minX": 156286, - "minY": 88447, - "zoom": 17 - }, - { - "maxX": 156289, - "maxY": 88412, - "minX": 156288, - "minY": 88411, - "zoom": 17 - }, - { - "maxX": 156289, - "maxY": 88413, - "minX": 156288, - "minY": 88412, - "zoom": 17 - }, - { - "maxX": 156289, - "maxY": 88414, - "minX": 156288, - "minY": 88413, - "zoom": 17 - }, - { - "maxX": 156289, - "maxY": 88415, - "minX": 156288, - "minY": 88414, - "zoom": 17 - }, - { - "maxX": 156289, - "maxY": 88416, - "minX": 156288, - "minY": 88415, - "zoom": 17 - }, - { - "maxX": 156289, - "maxY": 88417, - "minX": 156288, - "minY": 88416, - "zoom": 17 - }, - { - "maxX": 156199, - "maxY": 88449, - "minX": 156198, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88449, - "minX": 156199, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156199, - "maxY": 88450, - "minX": 156198, - "minY": 88449, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88450, - "minX": 156199, - "minY": 88449, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88451, - "minX": 156197, - "minY": 88450, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88452, - "minX": 156197, - "minY": 88451, - "zoom": 17 - }, - { - "maxX": 156199, - "maxY": 88451, - "minX": 156198, - "minY": 88450, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88451, - "minX": 156199, - "minY": 88450, - "zoom": 17 - }, - { - "maxX": 156199, - "maxY": 88452, - "minX": 156198, - "minY": 88451, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88452, - "minX": 156199, - "minY": 88451, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88456, - "minX": 156195, - "minY": 88455, - "zoom": 17 - }, - { - "maxX": 156197, - "maxY": 88453, - "minX": 156196, - "minY": 88452, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88453, - "minX": 156197, - "minY": 88452, - "zoom": 17 - }, - { - "maxX": 156197, - "maxY": 88454, - "minX": 156196, - "minY": 88453, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88454, - "minX": 156197, - "minY": 88453, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88454, - "minX": 156198, - "minY": 88452, - "zoom": 17 - }, - { - "maxX": 156197, - "maxY": 88455, - "minX": 156196, - "minY": 88454, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88455, - "minX": 156197, - "minY": 88454, - "zoom": 17 - }, - { - "maxX": 156197, - "maxY": 88456, - "minX": 156196, - "minY": 88455, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88456, - "minX": 156197, - "minY": 88455, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88456, - "minX": 156198, - "minY": 88454, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88456, - "minX": 156200, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88457, - "minX": 156195, - "minY": 88456, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88458, - "minX": 156194, - "minY": 88457, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88458, - "minX": 156195, - "minY": 88457, - "zoom": 17 - }, - { - "maxX": 156194, - "maxY": 88460, - "minX": 156193, - "minY": 88459, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88459, - "minX": 156194, - "minY": 88458, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88459, - "minX": 156195, - "minY": 88458, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88460, - "minX": 156194, - "minY": 88459, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88460, - "minX": 156195, - "minY": 88459, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88460, - "minX": 156196, - "minY": 88456, - "zoom": 17 - }, - { - "maxX": 156194, - "maxY": 88461, - "minX": 156193, - "minY": 88460, - "zoom": 17 - }, - { - "maxX": 156194, - "maxY": 88462, - "minX": 156193, - "minY": 88461, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88462, - "minX": 156194, - "minY": 88460, - "zoom": 17 - }, - { - "maxX": 156193, - "maxY": 88463, - "minX": 156192, - "minY": 88462, - "zoom": 17 - }, - { - "maxX": 156194, - "maxY": 88463, - "minX": 156193, - "minY": 88462, - "zoom": 17 - }, - { - "maxX": 156193, - "maxY": 88464, - "minX": 156192, - "minY": 88463, - "zoom": 17 - }, - { - "maxX": 156194, - "maxY": 88464, - "minX": 156193, - "minY": 88463, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88464, - "minX": 156194, - "minY": 88462, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88464, - "minX": 156196, - "minY": 88460, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88464, - "minX": 156200, - "minY": 88456, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88464, - "minX": 156208, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156194, - "maxY": 88465, - "minX": 156193, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156194, - "maxY": 88466, - "minX": 156193, - "minY": 88465, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88465, - "minX": 156194, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88465, - "minX": 156195, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88466, - "minX": 156194, - "minY": 88465, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88466, - "minX": 156195, - "minY": 88465, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88467, - "minX": 156194, - "minY": 88466, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88467, - "minX": 156195, - "minY": 88466, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88468, - "minX": 156194, - "minY": 88467, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88468, - "minX": 156195, - "minY": 88467, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88468, - "minX": 156196, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156195, - "maxY": 88469, - "minX": 156194, - "minY": 88468, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88469, - "minX": 156195, - "minY": 88468, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88470, - "minX": 156195, - "minY": 88469, - "zoom": 17 - }, - { - "maxX": 156196, - "maxY": 88471, - "minX": 156195, - "minY": 88470, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88470, - "minX": 156196, - "minY": 88468, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88470, - "minX": 156198, - "minY": 88468, - "zoom": 17 - }, - { - "maxX": 156197, - "maxY": 88471, - "minX": 156196, - "minY": 88470, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88471, - "minX": 156197, - "minY": 88470, - "zoom": 17 - }, - { - "maxX": 156197, - "maxY": 88472, - "minX": 156196, - "minY": 88471, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88472, - "minX": 156197, - "minY": 88471, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88472, - "minX": 156198, - "minY": 88470, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88472, - "minX": 156200, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156197, - "maxY": 88473, - "minX": 156196, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88473, - "minX": 156197, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88474, - "minX": 156197, - "minY": 88473, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88474, - "minX": 156198, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156198, - "maxY": 88475, - "minX": 156197, - "minY": 88474, - "zoom": 17 - }, - { - "maxX": 156199, - "maxY": 88475, - "minX": 156198, - "minY": 88474, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88475, - "minX": 156199, - "minY": 88474, - "zoom": 17 - }, - { - "maxX": 156199, - "maxY": 88476, - "minX": 156198, - "minY": 88475, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88476, - "minX": 156199, - "minY": 88475, - "zoom": 17 - }, - { - "maxX": 156199, - "maxY": 88477, - "minX": 156198, - "minY": 88476, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88477, - "minX": 156199, - "minY": 88476, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88478, - "minX": 156199, - "minY": 88477, - "zoom": 17 - }, - { - "maxX": 156200, - "maxY": 88479, - "minX": 156199, - "minY": 88478, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88476, - "minX": 156200, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88476, - "minX": 156204, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88478, - "minX": 156200, - "minY": 88476, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88478, - "minX": 156202, - "minY": 88476, - "zoom": 17 - }, - { - "maxX": 156201, - "maxY": 88479, - "minX": 156200, - "minY": 88478, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88479, - "minX": 156201, - "minY": 88478, - "zoom": 17 - }, - { - "maxX": 156201, - "maxY": 88480, - "minX": 156200, - "minY": 88479, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88480, - "minX": 156201, - "minY": 88479, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88480, - "minX": 156202, - "minY": 88478, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88480, - "minX": 156204, - "minY": 88476, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88480, - "minX": 156208, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156201, - "maxY": 88481, - "minX": 156200, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88481, - "minX": 156201, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156201, - "maxY": 88482, - "minX": 156200, - "minY": 88481, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88482, - "minX": 156201, - "minY": 88481, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88482, - "minX": 156202, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88483, - "minX": 156201, - "minY": 88482, - "zoom": 17 - }, - { - "maxX": 156202, - "maxY": 88484, - "minX": 156201, - "minY": 88483, - "zoom": 17 - }, - { - "maxX": 156203, - "maxY": 88483, - "minX": 156202, - "minY": 88482, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88483, - "minX": 156203, - "minY": 88482, - "zoom": 17 - }, - { - "maxX": 156203, - "maxY": 88484, - "minX": 156202, - "minY": 88483, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88484, - "minX": 156203, - "minY": 88483, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88484, - "minX": 156204, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156203, - "maxY": 88485, - "minX": 156202, - "minY": 88484, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88485, - "minX": 156203, - "minY": 88484, - "zoom": 17 - }, - { - "maxX": 156203, - "maxY": 88486, - "minX": 156202, - "minY": 88485, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88486, - "minX": 156203, - "minY": 88485, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88487, - "minX": 156203, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156204, - "maxY": 88488, - "minX": 156203, - "minY": 88487, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88486, - "minX": 156204, - "minY": 88484, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88486, - "minX": 156206, - "minY": 88484, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88487, - "minX": 156204, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88487, - "minX": 156205, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88488, - "minX": 156204, - "minY": 88487, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88488, - "minX": 156205, - "minY": 88487, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88488, - "minX": 156206, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88489, - "minX": 156204, - "minY": 88488, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88489, - "minX": 156205, - "minY": 88488, - "zoom": 17 - }, - { - "maxX": 156205, - "maxY": 88490, - "minX": 156204, - "minY": 88489, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88490, - "minX": 156205, - "minY": 88489, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88490, - "minX": 156206, - "minY": 88488, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88491, - "minX": 156205, - "minY": 88490, - "zoom": 17 - }, - { - "maxX": 156206, - "maxY": 88492, - "minX": 156205, - "minY": 88491, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88491, - "minX": 156206, - "minY": 88490, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88491, - "minX": 156207, - "minY": 88490, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88492, - "minX": 156206, - "minY": 88491, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88492, - "minX": 156207, - "minY": 88491, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88493, - "minX": 156206, - "minY": 88492, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88493, - "minX": 156207, - "minY": 88492, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88494, - "minX": 156206, - "minY": 88493, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88494, - "minX": 156207, - "minY": 88493, - "zoom": 17 - }, - { - "maxX": 156207, - "maxY": 88495, - "minX": 156206, - "minY": 88494, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88495, - "minX": 156207, - "minY": 88494, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88496, - "minX": 156207, - "minY": 88495, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88496, - "minX": 156208, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156208, - "maxY": 88497, - "minX": 156207, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156209, - "maxY": 88497, - "minX": 156208, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88497, - "minX": 156209, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156209, - "maxY": 88498, - "minX": 156208, - "minY": 88497, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88498, - "minX": 156209, - "minY": 88497, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88498, - "minX": 156210, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156209, - "maxY": 88499, - "minX": 156208, - "minY": 88498, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88499, - "minX": 156209, - "minY": 88498, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88500, - "minX": 156209, - "minY": 88499, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88500, - "minX": 156210, - "minY": 88498, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88500, - "minX": 156212, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156210, - "maxY": 88501, - "minX": 156209, - "minY": 88500, - "zoom": 17 - }, - { - "maxX": 156211, - "maxY": 88501, - "minX": 156210, - "minY": 88500, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88501, - "minX": 156211, - "minY": 88500, - "zoom": 17 - }, - { - "maxX": 156211, - "maxY": 88502, - "minX": 156210, - "minY": 88501, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88502, - "minX": 156211, - "minY": 88501, - "zoom": 17 - }, - { - "maxX": 156211, - "maxY": 88503, - "minX": 156210, - "minY": 88502, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88503, - "minX": 156211, - "minY": 88502, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88504, - "minX": 156211, - "minY": 88503, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88504, - "minX": 156212, - "minY": 88500, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88504, - "minX": 156216, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156212, - "maxY": 88505, - "minX": 156211, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88505, - "minX": 156212, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88505, - "minX": 156213, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88506, - "minX": 156212, - "minY": 88505, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88506, - "minX": 156213, - "minY": 88505, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88506, - "minX": 156214, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88507, - "minX": 156212, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88507, - "minX": 156213, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156213, - "maxY": 88508, - "minX": 156212, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88508, - "minX": 156213, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88508, - "minX": 156214, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88509, - "minX": 156213, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156214, - "maxY": 88510, - "minX": 156213, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156215, - "maxY": 88509, - "minX": 156214, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88509, - "minX": 156215, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156215, - "maxY": 88510, - "minX": 156214, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88510, - "minX": 156215, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156215, - "maxY": 88511, - "minX": 156214, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88511, - "minX": 156215, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156215, - "maxY": 88512, - "minX": 156214, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156216, - "maxY": 88512, - "minX": 156215, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88508, - "minX": 156216, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88508, - "minX": 156220, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88510, - "minX": 156216, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88510, - "minX": 156218, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156217, - "maxY": 88511, - "minX": 156216, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88511, - "minX": 156217, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156217, - "maxY": 88512, - "minX": 156216, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156218, - "maxY": 88512, - "minX": 156217, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156219, - "maxY": 88511, - "minX": 156218, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88511, - "minX": 156219, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156219, - "maxY": 88512, - "minX": 156218, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156220, - "maxY": 88512, - "minX": 156219, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156222, - "maxY": 88510, - "minX": 156220, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88510, - "minX": 156222, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156221, - "maxY": 88511, - "minX": 156220, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156222, - "maxY": 88511, - "minX": 156221, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156221, - "maxY": 88512, - "minX": 156220, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156222, - "maxY": 88512, - "minX": 156221, - "minY": 88511, - "zoom": 17 - }, - { - "maxX": 156223, - "maxY": 88511, - "minX": 156222, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156224, - "maxY": 88511, - "minX": 156223, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88480, - "minX": 156224, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88464, - "minX": 156256, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88456, - "minX": 156272, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88452, - "minX": 156280, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88450, - "minX": 156284, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88449, - "minX": 156286, - "minY": 88448, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88450, - "minX": 156286, - "minY": 88449, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88452, - "minX": 156284, - "minY": 88450, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88451, - "minX": 156286, - "minY": 88450, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88452, - "minX": 156286, - "minY": 88451, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88456, - "minX": 156280, - "minY": 88452, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88453, - "minX": 156284, - "minY": 88452, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88453, - "minX": 156285, - "minY": 88452, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88454, - "minX": 156284, - "minY": 88453, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88454, - "minX": 156285, - "minY": 88453, - "zoom": 17 - }, - { - "maxX": 156287, - "maxY": 88453, - "minX": 156286, - "minY": 88452, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88455, - "minX": 156284, - "minY": 88454, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88455, - "minX": 156285, - "minY": 88454, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88456, - "minX": 156284, - "minY": 88455, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88456, - "minX": 156285, - "minY": 88455, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88464, - "minX": 156272, - "minY": 88456, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88460, - "minX": 156280, - "minY": 88456, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88457, - "minX": 156284, - "minY": 88456, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88457, - "minX": 156285, - "minY": 88456, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88458, - "minX": 156284, - "minY": 88457, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88458, - "minX": 156285, - "minY": 88457, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88459, - "minX": 156284, - "minY": 88458, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88459, - "minX": 156285, - "minY": 88458, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88460, - "minX": 156284, - "minY": 88459, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88460, - "minX": 156285, - "minY": 88459, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88464, - "minX": 156280, - "minY": 88460, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88461, - "minX": 156284, - "minY": 88460, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88461, - "minX": 156285, - "minY": 88460, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88462, - "minX": 156284, - "minY": 88461, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88462, - "minX": 156285, - "minY": 88461, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88463, - "minX": 156284, - "minY": 88462, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88463, - "minX": 156285, - "minY": 88462, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88464, - "minX": 156284, - "minY": 88463, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88464, - "minX": 156285, - "minY": 88463, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88480, - "minX": 156256, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88472, - "minX": 156272, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88468, - "minX": 156280, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88465, - "minX": 156284, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88465, - "minX": 156285, - "minY": 88464, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88466, - "minX": 156284, - "minY": 88465, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88466, - "minX": 156285, - "minY": 88465, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88467, - "minX": 156284, - "minY": 88466, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88467, - "minX": 156285, - "minY": 88466, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88468, - "minX": 156284, - "minY": 88467, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88468, - "minX": 156285, - "minY": 88467, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88472, - "minX": 156280, - "minY": 88468, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88469, - "minX": 156284, - "minY": 88468, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88469, - "minX": 156285, - "minY": 88468, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88470, - "minX": 156284, - "minY": 88469, - "zoom": 17 - }, - { - "maxX": 156286, - "maxY": 88470, - "minX": 156285, - "minY": 88469, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88471, - "minX": 156284, - "minY": 88470, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88472, - "minX": 156284, - "minY": 88471, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88480, - "minX": 156272, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88476, - "minX": 156280, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88473, - "minX": 156284, - "minY": 88472, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88474, - "minX": 156284, - "minY": 88473, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88475, - "minX": 156284, - "minY": 88474, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88476, - "minX": 156284, - "minY": 88475, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88480, - "minX": 156280, - "minY": 88476, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88477, - "minX": 156284, - "minY": 88476, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88478, - "minX": 156284, - "minY": 88477, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88479, - "minX": 156284, - "minY": 88478, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88480, - "minX": 156284, - "minY": 88479, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88496, - "minX": 156224, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88496, - "minX": 156240, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156232, - "maxY": 88504, - "minX": 156224, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88504, - "minX": 156232, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156228, - "maxY": 88508, - "minX": 156224, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156232, - "maxY": 88508, - "minX": 156228, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156226, - "maxY": 88510, - "minX": 156224, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156228, - "maxY": 88510, - "minX": 156226, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156225, - "maxY": 88511, - "minX": 156224, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156226, - "maxY": 88511, - "minX": 156225, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156227, - "maxY": 88511, - "minX": 156226, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156228, - "maxY": 88511, - "minX": 156227, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156230, - "maxY": 88510, - "minX": 156228, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156232, - "maxY": 88510, - "minX": 156230, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156229, - "maxY": 88511, - "minX": 156228, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156230, - "maxY": 88511, - "minX": 156229, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156231, - "maxY": 88511, - "minX": 156230, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156232, - "maxY": 88511, - "minX": 156231, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156236, - "maxY": 88508, - "minX": 156232, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88508, - "minX": 156236, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156234, - "maxY": 88510, - "minX": 156232, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156235, - "maxY": 88509, - "minX": 156234, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156236, - "maxY": 88509, - "minX": 156235, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156235, - "maxY": 88510, - "minX": 156234, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156236, - "maxY": 88510, - "minX": 156235, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156233, - "maxY": 88511, - "minX": 156232, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156234, - "maxY": 88511, - "minX": 156233, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156235, - "maxY": 88511, - "minX": 156234, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156236, - "maxY": 88511, - "minX": 156235, - "minY": 88510, - "zoom": 17 - }, - { - "maxX": 156237, - "maxY": 88509, - "minX": 156236, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156238, - "maxY": 88509, - "minX": 156237, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156237, - "maxY": 88510, - "minX": 156236, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156238, - "maxY": 88510, - "minX": 156237, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156239, - "maxY": 88509, - "minX": 156238, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88509, - "minX": 156239, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156239, - "maxY": 88510, - "minX": 156238, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156240, - "maxY": 88510, - "minX": 156239, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156248, - "maxY": 88504, - "minX": 156240, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88504, - "minX": 156248, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156244, - "maxY": 88508, - "minX": 156240, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156248, - "maxY": 88508, - "minX": 156244, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156241, - "maxY": 88509, - "minX": 156240, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156242, - "maxY": 88509, - "minX": 156241, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156241, - "maxY": 88510, - "minX": 156240, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156242, - "maxY": 88510, - "minX": 156241, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156243, - "maxY": 88509, - "minX": 156242, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156244, - "maxY": 88509, - "minX": 156243, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156243, - "maxY": 88510, - "minX": 156242, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156244, - "maxY": 88510, - "minX": 156243, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156245, - "maxY": 88509, - "minX": 156244, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156246, - "maxY": 88509, - "minX": 156245, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156245, - "maxY": 88510, - "minX": 156244, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156246, - "maxY": 88510, - "minX": 156245, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156247, - "maxY": 88509, - "minX": 156246, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156248, - "maxY": 88509, - "minX": 156247, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156247, - "maxY": 88510, - "minX": 156246, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156248, - "maxY": 88510, - "minX": 156247, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156252, - "maxY": 88508, - "minX": 156248, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88508, - "minX": 156252, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156249, - "maxY": 88509, - "minX": 156248, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156250, - "maxY": 88509, - "minX": 156249, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156249, - "maxY": 88510, - "minX": 156248, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156250, - "maxY": 88510, - "minX": 156249, - "minY": 88509, - "zoom": 17 - }, - { - "maxX": 156251, - "maxY": 88509, - "minX": 156250, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156252, - "maxY": 88509, - "minX": 156251, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156253, - "maxY": 88509, - "minX": 156252, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156254, - "maxY": 88509, - "minX": 156253, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156255, - "maxY": 88509, - "minX": 156254, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156256, - "maxY": 88509, - "minX": 156255, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88496, - "minX": 156256, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88488, - "minX": 156272, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88484, - "minX": 156280, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88481, - "minX": 156284, - "minY": 88480, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88482, - "minX": 156284, - "minY": 88481, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88483, - "minX": 156284, - "minY": 88482, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88484, - "minX": 156284, - "minY": 88483, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88486, - "minX": 156280, - "minY": 88484, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88486, - "minX": 156282, - "minY": 88484, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88488, - "minX": 156280, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88487, - "minX": 156282, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88487, - "minX": 156283, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88488, - "minX": 156282, - "minY": 88487, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88488, - "minX": 156283, - "minY": 88487, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88485, - "minX": 156284, - "minY": 88484, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88486, - "minX": 156284, - "minY": 88485, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88487, - "minX": 156284, - "minY": 88486, - "zoom": 17 - }, - { - "maxX": 156285, - "maxY": 88488, - "minX": 156284, - "minY": 88487, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88496, - "minX": 156272, - "minY": 88488, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88490, - "minX": 156280, - "minY": 88488, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88489, - "minX": 156282, - "minY": 88488, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88489, - "minX": 156283, - "minY": 88488, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88490, - "minX": 156282, - "minY": 88489, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88490, - "minX": 156283, - "minY": 88489, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88492, - "minX": 156280, - "minY": 88490, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88491, - "minX": 156282, - "minY": 88490, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88491, - "minX": 156283, - "minY": 88490, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88492, - "minX": 156282, - "minY": 88491, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88492, - "minX": 156283, - "minY": 88491, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88494, - "minX": 156280, - "minY": 88492, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88493, - "minX": 156282, - "minY": 88492, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88493, - "minX": 156283, - "minY": 88492, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88494, - "minX": 156282, - "minY": 88493, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88494, - "minX": 156283, - "minY": 88493, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88496, - "minX": 156280, - "minY": 88494, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88495, - "minX": 156282, - "minY": 88494, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88495, - "minX": 156283, - "minY": 88494, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88496, - "minX": 156282, - "minY": 88495, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88496, - "minX": 156283, - "minY": 88495, - "zoom": 17 - }, - { - "maxX": 156264, - "maxY": 88504, - "minX": 156256, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88504, - "minX": 156264, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156260, - "maxY": 88508, - "minX": 156256, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156262, - "maxY": 88506, - "minX": 156260, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156264, - "maxY": 88506, - "minX": 156262, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156262, - "maxY": 88508, - "minX": 156260, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156263, - "maxY": 88507, - "minX": 156262, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156264, - "maxY": 88507, - "minX": 156263, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156263, - "maxY": 88508, - "minX": 156262, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156264, - "maxY": 88508, - "minX": 156263, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156257, - "maxY": 88509, - "minX": 156256, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156258, - "maxY": 88509, - "minX": 156257, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156259, - "maxY": 88509, - "minX": 156258, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156260, - "maxY": 88509, - "minX": 156259, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156261, - "maxY": 88509, - "minX": 156260, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156262, - "maxY": 88509, - "minX": 156261, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156263, - "maxY": 88509, - "minX": 156262, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156264, - "maxY": 88509, - "minX": 156263, - "minY": 88508, - "zoom": 17 - }, - { - "maxX": 156266, - "maxY": 88506, - "minX": 156264, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156268, - "maxY": 88506, - "minX": 156266, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156265, - "maxY": 88507, - "minX": 156264, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156266, - "maxY": 88507, - "minX": 156265, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156265, - "maxY": 88508, - "minX": 156264, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156266, - "maxY": 88508, - "minX": 156265, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156267, - "maxY": 88507, - "minX": 156266, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156268, - "maxY": 88507, - "minX": 156267, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156267, - "maxY": 88508, - "minX": 156266, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156268, - "maxY": 88508, - "minX": 156267, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156270, - "maxY": 88506, - "minX": 156268, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88506, - "minX": 156270, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156269, - "maxY": 88507, - "minX": 156268, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156270, - "maxY": 88507, - "minX": 156269, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156269, - "maxY": 88508, - "minX": 156268, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156270, - "maxY": 88508, - "minX": 156269, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156271, - "maxY": 88507, - "minX": 156270, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88507, - "minX": 156271, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156271, - "maxY": 88508, - "minX": 156270, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156272, - "maxY": 88508, - "minX": 156271, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88504, - "minX": 156272, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88498, - "minX": 156280, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88497, - "minX": 156282, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88497, - "minX": 156283, - "minY": 88496, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88498, - "minX": 156282, - "minY": 88497, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88498, - "minX": 156283, - "minY": 88497, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88500, - "minX": 156280, - "minY": 88498, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88499, - "minX": 156282, - "minY": 88498, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88499, - "minX": 156283, - "minY": 88498, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88500, - "minX": 156282, - "minY": 88499, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88500, - "minX": 156283, - "minY": 88499, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88502, - "minX": 156280, - "minY": 88500, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88501, - "minX": 156282, - "minY": 88500, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88501, - "minX": 156283, - "minY": 88500, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88502, - "minX": 156282, - "minY": 88501, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88502, - "minX": 156283, - "minY": 88501, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88504, - "minX": 156280, - "minY": 88502, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88503, - "minX": 156282, - "minY": 88502, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88503, - "minX": 156283, - "minY": 88502, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88504, - "minX": 156282, - "minY": 88503, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88504, - "minX": 156283, - "minY": 88503, - "zoom": 17 - }, - { - "maxX": 156274, - "maxY": 88506, - "minX": 156272, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156276, - "maxY": 88506, - "minX": 156274, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156273, - "maxY": 88507, - "minX": 156272, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156274, - "maxY": 88507, - "minX": 156273, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156273, - "maxY": 88508, - "minX": 156272, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156274, - "maxY": 88508, - "minX": 156273, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156275, - "maxY": 88507, - "minX": 156274, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156276, - "maxY": 88507, - "minX": 156275, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156275, - "maxY": 88508, - "minX": 156274, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156276, - "maxY": 88508, - "minX": 156275, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156278, - "maxY": 88506, - "minX": 156276, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88506, - "minX": 156278, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156277, - "maxY": 88507, - "minX": 156276, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156278, - "maxY": 88507, - "minX": 156277, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156277, - "maxY": 88508, - "minX": 156276, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156278, - "maxY": 88508, - "minX": 156277, - "minY": 88507, - "zoom": 17 - }, - { - "maxX": 156279, - "maxY": 88507, - "minX": 156278, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156280, - "maxY": 88507, - "minX": 156279, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88506, - "minX": 156280, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88505, - "minX": 156282, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156284, - "maxY": 88505, - "minX": 156283, - "minY": 88504, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88506, - "minX": 156282, - "minY": 88505, - "zoom": 17 - }, - { - "maxX": 156281, - "maxY": 88507, - "minX": 156280, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156282, - "maxY": 88507, - "minX": 156281, - "minY": 88506, - "zoom": 17 - }, - { - "maxX": 156283, - "maxY": 88507, - "minX": 156282, - "minY": 88506, - "zoom": 17 - } - ], - "sources": [ - { - "path": "7a2ad240-c8a9-44a9-ae67-915144abec49/8c1081ab-1552-418a-87ae-b4ae25cdbf7c", - "type": "S3" - }, - { - "grid": "2X1", - "path": "getmap_test_data/aza_north/gpkg/O_ihud_w84geo_Nov04_Sep22_gpkg_19_0.gpkg", - "type": "GPKG", - "extent": { - "maxX": 34.629350139437605, - "maxY": 31.552055574098873, - "minX": 34.49793037765059, - "minY": 31.401062364453793 - } - } - ], - "isNewTarget": true, - "targetFormat": "JPEG" - }, - "status": "In-Progress", - "percentage": 0, - "reason": "", - "attempts": 0, - "jobId": "a2569d7e-2b86-43af-a6e3-e2096bbad6c5", - "resettable": false, - "created": "2024-01-25 10:29:10.429855+02", - "updated": "2024-01-25 10:42:50.70713+02" -} diff --git a/MergerServiceUnitTests/Utils/TestData/validTaskMixedStrategy.json b/MergerServiceUnitTests/Utils/TestData/validTaskMixedStrategy.json new file mode 100644 index 00000000..f108e571 --- /dev/null +++ b/MergerServiceUnitTests/Utils/TestData/validTaskMixedStrategy.json @@ -0,0 +1,44 @@ +{ + "id": "3a59ce9f-9279-43e2-936c-868ee5d0b244", + "type": "tilesMerging", + "description": "", + "parameters": { + "batches": [ + { + "maxX": 156220, + "maxY": 88402, + "minX": 156219, + "minY": 88401, + "zoom": 17 + } + ], + "sources": [ + { + "path": "7a2ad240-c8a9-44a9-ae67-915144abec49/8c1081ab-1552-418a-87ae-b4ae25cdbf7c", + "type": "S3" + }, + { + "grid": "2X1", + "path": "getmap_test_data/aza_north/gpkg/O_ihud_w84geo_Nov04_Sep22_gpkg_19_0.gpkg", + "type": "GPKG", + "extent": { + "maxX": 34.629350139437605, + "maxY": 31.552055574098873, + "minX": 34.49793037765059, + "minY": 31.401062364453793 + } + } + ], + "isNewTarget": true, + "targetFormat": "JPEG", + "outputFormatStrategy": "mixed" + }, + "status": "In-Progress", + "percentage": 0, + "reason": "", + "attempts": 0, + "jobId": "a2569d7e-2b86-43af-a6e3-e2096bbad6c5", + "resettable": false, + "created": "2024-01-25 10:29:10.429855+02", + "updated": "2024-01-25 10:42:50.70713+02" +} diff --git a/MergerServiceUnitTests/Utils/TestData/validTaskNoStrategy.json b/MergerServiceUnitTests/Utils/TestData/validTaskNoStrategy.json new file mode 100644 index 00000000..ae7e54c0 --- /dev/null +++ b/MergerServiceUnitTests/Utils/TestData/validTaskNoStrategy.json @@ -0,0 +1,43 @@ +{ + "id": "3a59ce9f-9279-43e2-936c-868ee5d0b244", + "type": "tilesMerging", + "description": "", + "parameters": { + "batches": [ + { + "maxX": 156220, + "maxY": 88402, + "minX": 156219, + "minY": 88401, + "zoom": 17 + } + ], + "sources": [ + { + "path": "7a2ad240-c8a9-44a9-ae67-915144abec49/8c1081ab-1552-418a-87ae-b4ae25cdbf7c", + "type": "S3" + }, + { + "grid": "2X1", + "path": "getmap_test_data/aza_north/gpkg/O_ihud_w84geo_Nov04_Sep22_gpkg_19_0.gpkg", + "type": "GPKG", + "extent": { + "maxX": 34.629350139437605, + "maxY": 31.552055574098873, + "minX": 34.49793037765059, + "minY": 31.401062364453793 + } + } + ], + "isNewTarget": true, + "targetFormat": "JPEG" + }, + "status": "In-Progress", + "percentage": 0, + "reason": "", + "attempts": 0, + "jobId": "a2569d7e-2b86-43af-a6e3-e2096bbad6c5", + "resettable": false, + "created": "2024-01-25 10:29:10.429855+02", + "updated": "2024-01-25 10:42:50.70713+02" +} From 420288bad8b0699cf22135e0daf8cae7e74ff528 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 5 May 2024 14:35:12 +0300 Subject: [PATCH 10/14] chore(Tile): add class comment --- MergerLogic/Batching/Tile.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index a99e947a..de28907b 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -7,6 +7,10 @@ namespace MergerLogic.Batching { public delegate Tile? CorrespondingTileBuilder(); + // TODO: add to README that the Merger assumes EPSG:4326 + /// + /// Class Tile represents a position of an image in the EPSG:4326 geographic tiling scheme + /// public class Tile { public int Z From f0cb7c699a6a95a4b49c8302ece6135b0ab8c2e6 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 7 May 2024 20:09:50 +0300 Subject: [PATCH 11/14] test: add tests for tile merge --- .../ImageProcessing/TileMergerTest.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs index f3e34a09..fc97a008 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs @@ -63,6 +63,14 @@ public static IEnumerable GetMergeTilesTestParameters() File.ReadAllBytes("3_1_merged.jpeg"), }; + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + File.ReadAllBytes("3.jpeg"), + }; + yield return new object[] { new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), @@ -87,6 +95,14 @@ public static IEnumerable GetMergeTilesTestParameters() TileFormat.Png, File.ReadAllBytes("2_1_merged.png"), }; + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Png, File.ReadAllBytes("2_1_merged.png"), + }; + yield return new object[] { new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), From 3d5a587735a31fac336a2098adb2a2cdcbb7073e Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 7 May 2024 21:12:16 +0300 Subject: [PATCH 12/14] chore(resume): save and load startegy and output format from resume file --- MergerCli/Process.cs | 4 ++++ MergerCli/Program.cs | 6 +++++- MergerCli/utils/BatchStatusManager.cs | 30 ++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/MergerCli/Process.cs b/MergerCli/Process.cs index fec4be8f..e7ccb330 100644 --- a/MergerCli/Process.cs +++ b/MergerCli/Process.cs @@ -42,6 +42,10 @@ public void Start(IData baseData, IData newData, BatchStatusManager batchStatusM { resumeMode = true; this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] Resume mode activated, resume batchId: {resumeBatchIdentifier}"); + + // Set strategy from status manager + this._tileFormatStrategy = new TileFormatStrategy(batchStatusManager.Format, batchStatusManager.Strategy); + // fix resume progress bug for gpkg, fs and web, fixing it for s3 requires storing additional data. if (newData.Type != DataType.S3) { diff --git a/MergerCli/Program.cs b/MergerCli/Program.cs index 37db2662..32fdc752 100644 --- a/MergerCli/Program.cs +++ b/MergerCli/Program.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using System.Diagnostics; using System.Runtime.Loader; +using static MergerLogic.ImageProcessing.TileFormatStrategy; namespace MergerCli { @@ -38,6 +39,9 @@ private static void Main(string[] args) var config = container.GetRequiredService(); var pathUtils = container.GetRequiredService(); string outputPath = pathUtils.RemoveTrailingSlash(config.GetConfiguration("GENERAL", "resumeOutputFolder")); + + FormatStrategy outputFormatStrategy = config.GetConfiguration("TILE", "outputFormatStrategy"); + TileFormat outputFormat = config.GetConfiguration("TILE", "outputFormat"); _resumeFilePath = $"{outputPath}/status.json"; // If should resume, load status manager file and update states, else create from arguments @@ -48,7 +52,7 @@ private static void Main(string[] args) } else { - _batchStatusManager = new BatchStatusManager(args); + _batchStatusManager = new BatchStatusManager(args, outputFormat, outputFormatStrategy); } PrepareStatusManger(); diff --git a/MergerCli/utils/BatchStatusManager.cs b/MergerCli/utils/BatchStatusManager.cs index 7ba45edb..7f017fa2 100644 --- a/MergerCli/utils/BatchStatusManager.cs +++ b/MergerCli/utils/BatchStatusManager.cs @@ -1,6 +1,9 @@ -using System.Collections.Concurrent; -using System.Text.Json; +using MergerLogic.ImageProcessing; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System.Collections.Concurrent; using System.Text.Json.Serialization; +using static MergerLogic.ImageProcessing.TileFormatStrategy; namespace MergerCli.Utils { internal class BatchStatusManager @@ -38,16 +41,30 @@ public BaseLayerStatus() [JsonInclude] public Dictionary States { get; private set; } + [JsonInclude] + public FormatStrategy Strategy { get; private set; } + + [JsonInclude] + public TileFormat Format { get; private set; } + [JsonInclude] public string[] Command { get; private set; } static readonly object _locker = new object(); - public BatchStatusManager(string[] command) + [System.Text.Json.Serialization.JsonIgnore] + private JsonSerializerSettings _jsonSerializerSettings; + + public BatchStatusManager(string[] command, TileFormat format, FormatStrategy strategy = FormatStrategy.Fixed) { this.BaseLayer = new BaseLayerStatus(); this.States = new Dictionary(); + this.Strategy = strategy; + this.Format = format; this.Command = command; + + this._jsonSerializerSettings = new JsonSerializerSettings(); + this._jsonSerializerSettings.Converters.Add(new StringEnumConverter()); } public void SetCurrentBatch(string layer, string? batchIdentifier) @@ -177,12 +194,15 @@ public void ResetBatchStatus() public override string ToString() { - return JsonSerializer.Serialize(this); + return JsonConvert.SerializeObject(this, this._jsonSerializerSettings); } public static BatchStatusManager FromJson(string json) { - BatchStatusManager? batchStatusManager = JsonSerializer.Deserialize(json); + JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings(); + jsonSerializerSettings.Converters.Add(new StringEnumConverter()); + + BatchStatusManager? batchStatusManager = JsonConvert.DeserializeObject(json, jsonSerializerSettings)!; if (batchStatusManager == null) { throw new Exception("invalid batch status manager json"); From d1c968689cc8085881a98956f5d4e370ca9ed339 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 9 May 2024 19:35:52 +0300 Subject: [PATCH 13/14] chore: remove console log in test --- MergerServiceUnitTests/Utils/TaskUtilsTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs index bcbd2202..93fde34b 100644 --- a/MergerServiceUnitTests/Utils/TaskUtilsTest.cs +++ b/MergerServiceUnitTests/Utils/TaskUtilsTest.cs @@ -81,8 +81,6 @@ public void WhenGettingMalformedJsonTask_ShouldReturnNull(string json) var testTaskUtils = new TaskUtils(_configurationManagerMock.Object, _httpClientMock.Object, _taskUtilsLoggerMock.Object, _testActivitySource); - Console.WriteLine(json); - var resultTask = testTaskUtils.GetTask("testJobType", "testTaskType"); Assert.IsNull(resultTask); From a2304758d2655e3063bef5d9459733138f5394a3 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 23 May 2024 21:52:25 +0300 Subject: [PATCH 14/14] test(ImageFormatter): add cases for different png bit coding --- MergerLogic/ImageProcessing/ImageFormatter.cs | 2 +- .../ImageProcessing/ImageFormatterTest.cs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/MergerLogic/ImageProcessing/ImageFormatter.cs b/MergerLogic/ImageProcessing/ImageFormatter.cs index 79bb55e8..50c75d95 100644 --- a/MergerLogic/ImageProcessing/ImageFormatter.cs +++ b/MergerLogic/ImageProcessing/ImageFormatter.cs @@ -110,7 +110,7 @@ public static void ConvertToFormat(IMagickImage image, TileFormat format) return TileFormat.Jpeg; } - if (image.Format == MagickFormat.Png || image.Format == MagickFormat.Png32) { + if (image.Format == MagickFormat.Png) { return TileFormat.Png; } diff --git a/MergerLogicUnitTests/ImageProcessing/ImageFormatterTest.cs b/MergerLogicUnitTests/ImageProcessing/ImageFormatterTest.cs index 62258d4c..280908aa 100644 --- a/MergerLogicUnitTests/ImageProcessing/ImageFormatterTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/ImageFormatterTest.cs @@ -38,6 +38,30 @@ public static IEnumerable GetConvertToFormatTestParameters() TileFormat.Jpeg, true, }; + + yield return new object[] { + File.ReadAllBytes("5_8bit.png"), + TileFormat.Png, + true, + }; + + yield return new object[] { + File.ReadAllBytes("5_24bit.png"), + TileFormat.Png, + true, + }; + + yield return new object[] { + File.ReadAllBytes("5_32bit.png"), + TileFormat.Png, + true, + }; + + yield return new object[] { + File.ReadAllBytes("5_64bit.png"), + TileFormat.Png, + true, + }; } [TestMethod]