From dfae62e0a4e587a48dc7a4fcbc2e2bb9a253d667 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 4 Jun 2024 22:29:52 +0300 Subject: [PATCH 01/13] refactor(TileMerger): pass uploadOnly and skip merge in case there is only one source --- MergerCli/Process.cs | 18 +- MergerLogic/ImageProcessing/ITileMerger.cs | 2 +- MergerLogic/ImageProcessing/TileMerger.cs | 52 ++---- .../ImageProcessing/TestImages/1.jpeg | Bin 0 -> 5945 bytes .../ImageProcessing/TestImages/1.png | Bin 19336 -> 19504 bytes .../TestImages/3_2_1_merged.jpeg | Bin 0 -> 9610 bytes .../ImageProcessing/TileMergerTest.cs | 168 ++++++++++++++++-- MergerService/Runners/TaskExecutor.cs | 3 +- .../Runners/TaskExecutorTest.cs | 12 +- 9 files changed, 186 insertions(+), 69 deletions(-) create mode 100644 MergerLogicUnitTests/ImageProcessing/TestImages/1.jpeg create mode 100644 MergerLogicUnitTests/ImageProcessing/TestImages/3_2_1_merged.jpeg diff --git a/MergerCli/Process.cs b/MergerCli/Process.cs index e7ccb330..ff37b52c 100644 --- a/MergerCli/Process.cs +++ b/MergerCli/Process.cs @@ -12,7 +12,6 @@ namespace MergerCli { internal class Process : IProcess { - private Func _getTileByCoord; private readonly IConfigurationManager _configManager; private readonly ITileMerger _tileMerger; private readonly ILogger _logger; @@ -55,14 +54,6 @@ public void Start(IData baseData, IData newData, BatchStatusManager batchStatusM } this._logger.LogInformation($"[{MethodBase.GetCurrentMethod().Name}] Total amount of tiles to merge: {totalTileCount - tileProgressCount}"); - var uploadOnly = this._configManager.GetConfiguration("GENERAL", "uploadOnly"); - - uploadOnly = uploadOnly || baseData.IsNew; - bool shouldUpscale = !uploadOnly; - _getTileByCoord = uploadOnly ? - (_) => null - : - (targetCoords) => baseData.GetCorrespondingTile(targetCoords, shouldUpscale); ParallelRun(baseData, newData, batchStatusManager, tileProgressCount, totalTileCount, resumeBatchIdentifier, resumeMode, pollForBatch); @@ -118,16 +109,21 @@ private void ProcessBatch(IData baseData, List newTiles, ref long tileProg return; } + bool uploadOnly = this._configManager.GetConfiguration("GENERAL", "uploadOnly") || baseData.IsNew; + uploadOnly = uploadOnly || baseData.IsNew; + bool shouldUpscale = !uploadOnly; + for (int i = 0; i < newTiles.Count; i++) { var newTile = newTiles[i]; var targetCoords = newTile.GetCoord(); List correspondingTileBuilders = new List() { - () => _getTileByCoord(targetCoords), () => newTile + () => baseData.GetCorrespondingTile(targetCoords, shouldUpscale), + () => newTile }; - Tile? tile = this._tileMerger.MergeTiles(correspondingTileBuilders, targetCoords, this._tileFormatStrategy); + Tile? tile = this._tileMerger.MergeTiles(correspondingTileBuilders, targetCoords, this._tileFormatStrategy, uploadOnly); if (tile != null) { diff --git a/MergerLogic/ImageProcessing/ITileMerger.cs b/MergerLogic/ImageProcessing/ITileMerger.cs index e7428cc5..b1bd4610 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, TileFormatStrategy strategy); + Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy, bool uploadOnly = false); } } diff --git a/MergerLogic/ImageProcessing/TileMerger.cs b/MergerLogic/ImageProcessing/TileMerger.cs index 69a5461c..c3fc6c30 100644 --- a/MergerLogic/ImageProcessing/TileMerger.cs +++ b/MergerLogic/ImageProcessing/TileMerger.cs @@ -18,9 +18,21 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) this._tileScaler = tileScaler; } - public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy) + public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy, bool uploadOnly = false) { - var images = this.GetImageList(tiles, targetCoords); + if(uploadOnly) { + // Ignore target if in upload only mode + tiles = tiles.Skip(1).ToList(); + + // In case there is only one source then we can just return the data as is + if(tiles.Count == 1) { + Tile? rawTile = tiles[0](); + rawTile?.ConvertToFormat(strategy.ApplyStrategy(rawTile.Format)); + return rawTile; + } + } + + var images = this.GetImageList(tiles, targetCoords, uploadOnly); IMagickImage image; switch (images.Count) @@ -62,7 +74,7 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) return tile; } - private List GetImageList(List tiles, Coord targetCoords) + private List GetImageList(List tiles, Coord targetCoords, bool uploadOnly) { var images = new List(); int i = tiles.Count - 1; @@ -71,19 +83,10 @@ private List GetImageList(List tiles, Coo bool hasAlpha = false; try { - tile = GetFirstTile(tiles, targetCoords, ref i); - string message = tile == null ? "null" : $"z:{tile.Z}, x:{tile.X}, y:{tile.Y}"; - this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] first tile is {message}"); - this.AddTileToImageList(targetCoords, tile, images, out hasAlpha); - if (!hasAlpha) - { - return images; - } - for (; i >= 0; i--) { // protect in case all "sources" tiles are null - if (images.Count == 0 && i == 0) + if (images.Count == 0 && i == 0 && !uploadOnly) { this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] All sources are empty - return"); return images; @@ -112,29 +115,6 @@ private List GetImageList(List tiles, Coo return images; } - private Tile? GetFirstTile(List tiles, Coord targetCoords, ref int i) - { - // We only need to go over sources, target should be excluded (e.g. i > 0 and not i >= 0) - for (; i > 0; i--) - { - Tile? tile = tiles[i](); - if (tile != null) - { - // Check if should upscale tile (first tile does not upscale if there are no other tiles) - // TODO: refactor code in this class - if (tile.Z < targetCoords.Z) - { - tile = this._tileScaler.Upscale(tile, targetCoords); - } - - i--; - return tile; - } - } - - return null; - } - private void AddTileToImageList(Coord targetCoords, Tile? tile, List images, out bool hasAlpha) { if (tile is null) diff --git a/MergerLogicUnitTests/ImageProcessing/TestImages/1.jpeg b/MergerLogicUnitTests/ImageProcessing/TestImages/1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..fffa96eafa00cbc946d47e66d4b5dea6cba6db21 GIT binary patch literal 5945 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 literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/ImageProcessing/TestImages/1.png b/MergerLogicUnitTests/ImageProcessing/TestImages/1.png index 924a7b9ccb50058d3f9be463c8ca04182b729828..37d4b6e87c385b1cd3f29870f79a9d617fb61e7e 100644 GIT binary patch literal 19504 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 FV1g`trRD$t literal 19336 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 diff --git a/MergerLogicUnitTests/ImageProcessing/TestImages/3_2_1_merged.jpeg b/MergerLogicUnitTests/ImageProcessing/TestImages/3_2_1_merged.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..eafd9daab0c34ce4d9970df60bb67b91bafa2e7f GIT binary patch literal 9610 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èRTBpXG~V|{QhciR<1%Ww_oU?7Rmk& znXfH(aw(i5H_aDzO~1O9ot|V`%W*X+JZuzgGL6#c4|~}W(iYfbaXcdOL|?Hgx_<3l z&x26GzUJXGiP8;e7%jw;ZIjg4{l29R$*GSx*%@02$-n}=ql~v09azWjBkTwW_KKY! z1%zF?7NM^-V8?+)s(+8OvAR;RMez(-di2HJmq;PK{W_D$rh3$qPaQ|qY5%l~e;yip zxxP(nVQ+P8FveOx{7HA233- z_|qc_+YDM+DMDnJ58+MSCBQ`@D9f76$qGIrKC*`+c zk21|!FsHaoQ+`?jDETm$Cxn=jegRubQnP2aGZ?$e)l!;czgWodCOS<3BdN!uV7%;r zMzunYKRS7?D1}Cy&1CG literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs index fc97a008..536ac9b9 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs @@ -47,11 +47,12 @@ public static IEnumerable GetMergeTilesTestParameters() var targetCoordMediumZoom = new Coord(14, 0, 0); var targetCoordHighZoom = new Coord(15, 0, 0); + #region Regular merge test cases 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), TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("2_1_merged.jpeg"), }; @@ -59,7 +60,7 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3_1_merged.jpeg"), }; @@ -67,7 +68,7 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3.jpeg"), }; @@ -75,7 +76,7 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3_4_merged.jpeg"), }; @@ -83,7 +84,7 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png), TileFormat.Png, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png), TileFormat.Png, false, File.ReadAllBytes("2_1_merged.png"), }; @@ -92,7 +93,7 @@ public static IEnumerable GetMergeTilesTestParameters() 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"), + TileFormat.Png, false, File.ReadAllBytes("2_1_merged.png"), }; yield return new object[] { @@ -100,7 +101,7 @@ public static IEnumerable GetMergeTilesTestParameters() 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"), + TileFormat.Png, false, File.ReadAllBytes("2_1_merged.png"), }; yield return new object[] { @@ -108,7 +109,7 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), - TileFormat.Jpeg, File.ReadAllBytes("3_1_merged.jpeg"), + TileFormat.Jpeg, false, File.ReadAllBytes("3_1_merged.jpeg"), }; yield return new object[] { @@ -116,7 +117,7 @@ public static IEnumerable GetMergeTilesTestParameters() 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"), + TileFormat.Jpeg, false, File.ReadAllBytes("3_4_merged.jpeg"), }; yield return new object[] { @@ -124,14 +125,14 @@ public static IEnumerable GetMergeTilesTestParameters() 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("5.jpeg"), + TileFormat.Jpeg, false, File.ReadAllBytes("5.jpeg"), }; yield return new object[] { new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordLowZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3_1_merged_upscaled_5_15.jpeg"), }; @@ -139,18 +140,157 @@ public static IEnumerable GetMergeTilesTestParameters() new Tile[] { new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), new Tile(targetCoordMediumZoom, File.ReadAllBytes("1.png")) - }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3_1_merged_upscaled_14_15.jpeg"), }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, + File.ReadAllBytes("4.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Jpeg, false, File.ReadAllBytes("3_2_1_merged.jpeg"), + }; + #endregion + + #region Test cases for ignoring target + 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), TileFormat.Jpeg, true, + File.ReadAllBytes("1.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, true, + File.ReadAllBytes("1.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, true, + File.ReadAllBytes("3.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, true, + File.ReadAllBytes("4.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, true, + File.ReadAllBytes("1.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, true, File.ReadAllBytes("1.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, true, File.ReadAllBytes("1.png"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Png, true, File.ReadAllBytes("1.png"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, + File.ReadAllBytes("2_1_merged.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, + File.ReadAllBytes("3_1_merged.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, + File.ReadAllBytes("3.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, + File.ReadAllBytes("4.jpeg"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png), TileFormat.Png, true, + File.ReadAllBytes("2_1_merged.png"), + }; + + yield return new object[] { + new Tile[] { + new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), + TileFormat.Png, true, File.ReadAllBytes("2_1_merged.png"), + }; + #endregion } [TestMethod] [TestCategory("MergeTiles")] [DynamicData(nameof(GetMergeTilesTestParameters), DynamicDataSourceType.Method)] - public void MergeTiles(Tile[] tiles, Coord targetCoord, TileFormatStrategy strategy, TileFormat expectedForamt, byte[] expectedTileBytes) + public void MergeTiles(Tile[] tiles, Coord targetCoord, TileFormatStrategy strategy, TileFormat expectedForamt, bool uploadOnly, byte[] expectedTileBytes) { var tileBuilders = tiles.Select(tile => () => tile).ToList(); - var result = this._testTileMerger.MergeTiles(tileBuilders, targetCoord, strategy); + var result = this._testTileMerger.MergeTiles(tileBuilders, targetCoord, strategy, uploadOnly); Assert.IsNotNull(result); Assert.AreEqual(expectedForamt, result.Format); diff --git a/MergerService/Runners/TaskExecutor.cs b/MergerService/Runners/TaskExecutor.cs index 23e43bea..a8104cd1 100644 --- a/MergerService/Runners/TaskExecutor.cs +++ b/MergerService/Runners/TaskExecutor.cs @@ -162,6 +162,7 @@ public void ExecuteTask(MergeTask task, ITaskUtils taskUtils, string? managerCal List correspondingTileBuilders = new List(); // Add target tile correspondingTileBuilders.Add(() => getTileByCoord(sources[0], coord)); + // Add all sources tiles this._logger.LogDebug($"[{methodName}] Get tile sources"); foreach (IData source in sources.Skip(1)) @@ -170,7 +171,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, strategy); + Tile? tile = this._tileMerger.MergeTiles(correspondingTileBuilders, coord, strategy, metadata.IsNewTarget); tileMergeStopwatch.Stop(); this._metricsProvider.MergeTimePerTileHistogram(tileMergeStopwatch.Elapsed.TotalSeconds, metadata.TargetFormat); diff --git a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs index dd104637..5522ac56 100644 --- a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs +++ b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs @@ -206,10 +206,10 @@ private Tuple, Tile[]> SetupTestTask(int amountOfSources, var sourceDataMock = this._mockRepository.Create(); sourceDataMock.Setup(sourceData => sourceData.GetCorrespondingTile(testSourceCoords[index], It.IsAny())).Returns(tile); this._dataFactoryMock.Setup( - dataFactory => dataFactory.CreateDataSource( - testSources[index].Type, testSources[index].Path, It.IsAny(), - testSources[index].Grid, testSources[index].Origin, testSources[index].Extent, It.IsAny()) - ).Returns(sourceDataMock.Object); + dataFactory => dataFactory.CreateDataSource( + testSources[index].Type, testSources[index].Path, It.IsAny(), + testSources[index].Grid, testSources[index].Origin, testSources[index].Extent, It.IsAny()) + ).Returns(sourceDataMock.Object); return sourceDataMock; }).ToArray(); @@ -221,8 +221,8 @@ private Tuple, Tile[]> SetupTestTask(int amountOfSources, if (!isTargetNew) { - targetDataMock.Setup(targetData => targetData.GetCorrespondingTile(testTargetCoord, It.IsAny())).Returns(testTargetTile); - tileBounds = tileBounds.Prepend(new TileBounds(testTargetCoord.Z, testTargetCoord.X, testTargetCoord.X + 1, testTargetCoord.Y, testTargetCoord.Y + 1)).ToArray(); + targetDataMock.Setup(targetData => targetData.GetCorrespondingTile(testTargetCoord, It.IsAny())).Returns(testTargetTile); + tileBounds = tileBounds.Prepend(new TileBounds(testTargetCoord.Z, testTargetCoord.X, testTargetCoord.X + 1, testTargetCoord.Y, testTargetCoord.Y + 1)).ToArray(); } var testTask = new MergeTask("id", "type", "description", From b039cf7182d27feb16b9308f7c3f0a7ad8881f58 Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Thu, 20 Jun 2024 13:45:26 +0300 Subject: [PATCH 02/13] chore: added image dimensions validation function including tests --- MergerLogic/Utils/ImageUtils.cs | 16 ++++- MergerLogicUnitTests/Utils/ImageUtilsTest.cs | 58 ++++++++++++++++++ .../Utils/TestData/100x100.jpeg | Bin 0 -> 3640 bytes .../Utils/TestData/100x100.png | Bin 0 -> 5485 bytes .../Utils/TestData/100x256.jpeg | Bin 0 -> 4344 bytes .../Utils/TestData/100x256.png | Bin 0 -> 5421 bytes .../Utils/TestData/256x100.jpeg | Bin 0 -> 4345 bytes .../Utils/TestData/256x100.png | Bin 0 -> 5745 bytes 8 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 MergerLogicUnitTests/Utils/TestData/100x100.jpeg create mode 100644 MergerLogicUnitTests/Utils/TestData/100x100.png create mode 100644 MergerLogicUnitTests/Utils/TestData/100x256.jpeg create mode 100644 MergerLogicUnitTests/Utils/TestData/100x256.png create mode 100644 MergerLogicUnitTests/Utils/TestData/256x100.jpeg create mode 100644 MergerLogicUnitTests/Utils/TestData/256x100.png diff --git a/MergerLogic/Utils/ImageUtils.cs b/MergerLogic/Utils/ImageUtils.cs index 8d11a8d5..b834371f 100644 --- a/MergerLogic/Utils/ImageUtils.cs +++ b/MergerLogic/Utils/ImageUtils.cs @@ -12,14 +12,15 @@ public static bool IsTransparent(MagickImage image) } using var pixels = image.GetPixels(); - + foreach (var pixel in pixels) { - if (pixel.ToColor()?.A != 255) { + if (pixel.ToColor()?.A != 255) + { return true; } } - + return false; } @@ -35,6 +36,15 @@ public static bool IsFullyTransparent(MagickImage image) return pixels.Select(pixel => pixel.ToColor()).All(color => color?.A == 0); } + public static bool IsValidImageDimensions(MagickImage image) + { + if (image.Height == 256 && image.Width == 256) + { + return true; + } + return false; + } + // public static bool IsEmpty(MagickImage image) // { // using var pixels = image.GetPixels(); diff --git a/MergerLogicUnitTests/Utils/ImageUtilsTest.cs b/MergerLogicUnitTests/Utils/ImageUtilsTest.cs index cfce16fe..0b7f4e72 100644 --- a/MergerLogicUnitTests/Utils/ImageUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/ImageUtilsTest.cs @@ -88,5 +88,63 @@ public void IsFullyTransparent(byte[] imageBytes, bool expectedResult) } #endregion + + #region IsValidImageDimensions + + public static IEnumerable GetIsValidImageDimensionsTestParameters() + { + yield return new object[] { + File.ReadAllBytes("100x100.jpeg"), + false, + }; + + yield return new object[] { + File.ReadAllBytes("100x100.png"), + false, + }; + + yield return new object[] { + File.ReadAllBytes("100x256.jpeg"), + false, + }; + + yield return new object[] { + File.ReadAllBytes("100x256.png"), + false, + }; + + yield return new object[] { + File.ReadAllBytes("256x100.jpeg"), + false, + }; + + yield return new object[] { + File.ReadAllBytes("256x100.png"), + false, + }; + + yield return new object[] { + File.ReadAllBytes("no_transparency.jpeg"), + true, + }; + + yield return new object[] { + File.ReadAllBytes("no_transparency.png"), + true, + }; + } + + [TestMethod] + [DynamicData(nameof(GetIsValidImageDimensionsTestParameters), DynamicDataSourceType.Method)] + + public void IsValidImageDimensions(byte[] imageBytes, bool expectedResult) + { + using (var image = new MagickImage(imageBytes)) + { + var result = ImageUtils.IsValidImageDimensions(image); + Assert.AreEqual(expectedResult, result); + } + } + #endregion } } diff --git a/MergerLogicUnitTests/Utils/TestData/100x100.jpeg b/MergerLogicUnitTests/Utils/TestData/100x100.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7d59cac90370c2c5f110de8e8fe00394b7205760 GIT binary patch literal 3640 zcmb7_XH?V6*2e!Kp@q;vX-W%7KO__r2wiFr6byu>R4LMtCL&ExA%su_L3#^SI#Lut zq>CU3hpJ!@L8a>f34x36dDs1Ze;@YRGkZVJ+H2OVnUk55C4j@kz}Nr)fq;KGnFsU$ zFx?;iMDQsP2FM?n7#Qdon3KXTFya54d|fGZdz2GDVWz?`6yH-I1jfI)xw|9MZB5PE

xV^X&xu@`*FJjOLSkGx&h m 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 literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/Utils/TestData/100x256.jpeg b/MergerLogicUnitTests/Utils/TestData/100x256.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..81c34e886b43a6f79272e887878cc9e09f86bf0d GIT binary patch literal 4344 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 GGVFhzLW6z) literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/Utils/TestData/256x100.jpeg b/MergerLogicUnitTests/Utils/TestData/256x100.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b44f768a39f293000a127893015ab5294a3df859 GIT binary patch literal 4345 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 literal 0 HcmV?d00001 From 9107aae900a45c12cc21c2eef9d708559c84e1d1 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 20 Jun 2024 17:09:46 +0300 Subject: [PATCH 03/13] chore: remove duplicate section in upload only condition --- MergerCli/Process.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MergerCli/Process.cs b/MergerCli/Process.cs index ff37b52c..8fd5c307 100644 --- a/MergerCli/Process.cs +++ b/MergerCli/Process.cs @@ -109,8 +109,7 @@ private void ProcessBatch(IData baseData, List newTiles, ref long tileProg return; } - bool uploadOnly = this._configManager.GetConfiguration("GENERAL", "uploadOnly") || baseData.IsNew; - uploadOnly = uploadOnly || baseData.IsNew; + bool uploadOnly = baseData.IsNew || this._configManager.GetConfiguration("GENERAL", "uploadOnly"); bool shouldUpscale = !uploadOnly; for (int i = 0; i < newTiles.Count; i++) From 6be489f58701d2726f0c28d4f6ac756b937261bf Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 20 Jun 2024 17:13:21 +0300 Subject: [PATCH 04/13] chore(TileMerger): add logs for upload only mode --- MergerLogic/ImageProcessing/TileMerger.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MergerLogic/ImageProcessing/TileMerger.cs b/MergerLogic/ImageProcessing/TileMerger.cs index c3fc6c30..61dc203b 100644 --- a/MergerLogic/ImageProcessing/TileMerger.cs +++ b/MergerLogic/ImageProcessing/TileMerger.cs @@ -21,11 +21,13 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy, bool uploadOnly = false) { if(uploadOnly) { + this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] Configured to upload only mode"); // Ignore target if in upload only mode tiles = tiles.Skip(1).ToList(); // In case there is only one source then we can just return the data as is if(tiles.Count == 1) { + this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] Only one source was found, using raw image"); Tile? rawTile = tiles[0](); rawTile?.ConvertToFormat(strategy.ApplyStrategy(rawTile.Format)); return rawTile; From b1c090f27771307d1dd0b294166dfe138f336273 Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Thu, 27 Jun 2024 18:15:13 +0300 Subject: [PATCH 05/13] chore: added height and width attributes to Tile --- MergerLogic/Batching/Tile.cs | 21 ++++++++++++++++++++- MergerLogic/Utils/ImageUtils.cs | 9 +++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index de28907b..06b50a89 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -33,6 +33,10 @@ public int Y public TileFormat Format { get; internal set; } + public int Width { get; internal set; } + + public int Height { get; internal set; } + private byte[] _data; public Tile(int z, int x, int y, byte[] data) @@ -41,6 +45,11 @@ public Tile(int z, int x, int y, byte[] data) this.X = x; this.Y = y; this.Format = ImageFormatter.GetTileFormat(data) ?? throw new ValidationException($"Cannot create tile {this}, data is in invalid format"); + + var info = new MagickImageInfo(data); + this.Width = info.Width; + this.Height = info.Height; + this._data = data; } @@ -50,6 +59,11 @@ public Tile(Coord cords, byte[] data) this.X = cords.X; this.Y = cords.Y; this.Format = ImageFormatter.GetTileFormat(data) ?? throw new ValidationException($"Cannot create tile {this}, data is in invalid format"); + + var info = new MagickImageInfo(data); + this.Width = info.Width; + this.Height = info.Height; + this._data = data; } @@ -59,6 +73,8 @@ public Tile(Coord cords, IMagickImage image) 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.Width = image.Width; + this.Height = image.Height; this._data = image.ToByteArray(); } @@ -78,6 +94,8 @@ public virtual void Print() Console.WriteLine($"x: {this.X}"); Console.WriteLine($"y: {this.Y}"); // Console.WriteLine($"blob: {this.Blob}"); + Console.WriteLine($"width: {this.Width}"); + Console.WriteLine($"height: {this.Height}"); Console.WriteLine($"data Size: {this._data.Length}"); } @@ -86,7 +104,8 @@ public virtual byte[] GetImageBytes() return this._data; } - public int Size() { + public int Size() + { return this._data.Length; } diff --git a/MergerLogic/Utils/ImageUtils.cs b/MergerLogic/Utils/ImageUtils.cs index b834371f..371f7bb5 100644 --- a/MergerLogic/Utils/ImageUtils.cs +++ b/MergerLogic/Utils/ImageUtils.cs @@ -1,4 +1,5 @@ using ImageMagick; +using MergerLogic.Batching; namespace MergerLogic.Utils { @@ -36,13 +37,9 @@ public static bool IsFullyTransparent(MagickImage image) return pixels.Select(pixel => pixel.ToColor()).All(color => color?.A == 0); } - public static bool IsValidImageDimensions(MagickImage image) + public static bool IsValidImageDimensions(Tile tile, int allowedImageSize) { - if (image.Height == 256 && image.Width == 256) - { - return true; - } - return false; + return tile.Width == allowedImageSize && tile.Height == allowedImageSize; } // public static bool IsEmpty(MagickImage image) From bfabebc4f0073692ba4631e6d53986295c60b190 Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Thu, 27 Jun 2024 18:16:11 +0300 Subject: [PATCH 06/13] test: modified all tests to work on actual images instead of bytes --- MergerLogicUnitTests/Batching/TileTest.cs | 8 +++-- .../Clients/FileClientTest.cs | 21 +++++------ .../Clients/TestImages/image.jpeg | Bin 0 -> 8824 bytes .../Clients/TestImages/image.png | Bin 0 -> 128678 bytes MergerLogicUnitTests/DataTypes/FSTest.cs | 3 +- MergerLogicUnitTests/DataTypes/GpkgTest.cs | 6 ++-- MergerLogicUnitTests/DataTypes/S3Test.cs | 4 ++- MergerLogicUnitTests/DataTypes/TMSTest.cs | 5 +-- .../DataTypes/TestImages/image.jpeg | Bin 0 -> 8824 bytes MergerLogicUnitTests/DataTypes/WMTSTest.cs | 10 +++--- MergerLogicUnitTests/DataTypes/XYZTest.cs | 7 ++-- MergerLogicUnitTests/Utils/GeoUtilsTest.cs | 5 ++- MergerLogicUnitTests/Utils/GpkgUtilsTest.cs | 6 ++-- .../Utils/HttpSourceUtilsTest.cs | 6 ++-- MergerLogicUnitTests/Utils/ImageUtilsTest.cs | 33 +++++++++++++----- .../Utils/OneXOneConvertorTest.cs | 4 ++- MergerLogicUnitTests/Utils/PathUtilsTest.cs | 10 +++--- MergerLogicUnitTests/Utils/S3UtilsTest.cs | 15 ++++---- 18 files changed, 91 insertions(+), 52 deletions(-) create mode 100644 MergerLogicUnitTests/Clients/TestImages/image.jpeg create mode 100644 MergerLogicUnitTests/Clients/TestImages/image.png create mode 100644 MergerLogicUnitTests/DataTypes/TestImages/image.jpeg diff --git a/MergerLogicUnitTests/Batching/TileTest.cs b/MergerLogicUnitTests/Batching/TileTest.cs index 1731aac3..0ffbdc03 100644 --- a/MergerLogicUnitTests/Batching/TileTest.cs +++ b/MergerLogicUnitTests/Batching/TileTest.cs @@ -2,22 +2,26 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System.ComponentModel.DataAnnotations; +using System.IO; namespace MergerLogicUnitTests.Clients { [TestClass] [TestCategory("unit")] [TestCategory("Tile")] - public class TilesTest + [DeploymentItem(@"../../../Batching/TestImages")] + public class TilesTest { #region mocks private MockRepository _repository; + private byte[] _jpeg; #endregion [TestInitialize] public void beforeEach() { this._repository = new MockRepository(MockBehavior.Strict); + this._jpeg = File.ReadAllBytes("image.jpeg"); } #region CreateTile @@ -25,7 +29,7 @@ public void beforeEach() [TestMethod] [TestCategory("CreateTile")] [DataRow(null)] - [DataRow(new byte[] { 0x43, 0x44, 0x30, 0x30, 0x31 })] + [DataRow()] public void CreateTileWithUnknownDataFormatFails(byte[] data) { Assert.ThrowsException(() => new Tile(0, 0, 0, data)); diff --git a/MergerLogicUnitTests/Clients/FileClientTest.cs b/MergerLogicUnitTests/Clients/FileClientTest.cs index b7bf9dc2..1b9cd607 100644 --- a/MergerLogicUnitTests/Clients/FileClientTest.cs +++ b/MergerLogicUnitTests/Clients/FileClientTest.cs @@ -16,7 +16,8 @@ namespace MergerLogicUnitTests.Clients [TestCategory("unit")] [TestCategory("fs")] [TestCategory("FileClient")] - public class FileClientTest + [DeploymentItem(@"../../../Clients/TestImages")] + public class FileClientTest { #region mocks private MockRepository _repository; @@ -24,7 +25,7 @@ public class FileClientTest private Mock _fsMock; private Mock _fileMock; private Mock _pathMock; - private Mock _directoryMock; + private Mock _directoryMock; private Mock _imageFormatterMock; private byte[] _jpegImageData; private byte[] _pngImageData; @@ -44,8 +45,8 @@ public void beforeEach() this._fsMock.SetupGet(fs => fs.Directory).Returns(this._directoryMock.Object); this._imageFormatterMock = this._repository.Create(); - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; - this._pngImageData = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + this._jpegImageData = File.ReadAllBytes("image.jpeg"); + this._pngImageData = File.ReadAllBytes("image.png"); } #region GetTile @@ -61,7 +62,7 @@ public static IEnumerable GetGetTileParams() } [TestMethod] - [DynamicData(nameof(GetGetTileParams),DynamicDataSourceType.Method)] + [DynamicData(nameof(GetGetTileParams), DynamicDataSourceType.Method)] public void GetTile(bool useCoords, bool returnsNull, TileFormat targetFormat) { Coord cords = new Coord(1, 2, 3); @@ -88,7 +89,7 @@ public void GetTile(bool useCoords, bool returnsNull, TileFormat targetFormat) .Returns(targetFormat); } - var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object,this._fsMock.Object); + var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object); var res = useCoords ? fileClient.GetTile(cords) : fileClient.GetTile(cords.Z, cords.X, cords.Y); if (returnsNull) @@ -121,18 +122,18 @@ public void TileExists(bool exist) var seq = new MockSequence(); this._pathMock .InSequence(seq) - .Setup(util => util.Join(cords.Z.ToString(),cords.X.ToString(),cords.Y.ToString())) + .Setup(util => util.Join(cords.Z.ToString(), cords.X.ToString(), cords.Y.ToString())) .Returns("testTilePath"); this._directoryMock .InSequence(seq) .Setup(dir => dir.EnumerateFiles("testFilePath", "testTilePath.*", SearchOption.TopDirectoryOnly)) - .Returns(exist ? new string[]{"testFile"} : Array.Empty()); + .Returns(exist ? new string[] { "testFile" } : Array.Empty()); - var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object,this._fsMock.Object); + var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object); var res = fileClient.TileExists(cords.Z, cords.X, cords.Y); - Assert.AreEqual(exist,res); + Assert.AreEqual(exist, res); this._repository.VerifyAll(); } diff --git a/MergerLogicUnitTests/Clients/TestImages/image.jpeg b/MergerLogicUnitTests/Clients/TestImages/image.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..af16353152224db6f5a6723fbb68a607b6e13e2a GIT binary patch literal 8824 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 literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/Clients/TestImages/image.png b/MergerLogicUnitTests/Clients/TestImages/image.png new file mode 100644 index 0000000000000000000000000000000000000000..4c0485afc46e1e24eacbb8b2a62742f1e361ce43 GIT binary patch literal 128678 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 D2(Iaxf0n1QV|BWwFxa7$?W$fvt|#M9vXfIhXSq z6P3(ZlMindH+UWooCsslteor8vwO%|mpkR2Xm5?P2T1ho7I}oPBQ_;uXSi^BM>aw7 z7DDn7PC^K7p8LWuesQ~BbCLx!=s4$eW>UNv>Mbsj6fm?!;I&HGc%Gft@xaBo-#32s z%U@FT9=ZcfloVA@O50y)^5-SEsfn|nyssBC6aQUzYTlx1k!S%^>MRR0*q@)jroTHz zLALVOpS1m7{^Nh}LsB7ol!=o#bz;1e7=G}04VE~y-bf|KJ`W3Y7Qs4SgmlpbG%d^n z+qEpF*f|MRL)vN!)-co(%RB0cnqok5dJHIzBhcPBByHIB;k2@GuQ&4L5f7!`HK^1~ zKaKNzXA%syB_28$GbD!-N;FoT-oFWb5-PAf23EET{g{XZ`>m>9SnW*N8p({Dl=Jzb zj~TMva=+Ad##VAnYExi?mMgZL`8t2*x`{d4rbx|riZvw&b1nKj5%-9@);O3p@yJjN z_W|MqS7B>=Y$8N}!JJ{JaxscTm8Q+Om5pQtac4Xx&oP*8=;_D^#PrNjwU`;^A!QX` zxGicc?Cnz5jmh#%DusSTThX)yt_vqsBWcKe$2!Q;(2_a(D}qL{(=E6PZ}m=2m9Zx0 zj9}S(VZ}wkZP6sYpKXg^)uS(_FS-ZfZLb@xIleli2y8Wr^dt4g`{Tv){LHVu|BmlI z{E|7Ghwt6U$VxTBw%j9dS9C684V{OWDj>y5g(p{I?g>g1MZ6Ej>pMDFL^FGe7 z=i;1wF#5@OPHYaO2Gk5{}sEb~{?Fl9k;=tvX zP!OMNDRJ93BxS?`Nd+OMa#v)8Y&c!j5Xndw8a6##6IC)I5l6n8Eu1$bIeIiu$Q+O7TTb%ljq^s7`O*7E@!<2STP*h^2S@< z$Q}ntpEL3SBxX1vlS#}TjJz=&R{`w|H?R^9ct7dKNgOAWAptzezN4P-smO4~*;zlU z*o2>nmJ-xvF{f$`lUh^uTZ^{pxe$?XSmw#ra_}V|2k+0$t;P@&oqYQ4ja-y3udf`3 z^ZxbV^VeUazS!HRz-Xu7Kn8d?+OEg*!8k%sA`*k;Kl_W5KmYLyuLsDw;b}yrY%%ox z>q^?jGwHHryF2N>`^SIugQ${nX1RnnSsL?7c##!8!n-0UySPFQF6EP){WM1

WVHO{>YC<;0lq=-~`mhLQi0*}Byuu+ST(ROO@8^?Y zE7WsxO`%@{>*3f-{}+4j_G??3-e*1U`<=!ZbFH;&S5>>aeQJZP7y%OCNOogmhY*yT z2=On~AHgkmQMe?RNJO~+MFJy(gN-4U({`%uK2`79hc)LM<2!Tljk3b@=4Zdt(o05CjnqGrPzuQj}AE>CN|)p+7rL44XhrvL@$|gR0|TRBZWb)g=@`R54-QEI*#E_ zkDTEA3aMKZxf&3(7c1)!jr#AL#XrRx+|s)7%F*rW6C{wkGJCUoc(j2J41!ZyALvU7 zFF2lEhNF-cJv-i>E+_S54w_a*FNAJ3mSOP-W(A_fU&mCAy>RRY;lUFw(YpT_T%gs1 zay8^y6u~W#CIKl%BANq|n5<%mpxO*Gy?COt-u>tn!4@aD6j?EeXucj8w8o6d(g*s~ ztob+!^HX14pY2@ysf``TD2yd6=Np3$LD@ z_~h}CvJd=E^==et(>jlJ|D zH7ZLA+%KNe4zvgt2geC9&>(bo8h2YaVu~#SS$v>}z|rh3B!EU`Hc#u;4G<@`C3soJ z_iin|8E}gQg?yhlSqT?A=0`f?-2F~DRm(u{-JZT@`l|NH?4Ct88kIQ)Q3vV=A(?h; zCbPS?KA5*o{3L*%G${;ecz5>DJ4gYhQG#5uzuQ?ltxo*8&z&OpGY=t{#3GJ{m%)Lp z11}!dl(-*QI{$uK8HlTNI%5vjAv`TBZ%2oq zsCb*J4D;62TyQ?I_=RH>-rsJxs9Y{9;u5uFf@acXLx+-QCf9mm%1^?yx3r-QJB?Rh zr_<&E-Hx}TPo{X>Ozg9Aj62WeYjS%_oma|jaM=Qnmscz+R2t9aEr0cwKc?=DU-_l) z@apOFkDuM^eP=G2EnN7c|L1F*kG6qPiwf7#sG|~w(5u6z!1}P_7Dq2uSY!BqEu?LS z;9bOpgsa2)Fxt6n-mZ?Nn^{?>h0sRFs|H-R;lSby>>y_w%68}$*g4t5OtoT4Z-X|> zI+ENu*gEfR61NjXVcB&j9ybHjX7^_%czr2Mf=q;p>LBRKq0>;|!PCV$&4LZmDB$DD zrovusa6UYe8z0wUPQA6FgtMSi&y~-q=@Of`swfUy2YT<%AkSdTdh!R9QiR$(b#_{7 zv|-6N`!+Uf^evw5?Vs(nkrqcTo{@KQFO()Yow#7f>F&BwKZhE2yMqsrpo1jXP_9m- zRHoY6(#P|O>Aek!FzO7`BbpFz^OP|+^^k(Hbf7lXQtKER3Lr>32Td~#@Ov{o&$ z901o)=jmO~SnJD4C{XfY14{4cGB9VDm6ygT;ZPjDPeKf55l5Iv001BWNklC+uTVMD0Z<=%IG`u;t2FMR%uZ*h5O#6|g&Kl>>UDf0H~gZIbR3u*QQAS7Hx_wh+aBz6cYenHRg<>o;*inLQrk+;JA0{yNS}^bEf?eCL^g*% z6fe%oF7s>zp4mTCEUKyqNV93Q+A&L}K`5Opc(>W)a?Xz)wlOQE7Aq7?h>GmQEi6wx2a(j4=ggg}FE8QDF^;SnnJ_y$zYBIy=rQcol<5 zD1-xAh}Jfg%4M_D);z1FQyS0tPR*5`%Q>_fgyA3truPgPG;#Qpcnto0z zG4Mqm0`rQComaAevoxg4Zn15Fp-K#i6h0-jjoMdmSHvYoGY+8{kr%%GtzSXLU|UxH z!TN1sAD4r+PF%!QWiTXDVKcwevlJHPOYJbad@vk}+8B?RV#H5iBQ`NIbq zW*Oon@Ep&R+xr`D-oN9`yDPO-!lr!w*@bU>>obD?#8x7+^8DdFQEle%`qgK^g_&TKZ|YO}E) zJC9EZ(P$lVS=n=@m&xz{*`M;ZU=k)F%Or8&p-WTd*cL;v`J|d(ZG=lKlt$vIgXw9 zV7d5hTlu+H-!k0z95948w`YPnK6|{JMJ8*4&erL3p^k4*dnUNRLNGknv=iJ2Mz@_+ zxtEMeVN3B$CE6OT^vQ?om9bYYm&h7dTsn!zG+xa?t&{6<5MAd#{-s~$_{D>?Y&^sV z1EYw=Zol`{_b3Fu|K=G)3EIfxz;{cP)-kx3flFoylK!%kXy(_uLy?JGy6N4X8`p6) z2jMdQrIWVz>S#yddcW~OE0@yon` zQ6*y-+)yjMH=L|Y0>_w?la}k$Jn}tHqzTE1HMzVUQ=5nD?O?lXTppj0XkQeScoIu2 z9Ah!p!IWwi*O&DV4V|9CptK#0gDC?E!kQBEtmdl1e!tWDV3A<{v(t?y=&7x8b`Po@ zFNzNdkwBX#jo3K`#h{?-h|cJ$y`3(c;pkeSO%{!4bZ5SB!VtnVHPl`+d*4}OwDr&6 zr052V6Q6R;Hf-${f^zJjhcklZfdFMBd%G~ zv6R9bJ4>?Gol}1bM1g2mkJk4SglSp%bF)clo!}iY26E1{aS%|F3pkl)icpwmSWTP} zfI7prJYpv)>5)DrN2>;x35MlzXJ7u0|LiaM!B_8@PRKpm8goucw|IlC}d7o8jR~t5hj?uWTt`6#=7FPleh# zqZ+C%Ep~FMqoaL71NS@s>36?Su@7jjC#;apwG@k$Iz_{Yqjt(Ho#WmqwINAKYa-9W z-ZG7jjEEeKItCA~F2qGGktPc&!L-_Q7~yqxS~qUGvFgN%Dbs;A+?d2gDZNptY^%A} zrVhL)*W2BwD|4cf@WDP#W1bj)@wjHS;x=r{pwm%Ww(4$5OgbeO<`mYL?B1X4QIw)1 zh_`8~clclr8WH3CS&71?<++;jI=Eo1$~jp4a>i;+`#gtm7B2B>T582U(CVyUGkPHf ze}409-#_Qz%Qx>yV$o`s9GYy9IlEz@)|1Sn1V)SOwXq+S`-g-5*b&z_cAF}{diBK9 za<|KIgnY7s{qrsfGaf&a+R<%x?xeCQ7MNTY1Y4ayzBaGh3 zX9I6p7XHa!z2yf#ddHg&&m++{h*%J-iP&pC3xDX)Cnmi+!=V|6t4DD zG~%2ReIn?Bx{aoGg5DPU0{@F3ZF}!**gGa(Eet0r1Rv>5O{dPmY>h1~tm_5zd;zLL zhq2qRJS@&K1&k9LFSy_NPyYHBGRDaypENc1cs?dB4bq~xIBaJwj=kSF?gyx6eT+;u zxRydbCVhy}Q+nt5b|oc2K6UK^!mR!w1m4)YL9^QcELzFm=KXl*$wy2=?F zR-W%yx|<@dkj%};;IwCG+nP1*#P;H|cT303m!HxL!muGuKGuB;wt0C;Z(4$LVE-{)d+?s%9n;N^ z?m>q=biaIl&zt>*y1*=z<2dj!S(Un3sY|ETb7M*@>q-a7T?nE?bvQbs6;$oPIi1z_>rmQMYTGIG83~TZheulp zo-e={gdx?Ofa>rr;a#N9X1S2x`K{mjLR>I`hEISe3`cZ=Pf7^ZkV-1J85q*&G6?I& z79z79LU-D2pYNOgVL_JV1F5{O{6H%pF3$))h> z;Wgj>xo>iLxFB?L+4;*Ke#P~ANJJkw>VP(I&7-}rt-`VzSk;N+pO>_~t$};l$=A-)`kLg|lmFkT z$8MW=HQ|Wp&zu4h9k;r3JIt0Wng}7Maq1akP+P${Avml3&M8n0 z*PMJ{^g?YXKg}f*cibDxl8DjnQ)BvHPRE+Ddj*s(_fBK_0NT$}52vA~7?x`~qnr)FO^14m z7e^OR5#C+jQFCEVPnSVTu&xR9%CsXG*$ztPSa4?IsncS+v)k^|y<{=OWEDfYnQmMn zI_taF-cS$T8)M%)%aPRDXvN6A|Hq&FnD2l2mN5p6NtuPx3xRkt5v$Fcrls=4DZwW; zw_4WT85jkORE#R9aRUW|ddyLACq!j<$37~f4ciboAuWZF9G5kM8~pQ-wr}@mLW0#_ zSi%!2ZIp5FS3me6@1H;L{@r`h8tk;8YD6hNEdCrEy*7H@DdpfOmFYK@HR3JQe0Dn; zbry64f{!49IT}7Li|za8WVXUQ4tfaOmPBifP$J_lG?d{jq8SzTcF@Z-9XF9xw=oRJB{_qSh<5ND4FQ)LP8WKC>-8Du zJz)tasv6P?xBD~qz2O(b9(iXm;xQB-1ClI@E<>pKup{XC#gD<0Qsl^u`%&>~+%&hJ zoS_;?7rt(pH$VD5d}ZyjG!orG9|v>3v%H5>qI0x<&~BNio*0zrBeFWYv$%3+0fk<7 ze&ZLv#gxR`YhzMzV)xw7mJ643q4mnWWSkQoQ>2bg#u3^D5Jm!8W!Aza3Zo@j$w1~3 zS6;2JsH1T|4qWKO81TS9`qRI}i*QK^7fqNlXGgn0QG>TW1hfwro^@GpzSsj@gxRgl zM^I{RFb*RfcPj#jTG@(;(RZA!0kd@KxTC%?f&o)~3fAE38I_gf963xh39||QFtjhm@@Dw5gwkn{-p53AH7Gu6?px5pocqSPL5`b&6Wp?|0W&CV_HodaG~M4=P|7u z+iP^cQgY|*o42;fd3eC9!E=%%=9t{ufo9LPtVjs>;!rmU%wz z)Sg&Zn{JOWj6dI%hnSFDK?&hvDaGN8PyE3+mg6n zcWMUbqowtx;JnE@igaoQ#NMz+ZEVfq&j-K~R;E*)^PR0;NNKTSD2mj9NF%W#3UxNB z6rw6A1Y_Qnh3P%6SoO8_c5>;?;m>r`-l;>V(;fifEOQ8r(rmC5E}peTj$+rGFs=95 zhGDOU$q7g!9_4LkY5w$4)8s!0^rySF3ow{^V1fx8lcsuF$rJ2hyYQ z4sP$R^wvp_E9yPkCee!}_2hgQb;#p5A3ADB^$F4oW%hH8WCKe#20AmNJA!|}`$3+A z@BYen7zHxbz+M4rlat?n+HHJA@Pu<;->T5ZnM&)`oc7)!-YVSG^A>+1&ZY=m8%_vcV zQKPhNj`%_biiXRYZQ|6p0bU)o21cJab%YcdSW(A`5>Hgp(F+5c-s?~*mFYNTpY~t+ zWK@BmOb7fn7gL~&- z41|G9o9_SNU;GH~Jj*2z*F^7?>yho6k_V4zB__{tTxlb7SvF!an1>CkyfF>rh5y*k zinDDjM2ukDd$+*Wd1v?DSh2tHo$v6?%Y~nRb>Y`O{{)?a8^XE-Q>4FuFQW1e~|#s58k&mTJYC zlQvbliC|KQgkY8Vs0(r$mPDEz(dR&?GMfo?O3l#h=TX|h^EKNQG*y-@@~~}$>A0+$ z!B*o1N#T5GT6@+pk!n|?F&nuUBa&`{oUk~M%8@M%>4u}-?OGM1C%A|oQmI`Ty4cja zD_#auZC_nAaBG8c?C2akUTm@-;>MIgqf+{vS>=rLD{c$4YvoBV)Jx^f?Z$q;v)>n@ zZ>*QVbe@(oGA2Q7fLNz9u;Q@qg{lx{XALVi$>dRtMOX&=y>eO4eEb|dT`p*c`|*r8 z$E(XqaMAn%XXH4>jnb4hcJ@B-Lr4VZ276pmpftzzwxbI?Y!^%0dC$YL!tZ^nflx&XG6Q5BQmg4~gCy1>3hzQ6ussM{AzFRpP)l5YEIHAq-RlH4k#{ zNbB@`(9}BkDh3jL2=*r2!(e}ZXIzC+IvQ=w=+&`?gr6NKAB`|{n-xscGy}JjEGz^O zYbuVxfA!aYm7jcNC7IfG(z+sDDIeJn#`y!ahi`C5Rqm~rs=POnc)T0ujA7XQ75n#l z6&w@9wkhL;$8e&^<52$oAAZkH708Kpn=jQ5YN_~XJ%Jev?&8R{sw>^fRog#cn4{x{#k)oyxDat_v2QmW-NC`cpW6!I1g@yJZIYjOA8ZEGgd`{sKWGwHA|; z5^!@6@oawM!#wcpcria@Z-sq`)qkDM%!+nyd8h6R>yyXJ@XT&gS?4{f5$}!jCQguU z{JPp3wF_68K84&mO(sE< zJQE{#>X;U-oPr<1Ct-tEoi|^-rH%>WxaP{I^QA*%)E^Cwws&eRR^Z85VaHhwJvRVh$VTX+rzL%z|ta zl|rqPsH?3uM=_&rF#J@XFJ>k1K?q{OnOcR>^VyOU?$0}A3V!V@A@K0{>coT<-u>Vw z+-`^Mpx4b#6ZacFE+i+`5m3i$j&eU3S_yt3_`qnMCX>JYAN@L;3*=guZV+6sw+OHw znYjcsI(jh!Qe`5gF`YXTjcUG_bCufKjs566tSd44pDE$QW-H-j5#(csbD#ebM*3g= z=m+#u=(0M`=#`^Z#yOxxECVrTGCm-U7HrNFgAiA!CBw2HG1B)!x$lIg{5pS}K+85&c}IoR*#=?qvN6ZP6~r-ZJa(AnvXT0Q1KdSuxy%tL9T za~wOjtMYhRi9Xo1JSfyjeP6jBHy$ny_j|wn+h2@1>7(0|497e%;W)DeX|I;K_MNE7 zL?4$x+!jg~W>+-Y+hxv4ZjIngZ9JO|qIw@3?S@EadDu{m$h6G?GaEo81jeu&*-pf`!83X@8;ckJ(IVVhGmEQB zR&%a4@ekgvH#1wps)?<)%HFMV8!<0Iw*ZsT(3Ms?qxX*lpjijerL&-tjR&Wm(JHx> z6Byz?axf6{2G%l|+W6kP8%HS|<6!nq^tO8+y>ZVwtqBhgk*80#kJOpKB%bL=gJs!l zWg@h0u~8QW0r-ty{SHorsL2MGb098I#fn+?VsCXH>?|%89-kh)&|mx^g-g zwss8?SySL53tNmvXIc!(T2Hp*W3tRZqa$kTO{C#l!jVpcugOPS1s@!rz50~PdNGun zvunWXr%%{c%h8l_r%g+J%9$hSy(2VQpY$C@X+~I1k%wimjf=C>aPJv9L~*#^{k^~O z#VFG{?#@;}6I(~k(U4J0#XXFFrmnH3L|QjX^9vP=go-PG?Sa{ zDr4I4+rk=x9oK3xZhG)GfSmOO@kfY(K9qLy1$xVjQ^p8Nu693cSZ2FBCFcV_25Ct+ zFVtq#n(38*J8PQVq>gT!*4RQWjWt=?upX7(2GK>-odu}b&o8sq$QVCrq3nKX z8G%v@qDqixYOd&s&Yk^st1r(nxb26LW4vL!OFhw4Ln*y7+~l9V$<*4BYAeW;B4uXd z#I>C^m6!s{wxB~u64@d+CS}^7vUh84uF>&Z|KTt3@BYFQzxu7u`S$DA)Or8|=g+yu zNz-*9`T_&IY@4Hp(27W)PI%BmeC` z_#^({d*A2!d^4`#6eA;}v|MPpaFj}~jp?k9Z**j%^GKVfpo^wH9>vnEkMY5vurwA) z#A!K>!^80Byyqy?d@$5PRmV87@6%FGLb__M7%c;Yf?|k2ggxpwGuTD(?ZokJ)_x6GUQtDLTi~@ zy@Ly=^8{~+)_d#FARqe)a49%d9+s7~B)}PluVd-fG4P8^><)U%wx88`uGa<@ia!C9 zbW5kEMEAnJ?;N*|cH_*~lLMcknOko8PRDAtI8PoHh4n5l#xy6qIQle6i1-W(rY=Z4x%+emHLRN*)g1?O3)F7xX{S8 zBHa=E#HU1U2Q?R>Mp8%|EtBsV7b4=_`NgsiV4I11u8h$brIUhDb{P{lC+St9x*h5` z9Rr?v7<@IzdbXrC^619Cd$z9uXXbL_y6F}X*JW^;NB~@`;|3BUVri$?*^?6vnnGTSBodF z$)T$<;zuL;nKGQ%j8K_AF;9G$-Rc8QgZgu>0$w};R4Y) zobxsiRyiGl;C#TfVk=q%t%KeU?(GA)R(c;G53zWeJx&*=6>o^Im2>CwlWHvEcaKOMs;$^egP zf!wGE6deR{r+LOBQ_ibTq0h#>nj3Kf$E--b^AI-voB!c|=i$@M2)3=0QnY|j7JTq% zh)4oo4Mjihjoh=XhT{e32lCkSN6H?K(W{DI?0q2dR@lj6%tW1)b*LzTYV&6U4JDkvs+*fNykf4~>Uq zqm+ZaH-ZBljXs)jET>1k5*AM!EBD*Z^YzMSpFh}YeHd&cxXv+*m=yhmk~3peo0TAJ zo2Lly=_4aKuK5E;Ir!06Zx}Q_dHMwJl3kD1g%7u9{3R{SRyc+bg6-w^UXWgJDWUyr zd0~S&f@7bBS_-ZPXwF21tDe2_)gToowO0jF@I3g$F*?ydu#^jH9W-A}lcY)&8$1pt zr-IxH7j-BiN|;J@%4G@U;<&eILK2|nNLo6yhIfuNUd#hnDm?@%MoedjaRHwkiAdWU zgGQg#v}TK^4 z99v9;6zIKC_QHN5%DhuP`)uXas|T7`R5yk*+fh5E94wc`HX0&4h6`E^SQ@>py+`SE z$vCmv@x2%Ft)bG{oHHY{@RA0xlV6(*ccR$ZgiVO6CG_t5on9yEHVcwfC6~gc)70i* zMW&kBLPVEDFN(ItvOZA5jn)gf3(xtPy?kOr!1#);o`x{a*5qZq&_^TR2ZToSk>nOe zy0bkwG;H*Dg?I0-yg9DSX~eE|8;Ew+EpoJkPw~PS#$ylS@IKK5YR~qBKdoR4yVvgJ z4lWYe5H}Dxh|6LbXW+;OvzkaGsokA@2)ufHVt!CYZH!r=d31D=TiILZ?d_T93fsD% zK61amXUxR5OdIAnWpvx2zgoXR-9H$ay!%%&001BWNklFX zE!Bq?Yv}onzCg_r>F3NMcS5u;dYglwiC1akZh||4OU&M=wJ>$EE{PB(<$j|IJjBA1 z9uXO&vrfCZ1=YY_@2GY{x-fzN?BD-3Ovt^XMHyk(1bi48y7YmxMhuQ{qSP`4*FDKu z3$e|7f`|m4EE+Yj&x;$*_U~e%OCKD0bS9O*`#*n=S~_bGBncWL>+1_TngyPg4GoQc zpP+#;clNT=#sf(`qct>5Rv(x%lJAB4?aqFjY{ZnPYeFy9B5eMw9@lE7-d0I9;x(S| z5XFn#+nq}+Q#rKKs~SroZH)T|j(*tSxlO`iT!_79h869ZjT3@v9si=0#Rto;j7V-4 zWe?FYy$xP-&6EZbRxWFz)H_a>lixS2(WwFy_s%vDQQ!4q`_X zj(($z%#sp{GU|!+^5>-Zq!cypY%4p>O!LC4>-(ux>XWB+CCLNNrQnautA}XDmtxJX zsrCi--cd(Hr_%eti{Z>0Sk%%b#M|*Q21VSk8sOPEiyBBia4!elPr_om>RzTrM2F`R zpV%eS?%lHGT{ucMS}Tgf%s6OZ&kdi9gM)}+vSo5vAGlmLs)I5cL7K7Y4m$y@NeK^; z-~6>-U=1rz@exL$_4cu8>0+n!iX*bbl{Ol2OxySjL&0x8^1d{3F}tiK zD)g~4rQrO+?43Gx{=5J6Pw2g|EQW)N>xJO#K{oQhQJ87sx}al{Rx5km`i{oL>zD|A z(rTgE0SR3axWInRG?~P0p^cNxH+SCO1L@{?T0K$CYFxT;8@&o$h3Fk67fOI7Drp*# z%1wv!gLZo5Br2{%X32PjmOJ~*_GZs_`njIbpHb92jml!ADJESan=UNQb1j8B zDiOt-0vfs_xs^5Esbr3xIr5#yhtG)4PNNzW_h0_azxhQO#k9rIf*m0&Y^M?`fZf%+ zw*=X6l%sI3cf3>cun$L@LK_f$VhsrxwBD@u?_f+JXksso+p)8RfIDlSAx5@!WA)y4 zuP(7}kKj73+3>L|MCWndGTcY`!2P(>db7%?*pr+A_2_sFMD_Gq7_$>KT6n^}tV6`o zaYJdhK|74G=QUDklv%l?g*7SreWwgg>hEd7d9lb0Xr-DUA{ar~HAl~Or%W*c;cRwI z)@?N)h->G8+&TqQC%4;;IqZL{bI5s5cM|xsx9%^V+g3J(b37@{ttf91T1)x zUvTPA0E-DxWAF%_(zC5AM@E^rQwQyW0aSXQl+jR8f)BJ=nN}YnIGeohM?n?--tYef z|M&+#<)8fI9b?QhLC85|Y^3N3(c>4)m|O=khIQ139skE1JOn}M)SitixJ;&txFzCa zGIe=y_5jEQ7tBHN^zcAhCMgJVCjRC*Y<5m<;4DHe&xR(8D-Mex&mnZR6|EQL%t_)L zMA35-YJ$x&Cw(aM+$02rhj>A}P@4%yC$_1$-me4^F6#nhZuvb^gjbgf(c2fZ*1`R# z)NW}$RN~R;7&2=$U#( zytkO_YUBnpfG;l7N9EyRVOt#cz0k*GT^243Zuv$KI0=uYPUGCpGugKqqdWkZmrXo?&yGYeLF3Cid~?Sl`;!DU&{Hs~Gx>+k*=+xkFqf|E%unQ^TqJ(+_T1HF4j zFZQ$=&XDJ1_HrZnWcOehc9gB)+`{6mX?N6ylW35BunJwO3RHAIzB4iPjp>Pfi^m`4Q~6Lp~`l-5c=f0KXcEfCtK$QFP?S`#9K`o zok%z962Qeh@cMBh#mP{IzKA^3z66NSTE$^e>OteiZlfW6D7}1ubHHd5CgSM zdx)9YgDpnW#Jv!(o3RI62-M>Pwd~wxBeFoRl-|iX5l7-^9Y$lXcNPt}(Foo?zx!dC zmob$sSng%CL0mmse8rn)yvwh?dQTsLZGAi$8!Jp~(9ChV7eTzKo^m+|;t5W< zwa$GGf=^uHhKeTyPj7>gZziR5MljjJVuPhA4A*HjvqVpb%6;tYw>x<+h;s~Wn6U&lFn}sXt=+sv1{ugZrI@`puENT>Frwnf^ zN;4wqiTyI6qlnlV&DmS`B$%5gF(?zI*U9J>k#){OD7_C{uvvq5ld6q8GftE?CtU~P zIy6C?X}{aB`eqD{;0&ly>HPlx^`$Au#PRD-f_g_y$^w(t-)mL;AYb)|Jkej#}e0O3F$zq1Eneh86QEtIS(3^V+r2sp6JHURf`{)@l$Ma>;`N?KP&?YzG}(@Vvx(j0Vwh$WhOEvzxpy<>0POek2xt#u>x zv`{GJb~eMn&w!t19`+&NedNRSio>{WN6AQQEPA@cCWskBpN z_Q4txy%ya>3q=AZM1rN*^9O@`*DnS|5!z z8*6l^jB_t+4)@uIfiHVu$Uwb8Q0B`%-$4vEO}*#Cv`$N;kA`-!m7Ku3Bomp8NlfuH zCD{)6uf2NB=K|kc0{Jk9-s9sVDcEA%aA<+j%}(Sso))E-cArBv+V2^YwEVy9ynj4?kVVy&G!&#BX8Y&YOGTv*};87ypL*-aaajoRNb0)(*mDd&eE`4=GWxJCjA zgp3fz78qOd2e#bq>Z&@Kd#@D{^J5GyM&v1OaT{4j>Z*&9x=&?g=3Xme&N1Hic_b;r z8o2}jMx;}6#b&71|J%Rw_xa!c{y*ez{Nta5Avz_73A8BENLA9J=$c3+vECN$FO`~v z{r$=D_{_}FY+XoWSS9cE}irBai^cOuzj9g2k zA$^iljh_9bDEpGLaD|j=T&MOefl$99#i4nN0cRmIZ18y7u^!}RG|@%qp+Aim zgj`n*Db!`bWgz2`NX~#j$mAaL9Nl2pBg;Fx-==eOzImEB-j!tK^#`)Y4 zkH~Y%&d1j~`6@J7Hbj*~;-##CvfB@oNM;&_BWY{xHXq zp<}XDrKCzbPL6)WF>DBFX0~#}Q>=JCYN zwgXMV(GQ-(xZUr(-nI~tmU!Av3%495tabTbT9P%9wO|@Wm^S@-BM58FBr!}HDJA~e zfA_cf+rRmVT!J#>8rbUDW)!D#V%ajUA3tz^*(mpgl$@+k>dKP!TEiOJqw#16<#Hri z(wG@_4NI=W=kFeT{&bMmm8}-uKkqyr4~i>wTPOtv5P)RQGAZfi(zY)T-%a88?aF7y}C{V2r$&TJ=ho-E6q zrQGAnI4|X!z~OMVclvR}Ng^kTM*O#y8%Yz#aE{rd&{IOt!EizcRd8`eT?g&QuD>65%pmi5N#hgTLYq-@OMWGQS~;)Bso zM2UDL@fPph(6Uf#3Ds1om?(B-3u+2N3m4J}gtzy`oY4BbjH;om)S3ggXhx#Y}wp7cIga=HGjMoY?$!BWU2BgyFPL`%Z62ed+B z_|v;F?TCbB3TIsydm^c*seq@5f~L-Y^Vk0Y|NB4s8UO1)eDF7Zx|3=~vR(+PgiAOA z+cTJjwFtLcxf+MS7y;36nCHM-$EMOX-kwPlUo9KAmxa@eXB!kzN{7*-C-HpSIgiGD zyHTs~Ja;5nB>XJce>ErOGsGm%^V20WSy+}^tPN%l58fCg2bUbq!nIIJ#n@>a0an$* z^v?8HXBJ<`l9@h8npksU&cQLBs3;%nN)f%fE3w^Lq_S-<^m%ZcEjkvlG3SRu+D?D@ zFZ_jX^>W_ZoQyW2H$UQDH^uN4so<%~IgBYC%{A=6;#fbUykgF>B(fyFdHtG_6KC7$ z=G@bbRaW-n!Q1mBmxXDaHjHh%bN}$ddJj6$=jYC_NnSRVrE*{IC>D2p6(nV{RK{*( z$zcYbgGolc280p`3#%wPVw&E^iE5B_1IuJ|jRHwZ*IV2|`HXnz;MO-C# ztR{$DxD#)VWQl$Zv}SS%%aWvM!C_&tIs0IL4%Q24cG*7TDDB{5(vQIuSk@BNThEMP zWX+Tu_w(oT4Nb!Bb_-GI4B&^j;B#=!1F?mrEU`+piCi26-1x8m`rqXL_($JyyzjKL zQ%dw6sst2uihcnfhceC;A3f$DnxjuK!oye+7di}vT}EcY132tp*%t0!-U+5@vB&R&Qk<99HM$5G<&w1S@8P(|on_I0xo&YcHS6RIby+VgTg2B*FQ$QmmYDg> z_GI`;kwPtNJV=MqEsozQm6(^fky8er?Cl*<*w&ZOu%Qhm@P0h-5uvxUADA0I z6w-Ene}1N>7iwKN&j)Qk11s#oZO@wUDLnhmNQu+q?zNSbl8mvxbDoY~Ie@+kKYja- zZ(e_i+e_x07K5=O@nu?XEF;+MLlTeqq&zAa*U6xD5`dB^&U z4?~HGKfs=yy`4-yFw1Z@#<`F`Na)B5eE4uj#5irRpM(3d(8>6SXJpoxCL6 zlY&iSx=~p9Vu%>tfku%9<>LG&!Bm(@qFrbguG+$SY}O%Vwr%BT4<6^v>lSfOMaZTI z7HI5Kc(jvc6z=PW%4E3$O`Z*A$GS7yM5fYb2b&Zvlr=MYrdel<6NnQ`Ym>kBKmIRq z&lG1{H|B1q$TaEJ8`DpkUc+RZ%m6t8i-#_v5@7{S`V+-)%tfdM7}Hq z3V3tQIp|z1P?-$x%r+1+G*1kt&oDl33EBz!_GFVpR=w)Jl~Z<()=4=waYF~Y56%(c zgEb}Uy71}!jkoW9Mk*hf1N;`-qbU=WGivcUFl0Xc`#NzdO7bhc+V7F{9h3eB=@0(F zfAia#7R-&&4@wOMmMVxjORnI`XFKUvj3E=#-kg;_PKLvM+sHXnwDA7^Agz_#%SyJy zP3!llXY-2%-@&Kzcz^Ku@tIpHtXc4E-0Bh)Q=8E$bmwf1^EjDAeUdaus-zOe;^xNb zjd4zVbQTSRO_G3pj<3x++2z`-d?EWp zrE@fRJoj+?RYiSXljs%Kz*CRW5p_yg_^Ca=z-{$v4q}f8*eP346nrUa} z`8crY)R`$Jv~y=32iY~c=LUJpNXcwqBi4e$J0%NK;-5`RCZ&pcX3WO( zcmz{W;fF%nPJiSN|DkW!va+RuUlaCBtnFrwV9*pe`xzgCaRDE$N>-m1z2jODRWw(Q z-aw5XfBhA&b)%g|GpEhTe(W6miCWyDdmr@HNyJ+=rOJKVNN48QAIug(i+#S~8aCXd z7Myvzs-c^psWO^z?mOAj^#Dt(rIJ^em)-YhBh0&0YFXlxI45cet#RtHW)WKP#JW_Z zC{r9U_~MBi*5g#53u%cXt03X+b2!gn%hz153ANJ9F1oIgl5?IXez6J7oN00GK$VmW zlY=o1avI@B^uRp31=VNz;OGxb21{L7e8rMp0U_tV|9kKJpa0|&|MNfiC#Zi}V-~Dm zw8P|J9Zkml;|JCcFPM1TXM1o0MxQ*6M~Ed#A-N($(GofN7}H0X$YzEf?YusNu(NE5 zkFRU^2HPa*!kS}9m2zfTLuR2VF{Uwlkf_ldM^~Gi&y(Ha#FBF+*M-l|18dH9ucRe@ zJtQ_2hGD_UB6)0ButM_69Kv~wxZ=8D5=bq#!RV809_dWUq-BEy(+x4dV$YM-JE}RZ zyM#5UwS%+mU_t8rp^&!IAN|9B3)p$ZKM`1<)x;h7nA32g-6W=V#pY zMPrbaOhYu`acWpn#)e~~#hog4n@lrY66>Ofgc3}?{P)fQ(~)axoJ+yy0CPlQUf?o0 zj}u7&cIb12Bfc(3R?Iucc`#iN3aOO9SW9M{;ShM=Kd~Ptby>M@ACLrp=QmFNuiyA7 zZ||R&`_6Vtq~#KC5~2<;q<}|Qn6hN*hmDkk*5b=$Gq{B7npy96`ZONzCrhrZS}`+Z z!c58#V|dtzQ;NIy*&WeAN`oYcx~!;fq)U&s)RmXljV)K^2whbnMXOJRy4^{o^4;T| zW1PHv{Yv+Q<-$*Y{vfLbcKdp;c8>`5^brGH3F{Ckz#-C8WCbKncS684N{V~*JX$>D zRUj3lDzy}{E{G?R7Dk_e{ML-d*q^v~3~CmZwL&RKicjI}jd9`hdJeOvzT{e;~sAiHV=jahf&jOeH zL?l4J`xwzfDI4jJ{yYEnw@X&;A3l=r!oEL9xw5SbD*1A<4K|5qU9*m9(;A7K9B3^aMkaCg&S{Qi$HZBejU`1)SFCM}J+ao1A&A7p zbZ86&i|2S*N+Sglhf-=xd@V8(s)A^VCZop(LS{JHH7m6yk{hayq)U{cu=fL($+oO8 zLmrVzA*s@BaO_WJ58*^kCD{0yVGf?hJHJ^fT`Ir%*7*lN`;LG7^9Lr0^Ei0_{F$RQ zG^a>9x-o6=d^?svwesPmQgdc+_Pz7z z{_#f6%H!?H`{T*fxCG1=U=|@?-K~tzh|D_kA|aRf{d>QR!5}unh%Ldya1Fg%R&aWl zn}{8{%cOfKqC_+1EwJxpBT1nEhHaKiBOIp_)>>moxhAv< zP2<o!r369yxd|+x*wg<8)T=uaC$>lLGp^Dc#mcngfqZ>Vi-TV-Q$O#6GqT+&f$!t z_+qFp6cscDtZEW?tx{H=XJbDexH$Lw%8$SKhNAb#9cZGYu*Rgc{vwk5@l54?1>3G2Fn5{4D)ffqw@ z#uX=yqvg;m+>&E;=@NPJiG`?iPWo|Dvwkm`KnqKbwc-5oRx9mlf_3o1Z~W{#-ly^Y z_>B1ACY36&_B?&RL?>~r5D(BuPLXdvADt zJbv#Uu$E<6VrOo|Nyhv2Ae1->=)$JT?H(tZ=`i*)D7hx|)`CPNv4VD-x92C?4E0xn zf1xDgIU8$QSxU?}vIsLNDdp?IS146cQ;zfCoSlYow#E;Iw4MIsum0M%11D7@X~cc| zJjk-3C3Ci&**j#XSxkFh>Ybb_eU8vM`6OR|SW$4BERs-xb&Yk;(Pl^=JzRiWU0D{# zXM+@LB(u1asV}@gcAn=ae*E=UeD&cQMt6=g8gP62%w(|C4Ur3f2Ju!;2&XmNl;sP4x?5nAu2RNS!sbKp0Mz3?=N4g@q=NO(E(uC1L5y{` zNW6Kbjd3B&u1czwFz-4MI@S@#d~>#XkBTlDK_ZPS)ih_c&fop}@BHMqe$IFAKj(H| zX~TGXoZO_asF1I>*x3&DBUV9LDkB$2K`fGFfp$}3ST~#xwX!T5&0+%XCJYVSx|GV2 zGL()Fm_9hij;NDr3_oQ+9|z~r@WV;h-uZQse7d0Dpjc}b#sydYz+5Yce&;V~>V$1A`(MqH8g3+dP#O;K3$ zTxkaL2%&6FgQW^}xrgaTXGlNKP9HrUN^8LnqjbUCd7PbfNi1a{=fbwd=YF)oauwmu z-WWapclAq~Q3HU|4UWB${@p+JC%#1klz^GcG1oK|v)#AQ1s0~m6URN1x<)MaI@h2!mwbAPhc zM7_rh%X{=O)&xpNQpRneJ5u>FuYQXNWA+dtszNu; zvr*GUrx^w#Attmbw0&@nGoX`=B>(^*07*naR01~_zh5M-0J!2-$-?jW?0*|R```S@ zXa4SQ{1blm`5i}?V~{no)Enz|i!Y&7*19nI&iUA}X&@6{*Z9(Cdo~;Y* z0BxD=mMB}oEYfY$2BuM!R_8)d6CT2pqD$w-?PcSBUs;yIx@Ei%(twu_FO+p**kq<~ zEB4v37A-v$jrC=X_0&8i!e^&5JCF*u+Y5D#Rqy|wBxHz{p2b%5`{TNB%@8Cpx?v@9 zEQX`*9IbPngR&$R64etZjCSeCRQaKhw$rcu+OK{aleKZl8Yem;@r1&-T<*gLpWk<^ zN4#~&z;e7R;)@Y?T+vv?;PZEU_Wuk%`>kY}!*NdDA3Mi11_y4&I48@xa=YJnKA-f~ zE?fD$3M1)?aT`+;d3nJ{L*}4p1P#V;dXH$>wdL|w-M=Va`9oU%+KVTMe_E2|ACi%kdox`5IwV!d0pVR%F_Au_Z!iW1u)(tv?xAt@X z@jv>f^nLIv|H|*<R*p^cIjwn?}hF zn=oI4cA6l6`DTrJXV063f@|IR1aFH;x{`o;KDZB-VBwKS@`19 z8b14}u~*)I1154l_*dOV~`BHEb4sOw6ph0psZ&XM^zUa{sp&v#z7J4F-YY6aF* z8T|}tt2NFx5u1=BX1t%q`)-)PO#|Sep4g9rpZx3-@1NfIar#L5_%Y@O7dpLUWu8KR z#-M4qGOxb6dGr|cc4L}g&G8QFdSmK0FsQm$rd&EKocu17YhI3@}yNJ;znjG6GN zTUdsr{a{Gj*{-93lE~93wUAO}Nt1JStY;vx=E{11GMbZtTgm9@q@*0;v=$!*na%~> z;RK3L7L8*}w?>i3!?!s@5=k6ebCrNkq=?yyB)<9jYnHp>z4M$qzxC-8eQ*5IkAFA! zmqA@GSmWWGvr~I~*)l8Bo!j<8I|lFP8;6AXbw8iX+saxp!xpf_@J8!{XKJKmXpSc~ z7luqobUE3m*|o-K@|Va zzy5{(E4w$`QW#cjLMQM^W!xSqXcXm^ymW8GKh-KX9bA$Abqy-yLQoZ)HE5GM={|aKpZQW@7Kxh{r za$_<$dS|nW=7fyNmJ4=&;nVZyJm22P`G%?S=ug*=J)&BTL0)Mx|3CfjA6WA0!)8Eu8NXFpD8HF>J&D zOLKruL!sVLE7-i41n16veCFs6dONUMX@0>@FML}Pf%cB|5Nn+6U|Tm7r_V|AL7s`U zB~re2{#^b7P1jLB+VA5$kYVI)MQb758|%mcx0vyU(s_g+w7@(%vpZ7@H-jZ5mb@@a zy!qDKjh7D_sV;mzkJyVdShqx4Zs6|IBap3H9C*E=uk!oDBu<6!Z^SL=Hi+U;pJ7&;Uj}j)~nOymEGf>~Z9mNo#}8`#aMIOA&g1ay;i%^&LE( zpV_tu1)XPOCShJ@)X%(eno-tFnUyhMJUXSW3?GygZkmu|u;fGr4v%5oFaP*!+VA=p zQ|=LZu<3^EowqhgDMwi$1**)xoW_esz)1p^Jw`P5#<^o>BPV5hsjRuMyx!?3^K6u9 zG@qPfAcwQm!pGYUO__c+n)UzBBxGX`F{vcPD{e6?i%nHb`WJrv+dhnbDnlGB z-hOjVQWBP&qnDnQQWK}0JdYg(Zfi!sj}?}XBV=QSi=Zh)qM|~sv9fE=iCzlmHVr5K9#k`b=kNXBY-OS5%Fzvmkw!*m z2s z4Sh8TxBCif!IG1c(#}ph8gpD#+BIKZ0cZxT?@VbV$<(yQ&fmTOWWFHH1vjW=;r0H3 zl%w`LyT|WI4j|B61`)TVhp{Q?_vuN?lRlJW$}hdXGCclRDup63bdElVkm?1%?ZKK5 zQ^ey6TvDYmjlqozd0spE+$VQe=E&H4R9D~A86WT^UkNHGOJ!MO-*`S7 zx7&uMg|l_c11}xOt{jvUjN%)Pa?G9FJ6l;Ol4x{}**I+@myD-`jYgG)ZM$(k--AI| zgj@vjwW{%`y{@w2-RWn%{cKG%8MJXwa*jes05Ly_U8tqw!|1J%H;u;Nh__ymfzueOSn+5$GWd`F_^-re$Q&%Fwr%#{@&Vm~pK#ZO zUX?x?kF(Jp#xVyCC#86xh;F1MLNqRwwH6kP$8+cT9K3EHxUVmiFKDo|GUedskDmrQ zY{dGC;|wG2=&YJpe(4*A44%hMsj

ZI4u0y3<;ib+CkFD03onFwl!GWbDs4?ag+8xfXS^L1v;s5Mfn|*x`_DhWah{#mTVlBbvQ z4(?k;*6TAi4U(|wJ!nLI@Z1m9TFGg_o6_xI*q|(hCW9^~HQ)LA_7$IwcZxyUHg>aU zc6O!plZQU}M((`6F0}rOI`2~MHeuH(7~CnQBrL0##OlXDIbVA^C`;8qKk4P6WBQPoag zG9Jkh6H*N{dsKfNEl#Sj@tH)dc%CrZ5uNyW0W&91gOKE7#wkdRticL!j~t0(FlRt3 zRp@e|$eUpU^6Q=3Yhih*jBzqr@C2tP{L0%`%}80V@>YOhq{N-q%zp8g>x!fnp&d7r z!BP{qati^eDoHbIhIJ{dx>2M?L|TG5c$Yhi<{%s+WUHj4oO&{>ao-l!S7kDB3bztl ztHT;qGizQL4*PM?&K6VrIp``dg*hgp5Asr3Q^Lkz$YfkU=epjgWo35b*-yMgUZz{{ zGGh4NgX-nswQv~>J7f2egzVXVTXI3potFh91#Wp>z>J(1%IGl8YpU+(=^XoxxbW4> zE4QUEtuy?A_j@$+JPI{g3ioa0{e3dd#7x(b@&X+!t70Ek-rEs27hv@p)dd@n%B098 zjg&+#gE1Oy3c3VXaZd1c;uk@+9S81{mwdwrkq1?=BR0colbo*Pp9#PAZ~Y4Ib8tK@ zT7RZ!S?QNbD%(V)Au1GchB;~h{hVG&UPw9GjN}PvvY@1yVG09d?2Ub%Ogd9EG*}+B z;cZwCv=Vbc$M2l28LUC;q)VTc^U|E$icebAJ`dh$Wm8U6~^w^Y0MVao|IEO zNJWuqq)RULej5FG;w82ibuG*RHXXA8ZX}Js^+{wRiU{X(kjyAGC^aMURj@jCG|qF- zRB+AAy&=bB{U)($Mn%v9y2Tbo&%!)T=J6I+2az~Iilfc&9>Fvbg7GYbAxDD+XFl;+ zku0QAure?WH-Zq>4D-Zu4Lg_^)&?Ne%na*LOVY5zVE0u zWX8Pa$z(|j(<4e=HIvl&d=B2_q<4<~AWJ6wr+@K3{8l6?p;E4@>ZMbf(&(dcwsw6` z3Q6Oxs=zr;cI%X7WmzlTh3SD{PU#CYvqkK3j_*Bdvjveh=Zd=1?LZ9HRLK^h6uE*n zUYw&3Oq`s{C8q%ML@tHlgZJZ|>60OovMiD2GcKkfxWy0E-D%cI5?OmLW}seR5bK6D zuBd3R26Bx;i6p~3WFKzuqh$pT%y~a2qXz^+bJU{UuMmxn@XQlbmK?8D+^_9|C}uD% zrouLfqpLVNE8djnj7HyWd8On;JD;>YD%R7TV>GrU5@1`sk;o_sk;L8yv-ddm`Y#}( z@z!&elDRJ{awQ?xoEd#$XJg4JtW6x4I7wHMCR#H_>!^m#J8xg!iW*craq=2-lVfy7 z57EeI(E5q=gwBFlzJQj&!*3QR4e83h4}2J3eb`vHLTg6v2Ob5w@xSP?-`B87QGxa`nVN8cq@7d+BykXPo24kph3NyEpgBi@OD8a?zMxt$I(-as zHr9HhNXBjQLm_Razx=2F^ta*?3AL0l9ps!SInl@9`E0!JL5Nw(5`#55Tdg6ics^q~ zS?__R9ub2zA5ovw2t>?_vzE0mY;cZF&3AH!*(OJe0pU_AlTM!}nlqXU&7P5@yZmmh zL3mXW>Z0spCl}@Y{Rz1e^SDmQ8(#~W z;hV2MkaMQi#A{iuwF)o{#+RyYz}aJc2U!$zFcGAL*rakKU$QUvf?Eehvtb%_#DjPIXcgy!6o`^&mNIez4(Pi5mOee zEV+5q+%9>i=yRevVG0SoB&i{eiNSbq9QqX_&Z>|mZ|x1$!d8|zVf{cz z+vz{~bARUBenQoPCi(t8xulGDIIrQ$qEJi4k|A?aOF^Y@cH^7}%aS7nH7Du%;HDIr za>fibkz^LVG4!POBc`7@!wB+BQm2$Jf{ZBCh{l(B$Qf6+%g~z>%P1l`VXtQzJd5JAEL;7Wbi41ry`I2IGYFZFi?%PUo>R^*e;hEK(>jmGlhG$G6TLpnDW~f{qdILZHa=xpn3pTCa>yEDQ;&37P_j<*~xk90eA?U=CFZBIQC>7u=M2hGz45blPxk^~+JVVcjUXTy)Bl2} zAStLTnlhfEDx5vmOI#eZ|ltP6$4Dkw**=Og`AJIYYkWb~dZipuK9)HtQ zLst}Jg?K20%_xRYdeMm|&X{2Xaw!4s7-3|JQrNgwz7@aL!Cb#~{M$$pZ~vtvYSsW^ zSa2Tk9-csQ@DP1Q`70G<3Fd(-S4Fl{l5o2v(h`_7lff~1SbU38P;$wPY54U8jE#Nd z4a~y>xs()^9Z{b9XS~md%!W3jswEk9(PW zKs#-cHKVEUJaIq)Jm0BB zdAV=&HhA_yT@od)mozCuyBPVGO;vNuB!2Yz!b{mMWlY#&)FOKjocw~Q@@SK{aCZF2an6;2MA`v4lGKlF>_K4!Yg62sLszr^uJqWfaRx~*GuV@ld^x8Nl7AR|TeHPrMn z63>2eigQkjZ2r2155O9ug{4WZYSRAs$?NM!a#bGtgPfxuph@Yj_$-(!&w29Jo~Sur z-G9XW7S^IREv}!nQggIlH7V(@{P{oi?L|clOACHgdG+$>3C&K99-Z|pm8C9d62z~@ zoK1S0q?rPQL5MxSFv*r2Z~DXSD0wV`ZiiTCS1{OTJ$~N+Y|n%z}I7(LQrL_F&PMjm+}B^RV@k zJ_l=EDJjv$5x<9|s7!`kUyvMwQOyxFX&zt39?v!0gTOP1`)eN)m#YpMrGMttLBB1x z&|O)u4qNYx)?&r$(V`O-&gslP@e%m%^BDADj4Uh~#o=j^D+HmN0SxMx2& z`0R4{#Vwt$pu>v9o__BG{TBCevk~Cblwy0L8IhP3iFzpImx`nGvttqr z2=9YZ6{$;H8QKAUl1ippH14v-yklM)2(^ig2r512$?(Zm?rbF>HRdBSFTm9)i{%3TZq2=YQ$fzx{2=1tpVmMO-=BNlh`yP4|im5kT>Yqr~-89PDk6>3P{0-oi9f8J<$O_305UY@(HETp1L>p(}ZFSl!kN*z?4wlG)am2r~I#ZwK9H z%*{mT611T&1gLRFY3PSQ+D`w)U-|WKe>-wP(Ix1sMgAZ5-nLh>Ej!P;#u#(XwbrwD z)j6kM+{Pv(K|iPY>ONI_KYOkDa*zAI?nOMk7<6vsh9Q9(lb{Ia9LLP_9wJmp zifLJQ`w(Vyh7WzrN!kL&i3WR3Q2dG?c*-PUq-=bOe;dkH5?(JpzTP=~u8#Y-lx#V8 za5f{+B}vc{EW^6<9u0M@F>N4#Ji5U&KsxUj}Y&0g>f^rjvk`x*26lNxs5arAQ zj500CL^VyafhA{_iR6T64@jzJdLP{H7j0BXIe?t7CIvM{K-%dZbR>rJxEf;&I?8Al zh9Q!|*G{P4$qXSgG!$iuL8{zS97Mo)o0+bEdVe9xDDb_JujY~ zc8=Q7M?A~*b9^-iKL%wx^c`u z$`MybMkE&vuniR>`EqhF_@BJ{F6Dy9wlRkw1S9Wpk6!g% za;TUK&m`y~r&x@p+8~KWa7QwIu0V_#PNmI@q829#BsdBvxG}UrpX^%DV(Sr)AXA=( zG~v-M9^=7L3MB`#KTOFPSr14`F{SA4Ts=rLn}wh?#>DAJ&V;4VSN(X5sHQ})28kJK zk$`tPJ(%$VqOrp#wa;)!r{g(9LNSZNkr@x_B$IQ-wQ%|j*1o40L3!vAea?817m!0{ zB1u{=$||lzNRnx-g{ET(n-Wui+UT-IWJuU}tJ7to8r}-T5D8zy`3QR|5}HRa0w=P> zOjKxBqh8L_?Z$1}Y0|l7Lx(RLbUa`EQwHdCo}LS7Pr$@RAk0ifyDU zfkaa%8eM)#qp%}NOO!qB9IDILF_+LAcls@5NWnN%58HYCUIxQDXS+CGU-41VVx%Nt zE*q0a>!>8!=)8F@Oo#jV%4CqWph>yLT#lr63&S1d(aF|wq{BBXEw zvOt@?E(Oel?v<+rbv0WYwV1(qkCk0GQXCtd;Jlj(X+~zg6E$2R?-*^KygnL3BJyiF z!3h6-UPsR6&LA@VQ$TItGq7F5L&Z)e6b-(j4;alOUok5>BO~D&4@K>r^9-~%6HGT; zB&^VR=c(LCD;^qF&B*z0eVIN(>2b+jI|5DzVctg;_rteS+jXW(Zb3GWG0; zIATW8xjd{vZ2$lu07*naR6=2iylx8bmi6H9W%9uiLozaBbcH{YWFnjo;+ZEQu z`~8mPjpHffwm=4-D; zrvxMgdZg(B4fzI=zQTA}G2@w{V9xtbl5rPc?`n>ItYp?C%C{LlRKU(nS(nii9T+JC_it~De z04Nh3(S|A}tGYQ}#?~$#^+CzcJm22pmZ;uI*^$zD+|S6Pr{K9qU?wqUBnM5lX#XJ) z%gHi_ZYyFMvEDfBp+ftDKL9*GTMH$?@~d855Ny7LHmOX9I_n zBKTu7j5g{~AFivO`)U*ONly8*$%}EttWAhA&c2TC$q*WScy#EA(c0vEgfHKc20x(x zS!qTTvW5VMYD|kpH1TXtJ5u8Qpgpn@?w}&8RozHiVmj-YG+dNv;U$<8{EF^~R5m_! zaam5}Er+=J+9N+O;H<*qH6|SUZRa^9NJgEGtFDwR>}5knEb=aq-aG5bluj-izbK^b ze<3bq{fz= z(JC+P;^myd@>k>Z5XUNlr31DRR^%2y&`~3-LkX;DI6n>7u`AH>XRjNjZoi% z2o;JyIN6jwJgB#TX5*t>a8|ZGrZ+B$A&Yu4ovsZZl{_R+Y|C{w8&KxLuqo%Gaz0M- zb0R;LAWQ>fqqmc~h*L!b+Y4PXQiDV^9X0{8wQ*@@^nvV&VjAw&5f*GQ!M4Idl!#t0 zC$odB#$*|ezU{OT*U7pv4z0z;mI%RD3^s&jHSD%qUiyJz4d$p+I_ko%nKn9YiP~*+ zUS1xk-y-)RAqvkK;k2lF0kIU*6A!C(pOZSHOhqJ4T3gyEYBVf1$(A{L!zD4B@b%As z#+YXmv?k$;w{Q9K%^T9$Pxj-+A=?VE7)MdAnz;HPbefodiw;Nw%^BM|raPm;%gaYB zCGwtES_-xUUhf~dKRRiTVuWNY+pCgFMz%N(i3{yI!(FP?awykhpo%`8H8uw>r zI15Kf^j>Lak8vR&*-=v%iOJxWpLi~npMU(w{d%PwnLXXRdyXGQg>!bSPk{HkG`ytaV23IZ48S)*et)xYowre$N~FqG3k<|P z&m=ti-6b54wuG&9Zdi_i&`yL6+MfI`emNZk+W@zv9 z-omn+0qarCHk8F&T_>STz0MFQlQG1J&aenC{UVXJ?GJzNx8Hr2azT3Zv8%%EW|R{5 zLS5Xv*(atkx=L!amV>#jM&3$}hRQQrFF>dYKbO3A)@grYDAaB+}H$DgF$%$)Mx41*Jz5eHP{n zPrxVYZ5uOw{#9Qkx*l@xkT*2jimfg&WjfNAjP z@M!U~%`gZ>!EK1br0@XUKq9{jq!cyZRusvCju7hHA?f7lDUtGqdfeO5P92l`{Z4&7 znax)(gCKi`9G}UwM9Mo~90&Wh@%HHnH4TufMu%b_4|d&f839Vw=oj)yRGv#_Dm>+# zEE&ba`(cs08FP?xI3~S0SPDmOt)xj5%n+K<<-#15q;Qx;V-o?Hkr~fr)0pTSX(Myc zB{4|cwl}=lpSV43Oq?;5^tg9Q>Ksp*X^DPah)=SH`>0K0&V^E1;zXWF^ zw25tS*yMaTZ@(;j@9i7*n{wnrrto@x;QY|AwDabx1IfmFtDKLz^p%3VKY9QDC;Zyq z`W}Dh@BE0-;fvcFwp1A7MCC%oc+`vQY?x&<8=FM^S*_8L@cRDZF)H`#6<6gy_|+fq z{V(6rTSZX5{pLe3_#SuOe(`&b7B)kb9&R2X6bc=Q!@#wXC{@Xtwx$$y+ z%Q-u5%aUH^qa4-J@fYV_VXm9w;9($nLPS~pMLW*`WSq%f1ka?%>2#m ziIgJ*wQV6F{`|vxqz;~Lx6gIuEmkVpxH#`dN{Q{*!nUp9r>BMBDMZoin1;33`n}Jf z^vY_ivYn@=uh2Z{z2YdlZgf9+xn2VwK7t#;A&V3=QTqW?oa^;H(w+WAqFy)NKE37k zcE?BOyx-&JA77BSJ)-0-pedFFvmizH+DR#@&U;ppO%B}=SGu2k=#A~E@M}N(yA+MA z2%b?3pUK_^_K*JlfA#LWlnd7TW7TE{j_K`lsE?W=d*1ute!T{LByEu5I3wm@6-`mY zUB|WXO)D=g(Rz|gH0fUTVp^w^aM_KeklHZ11sJ31Tzt8uS^OLS-umRcH!_)R&mfgC zTBx!ZszDqY-Z{q^PAiLDFPV}xj`_96_%I3luiyNPoB|BdhGSd8te`W|N9BIL#xzWW zQIPfx(gq~58^wgQDLF&Vg-r#U8JCER=HtdK7iK@Xs$&w1a-!gU@>(B^8O5V16`pk? zYvGr5sw1VNT9~Kucr>s<(TIXijVqQ(SiHMC`?hq9a08c5^A`7pLZyz7&blz@n*d$?+Xyc-dlYQUG<%uy;7_BTqPD3K=pc0Jv ztKX@u#TBN3SHeB0;leXbt9iI$7Dw$#1cqpFHQQ3gN2T@1brjnevs3S#ecvcc+--}P z812V_CmR#c3O+-#(0FjO73RtU6p4lUs-Zb;WoIjyvyEUAq!1Nx#TIZ@W?Y?I`bu+Z zJP)EY0vM`+L5NLn&3DD;XJp$CzE{|vGjG3qLw<@Jh2u1Ogo!dy9O_Q37uy1^T)oG5 zH)UKVNDDHO$HXON!$*w*l+EamPEupvc7_OQIh?JwyeLz`m?jG`y2@&0L~cP4l9e@P zj_a{EUGHJ&PieU%rv~nPw2A$LzxNyOzDv2FNoMp59|K9@#Jk!EHy*;Cc7`d}b&}lK z_6oJ;}Ny&tLx3%%Pi!NEFdF85|V+*%oI|FQ3tgJY4sPXZlM`^~OVp$@N8W(O< zBnUMl?31EOmJ)Zgk|<_t#1abnbm#SPA{t}O$)vWJC5tO{G~6aX{owRAXpOM{j=)aY zT7^pzw!J_Oql&E>?|wee=`<5+trRKT^uRvx4Fs}IdOz_R{R%cSH+v#WJWyRiUH(|# z&Ji61*`jx0P7jKYj`dk~iWvBe=}uCZ z8Do+u^zOXe?^sgyV-JI%Op3*yAKy(5_i1mqkKj6_a7v1RWTO&Ap-ID>WV7IXEW@F3 zJA^GS0E(3ug^MyR;S$1iZ&8SvHe)tt^hQpJk_vTn>g6~Q+)@-I;Tq%Mk~0J6ydD@S zvN#>Ka-can5JvxXRGJ0+#SS@*|h&vhuu8sJWwT>a#=zECwjtUf2l9_p@$ zaoZBJcWQ5JTc()N$HjDufX#@=uFIf#3x||tBu8$*rjRLt>hb{t@)kP-bE2BUj{M1d zktS&-N>X%zPDLjaV@O2@WJ~<$t2eRJ$rgp7(J ze4a_M!iUEz=cwGagPaO|!syEE>pF%Zb0z6ytd}dURfsYzu7qRJdU8rZYLc)~Kdy`B zg4rH!L(6N<;DPy;ft#;@OsB++GKAFyp`8=(w9Hh4F*{lIsNfR$Joa^uIlQ=&G)GK& z;lsy#VBX21i=Z^QypxO3h=R@Gu>dHBO87>!q?K8T8gXaRJSbQuy6oJ_)Oco%$me5& zt>h4(HIq_8rmPe9Ne_1itD>3Y8n79QqM7c|N}>|1M@LZE0$(OQrq|3!SW1}PWR3-f z{U!YR^Xf;W%}A!~n~=;&76O?`xboiGGun->fBqqaIC{*i z%S7^Ia*-6C_k)rR?=6nnz!1SoVLPG?=&Y~wK7%{ou5b=&gn!tCFTVVWJsq@q;k}Uw zl2P}dN9D3(xx{$R6`O^mnK}oLUJ-=dHYCGEjTcY?wvtI~a!^X4+n`%;9p*LH$tqHy zrR;qFi?2v3ynp?M*Ll($UamC~9_nlmB2oWQ1 zbCB4Xv!e={3R65X20hSrC~Ua|4$KulD+ug)BVf}bx(buUn6mfKHGLqhk=mbi7L>B# zYooNX(HNh1@S?C;qNJG0)P85q%*-VcohfL*vOELB!-pY&%7{~hLLwT2D{ovsaK=*7IXbQGfyYCsB(L~8vAB! zIpWC2kr@KLb~eovOdG3#&l9}9xT}l8QFd^6oOdwg*q)eP zA{LwkN#VllLj$KhSKfihN+gZAZ*Ps)#~D=TT+kE=k!%H-PCZAQDpKSl%wwu!VkFO$ zEi-!M!|MkUnX;8gEKXln0wL#wX_RZ6-WKV1=bN8=;G1t>_&>jX&*M7Ta^lVH88M-E z$1rZ`M)k=Uk)%sWW3)UbAKDp$u^MSA^B%mwRMI*{cKQhL%p7pdisgtmPl;=S&V@fC z{003HxIL3S9G@x5XJ!gKJZTw_x}fPP06Vf$wx95QGkA_|jF?of^erOP@t`hYv*f~{ zGIhky_22%Z-+U+2c{&dElCeD5Y@_wT$JbX{8=qg;$Kwuek!Fi!hBh1Kf^l$pbkR?D za!TymC$orB(iUW)`iRz5jhQhX#2`UPstZ7RGUi4#Tt&pS_c1deP5-8j#T%#)Hb(+Xq8ifagCMrV7{Ep&l#k#r>#=j3q)yT5FS zJ|28~1~k*XhKjDMPhf(p;jYmtJENIsc=-I0xTi(YO8o!E02z%hATX3 zr?(ibna7o+j~dp{COjS&b;PXpZ>Bo`&#BJa=daj~Te$t^2>bCuzpG4+yklBEi(_~o z&|3EuQQyKmHiSp3hz^dllhn8#W3}`sYQejR!H*zn)OpeTflgsd84<%%imQMmvL?KZ zU=8F%ok4J@Bb=|vCbL`M^hTVPMAoR%LqJtaOrV{iNfiMh2Ug#V$Ms6RH^e0jc|
#BBkuhVu1KzTy4HSH69{{;gK`-~$CCz$}tqtqxMzm_Y3@ zxhOf2Eb%AbzM^w-*2Z;p@@8xpWf~~-dIfP-!yPt!#7G8XF8&~9-~$~k8fVg==ob9` zr%bu+)FDymSrp6R0K0l8C&juk`#J&+=j^ZiGEa4$pT1ABjov#ij|YfQQmFUnpzLvF zx$Y0z*)W-C&g{D(c`V-n=$e)U#5UttIPCDapHC;L;RCK!LXuLP4t+$DF{LO4Js+>M z>g@TMl2ddH%o&?!Fw%J3DRSZO2J&SjpOzPY|#5)S|IU@ zB`k$9de#rz&pUneb+3sdE)MOC53*=tEOvg;f|ZFapQ95!0^&-4b@~}L&!k~Ksk8C4 z?Hrr(xId^4Up&1bZRIayb#Gi0QvCB4V$JL8E7Rk@s~IwcIXfnq|LtcV7{GNoUMt0v zZ7U0W;%uw^sEgutMtH_T@SNB}a&^RObo_a+_0&4Ywy_;Il*D)_dI>rV8wtq{y9eCS zEkqp=x?WuUm0!lG&X0chLvF`ghE(Q^N~}5K>SD@je~KA8Q|Q;A*M<-1+PU2hj97ci*L45L+?W4t-p_++X8m^d1I_ZG}2Hv4T>awemHo(UIWcA!X^+fAg}OwH?=> z%O=a*`zzNN?6Q$JJcyjR&yo^}fIwJ_qT^W~i zuY=ciQTC0a+!!mFktA?nAK$-F=j6CWkKnwbb@;4TG*2a^j+nv}3s5Z6Vnk>waMqpv zh{BYV5-PE13_`OoF+P5LrOnAvlwwYj$<->!plo3?AG3nCum;PF`nUPX1E465pPlKG zvPYRNM7CfKXS8TLvYcYUl}ReQey4K59NRaVI&Y3=zR53Nm+S%w8 zKD>V5>3QR+>~t<-6E27kUSA*BTSLj?VMGaXWS%{o;PsAT}o>55-4xD;!6r-!IyEl5--J zMaGg~L)cy@TjJw+XC9Fe0PwTXlVUfCm~zh4rV&muMb)S@TJ5COaUd(;)anTJ-<-S( zeWh1=Yv`qj3zszP_kZWN-+h;I!Ibh^HP?)DL@m)+ynx{7IpujH?}pAqHs!o7TCe1! zBufFN9D}DEWt=4k@N!G`m$th5Yz*({5PU@V>Daf(()*-r<@0=bPUnyRua9gf*$x}!~z1j3&8-D6iK#b-Mr%_Uh?nwITRE%!M z)&i}*mxOs@cn>1bJY(}R!)vFgaoY--7La4L6PZmkDT&Pc`<<+XoJt_xl95v8^3FLb z>Y1Z#Xd>|MGRR_#+Bj>d{V6F^4U?E&B~wNneEfJvP|6krEKeO(32vsQ=;iFtYR5-K zl9AQ$7S~-NF~$t6yM#{wi(ZRV!gy8h(fq7Qsl%~<{*Qn2-FGP$+$1sD$}S7c8H>Wz zqyD*#rOqB3`?f_%qlH1@_2Yv)6St>*MNilL*#jOrm7vd=4z^n3s0-FGP$lo@3P zmJJX-zEsA5+Qu@31T{@dieScEX~He@d^|<%_PG9vtnMG!7A z#9;scAOJ~3K~#0Nl-JMd{K+>T7ikzg4O&;sl^?u)8;a}_ld^1>7}r&!>8LERwS_rI zJfM@z@W>Y_*hpl_?3zO8(kW?7};hVC5aBk`^%kQl&Q{-o)7k-+@AJu zYAR${{J~KACq%y99hEr!3E>f#(ou1AhK<%m7A0pQGLRvpER00Fj8miQQ3GM`BQ^|~ z1BlaKK8)jS4n4*d8M02dkhJi4ggWmt;^vc1P62c61KMZ|k2Wip#a-}(rb6qJF?w`h zSlrPieX?a6bf`6Sf!QZpiTQpsVhc{_3Mt1}8Dje3%SN0KaorT^zzy7_Q?AKq})%_cl!7zhMm;O{b`KZezTs~4DPb2)TQu4dme^DbxA1*u-T13M)w$Z8v=4GBsAc9f z`fPDhv&2+_8a+dNb`9novxcR30ydd*fMhHhL>M$CJqkf2#%nXd5To^geI}V~WkU)K zi_xrK(Nj^!#rBl>@_Sz}-7z>PU`O^cSPq-23436;c{BS_Q4Rcls|q0BrPGft81 zI_Ygh9|i&R>7!H6$(D^=!2ZP_{L^>erChLj#k;QxBSU)7h5nOY`;s4h|A}Au{u_Sq zy@Ox*^37lQ)&1-DA7Dz#GW_4{Wc~fV~t^+YVk0vZHxh1tl6Um{@DV z_#R9XQ=C=V0yLCCbmLG|NO_l`|i7x3ts0^ z*3G~MFV{ENt^Go-?tN6Q{vfA~Pn9TZ^c)2Z5-l!ihSl_^-=6Vj%&3vtDbd2)J6lTY zmpdchJttqidCT$q#Cdn__Y+1(20UtIh#)B#@>e~{5@P9VAKa&t)5cS|p|XNL-Kp1W z95pR=kz3xE=|}>5-Y)i%$VIvPgU9Qg>k(DpuAR$k^a5I@`Gu`9)~BLU73KADk}SnZ zPdwUm%ErELY_|}=nh)A)a<*ctRCZD%F|QbM7DloLsn8s{w-`IBp)->ugDQ{qU^dvbEb{ZJmGjON#dVeSu6nw% z2Nu887N(+q`aA#l-FGP$6a<$X{eiXpLa*+sa9tO3u?gKn-PakoYD<~HN$)4gI)D11 zE(q$N%njA(Gibe&lCzf^SrXF+?HZ^l+i~D+@c!i^qc)N%Jw6T!hWEi}m7^3!G9G=< z`aqd%mgysU7kaML`pSAPNi&mXRGR(!n(E|oFnh53o{OO~eEi2Aw$!;uKQi@mdofnX zxrC{vH|p}myM-1p5Lor^?hl$rO&K}vx?#SF79ULTHt<@*v?Uw9h*qY5)_fI8TYxkX zkG3(34#w-Xf(y4d&qxubU#l1=oT8dC^f(D1iA`^Gy=d(W?Iwj7+S|Z%hFevX?x7us z#>?F0isv82QrzE*2}Kih;Yd5L_meRLCLCwjooo36I)1&w>4qKmMI}|2E}<|KSgRg>4*vtycFb#+1QzUJ)-{=;orql$WIV zY@FB0n8HuKeMFbM3>uNY4))&QWBrI~=ExiFgW4*sHuijD+cV>FXV7?ldS=_BqAJft zdKnED;l-W$=+WlAs5vi>J5ww97A(BkJK9E6WSOIV@RvE&DdXbjKmYk>to6R77^4!C zny?2)Imhr2Tx}|s4+fD~E5%6a(dN^`oTRFs+nG!~t}Ek;LBot(#TZUnod=UJc;Qh+ z4i+iRC7ylq&AG()VwO>}5GNr3v$f)vbAP<&c-nb>vw=Iabu@+hkOfD%dPCF~zdua5 za|lHAN?#R_}LJkC2;|5S6H zIM0sv5#=J=hREdfYu)QCP7+hFE~}FL-VXrVPd$q5Vp8^g&8w`lHaK zfJXNd-Z<}--r#H($FcF%^K-C&yaz}{B;1qBSA5O7+@uM$%>8=c>TKJN&BPeOn3a@_ zIpDFbNn1`q@|hkzg{#_LKLKIZJMp-8UhglItUNy*wA#71PT7o{_Q0Q$pvvk&Tn3@E zSON=At|;9l-Y-v4&Z2>Nv)}!#-+K4wl?(o7|LNa~AMTfAb#HS7U~vrEc}07%fSZ73 zwqybBn3FLk|Hu0WNax50Niv0)#WRgw2Qnx7o;aS~psP&N$Dr39H00iC9{j&qxt4wM6lz3 zPeD?)99K?{{K3^*M0QPru`qmD%EK>GM_UH6XxF7fJttSY=rx>#Pj8+%_QE-?$Oi;g zgDsUvn4W{#CP%)JveDMAzU30x4DZx=2Q)k`?lA^Vg6hP(aJETfu$Mhfk8^}KBt@$6 zwLhqSvEK?QN3TOF79E!^s1z&(=WzJM=Bg8m5gFbLO9k~zlSVE=wiKZ>RqS_v`@ebj zsa)_sdh?bay?N$V3SWG2{L-!N!{Z91+T)n-lcPLQM|?iT;zXhrO~8Np%{QpPEkCoT z=a38~f+9{uRyFmUlWYfbI<22vtYQZd0G1%@>zUMniAV2+DrTT>-X0N~orN}{OhF}VwvLjIgM1te z6<+Hj@I+|_=rBz*$?9Pr0WDC8?lLvzY+SYCBZ3}knL%Kg@`6&jPZ)`;NBEsRc5a(t zl@y6xK_y4-T%uUC^~&r6d@{#!-ADn9vsGFP+N!9M*vNWBt@SiMeEY)dqq60lY0wu% zC8;1%Q7oXA!E0`U`t{FvoRPD4 zALOFwHkT)yh%H=mZ{AafbEIdU^%mZ6_b^j! z;g{d%4(H@2U;m8v-~5dF`jI(1U)~OmlDV#nv&N43sFhj=buLWy-+cYQzG~}S?ZVB; z$A%P(xjj)ns$IG6(M+9EBH4}EC+DLwEu5ZC!$nDXBbQIL?VVbqValc9(jX7szJ20$ z+jv|L9<`Iw!H~h(9!zWW*@A7jB~&J(pW*Ub?cQjMz7OdEsyRDtX&6Ht`&WPT&)#j4 z{$_PoqtCHC28H31vo{hOnsue93M+Y!nehHa@YxwXR{i0Dho0V08_crGIF2;G17P~Eefl3?Bn8H!Y@>>+nRzaN~e)T19%R#-I>XSMK-({*Z zHFmgCVoVB-mZ%d~Us(%TjWZIiKhurq!I^k<#*nyzY2eXV)#VHc7h3AH8KSP^G@ncJ z$xKmBuZ$K(u9PO-JEL_b5+|Gy9g!0#$s(oK{m+VPB#J)Aj44af9iK5OHZzh=XbtHd zH3@W=WQId;oi3B}s9f~}g66e_v6ag9c@5=TC-%yq3XwWzVmF++d&2{JGj zF0VYsgKM-1D7nzuNw&nkZCvfa=>xY+(T(mfXxwb)kPR6Qqs0q1qH8dxjn;+MgIsjG zJ+oKqPTXU$pJPyRW;-&j;R2mCJnrg>Nn#r8M;KLF ziyne3I}>=cJ9Si2%1gnH2A?rz2wkE~>mZG?%2grJ2+OwTPmMqEdkm;XG+p`s&EC88 zSe9nzdCywkW$$w$GP78HA!(A52@tjb8{oh&;DJ3b1*)m$%@$jtOv>vT$Xiru?uWEj)vPaWvqjB zC#TF_uS{tS>*O5V2a^LIjV#eFJ(~w)HdVAJKAmLiDvB|&0I&|>s#o@0Y5f_q0KT|6 zqfLAS(aN1bziVO+R@<^sN(9HuG?)n}_trpqfX)Bzx4!xIhpT(6?!NNVEOpg9PAz3i zXiXrK7y2L$|Kjr}Qcc|EjrYfM(2BN=$w6Bak>l2weXwQa;nf@RgK)n;lXB&X%V z!{8!86=>EmUA0{97#Yl%eXK^@$X2|0*ibRfaa&d5g5(gj{&iEG<$mVJzxIkB{mPGE z5ckm>Ey6~ao7$Mn(b*-FOXi%7PK$6!jtAFdE@3$Sck_t?*#(^%u0tz`7^Ot%NuPrv z7pi0squF4(veygZ;ND5YNhw7&d(;`TK;Mzt6fhqo0oPSb8p=`}v*!r9v81JrC+1j5 zxq4wvp?8l~CIVh7;yizOXAWpgO3ggJs+0=C#AfWI76*Zd^^O$gHVd+|dI}DMuR1v< z?QCHgu3NAc&oG*8HAR^09B2+VVAR|xqlL0hip}Tj(HU7%L571{h=Cr@kfx|z8xgA@ zYxFuQ%AB!KP9jOTl?D?;Z1#qTwNc z5x*Q;3ArrHX`Ev~Qk=XV@WI*dI56GW9(S(SExxWoPmYX5#!VZEw4#^a|K4;Rngr)} zKYP!s$BG-=j%S=n(TZl}oW6w3I9E(}%0ps%+&Eht?;fu^c~N&pZ;+kt!s!j!1<8TG z@;-6v0j&^lkLd8H*N1?6=!6mNIOlNwRa2eGg6B8lxF= zz@|I72LDecxDJpA13Q7JlcB2_InsvenJr)NPMFYg4oa|tOOL>m290;DDM8j8jln(W zMv|jUGnsII8VsAv6^`03(Yh4ruE<@uMWQt1z|f^k3@<_H$tnyF#lA`y#F`AUZgIWy zNCKu5^NbI-CuVX=-WD}z;nRH}67;3xywS!%VWXt7^r&$5S&Cl5R5G`AXPj-pUDi9I zvUrNIk-G^wC(^He-BDylrC37abYQEcRwi|YTT}%V_`UCbLEQ?MZMp0E zV0tE%LOWvSx@kBU2TrO+(y;sXd5~p8OXh5MX77-lW-#XDu|AMfrO&}RT0Beyc{r5d zxdJD!@0qP;jy7Y&wWd0ky0dML&jxAoSHJf4uuPNL@*Xchb8G-Pid%%RO{*uwPL%NT zBk^zv0S|39P*F-Q4DWb^P?!B#xF0Rpe_LG}i$?*e3b}>@bHuM5gNQc|$m?!hJQQ$e zc}g^{Qq$Mzf0cud`$RR$HJuQrljfzLL~72bp<1w{2s27&+z^XVErfP8ZP8B?>lhAC zw>$2G%fm)aiP`-x6&fvPi&0w9$~9NswZYj!6w?&rURG$QmW|qlX?I*2Dew54bi2p> z2&brEl235I=c#TNK<<1zBl$=_2#tGI8+fR}wHdU%tx*Vt_o}UkH_ljIM)Rh1EAN)4=Ce*U- zP7ZZO{Qlcys_qk__g@x}Wu z_+-AJiqmTkWVG&RR;;avaEl#4lYIPL#KW(=Kb~>hB6o0g>NQhp;nt1w)_Hsb*UOKv zz5bLW&e=}vsbgaV1f>?{jIxqYR})1FCnxvz%$5T#VG`G})*+>xJtuk}9DOWNDlO1S zr;mtp?|#K*V|0ttoW@B{Q79<{s4>7>;}^g2_J^x`tnPpK?qHbFp9l2N8jdF1p9el*zwSKd3^~y}823jD`p#ZAWQGuB z66w989k>ii-QcC)P7_rXx^bQ@YOIsdhQUaP32h4PJ~+q87?FVp%V}HzaK){XSD)No zGxd_V>^s-8A;9N<@a`_FSl42qp7E=k$N?lWp$@ix|DhX>b<1YIZ@twPm)o#4H z=QOTZ$Q?K<38~bF0)Kx&dHQu4yKe>8*$WIWy$!MG;XmNXbv=*h3PAm8e*46 zhCZnvGI3JqMH*T7{Yu7NDF6}1xuB*t12{}9I^p8>QqC#`$BYQ|(az(g4Y z{>g@*#iJi^QGO)BNPTfVC4vxAIQ!uA$uSPVxn8eauN%Mr`5j5oI&_{bd=Vy$BVd{j z4{_vf*4MRW(%VUr#C5yk(>Z}{g_ZCb$E;F9F`6SD8YVj8_dm*_pY#=!WVr@)jk8+EYLb%e^nxh(K*tr^jHHFd4ha=tbY%2^S z96kIimwE}(?hL_9(@q#p$H$@=(?dk>zUN80gvx$xzOFaA=Y(bBJc^B3O!aCMK> z{SUur(U7b0?_?HoHnPMAT`Ei_eYOZ@jLvAro`kY*aSWZ#o9#lIV-=qiL=$EnhN3x1 z9#+m_&eL&Y*bG7tndkRMB>%1(Nn;!~=8TRwj}|0Jil)rp_>cYyKk@Zfkd>M%Lg&^F zGzmvPxDDg_@WAWqCGu4zQjOD$vmaoKeV9Z1&6*Y`FZu%84BmoBn7fh~CT&$~7c3DA z!V1W!depd0;&YVnA6PMxhtQl#`grO{%MN_MN3q3T3QAOjnLB$afjN^AA(ynry?YXO zQ?qpxkBJLD5sS%(n;_W&&91^6ogtGg?d#cH=CmS|9Am>iLL3W7N|a}e?s%FE4m25+ z5}?i$B53bR4A(^2YFNDc%IHgs;EvhC*_R4xN~cF>zl1Gbb#?xCffCawQ-_&QTfQ8N z2BKUxE@h|nlVd*PIUy991@het(7~2BKrtKNcc|uw;=2*oXfx8^`lX+L`@_{eR`>6{ zk44O0j=UDspS%g_qLdo~&T}v{_E^PZwEjyYf zy+319*!BxmH@cme!zEX)IV!eP6ibQ!;;;S`Kl-5j%#Xg|r@!)=slrUrU@Hh`GVT~` zgJAL(LiLYNL18$I3-h=s7!2hM2wsZqsQ}AYfO7;+TydaJ7XTq zKKSbEPyfQA(Q-{6qxYqT*Cl=H7r*)ThpT(6?tl2Mal74U&j;Qk+N>_fUZ9kya7vk6 zcHUer?AylchX*t%XE#t`D2#b$*QgJV71^S2#X+ZkEOLA(J4FhLAtmadvqlYCDT$mb z)(ukT=l-9?35>;mwCo7+W za~_CoY-L+Sn~AKQ3pdmUc#qtNM5NVL=qbP#&e4wep0%#5hpf?Yc-&`ev=N|@$bn3( z$H+LZDUBlJlGnX>(l}9r%YKb9p-+UwmN(2T(wE}l6Is+8|5z6vp&jvX*0COXmlyAT zCdXtf?Be36mNmyTri=*MkeO-5X^Gf{KY8=XUpO?{F^}+xq@XJ0q?A>4o~sVdHaR?y zLT5g??mO3Xq4g&|oYC`tz3${hh<-BI_baNxhx0whJOd%s24wk&)0R@WUU!ZWKIa_c z1X??2sZdj)2{dUS8LgFZ1jGVXyKGW0p-%}Yf;v{CqunL6gl#K$6V7%g=S(U=W1Zbe zS%Ww`Ce|lfjH;PWAKsAs;N5x9=iur66aV!8ddK#lJiIE95O@$3b*GQw{}ETSb1V2bKNVd!e`(6l2Me$%L6p! zcz)(T`N;=LIryose9G&~18yyt^}2J(6`#>!Yz%xVL!;_zOC>(L9BxAE&TJEzN}nBU zQnXO^%;;e{8sh{)2yJbWi!DItB;|xyAxmfy;l_?*uct{7r7e=pXq`uV4hL(T9Y;Ay?|Y$CYZFq!ibr8=WGJE$1jpv7qCmyxe|kB%*m@s-!cL zf7*lY)R{8hwl#SKbucU1cexW!jiL*JrDfQKr0la(n z%=7z$em0JNa=K8j8?|O!5`Xh&f12ryc@8p}YptM;7b9swy?&euxDnG3iQYN)mC6K0 zgXh~lh96Z?pA<_Zc3cP34#wz+I;Ct&s~90zVu(loqKn{3W3f5Iyi!tLMi?cLDO#}} z7BtNvdipSGI4Wr8$zW2~*Ab64+=va=pfL42Sc{V#TU4#FPD2v*VzUL=oI)mJ!Ga5~ zf-b|+>M@qAVeVPaLlB_{$2k#6A6<3fkBiOA-7!1R)kbxA<90W+SJV=peC5rbOEg-M z8Yj$}18i#pEV1W;oAG=L${cNZCgQlI*DKQmYaYFA`<1B!#z{L5 zMic6+{MujtS?W>PN@cqij@GGd!`p}+xrYr)6I$3I#7pUFrKs?5 zecA>ax#uNXhXTw3WO1&*?qYKHNqZkE~rOAvmyhu#JI1Jusk@<242|~ zT+tZ}P9z5;lhHu)>K_EWEJx!6zWBEqKKj;w{-3dx3mk)~jhPxpbLJHGQb~^>^@48& z(GrZp?i}aIXMge;s>;`Y?8jFIT|d%aS=W<8!|J;yru4^7!V>N_)nxajhHY zd}fS0xo**Hdj?HeatKddojE3W6nSiRLABED1Rbcy*R<3b48}+ltJtz!7cG?Skx@<_Do7)_#*OHCNoK{Hu)d`zZ-T3$PGr`8LfJXYS%*!BOi{gwXqFaO+Id$GoN zbnX|+VP=sWM^4RHKk3#Gk??BADKS!BE;OIPQ&S;nLfuJQyq&sC2`~@|H_~J>Y*13B z=AGU;K4R`KMV8acUV2|vQ*FQ`RUp;Gf}R8`Ff>8NI8Y(rn(H_<%~wfErrUvaNVSGz zOEV(Q;N;G5EeSl6 z7QDpWNwPr>A$88+6o_aXeTXWyXq*uY4`a24C%$)ING;;?U)P99L}HO>H3rsr+2XXO zQCc#lV-m-I_pn5_IT6v-LZs!I#B?fo!c$&5VhOC4Ec?04=$Ud| z^;(fN*>n20f<{w~c)Jg0SYIIA_)G_e)k(d?!_eEw7=%rJ23oxCIj+4vK$RgxqB9jr z30O#Nw84~fjYGDj97JDw9Pgq*)ojvbEXryal5ioBC^(nx zLdpfDVybIV+F`Qt(Idhis+6)*OJ$BwW&il;#$J>@;XDVQK3;kK=>w%CYAPs78x21@ zXB&)eVSrk7WftzykQ+*XH2RpF_sP$EQV|z&tx<a);#0v=vRV?dT-Wj3yk1ak*qJ58Ddy zBvK8Qg7wZEj+Urxn;zrElyZ#O2tK0E@F$oI`Uqy>tNOTb*@fFYz%B4tDI$lqvL2VZ z)4Maz0IkL`_Xu5SDGDi7M2!15VNtOhzrm@5&%sv;_}~v3go0?W|kq0`ny6N+`N>KN{&b|Ephl` z!A1)!=ynMWB_&1=N^DyCM#iWmVbhu2uroqNU|cQ{6smezY05AM&DkP-mQpm&ntk+O z*kp}pBdR)e(!2+YAqDDNSDC4LxXucZmG2{R4k?A!bDZ}`dM-hC+B#7tr)mk-z?|qT zR7qIt^mA~%KA^?GdVpoz$*Bf0*k@G7yW%N)C@*CfNuz^ciX%CwNRD&6eTb<{F1Uq_ zR>cu1aebKsd{T2-zKxydr>B2oXf##9C5K>4iVE=*b$TyNSjmIMagIUNEy_bR^fFqY z=#p-@#^pn@rYvvdy_jyAoY-J;hGDmbPU;~|r^EUYK)Yu;@mxoOA zAP*H{Oj^s1n9-hBEtLtSM5ml+@ET0OlXK1+1?9S5NhSQ~Dw*Mi4~s<@jd}Hmm~Kvy zQMVBf-Wt-b$%9fnM-QY5VvbvM2*^}Y-tZJLUXzzH%!4+aQWMM^s&^Jrjgc>skmN{T zqs$C*!oFQeMX}YT7$?NJys*Ytwsgs%8)1g6k*%fxyO^vdT@t++!#Ya%F9aj4u(zhd zpsoG~Bc~nF!u>e^)M&J0GWCO36qXR6;b@q_{fI&(FBoGOQ)iZ~m=ceESz=b^qso{2A9*JD*%W ziB?u0VX^dr_(9DDPnGF2W}GYJ`-86T|K!`>W7_1h!L=4F8@d|{>DaW|doR!Mb-6186fs3pdn z92S9=>X2ka1^hYbV{km55tUV=os;f^lr~hAX%Rs!QbeuSGN5_k2{Z}^;%Mw~*;g>8>K{pf8K$DT+MG$$aMa$ZVpoPn((4EM~4W(Ep* zU1fzf16-3ziB3qBxEihJL@fLx!<}3!Up#&I|BXh|nK++ESmC#{+KFLGCu@LL&mQej zrLIm+R^CRVQQ2Mb9wwu@kYdvU`l?x?{g|+)dofB$^f3?%0Hr`$zXz%$iBanuu^CBB z&eGre)n9)5=XG@-UHR^JKI3~|yyrV#K5;*fC@{S~A}JpDMBZh&;>u1cbeUfBf#Tb*bMZxRn z5n(Q=1a3{>=#8X_OTC5-+$@@U(t@nmL@b3?q(;?BB;>;nA{H-N&fkw1WAUu!aC=}g zHn&s@pMCMiKQJ0C9N*pCnO+J5vow6NVt^g;Eq(-dYmrH@^8xZ~wfl?pt}F?C}6hpM=*V z_+~23rR*fFxI)bpY=#!FLO(feV8WQfhvWGNUfqBD_rJqdG7sC1tj3rivP|r3{M09z zy<}eJXirK$u~-ujF^*w;I6GR1o_!A~v$uOZ%x4sEOl>^Wor`ar_r6x`;3m*~X(Jv? zMM-4YDXQH44tjFEK2mCBTdVr86-i~ITSv9Ti?ISINMd$DryxzZ-&)wSUp-Lv$S@>= zCNoBuS5%FZOQ5KAL?TgaEu$WrfhSaiQWB*mYS|*hR5j}082EH@fm9+f+S`pluN>9<96JUEivwctciWwnGy>*79RS9l3b$1MHYTl5{?CggUCzd zRKq)>5x%h=SpkT4tGtBcmuG8sXXp%)kHTl)``*72jn+q_WF@B@zrPsD^F53fKcxBJ1IM$KzQ)Jfgr0Y7hd`q4?^XesP_ zLdrz3IGQJ6iY-!0!AL>P9p?|cy8rHXzlWHzX^XD2T-eeE>NF2NoQ{F_3F?ty7!qZUVu%{2 zciL#wT)5UphB%sgbiP|GY~chfoTHJahUq3j0qRg@4?UtwBWLBh6(S-KyaQJP+tvpu zJKMfPQo2oaI*izvBt@E2O@bz@O4%~xf>y-@x{sh4OEltoH|FS+oT<6e=AfO1k(U8X zBcP>$da0!_F^=<2B9k>p(ObQsB{q`aL@v^;Iyu9T18YXnN)l&Uk1YI}CK>usX`d1> znseSsQb;7`ni7f1vVBMVd|2bVpMUxPLZb;2lGDw2{&1&w=K8RsB_iBfV9ym7&(@{+UG$x zLv!Kr^2lB?!#dqz+cuKO$M!(+`2U!7Qi>5$(H%`!hK7gyy2lHA4r56CIg&7SRh6gM z!EBtkM$_+}mE;Yo$F)amXbCyd-EoUXCfB&am0X!aIjzw+@G-b5dUEkE)Pj)*Db# z^@x!ZDmZDf)xt2AmXwjTdpbw(Do8AkHrW(Q5_WYPjKB?rK9H6=F41`8vhL@2jLk*E zspxa*U-6l`8{hlaSPOWqS+FrICKx3z)R!A32GgipisUSg*@+S4DsWowND_9r#ET@Mg_M*iIdh&T zy${lV`*(iz?Vt7P{!l`B&9Xe;FYPlLZMCz_h~IhuN#+8KCMi*??Ezevr*Ugh)m-#rAZayQ9_Ab^aXhg2V6I!yR*p>Nyi$sYDFn{&Ugz?{-tJ8${c6syx$pWq^jg3;fm9p zEXw)ZINQl~x$yciagHZ$$H8U0@VGt1sY?@yiH(M8l#Tc*W$C62SNgcq`Uj*WUOm2| zqx9(lBeo`CgH)I*2q-FlVOo*uQ|T1pvxlcSPE>?^}4gCNX-3zt?vKZ|M3TWdGCCF-nkTI_Goie z2E848xZlVNmN|5iy|Q_sY?bTf4G-HMH;b`Yh{SQ*`?oEih{VdMAyH&Pey| z7hQy)076&`ox{bz158>k@wxak?oTIAU*72MTrY)NyK_EGUSEEMEnn6sXwr{+{M;I| zXVLGEm!u}1`<>_GnK>t-TR>bTyy%KB+~~98J)E6+&$Q8*bE1nbtST_#+NT=DEn^zZ zBej_|kzMgy%&~LLq+Br{jI~($gwq?Tz*ZEO*hti)D8tb>`Y*6-k{!d*Oz1;-#LPSs zWU3)(eh7Tm`W!{$d2tVaOP|pIoQcl`5!$@d*44L`8r~J1>tvOfGrqS!`jgM&I%g+a zF1&eo3{-b=_7W$hwoZn7&KQB56Bn{ZY^lwar+5MCO1L-Y5-gJhM`5lUi>8cfMOa0m zQ#fWvQy9*oX*Xi>(*`Vm%>4+4#g?}Pvr)F35#r~ZT}Z$AU;oP6e-o>_l%Vd|gx1b@ zp;_7e6h)CD2_(_2V|3~&sBlK~3g&Pa_TE4|T4*dg^=Kzrz|n1Qlr8aasgR7`VUvwqWL2LhYJFg@FS|(w z&m8xI=i3L$2ABN6US6|pSDGDs`w#z!cOTyK?#p*(;W3`_w$){>xc>4wlnC#nqVg{Te<_^`SOWzPJDDW4ev%0kmTeVFZ*#G zsAcx8tU?+C!g?%(InAwM=L8Y9Trpjz%2JR8Qt53lm~3?qZEbB@Nn*ii7ANPV@q3Pm z&BP_K)e7D@$DNY5Wu#ly0*`BnOD6r@U;Kr)f11^OyBaC=Reu#OH*4|YrxZtxlJZ(< z15q@6(tD44Ukcn;5{dXMFnut*qf+8tG#mF@4}(hz9ig8m(jFnw3OlnY$8?_G z-#Pk8-75R*LcPSv>WeQwW7tVMI$!(rtC$31HoA2)^!Mx~!Otw9z{b&-D@MT0@%fstcIfo;mcv#_;&Wt9MII9QMFi(G3|b18HW zg7izEN^?Q|rC1{tD|6w)hsk-rlRd?Z-r{q~dt4FBl%oy8pH!)3ixc&n(GO5#GGWcI zZipxLts*7H%VLn`%C%Szj;3y;&6Zz7qL{|vJlpaG)Sy?1(#)8{sVO$X^Ng|ZRtjc| z;_XolmvTY-IhLv68o+`Pky%fQ<_)icSHX1f6OXU?@%@pDXXqoaN1hhr-d0b#M{|w% zO4tqNI59aeIY3XU2x^7aiS!p1aEnPa*<1>y!Bg)RGupI8^2g1nYV6gS^WeEZ<9RN_ zPblX>Yzd@PP9=8vTmK>Z?1z8-ssDOi9(ded1&Cy3j&^XL2d)7KsU>qQk4$&&?WFq| zoe5q;gRntC*i)tK8Bw^OgER!~F#CzDy0o%|5Z`8C+Fp7sT%DAZ?2(A=$4NiW&^6+s z9sYn+xm-7TyGJjf2O!~@9uo(`GiTN-29BxyhZ1~)(x8@cA$rc5P*iGHAB^p z>ai!obVj{bZwSU#H&TvHckl%$&X|FvnD?I2BTJxhU2HSPu3M>;;?#Pj>K;K45kvx) zHr+xb8bUuOt)DPrRMN)5ho_THN4L&?tvp_@6i+-{u7M=456D&`6Q1KllyIbn6U}^Z zwniri%}V-snmW#oNC-~j7O1A$nw;k|$jNOE$}&dHF*w>u$%UMiHc!xa zUP_L>!O;gfCAMvgPW*cmz2>!{v=LWMUG?W5K0MRixm2YlBZ~)xH$mMlQF!Vtnxl{y z8Iury@c<}_VMn|Kbx#YU9WRtmi+eFqldtK8P90M*k;1t5kIuc*99yL9eY>!wa7}7f z1}BX($~?3pQgA)7){r5HWE#fM5Cn^7k`uLjIiR1V)W{bZQLLg-x~m!@y)%#*R~pSq zt%>A|VwJ){h{C-exJ)kF9?jG#kxGe#;=gQ_d-wc=%ND^3mgv_fhc+Izg3|G2u}nE; z)lOZmDvx7Yiu++If{n~v8*nbsUYgRtkA+uQ1qhaXG0Zmhoayt4b2RFHp_U6KO0vY$ zJ&xcJj~r*mQ?%G5 zS1KE_4c?z8y@tb2+Nyl&LXg{(DUGK#+1@K}Uf+3LF7dqr=9zDQ_FewHpZp1mR(fyY zQ>T#JsAR7B%6mV^+{qG}&K!-qNyL8>)U?rb@_gRu_nph@%uGTX9j72t*)+r~KU*}> zYNv5$PT`n?$9>~^*}0FC+tF~z)SM_&u{lVVxLgY3cG8c7Qt}c;bKI|0NPDGjnGeSe zzl0_OU`JwOlee37`#@mQV_NhLcLXTyrYc;gUWf?-&05Km6bM z?eBb!yq{^5lIYr+)X;5=$7}?WmvK7QPvQGT@hS^{%gIy5Y^rwxu7qT;1)XofyI zQzk_cvvrOZYJbieKmTg4$w`@Q^5Me`L8)6T{+1&omdmz$3{hNX6s$y;o`~493dI1}WN2 z*-B_>vj^WnT`*l!KGS7%ihu9E@+&z-y<4}nxhbi{X5wy?s<`K9Yn~IyQHGmes_31V z(&^wh52iVn`aoM{KQ(1?ydiKr&-W#}*MdX8xeHlG*7N?KvV2v(YS*H|28K=x%twQ_>}9 zDm^hqRB`1Z_z*^O)H^vXbz1JBs_KZE=oul8y3z+jg35DxR9%-X@@P2=d)~2j4ijQc=tts+V*gqowvsIdO_0`DMJseT*Pj}1v)W`UvQLT z-pRdlDH}y%H$GJi=91d?(e|1d0@7uZY|O{G!oBWI9nPl)6z%$A{5dBVR&XoC8vc+AViw zt94B{z!Eg+e0cuAC5IVHB!d;kIT39bWf6KxbUBU<;aErj03ZNKL_t(Za-rBxw-Zk< zM69$*C7>O5N=@v!F0RCh%%BPlCxSjHs?qHnjNB=g{IN(Ut6<(x5;bk~8Mt}#j!VHD z(tq=-zwlP4EC6UUib{$w(6kt*C09!1H2PamEm)9*r`@nes( zG0w)(dYC`bOF3y6O+*A4jwgba;$UmRdQ~5p#1U(kjp|Xhd1SD>pbkf)p9iK!ayZQB zec&Ee=xLKa*RCY{iZ4gEf@=UrbH4EPPrgRk3&*%~w@5Eq8eI0ms~T*#dpp9p+#ETC zjT!|OrLt*eoCn7dN7kx^y6tprbf1(I#SbD;jXuW7bH70#@m*z?uu^WdE<<7oE=S5l* zCsUwGurlU-#edTxK(X@rGd{OkIM0(|2L)wIg(SYP@`7vNza<&9Y)oQ=i^Qo`W@Val zj80}li!Pm`l79V{e*SGPFc;jQyEDfK3&L0pvqB^SkL-LQYwTR(fj+h_WM0gHQ#5W{$x)vlhQ`Wi5Q|EDT87GtWDw+lKGISMB&-KdJS}T zuH%7CDDlQEZ3N4Bh&i$?SVV}CHZIyYJ-bjFGK~7H9A6Gpl|2iziAs0SWl&Gp1z~ib zCWn%IwH7BGm#NxiTyyx9KqqAnl+6X3rU6+2tu{JS{q*KW@af?*F+agggV|Ob+fi_} z9+(Mx*--T`&ZI88v3j#qBT@Y`)!SgsND9GMUf3eq`ZetR^yqK5&c0=reWHG45r`5! z=wgF0-Af@!d?q~9bA_Y zb0J7r#wq7Ih)z^j9DNP-wzzrjZcM+!~Uc~g8Fm!dz&yAA5}mrR%o(#JmA?%Xa;zkIrXjdCttNfuDtv2d)(U!(s!~q^hbvy2N-+lIYYjDa`1=TO1)&J-V(x|G)Oa4{vib>7c+h7Gz5QYrpcovf8K z*z}*1nNjCbb%iy%5?x&r-^I_02XGetF6QV|p6~&@aaT?66AjVp#iJpbVG37!q9L+n zCqJbSxTno~1hFEE3Ivgo3LPh;B?$9A0W4Q@~}llHif%K8%WI4Fq2ydi3A( zEEA_Nrx^W|6BfnG0pNaOul%4`XOVblsuX(WV5yQ>o%PW@nN6hjbaV{`24Zhx|{!|Hg0s z?jIs^QZ`pco$sgL?+~uDa0e9^wyF?|4J+##CXn zigj~Vz+RT9wE2xqGbtu_&qW~x!`kpRTpRS+)?h4g)__c7FB>6F`tW0an-{OIclzjr ze1n+%e={aQ10^{Iyj3SQ2l4*F)b8fy=n#qLv+{nN%whh4Rp$)uIn&1E>+|VI_5Q4x${)CwEly&p9qXyKHS8!E1+TmDs%^nUiU(3$f9ha@HzSA)YF_5?91IpUg zi)|ty(uXHQeIOf{<`2%`9O!XwK~4-_cd04BHJ&o$)l##I%E>9`yO**NNWIV(c+tmbspl=i|w7 zI?g$lLfZ>^_cu+C>ps>RW|ONoO3TFcHk9?@3o3+A*i1RKF`Cz$bGb2}Upa^GGp!qG zi!ha=UEYGkw=*&LM0?txYGaF@hme`Mx+lC+4p?-Q)YUF(2T42ky-?eepc@v1kR~>q zz)ULK%9G;>U!NyG|HW4T{=~~?cgsmwpwQ*9zwdl`dvYFww5=;#fKetdnrP>Z^VvMn z*az2fVPTR5$}Mu+ZoHq3$NA)T+qlIS(t5a$X%K`QGEEwd$}nNmoti7{JQ&wW*b+&K zUu9Zl#_UnuVeUSN{`Ylpa1DQ;mKcbtq+k>>-;#VnuS@7xK@SNImt;Vp%ZfCI2-%SXbean>@hL#FMN6a zg6G>CG2WOud9-)R{+SRHa|Uvs9Md@3#f}r8<}z^yJn$3D?N>JabCVEy@By&Rojql2 zG>%c}Qi+n6g*cGK6Nr66ZJjVXS<{01OoTy6O3#Vs(Wu(EMTnbjv=gdM2Pl}qTvbb8 z&dRXPvjx<=QFU5F+LM=b!!**y;bn>7Ar>%fI0{?i!XK?al;|=F^}%2NTR&qA*NllM zdB2lFr?twwCV`3-BMd>OQTE7~@E8Z03*YBL8b)uGzPYJfH*bO+?-yN+eB0=mfoL%l@5iUD9 z#>Ln3;wPWJhpjT}2Gc z57jOgG|Z(s7Jq6E8!ifw^@9-~Ftj=8vyxJzuQkTaSyR@aA z%A&66nl9L^W{kNy++rk!mwfj@Yj3=tPYmBwyg%PbBHZ^4xOiM&FcCiA@8sxT%+@B) zv(bj9`C|Z(pgo?Q$Mc<>l$ZNXtDR@-2x<1CLN~w2RN=Tf-wnG*h_{KcwFyX^(`JqN80!U!Hnan2577%_Uo&CI-^ z*Ni>gh$+x!#~41$74ODZdjh^&m+6SO5I-1`!r6?*V9VQjQ2C5TqnmIa{h-c^?Usqj z^ARzJHE|bIG9e0MbjCD4YWrWKmxo$#jo3^yX{0Qq5EuSl>7)AESG}h)h6`Y#$O;fC zI+Q-YL40X_Lif*AO5T|nHdc5H(BUr>^K8tA^|v1bRc}BV9y1Q=O-5D~*oLF-XV6tE zhG-L+!$14@+-|s<2?8JLAKsq_W}W@+0Fv<6{_>yyVRU6$C5l^2|G#>|{g*%cNBj@J z_Xj?KuYwHaIvTxAjW6O)%#q-8NqGjcv=TqwZUV z5;sbWU=5K0V{jZ7F!}C&XWt7y`E=)2yp5(&e6(!g^kZ_#?@Sb?InMWr;ciTP*9Y2Ac284)uBfE`jKF zAbOEQVoMoTJy|iPc19ay*-@1DcTc8#{rLltM9B%wjeT<=<)giGoQmOc`UkOw~LJZ=y^ZC2Yj(Yr{yZ<;MQ`QDel+IvSXLhge$F-SaZMk}Ai!&gI=^8e7E*qTv z1dQA5#_d)JfAuf@<_{tc573qR`hW9;`_F#%kNLa*%kT0({{A02BqRhs{#P&3NLE5w zWReuvZiV|xCI{hoe{w#)x~b>rygjO~hO);((-w#&yVtyUQ0KZD5|wiM6H|V%S_AzCuh5;=Shy4yeB8YN+9P#N|CEKY+Rn; z6n_}$FnXsih> zTyrK_NA(c>G-XrP8`jHGa|-9U90Qw+ub8V3dQtVQ%mU=*80ZGi`dk@>jCDUH+;1D< z-~aQ!@k1bE*W!>%_Ygkk=9*=8pTfnDuz`TNo@O05nnwaiE__KFzRS@b@t(H%T8|}ADlT4 z(=-;u!MorTa=H;TaCYMy%?mxr zL6(_7UhG1@+k0+Z&9@`N94{9%xRy>G zpfRsW8*Z11xE9_%tUo9vM`pcvdptR(5hN3$UrI{)tfL9J9|s7}4oc;%`Q=$(ZgPoI$y5$&-GwBhkrNvkyk|1Y!sg zETG_QKlPK?SV1)n9k58L$wu(e!&%5K$hre7jYzsotzd>@Q`rPbl&7rI2 z81vh{6Rj&6gj*>b)rV@Tz6u-7S!TTlk|>eEWhXI2{;U7)pZYH}mH4ueKi{x1F!58t z0It~>hasa=w!pThH8ulk_l&|YuCGsLvuh&WU$I(In|zlF+dXm4!TGq@OCpUyuYoHz zj`vEhofmUuShovFF19=$C;J|WQRwpk;Jm(io;v>u_x%&04Xjs&8T7s?zlllnkVMJE z`QVygsHS91XcU-k(GgR!1gbQGM83Q2*c`m~CtYFBpBAvxk9JHUOJ)m&s~@z>=`D5L z+eQ$COc=Iku_s^O4fdaa2+uyh-9=TSzfCSfyKsvzrBIza#T5qg51yQ3@JV-K?7q*p z#B80z8aXK`Zj7tZ`aw*tw~`>_ee&Ax9AohH?Se3QTu06fP zh2{^J;Kxc&*9oWltV4~MBU=vC@u1J-r^pFsKd~N&sn7_Fx{kmhqgt`%$y7vKstPcK z%_29wvBd{(?ZKQIDxRP3b$B4n#zNA^Ra67ZizuD4r%{KXA!A$|)sbzJg3d`8$~h`x zP^}ZXqEbB0yd*U-DcLe_k0)XiNe~0nvvZy&ueZCyU?PiJRA4%gl-Yl2>lD7 zcu*+s0fsPVBSy$&LkL{eSC{hxb7f1Dt}yD8ZWl=sIc>xgk*>7q$8RSZc{?kH2sSwC zJEE{}FPMn)-^W~7F{cW>pAW1%e(h=})8;}v53aThF$~^o^^AH@G!3?>XG5>KFWIe z&9>w~lISbY=xIQgXezxLA0N0rD_5(ixer0Qf2Ov$fq4>6gTE>JBKAfVQjnF@^osky zn}j9#8+t|KFq_oJF?^~_U$eR>frhlEL`sZ+Exrt`Zu^8Fz z8!vmHy?@~sKfd$2dEV*M=fb@t7hN`CYK0Ime2Ok>vXA<)P3IurZs;5|Ym8a_4rM+C zKh^QeQ@Yon=Y>Y!-w$hCv#wruf&^BLYk1>N&Cy@o8l!f1F~s4R>|xB&*aOrHj{V6l z9)vM9AalvVSsNj4o+Z%EVV$e{FlY;bycNE@zw!3t&k5NI zH2}q7lfmF78EbcrQIS4qZ&2@pPu~T48>?38Ie@qKClYpEU$UdP+FZ^#CmY-Fqo}ES z?y^MMY&04r?6h)mTH_jC;0nQ(8cT>4X`?L*Zu#F08==ig5M#S#(gkOGqnw#7Z}g`0 zG>NG*gTD+U?Hpgfa2yqt8zBY1t~jHbJx9)Gq#l#9FYkODP4fk z1a;D_k)jJI+L(kA2_d5v>7(*IA1p#95)yGM5DO4VGmwK2i!Rw`rl=4sF{QhlWxsJt z8S5uk^;KaEfkH>J%!?M1X5O!p+TRJuznr}rQvHK5m(xIlBIe<%_j+K% z-)iJVz-?|s${|pa@63}#@)q181q%~5y|y|Aef@of0JrVNn3LKr_IyW0sfR~hQ!J#k zD7fZP+4DO5?I?y0e_%VaRtYdlbmKF@U4baAZgZs-1@wW4b58i)#gQJm?(5vuh zPlCF(DVjR1b?~k3=t;W7Y=U%ewe{iuzS|afeMv~@w676s%bgxK2=KZmaFse|8(uoG z=ugivX^)d1pOqer+w1qxd@b_h06o|M`XvcecC`|xHGkZy$G=&so!LzFRvdMOue z1)~xokv^KkG&K;!C{mDI=rnpA*wQs0_4J}j*wAR`#DR@-Fnf38Sc*vANKp}t%Z!*Z zd$@5OPcD?#vJ+MqCYR5IFd5T0u12c{J&+}>xr5V__gm%{kFSh4`4iDaBvA%3Cv8qd z0x|8x)H&NbVZB`jUU!a3*h`{Z_`gGp>uci|?ZKz}jUqyhZil+<8?~KWhp@@Ez76Vk z_b9xS9p)QnYmU7#hkexd!Q48fM9P`CtWw*-t~bCpHbbE7x*ozO68zs;WM>qgEM2|c4E)YN>-^5| z|F68ge_1V(QF4XKcU49Y#?tL}yX@}4W63AskbthQ(mOOlU-PvPibQhW=JbJ1sb&$61}^ zssbS)S$)5)1+hTTL~p~9-x^UL`xBO+GDo3o8B#(*a42`H^z%S%(t=QHB}?X}`!|1p z2qZOnKbh4@Ji!vTa3_h|n7UL#EWFh(%-(q|FW$gZBkvnq*$G2q{ibMS=^P^b4ObgaM2P8Q#lryL>vb8 zn$I70C!w6PA+uvE_IMo^V=8G6a6z-pI#Hc*pp1ePv4E0OE zsIHY3KA3C~8y=Z828cS?(G)SqHQR?^6m{H`4orRM6qf+S8E(EqHyJeZ-l}M1TE(Oj z(oT>>^7kEAy^u8(?l#t{&CM^P<3T6&wqS1;I$+D$hm>1DvryH4?YIRV^_}b8p`4`@ zBu}9Q*S%jd;g%;vJ@7@Qa4Ptb>n&HFJHYdk*(WVf>#>AuBiw)$4YZ=Ti z-E=)Vx!?>)yw@)x>!|LgsyRJWlVo#1%yRLm2y^;CTISkNX`xy7HE2lmI_b5cArd7b z$*&hd10oHZuA*bQSVqKr@F|fk-#v~k7a*ii)@#*k&mSH`Lz#2Xq%T;iuj?@(c=ClY zDuQ_ub~a3vsGDQtMX=FV!d6LXbMZ;XQ=`A}(_i~RMY-%?H0Sh=kBq)}Q_SY%dNhW( zc%xm0mdIZ2%+Wny6Z~j8q9UmvviY5UF1nC8T(p$pJM#(Gc_G%m?JHvtf);jFZuf#j zk4^UD`nHm6wbI(@8TR0Jx3}jP>hL~v0Ah%2_e9I5+i)oW_O+J;KTq5WBPM;U| z?M5zzI{MOft%SdL&O!QEXe_^;h&0T)8+B}L4aAX$6Bwhig^iMY#t}sr!Gk0I;7g>e zE?&J(uFwpGsbnUT+EzzjGOE$B)yrnAQ)x73_KVY|R2TEV2_(fLO!c0GPVp_! zbOKRKg*|Q5c5#je76U?}PM>Sc323Lp;z*O}xf9PWctOafHxikCq7_SsC>H#xs2a$U zY0Vb*5P!R_^YOrQ3y3mJ)_N~4^Ya9CLQo&Z6d@9Qm^fW{BBH-cXxgBSO0T{N5cT|p z;4954o;?T_u;2_eRgWwW=`N_1;fyWQ)qz<2&OiHS{>%?D2Uk5gPJaq(%Ji6AF_avP zFxC&e52JVEQ_hsKQ)gd)D50x=2qa}nh>#lAUG#DF15qPnFBwUP)=#dpVy6)n7*TAp z-4bP6frc?1A=VpX!l&=nL1&dzUGRdQ?iiD-Az9_T>5!6T5tYP+7fn7 zQuAH)<7#Zhxd1UH_TAx@y>^NwvPP~}>CKiuZ?zd!U<}&gE7abZ=6{|Pgxf8DYkKb4 zi8sgTP?o*ios+nTQxYMBL?7yLR`csd#DOy&WQz3GcpMHg%_)2S0-q^~P3k%P=e-7V zVfuRKHyC$`pT{k&e>4)4uRoN&XgTSYIFL-10|LZ zNQkiKjn<5Db$p)CW=jEaUjjK+pvQmUjW}Ty<7Mx4p zJ2@)bmTA}E{qdj&BbP{)L`h01f%Ejv{{G!()FzMj=gQA3L5dGnl53Ug>15h2Cqb2c z|3oeuTTYyBZ(PTdJqPmrjs~#i$Ez)X(vT3bS*Xv8LFEIOBG!GkElP^A-0c2LsAD*P z-VNw%_kt{@fSZAi=tubH_3(~+^fPz>ui%D?MwiIcaUtUOR24rW+jK6%G(VzR=;Z7y z{2}WaF#DL8$K<-%~2v9JAfB(el%ZM3U%yWP<=VKztWn-N1M zNb-C(HnW*o~=0HdDhfEw~ zbp&|6C-QBh4#9?^*`*d{#??D1Dxn9gyK{Do$=M%>47Qh>OD8QkIOL-ip3=&>+tP1) z0mK++NQ^4<>N;)};g%OZP6m)LB9Go_tr0?`B>%Fh^#z^v2h8ZMz>X4~PZtBdcZM`# zC?29|Uh+xNuQzt#>D2XiU5~-&1IZqzonvJzfH^&0KF3%*NWt3lKumyc7eN9Z{&up&%8VoVwmor<4ZCoyb@ zCc?k<(_j0+yWEqZfmmL!UXjsBUQ(iWqcsmEloEJ-+0o=2w^}x9ktCYMt7RF@zEV`%1}; z=_$j2fJR2|%hm4W;^2%`0+SpAXz(4n`ZRU`*EN~7l7mu8c7{EZvN(BNlvxdRKr%Lc zRxP3~-nku+gj-HsVnqEqO4ado!>=W-+7HumN6 z8?6AsKs~>@tTOqBcv$m+nK&D8Or-}eGmU;N7QH9&t~NZ4hojC%P_FAF&Pmxktkt@& z<}9jjZkjjr`WQ%<#E@vSa@EdWJZ;#{#^{qA@~R{Im&Cv5LTlYmX-P;qdl*J+#kxHs zP+Ro@m^gq$b0ml0gU1=zVsc2!aW431SxRzW$jMadXv|^R3n*@~C1T3yiG%TZr3csFC(I!Oh0ORlt{S){L`St6q5 z@{&3_t#?9lz>V`RgP$rshSqJ+&4@V@Q_7BOZce@pvvSpe%mL9|;>R_4KYU$tQx8R` z1&;IN4}SiI_b+e!vGAGj`LoXt)(pEU8l2so3^8Wcs%Ig0Bi)qe8F;jJt{I5KX8=2i z*(OywucbiQsP&?cMh+RIAr^^4k+JdzDum+UAhoslgC_TW+E$2_Pu7C<3_xISvyh3Isy zp~CF;0did#_uZ?s(g`VeSx6mWHJf3>C^*b=Orz6~O*|fI6+_8sXG@VeJS3BICZ|ZF z!>ojyiINz7cx&>elzn5$ppQzwI`wLpcDBux<9^kO)Z=0-oEwIRQw(m~E8oSRa4(Al zZQkHR1=Gl|=~tccA&Oasr=h-nn?6Mb#&@AnM6YLtpO6< zn}EAC29xtTmI};eB_;1@@@s;K6Qt%+%*W`%>{%yCGeL|oot^NJ6`1(ISY*woOt{8D zkVGK(a94F1vigb%NBXRUU;ooT{o%C3!!=ncp*RcQD%;B)Q=wsqM&g{@N@7b&8*p8n zpS;|7{mGq_0y!iUrS^(ljcZM%=bT;-oWktOe577D@%7o@ItFyN*v|8EF-V3_x1Ig< z#cR5KB6ZNNi`u+SoI>Ch6D4J4@3eYSdqcGnb8=F!O(Mq2zL7N2dLt>^_m`!!YE&+7 zXPGnR&3<|47FiD$jF{Zl#zL-Z@P`G{@#6OwiOKufvsRdcBGKDy!*%CdN_>8K^=j02+1g+(E8x*@u0Qw?F)MxPndzM4tGU`W{og~z|J-Ox@gmR^jisQ(4^#8 zoGeriBnHq3A2J^C-&0iQ;0-$&W{9rV+VG$@Yj0m`W6LWNzCP^!e;yL5wbRAhsbWr2 z(rn9e9T;Y-NEEB>d?=^(TKAb5Noa$t@ZoCO5Tg1%jfIe8Sv~Eqa3Q zXdc(xQ{?4-LxQY`C&XwNgR4)jx&R_6(hO!B?gdPaZkCW&*dseaE8@eBUP&dBZZ~9q zT`8O9esvRy#TEYzZg?3U=D6KA*pd%yf>N(WJu9QHD(&XOFahd>+75>2Kt&sj=3Q*$1RTvZal?>#Qw9zCEj>BopmiloQo%Hzyp){3wt>3YjdKFd|73TM5K6*tZu%GT_vpE{&9fLnOuZ5OYqR?@x~N zjZ^|#xl^*=@5h|Hoj=lMV^23^8pr#CsEPfSSJTXCHQk`q=v@q4pyHh0LZ6*(Mu|6O zSH7Mns>WWNH(=d!2_LasTjGphzWxmA*37vw2qw`7#>zROPhvB0duJKpNW7*Co&NgH*-RZnW0 zL@j8!G0Yf!_|(pGCxq1%XXbCTWD(b7MKi+YEC5;DITItyz^z2~EwGj70EkV9o0EMK z>MgpI9F{SC+fZlqt45xfPEy*qsizbZzCoEWdO~pq>REZVCo!nge`j!N(u5ofdn$lO zVq*@>;K#$Hg`;*J=fSp=V|^GYXKwq=@15rR<^A>vg10a&_%$d8=R{0_vwr1yK3(@U z{X~~bh6(K)#1$|aZC!6PyQVwlwP z{~rYBr7>$G2*3$NG?IXIyr}M|#6xOOnL0>GF}1+>i(~)UKl=5T=7VQ_;-kfEd+lUf zZFsF1i)pqc9#?1h;Mm|+GM*gW;~qXoylGS=_MR?Si4ROvf8+RSMG=QV#EQoSqn^=; zj~6gw0408LXCDmjm^w*WilbFP!C{PmRxbB>HbZJygVN_ax6hgFt)0iu7 zUo;_kk1TnQ<%+E9iF@pP<4&N6)%DGHl+IR+TfRkXbm`Cc1pAiR^&m^I;D$tF?JjpV zO*~%D2yJ-5Ou6);dkv$^XN{~pnOlyQ*y)v`i9K!f39s{{UNxrpqthZ8!svtEI%zBH zW_a&(8FZZHgR(?>U>jGzxO!zjGTUPDwXx7)C_0Smv5u~rMOjFQOn}De;%be~f~Bme z>_;S7RGCwmEkZ_RDaD4z$wpH|&7F$(#>^o(ZM}zOS4JqfEYU`%exxZ=oJgj}rf4sj z>owN*GTy#(t$Gzf)Tr~Kd03mb6iGc#DgGP@;;*;3{#j1c37v=lCliuQX15?J4_Wk} zuxm|^oQztKg4^lzHYfr@4zrROuj@g5HpGQ(+vzms92h%km5wH0|IvT^?|zwma=xwr zNu(P{?3=qsl1Md&#iUp2RYBo?+c`=KqUwNo4P;Ex5|)i6nN%}&%d{c%D~vO93b}-g zk;T%VvtwzZ$+)KB19A!Ci?k7t&*kqE32pRjjq`O~T8!#tB^j}XSx z)fX3b3e%m|J6lT2dpBw0ggN=)(`SyiJLl7RK2I1O8Stu=A%dhr9W4~vl7dLw2hZu` zv~e#tR94ZaJN0@5w#q`VdCU6>9SLqxCfZ9P7v$oql{#Vr&v)&vLcSlcqfro z#5RVKsK@5LONsOKpjBtjZVkxn&yUT42eID(kw~J&O4!q{Y6v%RmkoatPk7E*m9J1hr ziu4Ga$QHZ$-d84}<+%3y#a1`6Wn7h#L3L1N;HnXOJ>m75C_%B!htXQ6ef!1?;UPIG zDNn{c!82nhYH@q@>xyDiG(Pb~PL<`GpANG(PBpSCSzFL{r||BuXW>}g_dXiq8l)pQ z1W9K=Jbec>rq-o^Zsc@ZJpIbER$k}Hr`yJ!Ge7pPJO&(jLyOUwY#!YPo3ZO}8b@t^ zHonR`hb|s~8FQ;NzbGSWu8H8c`xxBr1xY{fH~;Eyc)gy#D5&S0Z0X>rf>Uzq9v7T1y=-hzGj_2&n3cCPc{VPDCA5O5GGyxk72`r`RI$qUFimkC(5 zNzR#LZb(&@R6cOtGmOte7PYB1YOCydJpfW-j2I-#3@J(T&RJh*5^~SQ0h%1{Gwv?GTd%iJ=zgI0#NP`%o$D7`$XQNjSk>P|bDaoR5?#r?(DUMQp zX{>ujOe~LEBB8Vv)Sz7A&8gGku0O&aV_DgD<@RYO=fv42*BF?0yv6!v-xE_dhR3Nw zl~u2t)GMGUBDTzIV;%ox%>~LzR(0;SaZAx`oMWImU_@k7Rq@{AsXs#5JY~>Uj5w)+ z4ZhWHsAi75g-xhcT5at4#&c+;c7F?1w+`~Oz-o<#i}3DFef8*LENagC>&etg zzA2IeE~#xGK5=uj500W_E7bGiY-d=KyI>=65C7@7lhpY6=db+q^H);Z*kl=K znCp}j`SYs_9cW`^?vIUq+v59ZF&%$=dy!}2cHhw)fEdlh9$lPsc_95GftYmxQZFoL z`WSSNKFa7$(hnoCQ*>d+$BbcJ5{jk8TI{&D7&2n?)@U8>`;JKnJT)goLL2XHanC0R z%Dx@~f{>C@N7Sp!IuS7~u3lzr+ZN!GS75xO#_QDHBE>1;Z2b1^L7S7KD8-y4ldDyd zLD>#aWy}iNmIizVv~@-pEt!U%{S1~x*=@NFLJL2KGg^EmEvHCQO1#+SG(tu}3GDpZk$tjN6J$cZ2SpT0QftBiQ;gQ#H zEls>D{n;aJWhJ7UfN3Gy7ONCf-u41hxvom@4Rc33)T>ilR5!Z@q>|->-;Nue!INMj zpdsNs8&k z`e2MeHYvii;0n4!vBF+5uk*>(KZF>G^IXY0%N*ObbX(U_URxvsr(j){yyN82YBVD) zD#BAnRIm5Jw%_>t=`)*VEIA`jl4K6efnaYJqKjCBbCiwN9L-^5%4x=WbxAljJ1CX| z$EVS82jSa$Welh-I01NUL$sv8Z7n5t8sQ=6FXy%w%B{pI^&?jyliEVk!Hn&PP9u4u z&Wn=6W^;NCjGRZ8z&y$^IW5)K43iSWDO=2ul!^O=W3iqic#dMiF2}m-Ma(vvkyGNj zE?VnsDX*{9xyD$SFle&}pFz|5XM3#H%n%#&v%;8I4%_f_#UuvhDHrN_^17bvTZxw; z&|a04l-qHjGX>JimFY$nBWc2Ev>N5Q>CQM|Oj!o4cvz(r{R;YI^mvgf!Q1e)UNs8# zCx80qUp%DWG_iHZiXoH&Vqweaqc1^24sb`0dm<8(NJ~mCWr+{gBwb~7njMpP`)}DO zDW;X~f;ZxN;A@ej8Jh#8lPn{fMxR-ip~c&(pc=L*W)qjr*;~{?vy#!Jh;ruo1zZa! zdjFufWVUQ!*%9UW`pR4oiny|9l%1wAvyk^-*o#0R`qWzDf#n`B$c@adTabQdOp3>x zAe|#0B*_$F7tb_$4VBZrCyx6kRKs8BV?@~rkF}Hs|8Lev1rJrO?hI*YD&PSm@pdhr z!(`ixB*w2k|3FU02Cwcy001BWNklx93I50g)Z-ehiMUS4Ad4|-O~&wu@wU))w@(BpirqNEu(qBfm+UGc^k&?FjSnxi)@9>a+?D&0Hg z7PADOA$;)gmN%b)j#>oZsX@6-dqQml9{Lvh^4SLcs@Qci;(CoVxbLEdY~tFsBD6p#>R<)fCH` zkZwHN#U+z#cx3bUgJcQuO0SKa3bLw6udh!&fBueCl*j8qO3@EcQ`%JK$oN#A9NoFfKxmO~N7 zjA{Px9;^!uBNlVAr9hLLDO-vJtV&`u;n^#tB=)@V(<3qs*%D(!{$$LUHE2?r4}3K8 zjF8dwtaRdYXR2#}xdzM^)aO|3z8EfgCf0Qe9^)UM?Kyb)Nlr?Z994ADl@2V-MYOif z(Zvl@EtnX7wHPMK2rHLZ7^2LuKmUur{L&U$eJ&^ZAnvcN52ma-Xq5gLtAl>qZZW0x z2`P?Kz1E0O&e&^<3fGv7Hkdu|-`Ck`-RVi#G>XH+D`nfF%{2$EFsd-xK*I6G^*Wh# zkX8Z6(S<6P)w+{d^S9{gt4_8(Qwoe8N^K>vl|o8zot4H!Q(D20kT@6x6@ksx8Yn~y z?m}VmDU~HnH8v}8T556ZobFt`;xxE@$=BzDVjDi4 z-p;6&=7q)f$(G_8^wlrg5{9RB%}PmW{i08}A4j0HH1q!c!1luJZ6~>L)3P*L5yzgy z32ctZ%17mLl27xujTmu*6Cpcz6P^5HqC5# ziy)FsQi-3{d7Tl*-trm-hoakN*nq}#rdRw57UPx*uF(K2IU^nqfL1%5!B%#X25cr6 zg7LtqK4Sf)8Pl@*`XOZ5N`cw9`iq>lby{7~g1P*ulBnKDGXNsrUQZ^SoGeOoBdY7e zLul$B5F1ZuDzqLdFipy4aYvW*!CN%wP;1NuW}j>&wq!|^se%)8g|x8huyA@SMw}3G zvZ(FrN6a!}%&Lk`r9CdL(NTl_wyk*1pr~U1_#glIm#h0Cki_J(`B)A22vNAk#Fr$X znPb~yH6+HE7w$cdAXAWB*3Nt&YotDV$EVX;XZAH^pHXY|wSS$O@V>SWVx&|M^9bS? z^zQUl{|<_f#v-Q1@ye&5s@!jJA9wG;fHPyxIPQqVibr%t&}EAPN4pv>i;mnnxhPVi z658tt^TKkXcr@;kuC<~^)Ok?$P&PEH#>J7f9UhOY;#H`E5Rz||_} z)!6gSVL2FtF_z<&cSed}&=9!V6}a^k@tkXw*@iQwaFnv%%!RXseDaTe_@2+@pk7Y( zNgadN`QmI()Z-4_T94d5&X|r_;eH(06)UY#LuvjR-$EKIf~g~Oq8=0Ze1uu2SLb@Y zNYmB>%-C}w?U6onSI!z{WFcbDA^jbw8(J*#@YO>PKaG7W@jaIr5Y~0e>>hl^tQ)rZ z;^_-!!TyV6<)oytT#!m#K-gk&g}kndsi6^bkIsh9kfd753{HAKN!Gb8r`A^pOtu}> zxB@$sP1b33L>?q*(6oCSxX0kyEUu!mtkQzjDyYcC^!*G7{o8R)&kH2Mb@%`sJpYCsn4H{R> zA4W(oLvNm;PQ1qnCxi!amD_G9NWqezCu(m@f)inC@nL30`D%i>GA-iAV|6VetW|?j zByswT`>(NY3*72)+F%Of>M&Mx7$N1%934DXydN8y>%8KHp#cIdYNQfeN}rAMIvH!| zD=4EzZa<}h&PnqVaoDYpJXjerXAB4P2eKd9P^KIgqNPU zr-=c!p<;npRz)=uU(FjS1<&5=#k|(Mz?^cA&iOfCoL6U;Ov)wp*E6kH?}e-wuNC7t zo_swYSW3KY8-tSyVc30EM(b=zxqteObQfN)2bK!QzM&FYt4ZgOL?(`h$QaTrvD_|a4;+I!1yjG+OB8iIA zH3outCTxOBU3hCD=Mt#_hw`B~*FcB`u%#m-(sG)VQVg4pY9wAoW7hL(CsPK;w!`Ra zivhKkRl6*zNHK)7>DX{ze^hX_+g#1U7U{x zJ}O#_ltNnB$K=&IDiJIF^j4S-&-1}#khP#mxyH(~uWIL*lYBR}w~ea?Nc8O%KEl`8 zf*O-1Z3@?{$Sz3QnJBXjW~@}=?mDA7{0F!Dnv+D^vbM_AC*72}IXXA83TgpE8w6e} z=bh(Od7TfYOz!ucKl;_L$a;_5fg0JA<_)v`?=tz_V~<^ot6sd17d;Vw?wpjguOLxe z0nIAIR~ak?PJ8rDpYgfs8qr>{AOM@%;t@urxaH6n9-3`4p?m zDY8y&j!5JS+IfY&Sir*?%9di_IF>&`EV1d0t{1JHQOZiua_ntj8lk306GpO6G=7=8 zT&raoEA@m>OemV53rE^{JWs|9OH`yJ4O5sJEk+RPs9b(wZs3V74cExB2y+>P!%9_b zi;DY%S8beUtddg>_ksP@pZ(*d220e-xvqCQ!C)H_9-rwRdSl{E%M@n)2>Mt63TF(g zd}Qj`5efEN(YdhNiM(%^JIR#m8P=6!%WV116fkx6oFb}dfeji{@iFPI>ldz@_+;M| zDT!%uj0d5QLG2eZXLR&69!$GTk_Z;<17tR)3j21%CPD;g^xknAQ=BZ(u+q)BWk4@3|u|PL~rFzvO*i3tJmnNFRZv|Ag1G93i}>n)w71(sm?&W9c5?R zCUaD<5VpEIE>Vqsf4q2JKl4XFe9!lvenoGS^Xjy-@v2`LbhdJ=thyoHnR;O*h{Nag zVCWeD4N=lwD3BAR>>5h2^-1e(xNvM9+IdsKo6|;%Q)-R} z`J7HJ%A6@k#$zBUu7^o8q5&UO4AmaTe4iZUP946yhw<;EmLl`Q!q`iMa_10=W+Vw+ zSQ;^l*};qzo~B?(%;lIUk`c*~lhLpdjccG7&$Chc@UO7vFo=H!&uDl}1Sqqj9@ zn=5aV1r>{$wZv+?OGTwHJd8o&!sAtAzL4Yh*M9wHzy5O7MynU?*~2bc0v-`*zKDJX zPrc&3;|`u@Ahs;WUBn|QEE;0aDH`DvdT;;&4f@MmL1t$+<96(bCBy?s6?DYN)l1W$ zrDz=OFvkLa5K>PyiX=oLt~_Ssv8@n=2Z@wl`bcn2=pH|$oboSlN*^`&0vfZ4K7xpR z_D(T4@>>iGy-~--^PG5Vk*4yP!p}JZ5#3==J8x+x&3KU1-opM=j8p{$-T^!pU!(9#P@#Bh<%dvgHI5mW&EVQu~+{2)g7AKLV;p(%+UY&3l zLZzsXSL8HI3NdFHS2z-L&I{nGD;XCul+cbjM>=S;VmXnm#4n7-4C~ofHbN6>ndkMw z)!DWkn~5=mF>Cbg2fSAQVao{_Go&LPz?i%=Zy}foP|fSvc|6}KS$Vr3wAy*LPT7o{ z_GJo4P-UG~H4=eou>__tJsPat!+%aK*m#bCISHo*G_N-(^ z>}K%UBYh^ysFiUxaDx1j44VcuhuZ&6nh|TF7{H-Q?+Z7slkL7ECGHQ}XY5xOJmJH)p0*VE{xKpw zCCaqO63hvH#TzY^jSm->Qt~EZ{u1k(_idcWDQKy!lnZy2t$3mR{ht0@k>Tuf5b{| zbs4&!WR%S^CUebBgsHlY@E))gJU-hp5gEuR44<66k=P<@f?~O>(9sA5-lH+w-8*$Y0gaBo2LRO42SHdkTd*7VvPUd@Mo(W;;L0EUMfHpQR#u=bdj zL-ryCOCc~F9^IGq16}eI!%{&#)1;A$kSzsmT9rO3t{%a;KlzhC{&KmXvn(}J+=Ve^ zRDRj>i!7&_Kq?lfVl81NSx&vU6DmFi-X?pF?y(RNOP?QE=BOLLw@Rzdu}3m#5;9J; zgrn5v_-qs%q#Qfb39-A@XoQ(0&R6ApywFYA?m7JN2uKJf&i7Y%*lJ(4n}B8vC*UNJ zO^&_mX!z(zF-o@h8b7jx8lVobs0m+JrHz5R(9c*u-S2VauHLBL88dKHCdO^MF~{Tr zHj#KJ&WM(V^M1wvN&{o1eWeE!y7(_2u&?hgyhVnfOUIKhKvA45KtdW}7Pe)H)SYb> zwA!_DOC*lv7f>?Z3$NCBosH+$lh^q|taHAi)b!nVpZR?MyyT|v`SWM)$7jx~!Hhgd z!eS6>jo}?hiCPEOHAy9)C$&wIZX{7e9o5ck?U$ime9#GWmquu+Gh?PC!qAmr5a?^t zzHeJxZM?&rm@nM7%$1|JAT&#KGfZM`6lk|lg83L+D|fK(`$`Xj%2=L5KJJr8yS_ zCy6sORxGzIaoZ1S>$nd}Iik0qt1UP(DLF~PL6=JmyxOR7f9p|#+D*cJ&>A)--)#qV z^dPi++($huF>`62_O#P|@_s()KEe=0;_>xFnQXT$PFE7;m*6dG$V)69q$-^)hwW+Z z&~sRS)nX7DDzwZso!2<|cK$7|*WdDZe&h9eacn!E?w`25Dcil!{p7Fz@4x1^zxfTH z?sx9DPn_34B^U>2kdwqMHZ2-{`>Q=sOYG&qdncQ5&*5y)RFOpmg2a}ie%pJGoPijY zG;#tsHdi=}kIHsD*grx}mB<==%&cN=<-~tNQj=4P0FBLGh|9*>w#@K1XtAh=um3$x zB}!+2^e8K-&@0rlMc8NCXdU_$+`e2A=wM1?T1F+UNWGvQM|e?T>Im3}vA&MZtG-C7 zgsFH|z{zD@k5@sh_Y1EL$r=^#2|in><8;#7VDwJPB~HyY!}hJwFG*a3&HR^jn0-_| zg;mgLYvr>NPAej%q8PCb43J~Od%Ur?68EcGh1L^o4tno&|KP;|Gd={mCq{}tJ85Uz zjjJa7dU1_P?SkpVavZ0J4LB0G26lTu%7v`XCd5##O{9h-(L_i~+eAuHRw1Y}%oL)> zv?`xI@M&D4;q^12>^n&`@KP4X(J>>NkTyemr}q|-y&+c zq37fpjnabcnAjO}ay#CrXXpL;#wiK|Ue}Xx+u3uX`vz|G8MBzDRm=k75nshz01%_e z#X%vhig(w}**oL;;`8kwTZviC9Hi+a1e*y zA)Au(LHCP3CiZ9l;7`8;5-IO|cO2~7#^?JTHRWm!8VIf)E{j`>U8`<{2Q zX!U)RJ$8mKUnsg=ZV(9kM`%kp1GG}6l zvu$u3k)fX+rJ!rUSWQ4J_=9c6uyT(0RNF@!RN@!hWdz^PHi~6f8GTJr(h`Y0i)t_; zdJTr3ZBg}=!4kg&9A^4*56Yk{WSOc&8eZd`-rI=sm}nGtB-7`KnUTzJYT)wJC=1#d z@K6OehBoMvUCUxUEP1C3d4@FQ)h=G+#Zd|+N5Cogk{MaKl`#h0V<4S#T98x=v5YHX zMr{q3LC))HIE~rh?49(N|Ng(jvt5yIFBui(^}2YzpCk(k@bJv@y2zTj-EQ>Wd0r1D z!u{>QP+V%{_FcK&FV1mdrW|Q!+w%eth4)TP`0=-Y%isL?BeEZScl(Z9IwFbBw;j<$ z@q()G{`kuC`W9}#?M|C8t{1b%aI4SG>wNL)^A=CIte70Uu8UD8`z^?uCL7n)`1W{5 zldv7JQ_f2nZ6f?n|MUOKc7MZ;Ocv#*cW1nRMI|H?J|rgY=Ym@7dz>iD@aG`eV4BkE zV9pn_JFN@P^Tp^-zJL47_rH4M`8@gY#}}XXgX1XZv7<8i`qNMJaq;Pg&zQdRyy`+Z z3)lPL)BX&(r^XQMr}-o8Ik2L9`uvG)`-JHm&({fa&^@j;(<^;Te0_C(^PB&NIvbz& zKj40RX6nWDI;q1sEK}0Pa3|X*{@x#c&-3-*fBC=uIq6?+{Nd++BTh6Z-W$LD@n5r9 zCg+W>*Lwh844&--Rm7qZSg*>lC6d57ogYeKKi+r({yIq_^s`Z~urT#wGJWHD20#SB zYvTPkKcYwG-}<-z9^0GZvvb!wZ+>U=6QN_~WD6RyrAV`yNWAr55p;V0`JK59&VSWN z_r%}-qrcB?J5|EO{Nw9uM4QJB`M}L-vqeU~PfRj5yYU>8SDTpD0P2j;h41%5PMPz% zxN76bJ88{6%w`Nb$DQ}!x1Y=iTqF%prFFbjTqmg{_F~lWpnE1I zBRib^WOgIvjfOF5AfD6;s+HMhAhaa{G7x&f8(M_n-Okr*}T@@nQM&-Nt>(;VEo_YmN0Ni=ML@ zVyM!+qdq9N8|uL(7+y(Qm@^Pqr_S}Z2;;N)g(jzzgE3opBY?bR$S~{V8lA@S@yVdi z#;85`j%frYd&Gw3FsK*2jwgr22{UFXg-c$XwP9)Jwi{hLui3eJ-1T=e%D(aQ`!~M* z^tV|4EGHRi+>I)o^G?dgztaa3)T;rp% z<+S!stlYHo^hfl%`(P%xe?Hd4d{XX#85=&hM(1Dr_0QOzs8{3pIHN=|64`}%y`qFO zHOMdy=}1V4Vvv0-z%@i8eFVLTIoP($=lf@7AAEg&L(SRt10-m>@2{VEwg)8_iY01? z)*8J=;po_QZpRI!@p?XKSEtqi!`SS`+o$is9oIV$JN2Y_$s{LgvHlbhw(X9P=vQBR zZ{a*UeMHf!4UZdNYn=Uz-MS{6iEE_Gatg9h8;)%Wvx3e3%U=cEdm$+|`HXxDR zC?=#$$r*AkY%18yxCHYcA2)8fF#E|>9h2xZBnsXqkNRTF*ypEIc+-unh4<^E_IE7D zFK6!)sY*#XB%Tny#u?k6_xf5Z-~?sWlp8^7He*}q%PfI4({&T}G1nA*2Df2-zs%sa z-x%)Hc5#$DDoTB|(BP$woL5zO3S-fmL?e-?BOX|?e1>9>Q=zqsSA9|P8*jJIxFxE0 zQg)Jg$Q$BQ(K8|;(0x({Uo!Pf36`{ zOyCyeRm+KIebKKP5oOhYLaMBLeGFixhwwlpGW(i9@ZTBt^nd>NV*m7p%jCQ&vxO13 zx549ltoU$_dT&=Wul?(s%XXvqNYFyl)JCkbw!`@D^Nx$t>%eqlPk~Cal-Ty22aGgD1BQsKeB9T<Q-DXvBqp_^%R#^5>-)5SVoQNrm$H%55ig0>W8K!H`)*>`OaXJz#!s(rbUL56 zPiza--o`~6C;PsW%bhV&ys*qdV=u9$RS9=#{yVH8bEM`TM zXuQ$_WV)q{k4o#Y0VuWw(*D`m_l;5lMB8ZLm$b4@i$V59D|qzu(I6aWE6i19D-!dD zs}9Ccwz9L8%-Kf3byBbnam7|OS!P2gxb!H*xvtZh(w0tCgX0qs;s5?0{neM>=O>)> z^gH98{*S-;k@D$?z(e5VagVtcv zgpS}Q#>JyklCbRsawIJc7_HLJ7doA0Lamh|g_|DOM-omT>!kM+uYujRnYr1WECI&o zQn9r0t^SPn&gbndBrG~9$IiYTm~KJ35#{QQF(zrnw4;OXbnm=+r%xy61MfjV8D(wH%&p)xs+OrM07%{#Nj!#BK$Nl zDJusbXll_o3A7oF-19S!ns$J-Sy%b8` zW4&60s_|#1-FVb@uJ?d)Zrg?wXTL2J`iRt}S$y!@6)|6tgsoYR$4ZDQaRtJIWhg1J zmFVm{lVXLhuLtL-+_r<93Vp)p8c1^qHN4DK1(&gYxpGj4B!1q#55~gH<&+}RFVNh1 zT^G#-vpwSSme;u4qxviZH(w3UPT3-F5+S7(ubzM>l2~lvW+%&z7G3kVD9yP?)mc1j z$VoTszxazk{_^|$g!}37{yXEI{`vp=HPGM^LmL%iBt`Ou$R2lkkDkDoq0Qd5AOpJ- zo$|TLA{rtJ(~U!w+daDFV?uvjj1~;MRx7QYv4gib*?fEcOdSzgG2&>t-!tXd7^Cri zUh$Bb; zyX|awt!_mari=X$*s5F+NHuF4d7m!&e4-j)J;0CrQRs zNZHs*B9h*dYvIwNoW+J4kBlPDc@mXuLlJdrpcWS#h$Ag)oqFg=}T!QWa z&P`_Vu*Q)Y2~hj5{^~#Z^85UR`|GxFaG8$)nfuaJ@)ll49S7_A~$9ab=lQl zh)%2osYN=$@;fW@oZ+J*A=BA!nQh+#eKn%CIeTL`eER+##M(MBjWALwncI=$XW%0u z&uNQO1mOiJX3(AStoSQz%A%9E`;C-0j4<>Hk+w{wV9Tt_M^lnl4D3D-R1g*&VM$ws z`g)Nx@wOe2Q4ov#65&LEh-A+e3A|iVM3lYZ1gu2YZaq#@p$?m=P#wk@L*Qhctq5hi zquCfbxV%!YM*Fbz?3sBwxrJNsakW^B=8cpx#}N(0UOU@Tl3lIR+g$#<4;PHU7&M3T zRii05Yw-Sf&@Jq;MKW7fw#_)t#+=Ua{deee9`DcCO^9N$k!&aB zVBgns&!o96%i-`13tBU;BMSEUs>24BTr>(RGn$W`tzi6|d1bpCh&pDaacuZ&8pOf8Q7& zqp>OMtCL`5W4mv-!fV;3hX>&ppGj_SuBjZ#0D#u zs2yMRVp^w^0G5nZ+_GVGb1W%U=hEJ-eEIopYQq zSFs4=B~!8rDG9X?y4NU*{g40jzx(q0{DhO#e`nm&zxbP#iIRKVi)f#6t0&6PDv{taEbK#&tzze#0o!BAZ^XK&ETNn}2H zK#2k+ORxdKGVF(`hm>K!ut7B}Qr%)Vt1>fU?=??j_+rdR-j;65Du5R}H7X+Zo@=f# z{{Q>d^cyc^?_bQx7=suSb=!x7IdtT`R=%ct3X-I6e$6?j`we47%r{B|=WT@GWZN@oZ(;6}C64V^D*>{ybert#$f=*?0#lj^1 z@Bijs{_u-F;cEQZxTnAP>sNZ8{Pg*O3A~&yWD&xC#c);oKv!feXW7+S9LP`)S6J^T zX6uI4K>2WE0-ry>@%H6nw9Yje&4hBRl#;OhYSW&Rx7R02FU~V_-VT;3V=QF&0JYXa zx5l!`HJ?lil$tqi2SJ4@gg1UKx>NjPKkk9i!gME431~OMVyo4BlH*LtiD)O_mF|TS;^eHAdfo^m z)-w>A5LP6vgk*(7eZ{N3J{1vWXteppT8mO|q}#!nGh)IT-HF0Ep-Wgc-r-l|l35y< zQHYXRvu$9A=TzEQo>f6O(!q*>)-IAN_3*IPm~-b#f^TkyH}vLONYw39?6f{P>x~ox z;~K1~lvq4~W;l&%`Icgg>9@2jPRZWytU<)ZIm@X|5&~I@zm}CmiP2xnHFBhksq*%` zHhi>hCHaQ7XrQlwMk9@3gmj?! zCD`fUUQe!ZarI8zJ5{|vEo^T+{>~}`xf?ZP))X?XRZgK&DUH|Mq;H&&Q18@*l3E|gXH z^!@k5+l{L&*4K^weH)}F{uUy0>l&PzhlgA4LrlO=444^nFD5WsHB)kd2!8cUP{HwY(*&3$hW}bioA_innu#{&+17=htg&8 zu~w)Dy*K6>lvqFpVu`c@vb-)F^Q4V|tVm8qs+BSQ;4h(2bLE)lmU_Ycm>y`H~qz!Xm0) z`$dhV-A}6|NcO-F;@a@zs6H|73mF-+#1x+`=rVerwlAfBPr>(oZ;%P9RcZWvqoQ?@OCxAAsp5 z+myVe3Vv$&RevA|vt7tk(s>X{Cf+;8Ox{*p{)7taBBX?6Sl3_;V};C3p+-NjR`w^~ zal7&I;Ut#Imv;GHoXK%UV!aVwp+qkciFo_Da6&fP)v)IMgK|GPkKs@5<;J8E97_7o zi-9xsgE*{Xb^qBz+*BnAzW;uA^BIJ6kfK8=!v6bV{%g_hKWmARlp=2$X{$LmLKbUG zo)&nChj;yF=Th-(MU0-mU!7PhVQmr+=G&Ycd0J=mP8=C#BGkamy9fd` zCtgzJ(nU!x9R1EYl$i!$uQZ1&AfZuwTd@|ZgQ3o^$QBqea6dAwM;_Ce3;?4Q>ak$D zoZ~EaH)Qp}%GqCgEV9%WBB@3yh54K)lVyVx3i(L%)`*fRrO@M`U7b3earh1ih22${ z2YoytPxn-cFh#MlIFg`}cz(WkbfJXGT*^~A_Ya37^QU)0j`Kuj$5hE>Q>D6d0*;!w z-X5f1`UxkpNEC9KT=PNeN~jr@v2b=fdwsPG{_9_VPyf50e9Ao)%taaU9DMD|y#eCU zUtO*~V_%6w*o2tvAjFK>o@nc&7&u=FN6OTXcLssgI(aF5dj#b&YRP=M-3T!;TBqw^ z2)vZeQ9mG})Q!YC<3R|S=Xkg|xZa(Z#M5&R5)mty`ml^Gk3_=O=_%<*$kw6j&RnQ1 z&_s#CJwz-Dk2bN{_A9_aqHtNKO$ZAF zf3JP^2gE|*hD1f=q8tZh9{^Xou#pI1uQv@+&V2gt5&II*F&%_46G0a>o;>H`$G5MP z*twktAr&5v&!|;yhe6c+ck~U@r}Nj0=NEMD(9)Wm62UrS7LHtbtkCU!5lkPkmyZN80R6AJe61oJV3j0+0SAOhZw|1ll+DdqU3Sh_m5O#WOo(QDUYRffs>3i7YHCB^WuM zq~n0&1G*Nh4l6=!(2Q>luMvrnfZkK zr-PLiv-EBMF-kgl@L*1eRXEDQ>djlH=AC~;NUM-XMrMTMYf?#zqn;aa2GgD_yQno2 zqro&}MAnMfT)d7~zTPV5s1%J*oLh0NH|OisN+6(P!)}uEFLc93W^yE*m^&K)W>?lT zFvB1$W!QO&KLHzCL!}|lT;m%iiiVb z#kij@#DDWI|MUlcgASBbX{&Mdr(gYo!#YqLH;j-%U|46_#WLH{PRDSCtsPc{-Uml1 zTP4Gw?k_`Wa4g8qF%y@;t+|sCdrI=I7CD?ch1C!>T{Iyh#WO}$?6c& zQ7QRGCU}c3XRnfL+;WueLeJuAvz!lZTb7dX4T`4Z2}OT4= z>*2bu{hCl}0flk7Rl0=48lI3Xp%9CC8#MaLHHL&}V7@8ya{5#Xg~6oT;9d{T8hAdQ zbcI};U1;BuYQCnN-D}1%yG$j{=(9C}S}Ks~t+AGI-cARC#7V>RZ^c`t9uvQ~&Qn zjL7ouL6l7VpZ@Wm{V;Vh&8X>y&cK(;4X9_WewIv6UcJY1ZS&ir`E@b|hqvoaS(zkX zi4k3r5Vx91_L9k5IN9c;gz9+Y;Kdty@DyFBSPh8OHXPVb7!g{g0o~q=X|A%%z#}owgg@0~m{cV7yykgzUph zQQSJvjMZTE%RBLTdk_~;{EKUIv2+rHk^=i++65F8)}mCw_QoQ|h;&6Kq>p!QA2ao( zFlS?SA=TliKDut+$lS6ITQBXDkT_Ch8a%Iy-nvim z*JK3W*H;2m8O@nSW`8UT!4<9*S?pzP$@wi}3WWlp{mI#tug3|g$mPC$$x4C$j zl2hegZUosypQ-fr=DN1%4vJeocIZgZ=w+g#BytHn^vUz>L3?&2Ml?*Cb{E^m%+N-R z$sG|AF1w+P3)wFC)c(CSOr{vLbBk z*CgRN2GFex_g5Xa;`u<=2&`e~@?>X>8KSb560^@5QZz=GG;2f&OfyzcBrcf#O6r!P zg{o3=Bu9s?4i@Qcyb(2WmWn=nP;{m{eO^4Couf|9lpJ zm@IRdg#=+}XPKXX4!d^aZ?1{DZmd3NuY>&JAD*>st06CH5ynkuZ-XIEQmC}Wo=@j9L=*DqJiGDrE4G1{IR#QSmO1Wetw4x|kkHn=*i^QSd2Wia7d+gFFb7wN zWDVpnNX7H;uL?&Nrzs6%uEA=Hbo%Te1tXeL^ze;I=$q3&$jN1Z?29WMv@;k+MM?5uO7mAOC$ngI5j92Km3A4f7f4bkBK=@kHGE2LC%S5 znA?eUqGOT7IF5u#WvSmPLhuSMX7sj*(cD8%_FIB(?oud-c)GDmCz8Q7LjuAUNcJZ};C4|hGE2@h=I-?Jce4`$j^?a}xyxd=?hdUOtMGu>; zfr{{|>h3}DL+ff!UY`#vbn?w%t~MuOEO$IcCCtTH0y!4?)wssxa`h?1l{oVai#`bc zaNbEF^7-=@e){}{lqyvcYk0KSZ%IN*nKp$9jI|S~XXU8Xe~-}^s=R%Dk}Yw&AB5~~ zhLGV%1rz1c$z1BeEWw$TB<5`ua|jbPsUNWlwm%ajr}c6>SZJtT2enRwqpb@;=O z$Q*+);eH%GT>Y64ocL#d{NMku%qgkmrIL?GFu#gjtubczCrwOl1m1DUn4{ZDk)763 zpMvr}4R^1=(&^sw5(%Okz7d&Iv8Db#ygDjMNFF1#_kDhZl6^q;Xcs1M9EGKmumoNH z)IE>N>Q1>WwR~$0nkoO+U;NeyuCfUG!yME0sU??KYB$z$E%Q>tG?0^Dvu9EV?XdrU zia1tk4yI0*F$lzD=nTxq-2d*yqnq24kYjZfRt&rx1uW27XU;)XB~0jT(uWtDX7F1T z+Xr9I8=67WPCAC@$;==u39L1!xpLfYUd3L^U$3H9TAeOr*z$E>NRi{bbC%4Rix1eg z{yHOwDK?zq6T(58i?#3}B!Wff3aUbhg`;Gi*Mm0Sg&2wJ+R3|^Icr74xU_BMb@XJQ z332+)zO9S5(Y+ZNy&`O~yn1~s>T%=ahmX{diAh=6NRl~2_U+YZNPuU*P?WP&#!y18 zl#>{A?(kl@b$H`7WCnq0Mun}p(KaVY$bPEf&RRhPvv$L%B^^o z;yqU(MjuV&u~97&-MWK~!%p=CoB`rl=?^rBt6I1q{`O;_^~( zo})zJkn?9laN?i-!+-e0FZqP~_y6fL5`732z-`C))Y}CO*})yt-xFQWHHj&ZOTo+! z2ZzeZt`#d${OMnFq@>_L3>93^J5cqjcnq0n%QajvBh~G*j?eZlxK~i4OG=`P9j`gO zG?fFHuoY2??JwXS$2umXh~?OK{_pMJx;X*n&)P%CFfX6hE+3 z9j9H%9H9~f+RiF0Gmy!dPm*K`k(?ZWGP@gqk0Wv3KM=MJTG#Tj6Y4`-b^f1qPX(_K zXz#SzR6rd_qN90vMa|J;68Y7~@5w3B`jer?J>EFv;Ca3A_0dSVvUJd=a-MhYA6_`_ z2NvMVV|)GTNv(zZaVMbut{()6i6n*jRFWiGAB;6wB!W5NSP+hM^VaM1S<{%!=}k4e zO30KEoc9pp{*0^3P!VsVy67`wB8)kJEVaHFD}Ixi5eN#B$PzT`x6iys)9NW zzm3WBF*!EU?B_sm;y?T2fAqsI`Gos_e*5Y_i$xz+nbKSHC&q#yTgZ{URVeD>$+0?9 zCs8BIc9-2e_%qZPYL1TD1YiqJxlKnRL^mNFH{UVXSj^TLQ=M=ln}`&Xw*zw^mIBdl zC?o4I1Fl#_a%4t}x4 zfj?=7EzYwdSy;=tjy9FGCMo-drmqWO5d?1eg(JQEZ7n+ll#Un-9hez8o|vg~5{8qJ z&@JHz37L_{Xf!d}QqSfeCn+XGJF^dRDsKEG^8E7P z>Hgv;c-$~il&(rhnIk240H`-GT@DlJ>)pY)w_4(d@6v^+f5xLEmIE5x>J*9-u7X#q zujMJum|YR({zvg`Mf925^Xg#svmrR~pZ@Xx@WU_pg!@1L(iPT*cymj39ULS~j{pD@ zcS%G+RMboVtldGs)tk>SwhOV3!R(!!_j|c5BnWL8YbDo5DX`}B3kiu@3MoOmI%Dgj z+0YXg{1k!+)GcLA<{wfO3dV<2+zF8*H5R`u4L_7kl{P!d*p{Nik%~i6-CF3@qO{0q zm&Gt%9~WO9Z&&*WIjA91b0rE$G*a=u)zvP7CXSl-Fj!q;V$s80rkHkgy9aA3Xz&JL$r({U z07joo7PTCt;IJ7dZ25uHbz!#rW*J;ux^!U@silAo+I;?O2u}Q`|KLx4_$8lk|L*_& zEkoCCxciDxgHL=(0wHtO!&gHRS=LaUEOkDj%RP6d*z}g<7;XgK7X&xX?)|H) z()_6{;szgyz5xjl=2YhByi0CkT8zF3CZ19=_b}dX{ywfcooNswX8v9;;sa0#=0TTQ zTw~q_Dq93OCbM9T)peRmbYh%8;!LqI=r88)Z)K$ zF^913x6G-|XUw4ztJk&#apROhYklVe3MsnKw{IY9iT(=NTKm}$ocOQ)*`NRLOFrTL z@4xzM#^sZ56X*8F=o<>xX$SYGOC}k-J}$1SV@o&p4xa(25y)6dq?~b?uOTaJxTW#d z8^;m3A9n|PT%9!yp^|GPCLgw;gq7c>nke+O7%5i-~S#_-3MXQ-FxprGE=|f zhy_%I5Zw=O=FIoUM~;vQEP@7tC}VZ5@j$1)FdV6pO5pS3iLS}Z%Z(4W1D5jp-~WN1 ze*6QA#&;j@e7L_LaWQBmPA)3Dcp`i0It=x@WQy-Vs_^al$xm( z`g&uG&u%I%U_t$|hPlIO>h#cB7==?1igA@O9pC7$06DxgQ3{RQIb38b8r9#qQq1vR@(}`+>5-1;w-|S*^A7iTIco2f{ zQW77J8zG4cGy|9pH##GXJ{W!Qcy=@FXEE<-a5`3$N zLr-kMG#>)4Nr{POjhuyBIXB@dAq3_ezP*X!;V)^NS@`~TCxk#(c-rFg^GRzEEs%n6 zzGU(VExd8*wGGV$;$pRiY{`j9WF|jsR$rvGsmRI8K1Vr8rMhgi`9sESzJ3$(;Vty5 zGuLqARS;^15Z&@sYDJ^c^g+xJ#b<0L>{m>89<-+t|F?hjKmYJcKH+}zyEg=L>4S-H z0s3IdUXdXlk?;30zN)ry@>8c1EBfd&*4^MjP~|+;2B-^MNe4#2hBpa4yaZ+oMfs!K zeSe4-OsC_tY0Ma~ssyX#AcW{Jw1wlfaz1#p&hvW1#JJxNe*LRok;C0{2O*MUVCW#m z<8KqIbFZUIr1i$@dNPwM;KhuRjvXX=54m-g20|$06cHJ$Ihp34s~J4nE7AFwF~rRy z^fqBRP6*KFVCitYm}6FV*v=!xGYljJYVy^kiR@dOx~Oz5#?>gvw@&I#J!K0!W_$81SJw}XZNFLqzU|N%-3&z_ahT$uq`pq!KflB ze)Gp;g7x>HPb7%9yFvh6nSQy+NMfV}+gR;HJ}Oa_6a($?q>t&b-F(LcVo;8pNXfw{ zsIkn!CiB_8aot3X;|NGeZd%@7+PM~eHdl(jlYAv|h>=8y-abHVU_m(Q>6-`tB1+lG7VKl&4XTI3)4lZnX?wAO-EQ+BIZoL z6w^cv)p1=Iu_!Tk+;^;tB$bd8tv^{~_`p@2tMF3pq*xeh(q?xH)y9hZ&0tZ*|31f& zs3mdr#k55?MF^bbpjN|Hhq%bmZ=foXV3pUmCy(}-Uw{7{-+lNMa~N0ihUK&Sz_^wZ zk&VxqiiJijP8`148!KF1|CT^H3MFPH{+W*mO*^K+Z$?2_LxJd9q_Ah;n;M;h|If{w zYbhx@`DrL)4c~xdKgex2FwK&ajMqYvzaFNLk>F^)KqQ3e4?#7~a;God-oqVzkI7-H z|Mp+}`47M36Yf9!)n}wQ)WXwz9{qIMa7X7v6*T)hN{-pfKDzuC5?l;w5_WHUf{G)~ zv2Sw)vB?o5xAQ<^Le!B|;G|8nfQ<01dK`j4R3hqo{TQ(jDUuM0EL_K>>T`n>WmgT9 z^p5*7SFH=;dG-yb)Ya)@Lh#wdT<$Ws=A=Y8^NSA)bF4VwztG?xVxJEogC8Wtw6U@l#+r{gnb1Oc?BuqYi_d?2n zFVC-Bm+|`b;`7(v6KrwTPY#)l&Vh9Buy0r19&e0m`U6CKuzc3Thr7Y4$8XJVE@yp* zaRwKbveCv`P+f%Rn-39RJ&Os`hR5x3haq%I5b}jyT!!NA zN99Z>!#XjiE$?w@t(X!2*MITnKm3wUxZnK8pZsU@$t7yj(`OP`y|b?2ZNVhO6p7|R zo1n=Li<}?|Z5UCFoH8*)i~+0pu1&lp#@yHU6cGkC?T9qC#Ine@@zLzK(uxVQ#RjZ-k12UL|srL^&Npcgq#09!^qt-$q3u zPLO&$I-kG3lA?=T*6Nf)II1@XYrPX?lc8>RG`RRBN4GwyZ0Bq=+8p#Y$ONc4^&!}JnC?0=R3tZ36^}M_wbuZri z$Ke8VT=Z85RumE9QJ9jE?j#~psNyJh6(NM_nCT-?HWWpdAi+J2u@+8zDA`^w99olo zOR<#jaeDJnJAMBR$8c+IB9TKyB2&fQF9g@3PYo_FB*p??op`lnd{Y-xHj*^0+RRF3xgr)`ETTw%~dQA^Pt;sd0vi@+fM9TKxU0cVW!Lu*IB{sc{p9{L7hRBpivA{69N|Nj)O1 zC$v3jtJ9}AVm;?_M>Q<*te-(12`f!#<3m zoh+Uf?Q8jL1a;qH@mD(+XLu;y?ZLVo962$yf<~tKEankAF*?MS&ZI|@$B^QgmOTDFn8QKRbFb~>)R{sF{r0P zh-i#H)D|QD>wo@Feki%_tKsmpn+k0_2r+S#6P^CyzUN~j!#lF6K#-`}>$h`G-&;x~ zrr=2^lxRDC%R7`}I;~{KI6MACeV@wvWM18Ik88Mc@)ORYePhc19L(2W{N*1YS3-`v zwz@s&2D2Ha&WC-KV|+T2BWU91Jex5|EaBv{kv(+6=ZC1w0|WkL|+{^5mE z)2`A^PXIRaSDzT@0;?@*iauKq2*KBeMS{-*EW&fbb3hD;c|gbox4x+$c}+GYw>-xZ zkSv7dgF033@Zax=lq*5~y`3=W%XmB<^tTHeN(|~6?IT0>--*RU$_Jm$lcQEX-tUAM zXv6stGr(L=j!@n8sJ`|zoH`ShktJgR?)e}~CZI@8NDQP9{GB^{Vp4}fOdj;=on+u& z7oQU~6>RxIf5zy>CcF(Q7BLBo;2WJYRWc`25{tyGe&EA#=XS3c%CbN$ANlUn_k6m) z>>*l5SWa0AE;Wf32`TKvoe$l9di{yfI%bI_O0967m5>6a9+_{xT=Ktd6jY31KCHCm zCw_dtfr@{@RhHAQVx`0kOBrhtl9#kZT!R;aGa_d9HgBw6gp container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region TileExists diff --git a/MergerLogicUnitTests/DataTypes/GpkgTest.cs b/MergerLogicUnitTests/DataTypes/GpkgTest.cs index 82c01d8f..6108e7b1 100644 --- a/MergerLogicUnitTests/DataTypes/GpkgTest.cs +++ b/MergerLogicUnitTests/DataTypes/GpkgTest.cs @@ -9,7 +9,7 @@ using Moq; using System; using System.Collections.Generic; -using System.IO.Abstractions; +using System.IO; using System.Linq; namespace MergerLogicUnitTests.DataTypes @@ -18,6 +18,7 @@ namespace MergerLogicUnitTests.DataTypes [TestCategory("unit")] [TestCategory("gpkg")] [TestCategory("gpkgDataSource")] + [DeploymentItem(@"../../../DataTypes/TestImages")] public class GpkgTest { #region mocks @@ -62,8 +63,7 @@ public void BeforeEach() .Returns(this._geoUtilsMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); - - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region TileExists diff --git a/MergerLogicUnitTests/DataTypes/S3Test.cs b/MergerLogicUnitTests/DataTypes/S3Test.cs index a89ad970..50b286bf 100644 --- a/MergerLogicUnitTests/DataTypes/S3Test.cs +++ b/MergerLogicUnitTests/DataTypes/S3Test.cs @@ -11,6 +11,7 @@ using Moq; using System; using System.Collections.Generic; +using System.IO; using System.Threading; namespace MergerLogicUnitTests.DataTypes @@ -19,6 +20,7 @@ namespace MergerLogicUnitTests.DataTypes [TestCategory("unit")] [TestCategory("S3")] [TestCategory("S3DataSource")] + [DeploymentItem(@"../../../DataTypes/TestImages")] public class S3Test { #region mocks @@ -81,7 +83,7 @@ public void BeforeEach() this._configurationManagerMock.Setup(cm => cm.GetConfiguration("S3", "bucket")) .Returns("bucket"); - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region TileExists diff --git a/MergerLogicUnitTests/DataTypes/TMSTest.cs b/MergerLogicUnitTests/DataTypes/TMSTest.cs index f969b056..fbd30f71 100644 --- a/MergerLogicUnitTests/DataTypes/TMSTest.cs +++ b/MergerLogicUnitTests/DataTypes/TMSTest.cs @@ -9,6 +9,7 @@ using Moq; using System; using System.Collections.Generic; +using System.IO; using System.IO.Abstractions; using System.Linq; @@ -19,6 +20,7 @@ namespace MergerLogicUnitTests.DataTypes [TestCategory("TMS")] [TestCategory("TMSDataSource")] [TestCategory("HttpDataSource")] + [DeploymentItem(@"../../../DataTypes/TestImages")] public class TMSTest { #region mocks @@ -62,8 +64,7 @@ public void BeforeEach() .Returns(this._loggerFactoryMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); - - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region TileExists diff --git a/MergerLogicUnitTests/DataTypes/TestImages/image.jpeg b/MergerLogicUnitTests/DataTypes/TestImages/image.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..af16353152224db6f5a6723fbb68a607b6e13e2a GIT binary patch literal 8824 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 literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/DataTypes/WMTSTest.cs b/MergerLogicUnitTests/DataTypes/WMTSTest.cs index 57684f87..cdad773a 100644 --- a/MergerLogicUnitTests/DataTypes/WMTSTest.cs +++ b/MergerLogicUnitTests/DataTypes/WMTSTest.cs @@ -9,7 +9,7 @@ using Moq; using System; using System.Collections.Generic; -using System.IO.Abstractions; +using System.IO; using System.Linq; namespace MergerLogicUnitTests.DataTypes @@ -19,6 +19,8 @@ namespace MergerLogicUnitTests.DataTypes [TestCategory("WMTS")] [TestCategory("WMTSDataSource")] [TestCategory("HttpDataSource")] + [DeploymentItem(@"../../../DataTypes/TestImages")] + public class WMTSTest { @@ -64,8 +66,8 @@ public void BeforeEach() .Returns(this._loggerFactoryMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); - - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + + this._jpegImageData = File.ReadAllBytes("image.jpeg"); } #region TileExists @@ -637,7 +639,7 @@ public void GetNextBatch(bool isOneXOne, GridOrigin origin, int batchSize) }; var tileBatches = tiles.Where(t => t is not null && (!isOneXOne || t.Z != 0)).Chunk(batchSize).ToList(); var seq = new MockSequence(); - + for (var i = minZoom; i <= maxZoom; i++) { this._geoUtilsMock diff --git a/MergerLogicUnitTests/DataTypes/XYZTest.cs b/MergerLogicUnitTests/DataTypes/XYZTest.cs index 8bec11fe..211a985b 100644 --- a/MergerLogicUnitTests/DataTypes/XYZTest.cs +++ b/MergerLogicUnitTests/DataTypes/XYZTest.cs @@ -9,6 +9,7 @@ using Moq; using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace MergerLogicUnitTests.DataTypes @@ -18,6 +19,7 @@ namespace MergerLogicUnitTests.DataTypes [TestCategory("XYZ")] [TestCategory("XYZDataSource")] [TestCategory("HttpDataSource")] + [DeploymentItem(@"../../../DataTypes/TestImages")] public class XYZTest { @@ -62,8 +64,7 @@ public void BeforeEach() .Returns(this._loggerFactoryMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); - - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region TileExists @@ -635,7 +636,7 @@ public void GetNextBatch(bool isOneXOne, GridOrigin origin, int batchSize) }; var tileBatches = tiles.Where(t => t is not null && (!isOneXOne || t.Z != 0)).Chunk(batchSize).ToList(); var seq = new MockSequence(); - + for (var i = minZoom; i <= maxZoom; i++) { this._geoUtilsMock diff --git a/MergerLogicUnitTests/Utils/GeoUtilsTest.cs b/MergerLogicUnitTests/Utils/GeoUtilsTest.cs index df06cf55..8740ccbf 100644 --- a/MergerLogicUnitTests/Utils/GeoUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/GeoUtilsTest.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; +using System.IO; namespace MergerLogicUnitTests.Utils { @@ -12,6 +13,8 @@ namespace MergerLogicUnitTests.Utils [TestCategory("unit")] [TestCategory("geo")] [TestCategory("geoUtils")] + [DeploymentItem(@"../../../Utils/TestData")] + public class GeoUtilsTest { #region mocks @@ -23,7 +26,7 @@ public class GeoUtilsTest [TestInitialize] public void BeforeEach() { - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region FlipY diff --git a/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs b/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs index d9d4b7ec..dc5ff40b 100644 --- a/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Data; using System.Data.SQLite; +using System.IO; using System.IO.Abstractions; using System.Linq; @@ -19,6 +20,7 @@ namespace MergerLogicUnitTests.Utils [TestCategory("unit")] [TestCategory("gpkg")] [TestCategory("gpkgUtils")] + [DeploymentItem(@"../../../Utils/TestData")] public class GpkgUtilsTest { #region mocks @@ -47,7 +49,7 @@ public void BeforeEach() this._fileSystemMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); this._loggerMock = this._repository.Create>(MockBehavior.Loose); - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region GetTile @@ -129,7 +131,7 @@ public void TileExists(bool exist) } #endregion - + #region GetBatch public static IEnumerable GenGetBatchParams() { diff --git a/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs b/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs index 5a86da28..bfc9faf4 100644 --- a/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs @@ -3,6 +3,7 @@ using MergerLogic.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using System.IO; namespace MergerLogicUnitTests.Utils { @@ -10,6 +11,7 @@ namespace MergerLogicUnitTests.Utils [TestCategory("unit")] [TestCategory("http")] [TestCategory("HttpUtils")] + [DeploymentItem(@"../../../Utils/TestData")] public class HttpSourceUtilsTest { #region mocks @@ -28,7 +30,7 @@ public void beforeEach() this._pathPatternUtilsMock = this._repository.Create(); this._geoUtilsMock = this._repository.Create(); - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region GetTile @@ -88,7 +90,7 @@ public void TileExists(bool exist) var res = httpSourceUtils.TileExists(cords.Z, cords.X, cords.Y); - Assert.AreEqual(exist,res); + Assert.AreEqual(exist, res); this._repository.VerifyAll(); } diff --git a/MergerLogicUnitTests/Utils/ImageUtilsTest.cs b/MergerLogicUnitTests/Utils/ImageUtilsTest.cs index 0b7f4e72..cd50ed5e 100644 --- a/MergerLogicUnitTests/Utils/ImageUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/ImageUtilsTest.cs @@ -1,6 +1,8 @@ using ImageMagick; +using MergerLogic.Batching; using MergerLogic.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; using System.Collections.Generic; using System.IO; @@ -89,61 +91,74 @@ public void IsFullyTransparent(byte[] imageBytes, bool expectedResult) #endregion - #region IsValidImageDimensions + #region ImageDimensions - public static IEnumerable GetIsValidImageDimensionsTestParameters() + public static IEnumerable GetImageDimensionsTestParameters() { yield return new object[] { File.ReadAllBytes("100x100.jpeg"), + (100, 100), false, }; yield return new object[] { File.ReadAllBytes("100x100.png"), + (100, 100), false, }; yield return new object[] { File.ReadAllBytes("100x256.jpeg"), + (100, 256), false, }; yield return new object[] { File.ReadAllBytes("100x256.png"), + (100, 256), false, }; yield return new object[] { File.ReadAllBytes("256x100.jpeg"), + (256, 100), false, }; yield return new object[] { File.ReadAllBytes("256x100.png"), + (256, 100), false, }; yield return new object[] { File.ReadAllBytes("no_transparency.jpeg"), + (256, 256), true, }; yield return new object[] { File.ReadAllBytes("no_transparency.png"), + (256, 256), true, }; } [TestMethod] - [DynamicData(nameof(GetIsValidImageDimensionsTestParameters), DynamicDataSourceType.Method)] + [DynamicData(nameof(GetImageDimensionsTestParameters), DynamicDataSourceType.Method)] + public void IsDimMatchProperties(byte[] imageBytes, (int, int) dimensions, bool shouldBeValid) + { + Tile tile = new Tile(0, 0, 0, imageBytes); + Assert.AreEqual((tile.Width, tile.Height), dimensions); + } - public void IsValidImageDimensions(byte[] imageBytes, bool expectedResult) + [TestMethod] + [DynamicData(nameof(GetImageDimensionsTestParameters), DynamicDataSourceType.Method)] + public void IsValidImageDimensions(byte[] imageBytes, (int, int) dimensions, bool shouldBeValid) { - using (var image = new MagickImage(imageBytes)) - { - var result = ImageUtils.IsValidImageDimensions(image); - Assert.AreEqual(expectedResult, result); - } + Tile tile = new Tile(0, 0, 0, imageBytes); + var result = ImageUtils.IsValidImageDimensions(tile, 256); + Assert.AreEqual(shouldBeValid, result); } #endregion } diff --git a/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs b/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs index 3a713203..0706d4c7 100644 --- a/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs +++ b/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs @@ -4,6 +4,7 @@ using MergerLogicUnitTests.testUtils; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; +using System.IO; namespace MergerLogicUnitTests.Utils { @@ -11,6 +12,7 @@ namespace MergerLogicUnitTests.Utils [TestCategory("unit")] [TestCategory("1X1")] [TestCategory("OneXOneConvertor")] + [DeploymentItem(@"../../../Utils/TestData")] public class OneXOneConvertorTest { @@ -30,7 +32,7 @@ public enum OneXOneConvertorParameterType [TestInitialize] public void BeforeEach() { - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region FromTwoXOne diff --git a/MergerLogicUnitTests/Utils/PathUtilsTest.cs b/MergerLogicUnitTests/Utils/PathUtilsTest.cs index 2a93bc82..3002162c 100644 --- a/MergerLogicUnitTests/Utils/PathUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/PathUtilsTest.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System.Collections.Generic; +using System.IO; using System.IO.Abstractions; namespace MergerLogicUnitTests.Utils @@ -12,6 +13,7 @@ namespace MergerLogicUnitTests.Utils [TestClass] [TestCategory("unit")] [TestCategory("PathUtils")] + [DeploymentItem(@"../../../Utils/TestData")] public class PathUtilsTest { #region mocks @@ -35,8 +37,8 @@ public void BeforeEach() this._fileSystemMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); this._imageFormaterMock = this._repository.Create(); - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; - this._pngImageData = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); + this._pngImageData = File.ReadAllBytes("no_transparency.png"); } #region RemoveTrailingSlash @@ -88,7 +90,7 @@ public static IEnumerable GenGetTilePathCoordsParams() } [TestMethod] - [DynamicData(nameof(GenGetTilePathCoordsParams),DynamicDataSourceType.Method)] + [DynamicData(nameof(GenGetTilePathCoordsParams), DynamicDataSourceType.Method)] public void GetTilePathCoords(bool isS3, TileFormat format) { var utils = new PathUtils(this._fileSystemMock.Object); @@ -120,7 +122,7 @@ public static IEnumerable GenFromPathParams() } [TestMethod] - [DynamicData(nameof(GenFromPathParams),DynamicDataSourceType.Method)] + [DynamicData(nameof(GenFromPathParams), DynamicDataSourceType.Method)] public void FromPath(bool isS3, TileFormat expectedFormat) { var utils = new PathUtils(this._fileSystemMock.Object); diff --git a/MergerLogicUnitTests/Utils/S3UtilsTest.cs b/MergerLogicUnitTests/Utils/S3UtilsTest.cs index b6c79901..19739c8b 100644 --- a/MergerLogicUnitTests/Utils/S3UtilsTest.cs +++ b/MergerLogicUnitTests/Utils/S3UtilsTest.cs @@ -21,6 +21,7 @@ namespace MergerLogicUnitTests.Utils [TestCategory("unit")] [TestCategory("S3")] [TestCategory("s3Utils")] + [DeploymentItem(@"../../../Utils/TestData")] public class S3UtilsTest { #region mocks @@ -50,7 +51,7 @@ public void BeforeEach() this._loggerFactoryMock = this._repository.Create(); this._loggerFactoryMock.Setup(f => f.CreateLogger(It.IsAny())).Returns(this._loggerMock.Object); - this._jpegImageData = new byte[] { 0xFF, 0xD8, 0xFF, 0xDB}; + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } #region GetTile @@ -69,7 +70,7 @@ public static IEnumerable GenGetTileParams() [TestMethod] [TestCategory("GetTile")] [DynamicData(nameof(GenGetTileParams), DynamicDataSourceType.Method)] - public void GetTile(bool exist, GetTileParamType paramType,TileFormat tileFormat) + public void GetTile(bool exist, GetTileParamType paramType, TileFormat tileFormat) { var seq = new MockSequence(); var data = this._jpegImageData; @@ -97,7 +98,7 @@ public void GetTile(bool exist, GetTileParamType paramType,TileFormat tileFormat It.IsAny())) .ReturnsAsync(new ListObjectsV2Response() { - S3Objects = exist ? new List() {new S3Object(){Key = "key"}} : new List() + S3Objects = exist ? new List() { new S3Object() { Key = "key" } } : new List() }); } @@ -135,10 +136,10 @@ public void GetTile(bool exist, GetTileParamType paramType,TileFormat tileFormat tile = s3Utils.GetTile(cords.Z, cords.X, cords.Y); break; case GetTileParamType.String: - if(exist) + if (exist) { tile = s3Utils.GetTile("key"); - } + } else { Assert.ThrowsException(() => s3Utils.GetTile("key")); @@ -167,7 +168,7 @@ public void GetTile(bool exist, GetTileParamType paramType,TileFormat tileFormat { this._pathUtilsMock.Verify(utils => utils.GetTilePathWithoutExtension(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); - this._s3ClientMock.Verify(s3=> s3.ListObjectsV2Async(It.IsAny(),It.IsAny()),Times.Once); + this._s3ClientMock.Verify(s3 => s3.ListObjectsV2Async(It.IsAny(), It.IsAny()), Times.Once); } if (exist || paramType == GetTileParamType.String) @@ -245,7 +246,7 @@ public void UpdateTile() this._geoUtilsMock.Object, this._loggerMock.Object, "STANDARD", "bucket", "test"); s3Utils.UpdateTile(testTile); - this._pathUtilsMock.Verify(utils => utils.GetTilePath(It.IsAny(),It.IsAny(), It.IsAny()), Times.Once); + this._pathUtilsMock.Verify(utils => utils.GetTilePath(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); this._s3ClientMock.Verify(s3 => s3.PutObjectAsync(It.Is(req => req.BucketName == "bucket" && req.Key == "key"), It.IsAny()), Times.Once); From 61da9e56499e96f415180f8af27ebdd2a1caf591 Mon Sep 17 00:00:00 2001 From: Nitzan Morr Date: Mon, 1 Jul 2024 02:26:40 +0300 Subject: [PATCH 07/13] test: fixed the tests that uses data row --- .../Batching/TestImages/image.gif | Bin 0 -> 38456 bytes .../Batching/TestImages/image.jpeg | Bin 0 -> 8824 bytes .../Batching/TestImages/image.png | Bin 0 -> 128678 bytes MergerLogicUnitTests/Batching/TileTest.cs | 22 +++++++++++++----- 4 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 MergerLogicUnitTests/Batching/TestImages/image.gif create mode 100644 MergerLogicUnitTests/Batching/TestImages/image.jpeg create mode 100644 MergerLogicUnitTests/Batching/TestImages/image.png diff --git a/MergerLogicUnitTests/Batching/TestImages/image.gif b/MergerLogicUnitTests/Batching/TestImages/image.gif new file mode 100644 index 0000000000000000000000000000000000000000..1af68430045a2d5138b1e0c0a8500669af2d5e3a GIT binary patch literal 38456 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%0DJ zRwSInwWl{c5nCgEDX{TCNL;8vQ&a!;Vyx8M5>_iggBQ^7!qk0;Bnh#|%<^)dgIGl) zYQhy-R`dbs9#b$vpc;j5DR#8T9qPgmJfP=HLg@q^x`4tu2+B5&xQdD* zYR^qfM3w!sStHP}g)Yz`D~f`Vf0*bri%zO3bBj=D+{85kdMklUGZw&B2G9>?O*D<6 zl|d(pI2pmnI6X^Lu?P0Uj>n39rB98u#a}VTiDW2feN?uaTIK6;{1%q zzRtx=O;;UPaSqorM3D$h_1g`h;-!!z`e%ttZ5q%@fd@Bu!3%aJ4`c9jDRpKHH)$2l z--?Hl@NH#Q;~bNTC`J&2fHSyI?F?v&*E`Y}3}$UXg(_t63olaSvXxZ@V5aNY$9#yV zLbb@L1V)??T{W-JLy8*XgR?|UtVH~I3q~R2p4)Qa2t^>l6d-nh+g`b|R^* zal&B_#R?j_&;>M5hm{JWj2X~C#KmTElKDk!!Hid%my}{Ty<6FxXaq2qsX`T&?P4j! zt67H5M?S#2)y*fpP>al>+=^ny zl`@@zg2n=|8B0t*t~9C+bZEpXBB6#u0BjX|T~?zxfd?;a!3%d-aAdpoK0p=wl<67B z`wEz1=cME%u$;EamUbzr!mxj@df;E+qM~%&Wj$=oZXmm@fW}F_{v0nAh+o7U?pd^tQ09xD3Z2`kcOJmLMjmGZB8R@a04OdwsV}b z7Y*scBbA1N(8;;6hjKuJ94_3fpX}j`fmazO+WP{NJWpovvf>51GNrO7*H zU6NH$Typ<;?oCK6G7I4|Z=X$xK)j0aZTF7Eba&9se`zbTCI>1@0rPR-1wYCVQe9QD zOUjGD1vh*fkL)FUmAqpY9I;{2n7{)a&_IW3mf7FJ`6Ya+B^nP!wj>Ts1Ra!c0wpX0 zfxNehP)(Ay&nn5t$@}v@Usf+@F5BSjB`oIwUpb}{02D5C&@0C%xl!Thp zm5PANPap*SnV$!$L?XBWHCf+^gd4(830L67_fg3&#oBzak@UfvL?ll={RA4hM~>Xc zB51-TxC{Um31|fwR8U`|h26M}PAZuRgK&$5#L@x+jAa#0bI?V_36wp_Q%~%iUCo}l zsSp2>ZD6d;kYS(*A+1y*TmctU6XAW`2W{GsBug4SMI}X!aHty6MMa7LQ`2A|tRw^` z)Ik>%0UOA|Fs#H7h8))1;Ml27#jO~fq>@6ojD=j*ivfj?z|(KI)8B9lYXFo*?cCL9 zpeY&4MKF+*Fk8B%4p4~JvQVFJ2vwap67)2Mv6$9yIEwR}N^sZ#aRuIB90=BtT>rQS zR!~hA@QWd&ShFPD%5@#hv`sRxnk1r3{1K5B?S!?-j?0LJjTl0oH5kVA1|+`K%B3|7v(%nP^(l#cNj8%S9e)ItAS znBswDhK?oLd1WBr*u+GzUBGCflw88Ucwn1Oi_~3PvMT#u9J=5xH7O)ly=yiX@_< z@vzKlz>OCD3&5n}y==!Kc;#1qWiA3v?m)~-d`3~BB+JcDt+0x~0F7x3QR6hiCd^>F zvD|tfPOChHx{O=qbA z0xU62NLGhsjY4)9LUxE|c6eot=nqjoh#7fCFMx&^!iZu`%38_@!;}yC>CpcRVURGj z3gU^7@%b3y)C-mbnNZNd7BImUpg} zja&zJER9zlf+C2gXl}>9RA>795qb~=-0)91p5~;q8r_*uiVe^PqLfO2lnPcFL-B=h z4u_-J5k?h7aF!N|G|H!Z;3>gW{5Z(0SP!x!nsl1n$;}ydW>#it+-9alBSb=teCSsa z1y~ZrhlUSd_|GRP%X1;mTn%V^R;0a^9AtD>&izCT&ezNx*hYn$;lT)j7U+8z#cDO- za!wTusnbFr(wuP(dX-pbU1)|zL?3O-gN!J5h$xAECy?q)MCMK|BHI5(MJ1xSAMO|$ zvOPtnQAP_c1y4vOXtg6tIv#=M6?_PWu9R0wIcZZ8#u35Rwl%4l+@M`dWX-&owRz)| zB2bZ_1xTVrSBmI}mL^7x&Xc@mB2Go5KLF-1jT z4xQ2xL^#y3sSaW`QA3c`)}W456~ujNPDjNjqA5*g0Y+syD!^RnqiU(7PO68BrISQh zMo92r(rxom55PB`9*i;CxIG zj_O}vt2ZrCvBik900|4R(4royXCA7Q?j(@bNTedGc0B511_l2fSHF z%unF_AN(QK!ulVtWNHIVT8tzGQN*La#p5IR8(>JqP@dI^L}H;`MQUWKQY=|j945D| zTryok&gN{uW>zKwNrv_jh?*$D66kpniAyn-p}5<*92ilQm~^_7@CD0$WP)%!D{vHr z%gxfe)JQ;aMmQN)XHg1@;L&C<)XD)Bq7e$T3h9{q#qa@Ob?$_tW~HzqP)G7?W=VpH zN`fRT&Cn9XC`1C_cIb#AtXP@`d|VKutSVChMrsTT5^btWC7V!K4@m9BM2T#;)+v1P zn<*W~T%;^drB~qfAoh9BfQZ|XcqyZ@E%Y>3Itd@G&h7uBf=b@L7~TRc0!f00_ALSp z?eBI+!5Xf1ECQhkqDU!E{JAkcr1h*SXz(rz2h&=;~~#CwTRax~Bfkwn#s2~Y-I zwOR$Hl;B?=ZVr_ESZXVAc!+Z6x^Z z(x8PKCu<~xry`K%cBsk=Cc?1&39Cp7idsn(Ee#a%YH_howj8Os4bR{d%bgag!>lS4 zj|dc3j-a4~N&L`*foV{H+6rk-Q;5)UU{1b)%OOKxv7xbBIO-x;#CCL~TCk8BXDAyZ z(00HvcBq9M&$3#4r6jOLijCvnX-UoF+)EB5ei-ni| zqC$zjad)sWfmW7vPKwh)BY-9I*jx)xT1 z1ygd+tA3pAe3?!sP|$(C>=ips_I`4F>JyX}$2>aJnX*r2?Nw!YW=9I4SIYBwUWzNz zbd3cqM!B&*1GWA&!etS~BLsC28Uh@I#Y%{UQ{Zudz@1ZDhg(F}{!(bQaK-f*V``a{f}&?CDIKiA|7#Xn3`vW+*I=LeBd3(H@r& zidQ4Fu>c!3O?#$hd8XfTmw2(#a#x4ir5Mj(L>>|p%jgdk zwHg#0L8`J?DoB*9bMW&B3h?vr@d=43ND7I_iSqGDsY%Nrkjl!+ zf|43K>WbP5O3I4=iGb+n=osi3;EarLMPWW+#s4$@3<0dP|HVWN5&@`KLDa0EKcfH- z@OS?g!2f`X8VmwxAb&Yk7Jv#wO-%&`LjVZ%e@8%6tN^tzm<_3C%Pw*qL!+3Q$04d; z)i%tjWQUHJ+y4B;{;wVUKf(Vk`JW**_%9>K`u~~#-HZ&;n>n+44ysbt`xyDE26O@-LyRnOG`?aeU9`LBB2a4KDbsE zn)^Zr;Bmve=x381XbCK}l?EP&MMz){^t@!k)+*`trEjP7=~i8nIje`gJ826;Nml1r z#$TkOP4klizwEAyPwDME!?$lcBn8`f*%z5gh)5SRb{)HQ(|PKj;0N&jnd`>t%1-jh zuHIEDYxTwblErcG+l0N9LUNdeL@9% z_VM6IZBN|*C}qb+*LDR6LN@oZ;dPZA4&V*|PEAmU0A0`peGIE;H= z>g_-W*w+k&?bdRyQt7qYbus+6_1My{j5h8=oDgSkvBwD z`0Xqwd2x`Al26`9-M`gXO{Rhf&DG{!_b@9h$c9(7FSjVkeG*Nvu9GRtuGxI>P`qTA z#aky3pY}7UgSZuXt7n4xlS55|$95_|ZGCGX*YCS6hwd8On}&8L#f}~K{Ube0$6zJr zixZFCa7}9ehCX2$VbHRVt*^MKXIpv=v$qU1K9qa^yV2?A)qeF$wvKKhGQTVno<@0x z>2YT1BKruh_G{L+xo(Bk=W%YP4iP3B4&FJ>!e$W>E3s!J_5g;GE(7w$f7i7>{d=L zTXtHT;47v$xfyj*I#{NUwUVC(+2+_{BDNUfY$5{q-S1?;Bt9|3b?}Yc=Bnm&)Mec##8Am>Ov`c_+kv9LsYJnAMARFSWxMI+GT_Qo!4tvBT==IRT^-az8Z8$R z&(BZScD;048H`niG`xk3!Zto~)v4OAZB!7v8H*8>74{AfI8qd$%J-%vU!SQcD~#Wb zn7g#((3V1NsY2Sakq3*h3J)&mH=2NP^LaVnl?~n*n$B>(N6jk~|GF6N;++vrbc{JU z2%2yoQWWoQwe6EEKY0XOiI+@eHEgtCabwNaagm8w)7NMqU4B-yGRj;kk$0)A;$KWGq9{7mKdufyl|> z*Q`iD<_{39bRJZOBKRKt%QdzGSjFrPnEO!(i;Cn0sMnap+ZhV>AMS9EU^%kt1B-~D zCa2<+%RB&ci#Ao*#urwse4qDw+tM*5&*Yk&n2dTCLga*TY4w0?C+V~dJ7wZ43Xy%s zggtHXUJDLstTv@G<$QYkAt@Q9oy4=&dA2yZrq?Y^<^KmLycFJd&C40hK&ADCXk6pm z>l(FBWR|0NR#}6P#oEP6cIS(V8y$2K)W*}xpB#iQiCa%yJ{93|&l8GVv1ip!?f;5_ zH?K4boJ#}qVVb>{gz`$TA6~<1Zt#Q4gZzaAl~M)*v2`0uowcT~9>|P(Sy%;6OGXn^ zkGmS`#9#F~JX;52OY6frS9`X`&;Q;XMiiMtTgR+*OD+2-d|?lp(_0puhFJM~?{vil z!J2;n&W2HeeHJi|0p%1C$7e^`)XGu~V~Ci8o>eFA1DlQx<#n<$vubK$OdZK^`BCha zgWi}?*lzb%t(ba*kn^``WXfIa3cR4agP}WBz4}S-8v}6K5IVu>z%*Fb-Pd1G8Dr?! z)j;EYYHe#8lj!Uf`X=VwX>dmdi9n!JKo8-u(@W0fpob>)r#kyzcww_v!T_pDhR|Zk&tRl-Yfn32rCpS zj3S$|&?wnVUW$^=PS@j8JYFl__aqBvWu4VABQJ|ApEep*D}jrq6JcZfEHx##blV!9 zd(}It^AOW1Typ*~Dk4WOTQK>wsp2ljcOULtg5=P`bw|g?7KQf6BbmHtRQ9;W&h5at zf669OkOJPD&l|7SST&D^c!|VjhqW%CJ{N`oTzibx$zOv`VZ|Gnsp3E9ltz;V6YAd0 zjL`UXMQq>t10cnmdPTlhF0KyrnMZ7i-<;%0ZqxhxdTlv!_Xx%;*Z(VUx+c_W!)!g# z%J`5adGUj)g0$F%T!QzHx?^^&x}az$IjM&*>zkHV(E)(ahOdZT=bd_mgJQ~*sf3Hl$7~%V)c_OOP*5O3=9czc)$Iq3^I!QZ4(GVS( z+8t&Nrc7R4mHW=6TS3Y*JE-0__Xp&9A(l=d@_4jB!DvkTk3a zq(!3ISW0x&B6Rl%VVUG^38CC0?Ct~c$SVXZ`UVz|I~L6qtwoZtRR=x26p}a8C=!~+ zfKHtiE)PuSigfy(EwKXZFwuAqOb5)~ zeyt|&U(N%G2fX$P+x_OB3NFx3U+?4}I4KK2swu0C{ZpMmD{@y?QZ!oaL})>}pWNWt z>Dc1Kp4;y^$2N!W@I`T`5%=1Dh|%B9e)T}2eG8pFj>ghb(Sa*4x-FV0%}fC;CE9iP z7msM0=SK`wzpD|!p*m&DkH{S_cMRL~YkviP?vate*c&$Zh(ercytqGEuY^e-GgeMe z-A++_F0^B4WOe@d;r-(DK2c1;3DM@)VI%n}6gK#ynL&ZE>Mo>nUnaHYU(Vu|47&(P z0!NFR@$h<%woOn6*GOjG0sp>=X!uJ4ZMDe_jphXuiYE$;h=H>cQM*b@vd34~W2-QX zA_P9Th&Mi>A@&t9(plXJP=;vRmCusFrgfgZY=?~PC|F>l7S>8exW@#IVDj#;ciLB@ zdP{|%t#j`Z>I%W$Y2jEbBi>y{fQZ*@4on9xy!@CVIFEnQ< zT=tV<T^Hc%+jiD?s(E>7OOhYuZds)vOBLJY;!21-e4Kh7U#Bkrt1<$pt3Y?!@s}4v&3#gLIJ_xc|^* z!uGPjzC`O}fhSHZn;41g0(@?9UM_PD`ZYuk{<^ohptKhBD1|r#Y#SOn{c}E#I?sHL z;glC-%vPCrNpe|yQN2X$d9qgd!&=Fq(B-w^@A3{IGnUYHlYK+%4Yf%68!WkzrXd^G z)LmZLX;iB*#Ot0D!gega8d(VI&)4YJo)<`D3$3SL7kWey8XsUq<#ux0F%+ly=YP7aA1juSNk$3Hw||P!gcQ4s6A*c6q*#h8F?cLw@tf#~ea8_M!z0-B?h#(+ zPiBG-lXs*6sCv%H#`9v)16Lb<;u&Z0KGKRg9Sih)oukpfJ*+Wc>vLz=g*=P`D*pg= zWlP4ShjDih)+*4)kp{i{eY@`Vy{-;JS=b;~P4g~=nqntzgK4`mYsJ8fS*ojG$IcRu zZZF9g!x8S*;A(P+2-s(wvzD>$)(_pm5@xoV)(($zcuw;M) z{)?6G*IAl3OabZM^F4sGPMj=4q%>?f~%i_)6ePnyjm0d;ZI2va?sgRP9f3r>^ z)426#YS?iuE5aOJ;E5-r_m;Z*=JnD?v6dIAxYe=%x_u72Yx}Z^;Ra#g(V@UPo!b5k za+0^dFmgvTg0Wp-<^H^)k<#~jp{_nJCYrcXc)jrs@~pFh zc!Rp-7Y*E8^Yv5={c3Av$?ra!eNWZPfh3`CioYww}g?FWu_O9?N)ht{Ilt2Yb7U!jRxR z_}4UD*_BX+9Gluu|M->?C+0{i-|9ej(!3PREs_`Y{q`=l27H3!vM@f9p6y7 zH=xVLivJvHex9do6KI>pkggXh)@B!9r)L8(;ae8^Fnm(2+%A<7Cc}uX>qen0Tp+I- zek2jy_F`Ts-k{|VZYE=*(@~w!t5(+CO&YT?E&9!+sWSl@6NTTi*1Sd)9*As}U;-q98cuUy!-w+=yd)PiPOkVP#; z^x%m{#PIT~e!rW17<_0yxyR)UNXc)ogR`C>@vaQx1X{ofuWHz2RB2FpP(^Ri}Ge=TRgo0mWZl ze8iX{`7xzv+!bQ4}o@UT2+yK1> zM4G67UrRuT_xRbGc->(1|L8rlgu3;aH(l&|&&6^@=q*mXucOCqNO&AXa&RC~lcII& zHlfM#y&oi*aAoAA#%eljr)8W~eHVA2jeb)W@~mfT1AWsmJ%{##(Gw?zLlYSWlge8R zgr!c}07mv#jiHr^rg8lE3?pW+@`BvEb{h zG@5A0r7~GbwFQjhc(Zj=3v}-r@1+$0KQ}k(LuJUeAyPK#b%pruG?}W&N(H3dx*o5G zpH-xzto{W$0Gmc9l4xgB6>9bhjui`?)ZIZBe81Ca`eOJ}AD{hFz8YC(GBQ2gteQ-W zx;}^#_xjfYyTX4+=d|c9365%(;_j3?7Q+QAtllj_x&|1UvS~DC$TZd^ceHHpvWWz@ z=6~wASu_7k?%56$kBAf=hQ7`TPu9JS)bi&PQz5y299+SvTlz`SXWYt@LBacEA)A5Y1}gY>={vSRmsKA%-!TZ&%2Arf zaipf3ONV`BeZ|*sVAj?oRu)^>L=BuMGbuQ{qZ243@}_uU-URpXWzT{5{Z||udNUat zo(J3sCpp|D+A3eq$I9| z-z0THi4&)J40g@qKX7_;oW87lF{IPu%E?g{Ds-__PTfm(Q)FaQH;*q>ZXdyjozs0X z=-ALP{DOOt;p*SJ8J$sT!+dPfogNeE>I>r%PpW^dmf0812b(^zj`|)bd~-@Sb!Gq= zP6K;8u_J>Ppqv(6hQGS9#8ppttk_Q8B&JamZ(*x5efvTx3K`Nr*nRlT(@Pei;00uI ztliq=xH_o;WD&pgrE7MbYi}Oi{sUmxIV!gF`MG-k0JpzYe+Ce;oDY-PeI9z~%+T94 zno+_J>n+9a#oqMk&~_<>mYo2cT zOS_Xnl`4tn7%DG>iRBdP^FCl6;9{gUxom65qFV#!?BT-_C6tV@G!L3hvdKP$Iz|@`_T^9RTRGrAfP+I9KwDXwu(iy&bw>(H3V!Tn4nVyp&atzZiU6fN*xi8h zW&7xR+y_z@Hx^sV=MtZUwvD$~*1Z@)WURY%UiF$!md7a2J1Ml+?aEA#UPM}2YLV9l zHL^Q?1>0H3&Pv$O>?@hx%fb4OTnF!9T=7wfKCfO#yaTIl?)jW$`+$kezzK#c@4sc7r%?GJ3Hkc`dVv$d+HqACMTff z`W?T|r9tbg+S>~*KHL=S{Ov}bjrX}hgu(}%;!y^x_ zf(7L<>(=nbR0z{1a2S9`OG}*ze1NtQpbXYm%mNFB1PUvMppXs;q(rJIA5Q)){L#01 zd}I5%Vz>63%CoCV9?@g3uBWb;R?P>628GafE~S-&xEpg&TE?cI3_l2=yQalvRC2ES zSLoSTy&<_EO173@ual4&6w`tCCeT2Q=8ooPx)-yK2-Qadg>rqZKieI=*B2;{KR`d3 zb@$mP)ccDK>&Qqk=Wp4K+_bO?2-D@gi}iK|b5V;K&L0^l%DqL17%Q`Uh`QU_$?p*E zh!}Ma7$MJ#a!Bm64DG7yKf5EwBoou=x#cUaBoBS$^zNtLT3gscU*nz4Na_|1-864y z7a`c|%)bo`oet2Dz!sW$)k%U@hzRQ>(yH6?Ex;xak!Bemh$b~o8iEAqn|Gco9=^$WC|Cw-gJW}9vx|`e1^bb%h#mwKNnlwnC9fG?Z+4ZOrty-ein5?#Bvo~Xl#S^J92>rD z5*!WbN@!`*NF5InPt)#cN)Zia62-IgkAb#^TV(a2)0?S@DMEjz1#7oc7;>cQjG(OA zAcM9HQy|eEs^s!^mLY5BVFVhKZaCeR6exibWjAFpGl6OxN!R`mNnsg8;)H&U%5&Dd zO@FoXq`U97>h=OeCM_XdrH=b=O%!>N*M56xVYPf;m&kTiJzAhCExPj0u}82~F^HA} zHs}+j3fZ!D<$Pv3wY$Jsdm?5`xUS`l3E-cW5~^gMA|XXot3t-LlMb&pn&)m;`bl^V z!;%Shxl)gkOzYKK6P8&LD+p9Ab2o}H+n*ba&n)u(KHeI~(HBmIe%reT`aTF4hk`#o zQU}jAC7Rt~YmuU%bR-+=&-$%l{$269gL00a^|5Qj&RXc*8}!SHjX!z3YS|)14?Gx* z6FjPa!~f+yC#o3wRCL#Ku*l|f8VHzhs}LFP*D<{3TYx9b4~afn(yMtuHW@yxyHZ5Q z{jFA!&F_)*11o>9jeH3!ixKkb@ECItJnvm@(BA#bIB5S8L#g(1)Tre@Bl3ITr)?V5 z40hCpXH6**hUnni82v$I!GTD)SFmsyMilEY<^V20u07(XGJL!E77{|OE3z8d)3$FZ zm_a+kS;g$O17;f&N%e*5GyfeDy!?pP!g_T|_zNsO)AA=_i7oaIIM5`38iPl?l5ZByD<0K%R2-O!UE59i4&3 zvjbtDSdOxUsIKV85Es2S%=6`ddQ(^xdSj5CNY4~6G)LtSF}^AFZFknD4P>!X$zl~T z-iAb#wqA>`h7Lf&lmoxM$FYI3TJ%9p=_Z~}sIm&P0z}&?`=VG0MncLA@6VfrD%aNl zy^~tPD=_kXTA*mm_4@&Aiatw2r?Ty)tS-C2lt5f<3o+CLmCJOqduu`ApNuWO8R&rD zaLv=W8r$yc)y20}NJiiywvlI5#_!Q>LV4^f^Ll#kl?+4)F}wHYRO)ENcw}?yTeB^k zt`yM=00p+@$gktBmkAI2io&*&>|FtUDW$`pqVjdSDNqS^hxw*G)maJNvnOnVW(}ka z7NJwZj%kIa84mzUsG%u#c8-v(A#O;iz1y?(WrR|C>U6~89?2CazI;p02jt&g&XrgZ zuU*c+KQ)v`uY?2&jb-6Vd9K}TLc@DSfk)4~R|ybm_GxVz7j_Q#^8)o6Pk+4MP`t|R zMwY(kYb7;co=fgl*7(?xNFx;to!BUL2{WubW)sP02Mg79O81WeeK1t7rDoKzRCZq< uGA5;%Ow(nR7bemctUXguasXx~k@|{WxA>NL!60>&7ko#O2M2n8R{tMM)czO% literal 0 HcmV?d00001 diff --git a/MergerLogicUnitTests/Batching/TestImages/image.png b/MergerLogicUnitTests/Batching/TestImages/image.png new file mode 100644 index 0000000000000000000000000000000000000000..4c0485afc46e1e24eacbb8b2a62742f1e361ce43 GIT binary patch literal 128678 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 D2(Iaxf0n1QV|BWwFxa7$?W$fvt|#M9vXfIhXSq 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
j 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 GenCreateTileUnknownFormatParams() + { + yield return new object[] { null }; + yield return new object[] { File.ReadAllBytes("image.gif") }; + } + [TestMethod] [TestCategory("CreateTile")] - [DataRow(null)] - [DataRow()] + [DynamicData(nameof(GenCreateTileUnknownFormatParams), DynamicDataSourceType.Method)] public void CreateTileWithUnknownDataFormatFails(byte[] data) { Assert.ThrowsException(() => new Tile(0, 0, 0, data)); this._repository.VerifyAll(); } + public static IEnumerable GenCreateTileParams() + { + yield return new object[] { File.ReadAllBytes("image.jpeg") }; + yield return new object[] { File.ReadAllBytes("image.png") }; + } + [TestMethod] [TestCategory("CreateTile")] - [DataRow(new byte[] { 0xFF, 0xD8, 0xFF, 0xDB })] - [DataRow(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A })] + [DynamicData(nameof(GenCreateTileParams), DynamicDataSourceType.Method)] public void CreateTile(byte[] data) { Tile tile = new Tile(0, 0, 0, data); From cc48e8e1aec4de774265da019aac988362f8b735 Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Wed, 3 Jul 2024 18:15:42 +0300 Subject: [PATCH 08/13] test: moved the tests to TileTest --- MergerLogicUnitTests/Batching/TileTest.cs | 60 ++++++++++++++++ MergerLogicUnitTests/Utils/ImageUtilsTest.cs | 72 -------------------- 2 files changed, 60 insertions(+), 72 deletions(-) diff --git a/MergerLogicUnitTests/Batching/TileTest.cs b/MergerLogicUnitTests/Batching/TileTest.cs index 92406654..53f0a398 100644 --- a/MergerLogicUnitTests/Batching/TileTest.cs +++ b/MergerLogicUnitTests/Batching/TileTest.cs @@ -2,6 +2,7 @@ using MergerLogicUnitTests.testUtils; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; @@ -28,7 +29,9 @@ public void beforeEach() public static IEnumerable GenCreateTileUnknownFormatParams() { +#nullable disable yield return new object[] { null }; +#nullable enable yield return new object[] { File.ReadAllBytes("image.gif") }; } @@ -58,6 +61,63 @@ public void CreateTile(byte[] data) } #endregion + + #region imageDimensions + public static IEnumerable ValidTilesSizeTestParameters() + { + yield return new object[] { + File.ReadAllBytes("no_transparency.jpeg"), + (256, 256) + }; + yield return new object[] { + File.ReadAllBytes("no_transparency.png"), + (256, 256) + }; + } + public static IEnumerable InvalidTilesSizeTestParameters() + { + yield return new object[] { + File.ReadAllBytes("100x100.jpeg"), + (100, 100) + }; + yield return new object[] { + File.ReadAllBytes("100x100.png"), + (100, 100) + }; + yield return new object[] { + File.ReadAllBytes("100x256.jpeg"), + (100, 256) + }; + yield return new object[] { + File.ReadAllBytes("100x256.png"), + (100, 256) + }; + yield return new object[] { + File.ReadAllBytes("256x100.jpeg"), + (256, 100) + }; + yield return new object[] { + File.ReadAllBytes("256x100.png"), + (256, 100) + }; + } + + [TestMethod] + [DynamicData(nameof(ValidTilesSizeTestParameters), DynamicDataSourceType.Method)] + public void IsAcceptsValidTileSize(byte[] imageBytes, (int, int) dimensions) + { + Tile tile = new Tile(0, 0, 0, imageBytes); + Assert.AreEqual((tile.Width, tile.Height), dimensions); + } + + [TestMethod] + [DynamicData(nameof(InvalidTilesSizeTestParameters), DynamicDataSourceType.Method)] + [ExpectedException(typeof(ArgumentException))] + public void IsRejectsInvalidTileSize(byte[] imageBytes, (int, int) dimensions) + { + new Tile(0, 0, 0, imageBytes); + } + #endregion } } diff --git a/MergerLogicUnitTests/Utils/ImageUtilsTest.cs b/MergerLogicUnitTests/Utils/ImageUtilsTest.cs index cd50ed5e..cdadf69e 100644 --- a/MergerLogicUnitTests/Utils/ImageUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/ImageUtilsTest.cs @@ -88,78 +88,6 @@ public void IsFullyTransparent(byte[] imageBytes, bool expectedResult) Assert.AreEqual(expectedResult, result); } } - - #endregion - - #region ImageDimensions - - public static IEnumerable GetImageDimensionsTestParameters() - { - yield return new object[] { - File.ReadAllBytes("100x100.jpeg"), - (100, 100), - false, - }; - - yield return new object[] { - File.ReadAllBytes("100x100.png"), - (100, 100), - false, - }; - - yield return new object[] { - File.ReadAllBytes("100x256.jpeg"), - (100, 256), - false, - }; - - yield return new object[] { - File.ReadAllBytes("100x256.png"), - (100, 256), - false, - }; - - yield return new object[] { - File.ReadAllBytes("256x100.jpeg"), - (256, 100), - false, - }; - - yield return new object[] { - File.ReadAllBytes("256x100.png"), - (256, 100), - false, - }; - - yield return new object[] { - File.ReadAllBytes("no_transparency.jpeg"), - (256, 256), - true, - }; - - yield return new object[] { - File.ReadAllBytes("no_transparency.png"), - (256, 256), - true, - }; - } - - [TestMethod] - [DynamicData(nameof(GetImageDimensionsTestParameters), DynamicDataSourceType.Method)] - public void IsDimMatchProperties(byte[] imageBytes, (int, int) dimensions, bool shouldBeValid) - { - Tile tile = new Tile(0, 0, 0, imageBytes); - Assert.AreEqual((tile.Width, tile.Height), dimensions); - } - - [TestMethod] - [DynamicData(nameof(GetImageDimensionsTestParameters), DynamicDataSourceType.Method)] - public void IsValidImageDimensions(byte[] imageBytes, (int, int) dimensions, bool shouldBeValid) - { - Tile tile = new Tile(0, 0, 0, imageBytes); - var result = ImageUtils.IsValidImageDimensions(tile, 256); - Assert.AreEqual(shouldBeValid, result); - } #endregion } } From 73bef7c1d56349a39ce56a3c7546da2372d648fe Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Wed, 3 Jul 2024 18:16:39 +0300 Subject: [PATCH 09/13] chore: moved the tile size validation to Tile class and added allowedSize config --- MergerLogic/Batching/Tile.cs | 8 ++++++++ MergerService/appsettings.Development.json | 3 ++- MergerService/appsettings.json | 3 ++- helm/templates/configmap.yaml | 1 + helm/values.yaml | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index 06b50a89..999c8f0c 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -1,6 +1,7 @@ using ImageMagick; using MergerLogic.DataTypes; using MergerLogic.ImageProcessing; +using MergerLogic.Utils; using System.ComponentModel.DataAnnotations; namespace MergerLogic.Batching @@ -51,6 +52,13 @@ public Tile(int z, int x, int y, byte[] data) this.Height = info.Height; this._data = data; + + // int allowedPixelSize = configuration.GetConfiguration("GENERAL", "allowedPixelSize"); + int allowedPixelSize = 256; + if (this.Width != allowedPixelSize || this.Height != allowedPixelSize) + { + throw new ArgumentException($"The image dimensions ({this.Width}x{this.Height}) does not match the allowed size ({allowedPixelSize})"); + } } public Tile(Coord cords, byte[] data) diff --git a/MergerService/appsettings.Development.json b/MergerService/appsettings.Development.json index d3d126aa..3364d311 100644 --- a/MergerService/appsettings.Development.json +++ b/MergerService/appsettings.Development.json @@ -8,7 +8,8 @@ "batchSize": { "limitBatchSize": true, "batchMaxSize": 1000 - } + }, + "allowedPixelSize": 256 }, "TASK": { "jobManagerUrl": "http://localhost:8081", diff --git a/MergerService/appsettings.json b/MergerService/appsettings.json index 1d96c4c1..f73817a4 100644 --- a/MergerService/appsettings.json +++ b/MergerService/appsettings.json @@ -8,7 +8,8 @@ "batchSize": { "limitBatchSize": true, "batchMaxSize": 1000 - } + }, + "allowedPixelSize": 256 }, "TASK": { "jobManagerUrl": "http://localhost:8081", diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml index b6c494c7..9d8eef34 100644 --- a/helm/templates/configmap.yaml +++ b/helm/templates/configmap.yaml @@ -13,6 +13,7 @@ metadata: name: {{ $configmapName }} data: GENERAL__validate: {{ .Values.env.general.validate | quote }} + GENERAL__allowedPixelSize: {{ .Values.env.general.allowedPixelSize | quote }} TASK__jobManagerUrl: {{ $serviceUrls.jobManager | quote }} {{- range $i, $e := .Values.env.TASK.types }} TASK__types__{{ $i }}__jobType: {{ $e.jobType }} diff --git a/helm/values.yaml b/helm/values.yaml index 1f6e593b..d1a32d10 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -87,6 +87,7 @@ env: batchSize: limitBatchSize: true batchMaxSize: 1000 + allowedPixelSize: 256 TASK: types: - jobType: 'Ingestion_Update' From b42561a34a686182607cc23f57cba3d682a8efd9 Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Sun, 7 Jul 2024 16:56:06 +0300 Subject: [PATCH 10/13] feat: addded pixel size validation to the Tile constructor itself --- MergerLogic/Batching/Tile.cs | 31 ++++++++++------------- MergerLogic/Clients/FileClient.cs | 6 ++--- MergerLogic/Clients/GpkgClient.cs | 2 +- MergerLogic/Clients/HttpSourceClient.cs | 2 +- MergerLogic/Clients/S3Client.cs | 12 ++++----- MergerLogic/ImageProcessing/TileMerger.cs | 12 ++++++--- MergerLogic/ImageProcessing/TileScaler.cs | 7 +++-- MergerLogic/Utils/DataUtils.cs | 9 ++++--- MergerLogic/Utils/UtilsFactory.cs | 12 ++++++--- 9 files changed, 52 insertions(+), 41 deletions(-) diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index 999c8f0c..175c8a4b 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -40,12 +40,15 @@ public int Y private byte[] _data; - public Tile(int z, int x, int y, byte[] data) + private readonly IConfigurationManager _configManager; + + public Tile(IConfigurationManager configuration, int z, int x, int y, byte[] data) { this.Z = z; this.X = x; this.Y = y; this.Format = ImageFormatter.GetTileFormat(data) ?? throw new ValidationException($"Cannot create tile {this}, data is in invalid format"); + this._configManager = configuration; var info = new MagickImageInfo(data); this.Width = info.Width; @@ -53,30 +56,18 @@ public Tile(int z, int x, int y, byte[] data) this._data = data; - // int allowedPixelSize = configuration.GetConfiguration("GENERAL", "allowedPixelSize"); - int allowedPixelSize = 256; + int allowedPixelSize = configuration.GetConfiguration("GENERAL", "allowedPixelSize"); if (this.Width != allowedPixelSize || this.Height != allowedPixelSize) { throw new ArgumentException($"The image dimensions ({this.Width}x{this.Height}) does not match the allowed size ({allowedPixelSize})"); } } - public Tile(Coord cords, byte[] data) - { - this.Z = cords.Z; - this.X = cords.X; - this.Y = cords.Y; - this.Format = ImageFormatter.GetTileFormat(data) ?? throw new ValidationException($"Cannot create tile {this}, data is in invalid format"); - - var info = new MagickImageInfo(data); - this.Width = info.Width; - this.Height = info.Height; - - this._data = data; - } + public Tile(IConfigurationManager configuration, Coord cords, byte[] data) => new Tile(configuration, cords.Z, cords.X, cords.Y, data); - public Tile(Coord cords, IMagickImage image) + public Tile(IConfigurationManager configuration, Coord cords, IMagickImage image) { + this._configManager = configuration; this.Z = cords.Z; this.X = cords.X; this.Y = cords.Y; @@ -84,6 +75,12 @@ public Tile(Coord cords, IMagickImage image) this.Width = image.Width; this.Height = image.Height; this._data = image.ToByteArray(); + + int allowedPixelSize = configuration.GetConfiguration("GENERAL", "allowedPixelSize"); + if (this.Width != allowedPixelSize || this.Height != allowedPixelSize) + { + throw new ArgumentException($"The image dimensions ({this.Width}x{this.Height}) does not match the allowed size ({allowedPixelSize})"); + } } public bool HasCoords(int z, int x, int y) diff --git a/MergerLogic/Clients/FileClient.cs b/MergerLogic/Clients/FileClient.cs index 25544910..1496fcdb 100644 --- a/MergerLogic/Clients/FileClient.cs +++ b/MergerLogic/Clients/FileClient.cs @@ -8,8 +8,8 @@ public class FileClient : DataUtils, IFileClient { private readonly IFileSystem _fileSystem; - public FileClient(string path, IGeoUtils geoUtils, IFileSystem fileSystem) - : base(path, geoUtils) + public FileClient(string path, IGeoUtils geoUtils, IFileSystem fileSystem, IConfigurationManager configuration) + : base(path, geoUtils, configuration) { this._fileSystem = fileSystem; } @@ -31,7 +31,7 @@ public FileClient(string path, IGeoUtils geoUtils, IFileSystem fileSystem) public override bool TileExists(int z, int x, int y) { - return this.GetTilePath(z,x,y) != null; + return this.GetTilePath(z, x, y) != null; } private string? GetTilePath(int z, int x, int y) diff --git a/MergerLogic/Clients/GpkgClient.cs b/MergerLogic/Clients/GpkgClient.cs index 1a7187dc..7bde0153 100644 --- a/MergerLogic/Clients/GpkgClient.cs +++ b/MergerLogic/Clients/GpkgClient.cs @@ -19,7 +19,7 @@ public class GpkgClient : DataUtils, IGpkgClient private readonly IFileSystem _fileSystem; public GpkgClient(string path, ITimeUtils timeUtils, ILogger logger, IFileSystem fileSystem, - IGeoUtils geoUtils) : base(path, geoUtils) + IGeoUtils geoUtils, IConfigurationManager configuration) : base(path, geoUtils, configuration) { this._timeUtils = timeUtils; this._logger = logger; diff --git a/MergerLogic/Clients/HttpSourceClient.cs b/MergerLogic/Clients/HttpSourceClient.cs index 240b46d9..2a76cb7c 100644 --- a/MergerLogic/Clients/HttpSourceClient.cs +++ b/MergerLogic/Clients/HttpSourceClient.cs @@ -9,7 +9,7 @@ public class HttpSourceClient : DataUtils, IHttpSourceClient private IPathPatternUtils _pathPatternUtils; public HttpSourceClient(string path, IHttpRequestUtils httpClient, IPathPatternUtils pathPatternUtils, - IGeoUtils geoUtils) : base(path, geoUtils) + IGeoUtils geoUtils, IConfigurationManager configuration) : base(path, geoUtils, configuration) { this._httpClient = httpClient; this._pathPatternUtils = pathPatternUtils; diff --git a/MergerLogic/Clients/S3Client.cs b/MergerLogic/Clients/S3Client.cs index 60c9c5ee..c404664b 100644 --- a/MergerLogic/Clients/S3Client.cs +++ b/MergerLogic/Clients/S3Client.cs @@ -16,8 +16,8 @@ public class S3Client : DataUtils, IS3Client private readonly IPathUtils _pathUtils; private readonly S3StorageClass _storageClass; - public S3Client(IAmazonS3 client, IPathUtils pathUtils, IGeoUtils geoUtils, ILogger logger, - string storageClass, string bucket, string path) : base(path, geoUtils) + public S3Client(IAmazonS3 client, IPathUtils pathUtils, IGeoUtils geoUtils, ILogger logger, IConfigurationManager configuration, + string storageClass, string bucket, string path) : base(path, geoUtils, configuration) { this._client = client; this._bucket = bucket; @@ -105,10 +105,10 @@ public void UpdateTile(Tile tile) var request = new PutObjectRequest() { - BucketName = this._bucket, - CannedACL = S3CannedACL.PublicRead, - Key = String.Format(key), - StorageClass=this._storageClass + BucketName = this._bucket, + CannedACL = S3CannedACL.PublicRead, + Key = String.Format(key), + StorageClass = this._storageClass }; byte[] buffer = tile.GetImageBytes(); diff --git a/MergerLogic/ImageProcessing/TileMerger.cs b/MergerLogic/ImageProcessing/TileMerger.cs index 61dc203b..181ef9b1 100644 --- a/MergerLogic/ImageProcessing/TileMerger.cs +++ b/MergerLogic/ImageProcessing/TileMerger.cs @@ -11,22 +11,26 @@ public class TileMerger : ITileMerger { private readonly ITileScaler _tileScaler; private readonly ILogger _logger; + private readonly IConfigurationManager _configurationManager; - public TileMerger(ITileScaler tileScaler, ILogger logger) + public TileMerger(ITileScaler tileScaler, ILogger logger, IConfigurationManager configuration) { this._logger = logger; this._tileScaler = tileScaler; + this._configurationManager = configuration; } public Tile? MergeTiles(List tiles, Coord targetCoords, TileFormatStrategy strategy, bool uploadOnly = false) { - if(uploadOnly) { + if (uploadOnly) + { this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] Configured to upload only mode"); // Ignore target if in upload only mode tiles = tiles.Skip(1).ToList(); // In case there is only one source then we can just return the data as is - if(tiles.Count == 1) { + if (tiles.Count == 1) + { this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] Only one source was found, using raw image"); Tile? rawTile = tiles[0](); rawTile?.ConvertToFormat(strategy.ApplyStrategy(rawTile.Format)); @@ -70,7 +74,7 @@ public TileMerger(ITileScaler tileScaler, ILogger logger) break; } - Tile tile = new Tile(targetCoords, image); + Tile tile = new Tile(this._configurationManager, targetCoords, image); image.Dispose(); tile.ConvertToFormat(strategy.ApplyStrategy(tile.Format)); return tile; diff --git a/MergerLogic/ImageProcessing/TileScaler.cs b/MergerLogic/ImageProcessing/TileScaler.cs index 592c18ce..06599a95 100644 --- a/MergerLogic/ImageProcessing/TileScaler.cs +++ b/MergerLogic/ImageProcessing/TileScaler.cs @@ -14,15 +14,18 @@ public class TileScaler : ITileScaler private const int TILE_SIZE = 256; private readonly IMetricsProvider _metricsProvider; private readonly ILogger _logger; + private readonly IConfigurationManager _configurationManager; - public TileScaler(IMetricsProvider metricsProvider, ILogger logger) + public TileScaler(IMetricsProvider metricsProvider, ILogger logger, IConfigurationManager configuration) { this._metricsProvider = metricsProvider; this._logger = logger; + this._configurationManager = configuration; } public MagickImage? Upscale(MagickImage baseImage, Tile baseTile, Coord targetCoords) { + string fromTileToCoordMessage = $"from tile z:{baseTile.Z}, x:{baseTile.X}, y:{baseTile.Y} to coords z:{targetCoords.Z}, x:{targetCoords.X}, y:{targetCoords.Y}"; this._logger.LogDebug($"[{MethodBase.GetCurrentMethod().Name}] MagickImage Upscale Begin {fromTileToCoordMessage}"); var upscaleStopwatch = Stopwatch.StartNew(); @@ -135,7 +138,7 @@ public TileScaler(IMetricsProvider metricsProvider, ILogger logger) ImageFormatter.RemoveImageDateAttributes(upscale); } - return upscale is null ? null : new Tile(targetCoords, upscale.ToByteArray()); + return upscale is null ? null : new Tile(this._configurationManager, targetCoords, upscale.ToByteArray()); } } } diff --git a/MergerLogic/Utils/DataUtils.cs b/MergerLogic/Utils/DataUtils.cs index c924d7c2..962b6cdb 100644 --- a/MergerLogic/Utils/DataUtils.cs +++ b/MergerLogic/Utils/DataUtils.cs @@ -9,14 +9,17 @@ public abstract class DataUtils : IDataUtils protected readonly string path; protected readonly IGeoUtils GeoUtils; protected readonly IImageFormatter Formatter; + private readonly IConfigurationManager _configurationManager; - public DataUtils(string path, IGeoUtils geoUtils) + public DataUtils(string path, IGeoUtils geoUtils, IConfigurationManager configuration) { this.path = path; this.GeoUtils = geoUtils; + this._configurationManager = configuration; } - public virtual bool IsValidGrid(bool isOneXOne = false) { + public virtual bool IsValidGrid(bool isOneXOne = false) + { return true; } @@ -36,7 +39,7 @@ public virtual bool IsValidGrid(bool isOneXOne = false) { return null; } - return new Tile(z, x, y, data); + return new Tile(this._configurationManager, z, x, y, data); } protected Tile? CreateTile(Coord coord, byte[]? data) diff --git a/MergerLogic/Utils/UtilsFactory.cs b/MergerLogic/Utils/UtilsFactory.cs index c61ca3fb..00732cbd 100644 --- a/MergerLogic/Utils/UtilsFactory.cs +++ b/MergerLogic/Utils/UtilsFactory.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using System.IO.Abstractions; using MergerLogic.Clients; +using System.ComponentModel; namespace MergerLogic.Utils { @@ -30,19 +31,21 @@ public UtilsFactory(IPathUtils pathUtils, ITimeUtils timeUtils, IGeoUtils geoUti public IFileClient GetFileUtils(string path) { - return new FileClient(path, this._geoUtils, this._fileSystem); + return new FileClient(path, this._geoUtils, this._fileSystem, this._container.GetRequiredService()); } public IGpkgClient GetGpkgUtils(string path) { var logger = this._container.GetRequiredService>(); - return new GpkgClient(path, this._timeUtils, logger, this._fileSystem, this._geoUtils); + return new GpkgClient(path, this._timeUtils, logger, this._fileSystem, this._geoUtils, + this._container.GetRequiredService()); } public IHttpSourceClient GetHttpUtils(string path) { IPathPatternUtils pathPatternUtils = this.GetPathPatternUtils(path); - return new HttpSourceClient(path, this._httpRequestUtils, pathPatternUtils, this._geoUtils); + return new HttpSourceClient(path, this._httpRequestUtils, pathPatternUtils, this._geoUtils, + this._container.GetRequiredService()); } public IS3Client GetS3Utils(string path) @@ -55,7 +58,8 @@ public IS3Client GetS3Utils(string path) throw new Exception("S3 Data utils requires s3 client to be configured"); } var logger = this._container.GetRequiredService>(); - return new S3Client(client, this._pathUtils, this._geoUtils, logger, storageClass, bucket, path); + return new S3Client(client, this._pathUtils, this._geoUtils, logger, this._container.GetRequiredService(), + storageClass, bucket, path); } public T GetDataUtils(string path) where T : IDataUtils From 72d92c9aa511cddbef17659ee67c79a558c563bc Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Wed, 17 Jul 2024 09:45:22 +0300 Subject: [PATCH 11/13] test: modified tests to use actual images --- MergerLogicUnitTests/Batching/TileTest.cs | 15 +- .../Clients/FileClientTest.cs | 10 +- MergerLogicUnitTests/DataTypes/FSTest.cs | 26 +- MergerLogicUnitTests/DataTypes/GpkgTest.cs | 23 +- MergerLogicUnitTests/DataTypes/S3Test.cs | 18 +- MergerLogicUnitTests/DataTypes/TMSTest.cs | 30 +- MergerLogicUnitTests/DataTypes/WMTSTest.cs | 31 +- MergerLogicUnitTests/DataTypes/XYZTest.cs | 30 +- .../ImageProcessing/TileMergerTest.cs | 141 +++--- .../ImageProcessing/TileScalerTest.cs | 13 +- MergerLogicUnitTests/Utils/GeoUtilsTest.cs | 7 +- MergerLogicUnitTests/Utils/GpkgUtilsTest.cs | 71 +-- .../Utils/HttpSourceUtilsTest.cs | 9 +- .../Utils/OneXOneConvertorTest.cs | 14 +- MergerLogicUnitTests/Utils/PathUtilsTest.cs | 6 +- MergerLogicUnitTests/Utils/S3UtilsTest.cs | 12 +- .../Runners/TaskExecutorTest.cs | 422 +++++++++--------- 17 files changed, 493 insertions(+), 385 deletions(-) diff --git a/MergerLogicUnitTests/Batching/TileTest.cs b/MergerLogicUnitTests/Batching/TileTest.cs index 53f0a398..85c9b878 100644 --- a/MergerLogicUnitTests/Batching/TileTest.cs +++ b/MergerLogicUnitTests/Batching/TileTest.cs @@ -1,5 +1,5 @@ using MergerLogic.Batching; -using MergerLogicUnitTests.testUtils; +using MergerLogic.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System; @@ -17,12 +17,17 @@ public class TilesTest { #region mocks private MockRepository _repository; + private Mock _configurationManagerMock; #endregion [TestInitialize] public void beforeEach() { this._repository = new MockRepository(MockBehavior.Strict); + this._configurationManagerMock = this._repository.Create(); + + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); } #region CreateTile @@ -40,7 +45,7 @@ public static IEnumerable GenCreateTileUnknownFormatParams() [DynamicData(nameof(GenCreateTileUnknownFormatParams), DynamicDataSourceType.Method)] public void CreateTileWithUnknownDataFormatFails(byte[] data) { - Assert.ThrowsException(() => new Tile(0, 0, 0, data)); + Assert.ThrowsException(() => new Tile(this._configurationManagerMock.Object, 0, 0, 0, data)); this._repository.VerifyAll(); } @@ -55,7 +60,7 @@ public static IEnumerable GenCreateTileParams() [DynamicData(nameof(GenCreateTileParams), DynamicDataSourceType.Method)] public void CreateTile(byte[] data) { - Tile tile = new Tile(0, 0, 0, data); + Tile tile = new Tile(this._configurationManagerMock.Object, 0, 0, 0, data); Assert.AreEqual(tile.GetImageBytes(), data); this._repository.VerifyAll(); } @@ -106,7 +111,7 @@ public static IEnumerable InvalidTilesSizeTestParameters() [DynamicData(nameof(ValidTilesSizeTestParameters), DynamicDataSourceType.Method)] public void IsAcceptsValidTileSize(byte[] imageBytes, (int, int) dimensions) { - Tile tile = new Tile(0, 0, 0, imageBytes); + Tile tile = new Tile(this._configurationManagerMock.Object, 0, 0, 0, imageBytes); Assert.AreEqual((tile.Width, tile.Height), dimensions); } @@ -115,7 +120,7 @@ public void IsAcceptsValidTileSize(byte[] imageBytes, (int, int) dimensions) [ExpectedException(typeof(ArgumentException))] public void IsRejectsInvalidTileSize(byte[] imageBytes, (int, int) dimensions) { - new Tile(0, 0, 0, imageBytes); + new Tile(this._configurationManagerMock.Object, 0, 0, 0, imageBytes); } #endregion } diff --git a/MergerLogicUnitTests/Clients/FileClientTest.cs b/MergerLogicUnitTests/Clients/FileClientTest.cs index 1b9cd607..b26532d6 100644 --- a/MergerLogicUnitTests/Clients/FileClientTest.cs +++ b/MergerLogicUnitTests/Clients/FileClientTest.cs @@ -27,6 +27,7 @@ public class FileClientTest private Mock _pathMock; private Mock _directoryMock; private Mock _imageFormatterMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; private byte[] _pngImageData; #endregion @@ -40,9 +41,12 @@ public void beforeEach() this._fileMock = this._repository.Create(); this._pathMock = this._repository.Create(); this._directoryMock = this._repository.Create(); + this._configurationManagerMock = this._repository.Create(); this._fsMock.SetupGet(fs => fs.File).Returns(this._fileMock.Object); this._fsMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); this._fsMock.SetupGet(fs => fs.Directory).Returns(this._directoryMock.Object); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._imageFormatterMock = this._repository.Create(); this._jpegImageData = File.ReadAllBytes("image.jpeg"); @@ -89,7 +93,7 @@ public void GetTile(bool useCoords, bool returnsNull, TileFormat targetFormat) .Returns(targetFormat); } - var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object); + var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object, this._configurationManagerMock.Object); var res = useCoords ? fileClient.GetTile(cords) : fileClient.GetTile(cords.Z, cords.X, cords.Y); if (returnsNull) @@ -129,7 +133,7 @@ public void TileExists(bool exist) .Setup(dir => dir.EnumerateFiles("testFilePath", "testTilePath.*", SearchOption.TopDirectoryOnly)) .Returns(exist ? new string[] { "testFile" } : Array.Empty()); - var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object); + var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object, this._configurationManagerMock.Object); var res = fileClient.TileExists(cords.Z, cords.X, cords.Y); @@ -152,7 +156,7 @@ public void TileExistsReturnFalseWhenDirectoryDontExist() .Setup(dir => dir.EnumerateFiles("testFilePath", "testTilePath.*", SearchOption.TopDirectoryOnly)) .Throws(); - var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object); + var fileClient = new FileClient("testFilePath", this._geoUtilsMock.Object, this._fsMock.Object, this._configurationManagerMock.Object); var res = fileClient.TileExists(cords.Z, cords.X, cords.Y); diff --git a/MergerLogicUnitTests/DataTypes/FSTest.cs b/MergerLogicUnitTests/DataTypes/FSTest.cs index dfb5bd54..a5b3b957 100644 --- a/MergerLogicUnitTests/DataTypes/FSTest.cs +++ b/MergerLogicUnitTests/DataTypes/FSTest.cs @@ -37,6 +37,7 @@ public class FSTest private Mock _fileInfoFactoryMock; private Mock _pathMock; private Mock _metricsProviderMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion @@ -53,6 +54,9 @@ public void BeforeEach() this._fileInfoFactoryMock = this._repository.Create(); this._pathMock = this._repository.Create(); this._fileSystemMock = this._repository.Create(); + this._configurationManagerMock = this._repository.Create(); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._fileSystemMock.SetupGet(fs => fs.Directory).Returns(this._directoryMock.Object); this._fileSystemMock.SetupGet(fs => fs.FileInfo).Returns(this._fileInfoFactoryMock.Object); this._fileSystemMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); @@ -137,7 +141,7 @@ public void TileExists(bool isBase, Coord cords, bool isOneXOne, GridOrigin orig } else { - var tile = new Tile(cords, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, cords, this._jpegImageData); Assert.AreEqual(expected, fsSource.TileExists(tile)); } this._fsUtilsMock.Verify(util => util.TileExists(cords.Z, cords.X, cords.Y), @@ -172,7 +176,7 @@ public void GetCorrespondingTileWithoutUpscaleWithoutConversion(int batchSize, b { this.SetupConstructorRequiredMocks(isBase); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); this._fsUtilsMock.Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => z == 2 ? existingTile : nullTile); @@ -223,7 +227,7 @@ public void GetCorrespondingTileWithoutUpscale(bool isBase, Coord cords, bool en bool expectedNull = cords.Z != 2; this.SetupConstructorRequiredMocks(isBase); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) { @@ -327,7 +331,7 @@ public void GetCorrespondingTileWithUpscale(bool isBase, bool isOneXOne, GridOri { this.SetupConstructorRequiredMocks(isBase); Tile nullTile = null; - var tile = new Tile(2, 2, 3, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) @@ -468,8 +472,9 @@ public void UpdateTiles(bool isBase, bool isOneXOne, GridOrigin origin) var testTiles = new Tile[] { - new Tile(1, 2, 3, this._jpegImageData), new Tile(7, 7, 7, this._jpegImageData), - new Tile(2, 2, 3, this._jpegImageData) + new Tile(this._configurationManagerMock.Object, 1, 2, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 7, 7, 7, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData) }; var tileComparer = EqualityComparerFactory.Create((tile1, tile2) => @@ -768,8 +773,11 @@ public void GetNextBatch(bool isOneXOne, bool isBase, GridOrigin origin, int bat { var tiles = new Tile?[] { - new Tile(0, 0, 0, this._jpegImageData), new Tile(1, 1, 1, this._jpegImageData), null, - new Tile(3, 3, 3, this._jpegImageData), new Tile(4, 4, 4, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 1, 1, 1, this._jpegImageData), + null, + new Tile(this._configurationManagerMock.Object, 3, 3, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 4, 4, 4, this._jpegImageData), }; var tileBatches = tiles.Where(t => t is not null && (!isOneXOne || t.Z != 0)).Chunk(batchSize).ToList(); var seq = new MockSequence(); @@ -946,7 +954,7 @@ private void SetupGetTiles(bool isBase, bool isOneXOne, GridOrigin origin) .Returns(new Coord(0, 0, 0)); this._fsUtilsMock .Setup(utils => utils.GetTile(It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); if (origin != GridOrigin.LOWER_LEFT) { this._geoUtilsMock diff --git a/MergerLogicUnitTests/DataTypes/GpkgTest.cs b/MergerLogicUnitTests/DataTypes/GpkgTest.cs index 6108e7b1..e3f7cbe0 100644 --- a/MergerLogicUnitTests/DataTypes/GpkgTest.cs +++ b/MergerLogicUnitTests/DataTypes/GpkgTest.cs @@ -53,6 +53,8 @@ public void BeforeEach() this._loggerFactoryMock = this._repository.Create(); this._loggerFactoryMock.Setup(f => f.CreateLogger(It.IsAny())).Returns(this._loggerMock.Object); this._serviceProviderMock = this._repository.Create(); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._serviceProviderMock.Setup(container => container.GetService(typeof(IOneXOneConvertor))) .Returns(this._oneXOneConvertorMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IUtilsFactory))) @@ -127,7 +129,7 @@ public void TileExists(bool isBase, Coord cords, bool isOneXOne, GridOrigin orig } else { - var tile = new Tile(cords, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, cords, this._jpegImageData); Assert.AreEqual(expected, gpkg.TileExists(tile)); } this._gpkgUtilsMock.Verify(util => util.TileExists(cords.Z, cords.X, cords.Y), @@ -163,7 +165,7 @@ public void GetCorrespondingTileWithoutUpscaleWithoutConversion(int batchSize, b var extent = new Extent() { MinX = -180, MinY = -90, MaxX = 180, MaxY = 90 }; this.SetupRequiredBaseMocks(isBase, false, extent); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); this._gpkgUtilsMock.Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => z == 2 ? existingTile : nullTile); @@ -219,7 +221,7 @@ public void GetCorrespondingTileWithoutUpscale(bool isBase, Coord cords, bool en this.SetupRequiredBaseMocks(isBase, isOneXOne, extent); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) { @@ -325,7 +327,7 @@ public void GetCorrespondingTileWithUpscale(bool isBase, bool isOneXOne, GridOri var extent = new Extent() { MinX = -180, MinY = -90, MaxX = 180, MaxY = 90 }; Grid grid = isOneXOne ? Grid.OneXOne : Grid.TwoXOne; Tile nullTile = null; - var tile = new Tile(2, 2, 3, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); this.SetupRequiredBaseMocks(isBase, isOneXOne, extent); @@ -461,8 +463,9 @@ public void UpdateTiles(bool isBase, bool isOneXOne, GridOrigin origin) var testTiles = new Tile[] { - new Tile(1, 2, 3, this._jpegImageData), new Tile(7, 7, 7, this._jpegImageData), - new Tile(2, 2, 3, this._jpegImageData) + new Tile(this._configurationManagerMock.Object, 1, 2, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 7, 7, 7, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData) }; gpkg.UpdateTiles(testTiles); @@ -708,7 +711,7 @@ public void Reset(bool isOneXOne, bool isBase, GridOrigin origin, int batchSize) this.SetupRequiredBaseMocks(isBase, isOneXOne, extent); this._gpkgUtilsMock.Setup(utils => utils.GetBatch(batchSize, It.IsAny())) - .Returns(new List { new Tile(0, 0, 0, this._jpegImageData) }); + .Returns(new List { new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData) }); if (origin == GridOrigin.UPPER_LEFT) { this._geoUtilsMock.Setup(converter => converter.FlipY(It.IsAny())) @@ -759,8 +762,10 @@ public void GetNextBatch(bool isOneXOne, bool isBase, GridOrigin origin, int bat Grid grid = isOneXOne ? Grid.OneXOne : Grid.TwoXOne; var tiles = new Tile[] { - new Tile(0, 0, 0, this._jpegImageData), new Tile(1, 1, 1, this._jpegImageData), - new Tile(2, 2, 2, this._jpegImageData), new Tile(3, 3, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 1, 1, 1, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 2, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 3, 3, 3, this._jpegImageData), }; var tileBatches = tiles.Chunk(batchSize).ToList(); diff --git a/MergerLogicUnitTests/DataTypes/S3Test.cs b/MergerLogicUnitTests/DataTypes/S3Test.cs index 50b286bf..71f3a43e 100644 --- a/MergerLogicUnitTests/DataTypes/S3Test.cs +++ b/MergerLogicUnitTests/DataTypes/S3Test.cs @@ -7,6 +7,7 @@ using MergerLogic.Utils; using MergerLogicUnitTests.testUtils; using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System; @@ -82,6 +83,8 @@ public void BeforeEach() .Returns(this._configurationManagerMock.Object); this._configurationManagerMock.Setup(cm => cm.GetConfiguration("S3", "bucket")) .Returns("bucket"); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } @@ -144,7 +147,7 @@ public void TileExists(Coord cords, bool isOneXOne, GridOrigin origin, bool useC } else { - var tile = new Tile(cords, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, cords, this._jpegImageData); Assert.AreEqual(expected, s3Source.TileExists(tile)); } @@ -179,7 +182,7 @@ public void GetCorrespondingTileWithoutUpscaleWithoutConversion(int batchSize, i bool expectedNull) { Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); this.SetupConstructorRequiredMocks(); this._s3UtilsMock.Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) @@ -228,7 +231,7 @@ public void GetCorrespondingTileWithoutUpscale(Coord cords, bool enableUpscale, { bool expectedNull = cords.Z != 2; Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); this.SetupConstructorRequiredMocks(true, sequence); @@ -332,7 +335,7 @@ public static IEnumerable GenGetCorrespondingTileWithUpscaleTwoXOnePar public void GetCorrespondingTileWithUpscale(bool isOneXOne, GridOrigin origin, bool isValidConversion) { Tile nullTile = null; - var tile = new Tile(2, 2, 3, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); this.SetupConstructorRequiredMocks(true, sequence); @@ -447,8 +450,9 @@ public void UpdateTiles(bool isOneXOne, GridOrigin origin) { var testTiles = new Tile[] { - new Tile(1, 2, 3, this._jpegImageData), new Tile(7, 7, 7, this._jpegImageData), - new Tile(2, 2, 3, this._jpegImageData) + new Tile(this._configurationManagerMock.Object, 1, 2, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 7, 7, 7, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData) }; var seq = new MockSequence(); this.SetupConstructorRequiredMocks(true, seq); @@ -701,7 +705,7 @@ public void Reset(bool isOneXOne, GridOrigin origin, int batchSize) }); this._s3UtilsMock .Setup(utils => utils.GetTile(It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); if (origin != GridOrigin.LOWER_LEFT) { this._geoUtilsMock diff --git a/MergerLogicUnitTests/DataTypes/TMSTest.cs b/MergerLogicUnitTests/DataTypes/TMSTest.cs index fbd30f71..8ed57be9 100644 --- a/MergerLogicUnitTests/DataTypes/TMSTest.cs +++ b/MergerLogicUnitTests/DataTypes/TMSTest.cs @@ -34,6 +34,7 @@ public class TMSTest private Mock _loggerFactoryMock; private Mock> _loggerMock; private Mock _metricsProviderMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion @@ -47,6 +48,8 @@ public void BeforeEach() this._geoUtilsMock = this._repository.Create(); this._utilsFactoryMock = this._repository.Create(); this._metricsProviderMock = this._repository.Create(MockBehavior.Loose); + this._configurationManagerMock = this._repository.Create(); + this._utilsFactoryMock.Setup(factory => factory.GetDataUtils(It.IsAny())) .Returns(this._httpUtilsMock.Object); @@ -65,6 +68,9 @@ public void BeforeEach() this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); + } #region TileExists @@ -124,7 +130,7 @@ public void TileExists(Coord cords, bool isOneXOne, GridOrigin origin, bool useC } else { - var tile = new Tile(cords, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, cords, this._jpegImageData); Assert.AreEqual(expected, tmsSource.TileExists(tile)); } this._httpUtilsMock.Verify(util => util.TileExists(cords.Z, cords.X, cords.Y), @@ -158,7 +164,7 @@ public void GetCorrespondingTileWithoutUpscaleWithoutConversion(int batchSize, i { this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); this._httpUtilsMock.Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => z == 2 ? existingTile : nullTile); @@ -207,7 +213,7 @@ public void GetCorrespondingTileWithoutUpscale(Coord cords, bool enableUpscale, bool expectedNull = cords.Z != 2; this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) { @@ -311,7 +317,7 @@ public void GetCorrespondingTileWithUpscale(bool isOneXOne, GridOrigin origin, b { this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var tile = new Tile(2, 2, 3, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) @@ -431,8 +437,9 @@ public void UpdateTiles(bool isOneXOne, GridOrigin origin) var testTiles = new Tile[] { - new Tile(1, 2, 3, this._jpegImageData), new Tile(7, 7, 7, this._jpegImageData), - new Tile(2, 2, 3, this._jpegImageData) + new Tile(this._configurationManagerMock.Object, 1, 2, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 7, 7, 7, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData) }; Assert.ThrowsException(() => tmsSource.UpdateTiles(testTiles)); @@ -581,7 +588,7 @@ public void Reset(bool isOneXOne, GridOrigin origin, int batchSize) .Returns(t => t); this._httpUtilsMock .Setup(utils => utils.GetTile(It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); this._oneXOneConvertorMock .Setup(converter => converter.TryFromTwoXOne(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => new Coord(z, x, y)); @@ -590,7 +597,7 @@ public void Reset(bool isOneXOne, GridOrigin origin, int batchSize) { this._httpUtilsMock .Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); } var extent = new Extent() { MinX = -180, MinY = -90, MaxX = 180, MaxY = 90 }; @@ -630,8 +637,11 @@ public void GetNextBatch(bool isOneXOne, GridOrigin origin, int batchSize) // z = 0 is invalid conversion tile z = 2 is missing tile var tiles = new Tile?[] { - new Tile(0, 0, 0, this._jpegImageData), new Tile(1, 0, 0, this._jpegImageData), null, - new Tile(3, 0, 0, this._jpegImageData), new Tile(4, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 1, 0, 0, this._jpegImageData), + null, + new Tile(this._configurationManagerMock.Object, 3, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 4, 0, 0, this._jpegImageData), }; var tileBatches = tiles.Where(t => t is not null && (!isOneXOne || t.Z != 0)).Chunk(batchSize).ToList(); diff --git a/MergerLogicUnitTests/DataTypes/WMTSTest.cs b/MergerLogicUnitTests/DataTypes/WMTSTest.cs index cdad773a..a7fc8f39 100644 --- a/MergerLogicUnitTests/DataTypes/WMTSTest.cs +++ b/MergerLogicUnitTests/DataTypes/WMTSTest.cs @@ -1,4 +1,5 @@ -using MergerLogic.Batching; +using Amazon.Runtime; +using MergerLogic.Batching; using MergerLogic.Clients; using MergerLogic.DataTypes; using MergerLogic.Monitoring.Metrics; @@ -35,6 +36,7 @@ public class WMTSTest private Mock _loggerFactoryMock; private Mock> _loggerMock; private Mock _metricsProviderMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; @@ -49,6 +51,7 @@ public void BeforeEach() this._geoUtilsMock = this._repository.Create(); this._utilsFactoryMock = this._repository.Create(); this._metricsProviderMock = this._repository.Create(MockBehavior.Loose); + this._configurationManagerMock = this._repository.Create(); this._utilsFactoryMock.Setup(factory => factory.GetDataUtils(It.IsAny())) .Returns(this._httpUtilsMock.Object); @@ -66,6 +69,8 @@ public void BeforeEach() .Returns(this._loggerFactoryMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("image.jpeg"); } @@ -127,7 +132,7 @@ public void TileExists(Coord cords, bool isOneXOne, GridOrigin origin, bool useC } else { - var tile = new Tile(cords, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, cords, this._jpegImageData); Assert.AreEqual(expected, wmtsSource.TileExists(tile)); } this._httpUtilsMock.Verify(util => util.TileExists(cords.Z, cords.X, cords.Y), @@ -161,7 +166,7 @@ public void GetCorrespondingTileWithoutUpscaleWithoutConversion(int batchSize, i { this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); this._httpUtilsMock.Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => z == 2 ? existingTile : nullTile); @@ -211,7 +216,7 @@ public void GetCorrespondingTileWithoutUpscale(Coord cords, bool enableUpscale, bool expectedNull = cords.Z != 2; this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) { @@ -315,7 +320,7 @@ public void GetCorrespondingTileWithUpscale(bool isOneXOne, GridOrigin origin, b { this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var tile = new Tile(2, 2, 3, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) @@ -435,8 +440,9 @@ public void UpdateTiles(bool isOneXOne, GridOrigin origin) var testTiles = new Tile[] { - new Tile(1, 2, 3, this._jpegImageData), new Tile(7, 7, 7, this._jpegImageData), - new Tile(2, 2, 3, this._jpegImageData) + new Tile(this._configurationManagerMock.Object, 1, 2, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 7, 7, 7, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData) }; Assert.ThrowsException(() => wmtsSource.UpdateTiles(testTiles)); @@ -585,7 +591,7 @@ public void Reset(bool isOneXOne, GridOrigin origin, int batchSize) .Returns(t => t); this._httpUtilsMock .Setup(utils => utils.GetTile(It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); this._oneXOneConvertorMock .Setup(converter => converter.TryFromTwoXOne(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => new Coord(z, x, y)); @@ -594,7 +600,7 @@ public void Reset(bool isOneXOne, GridOrigin origin, int batchSize) { this._httpUtilsMock .Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); } var extent = new Extent() { MinX = -180, MinY = -90, MaxX = 180, MaxY = 90 }; @@ -634,8 +640,11 @@ public void GetNextBatch(bool isOneXOne, GridOrigin origin, int batchSize) // z = 0 is invalid conversion tile z = 2 is missing tile var tiles = new Tile?[] { - new Tile(0, 0, 0, this._jpegImageData), new Tile(1, 0, 0, this._jpegImageData), null, - new Tile(3, 0, 0, this._jpegImageData), new Tile(4, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 1, 0, 0, this._jpegImageData), + null, + new Tile(this._configurationManagerMock.Object, 3, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 4, 0, 0, this._jpegImageData), }; var tileBatches = tiles.Where(t => t is not null && (!isOneXOne || t.Z != 0)).Chunk(batchSize).ToList(); var seq = new MockSequence(); diff --git a/MergerLogicUnitTests/DataTypes/XYZTest.cs b/MergerLogicUnitTests/DataTypes/XYZTest.cs index 211a985b..e0c10222 100644 --- a/MergerLogicUnitTests/DataTypes/XYZTest.cs +++ b/MergerLogicUnitTests/DataTypes/XYZTest.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Moq.Protected; using System; using System.Collections.Generic; using System.IO; @@ -34,6 +35,7 @@ public class XYZTest private Mock _loggerFactoryMock; private Mock> _loggerMock; private Mock _metricsProviderMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion @@ -47,6 +49,7 @@ public void BeforeEach() this._geoUtilsMock = this._repository.Create(); this._utilsFactoryMock = this._repository.Create(); this._metricsProviderMock = this._repository.Create(MockBehavior.Loose); + this._configurationManagerMock = this._repository.Create(); this._utilsFactoryMock.Setup(factory => factory.GetDataUtils(It.IsAny())) .Returns(this._httpUtilsMock.Object); @@ -64,6 +67,9 @@ public void BeforeEach() .Returns(this._loggerFactoryMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); + this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } @@ -124,7 +130,7 @@ public void TileExists(Coord cords, bool isOneXOne, GridOrigin origin, bool useC } else { - var tile = new Tile(cords, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, cords, this._jpegImageData); Assert.AreEqual(expected, xyzSource.TileExists(tile)); } this._httpUtilsMock.Verify(util => util.TileExists(cords.Z, cords.X, cords.Y), @@ -158,7 +164,7 @@ public void GetCorrespondingTileWithoutUpscaleWithoutConversion(int batchSize, i { this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); this._httpUtilsMock.Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => z == 2 ? existingTile : nullTile); @@ -208,7 +214,7 @@ public void GetCorrespondingTileWithoutUpscale(Coord cords, bool enableUpscale, bool expectedNull = cords.Z != 2; this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var existingTile = new Tile(2, 2, 3, this._jpegImageData); + var existingTile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) { @@ -312,7 +318,7 @@ public void GetCorrespondingTileWithUpscale(bool isOneXOne, GridOrigin origin, b { this.SetupConstructorRequiredMocks(); Tile nullTile = null; - var tile = new Tile(2, 2, 3, this._jpegImageData); + var tile = new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData); var sequence = new MockSequence(); if (origin != GridOrigin.LOWER_LEFT) @@ -432,8 +438,9 @@ public void UpdateTiles(bool isOneXOne, GridOrigin origin) var testTiles = new Tile[] { - new Tile(1, 2, 3, this._jpegImageData), new Tile(7, 7, 7, this._jpegImageData), - new Tile(2, 2, 3, this._jpegImageData) + new Tile(this._configurationManagerMock.Object, 1, 2, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 7, 7, 7, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 3, this._jpegImageData) }; Assert.ThrowsException(() => xyzSource.UpdateTiles(testTiles)); @@ -582,7 +589,7 @@ public void Reset(bool isOneXOne, GridOrigin origin, int batchSize) .Returns(t => t); this._httpUtilsMock .Setup(utils => utils.GetTile(It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); this._oneXOneConvertorMock .Setup(converter => converter.TryFromTwoXOne(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((z, x, y) => new Coord(z, x, y)); @@ -591,7 +598,7 @@ public void Reset(bool isOneXOne, GridOrigin origin, int batchSize) { this._httpUtilsMock .Setup(utils => utils.GetTile(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(new Tile(0, 0, 0, this._jpegImageData)); + .Returns(new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData)); } var extent = new Extent() { MinX = -180, MinY = -90, MaxX = 180, MaxY = 90 }; @@ -631,8 +638,11 @@ public void GetNextBatch(bool isOneXOne, GridOrigin origin, int batchSize) // z = 0 is invalid conversion tile z = 2 is missing tile var tiles = new Tile?[] { - new Tile(0, 0, 0, this._jpegImageData), new Tile(1, 0, 0, this._jpegImageData), null, - new Tile(3, 0, 0, this._jpegImageData), new Tile(4, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 1, 0, 0, this._jpegImageData), + null, + new Tile(this._configurationManagerMock.Object, 3, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 4, 0, 0, this._jpegImageData), }; var tileBatches = tiles.Where(t => t is not null && (!isOneXOne || t.Z != 0)).Chunk(batchSize).ToList(); var seq = new MockSequence(); diff --git a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs index 536ac9b9..0eed29a3 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs @@ -2,6 +2,7 @@ using MergerLogic.DataTypes; using MergerLogic.ImageProcessing; using MergerLogic.Monitoring.Metrics; +using MergerLogic.Utils; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -24,6 +25,8 @@ public class TileMergerTest private TileMerger _testTileMerger; + private Mock _configurationManagerMock; + #endregion [TestInitialize] @@ -34,14 +37,18 @@ public void BeforeEach() var metricsProviderMock = this._mockRepository.Create(); var tileScalerLoggerMock = this._mockRepository.Create>(); var tileMergerLoggerMock = this._mockRepository.Create>(); + this._configurationManagerMock = this._mockRepository.Create(); + + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); - var testTileScaler = new TileScaler(metricsProviderMock.Object, tileScalerLoggerMock.Object); - this._testTileMerger = new TileMerger(testTileScaler, tileMergerLoggerMock.Object); + var testTileScaler = new TileScaler(metricsProviderMock.Object, tileScalerLoggerMock.Object, this._configurationManagerMock.Object); + this._testTileMerger = new TileMerger(testTileScaler, tileMergerLoggerMock.Object, this._configurationManagerMock.Object); } #region MergeTiles - public static IEnumerable GetMergeTilesTestParameters() + public IEnumerable GetMergeTilesTestParameters() { var targetCoordLowZoom = new Coord(5, 0, 0); var targetCoordMediumZoom = new Coord(14, 0, 0); @@ -50,114 +57,114 @@ public static IEnumerable GetMergeTilesTestParameters() #region Regular merge test cases yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, 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")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, 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")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3_4_merged.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png), TileFormat.Png, false, 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")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Png, false, 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")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Png, false, 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")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Jpeg, false, 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")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Jpeg, false, File.ReadAllBytes("3_4_merged.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("5.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("5.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("5.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("5.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Jpeg, false, File.ReadAllBytes("5.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordLowZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordLowZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3_1_merged_upscaled_5_15.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordMediumZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordMediumZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("3_1_merged_upscaled_14_15.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, false, File.ReadAllBytes("4.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Jpeg, false, File.ReadAllBytes("3_2_1_merged.jpeg"), }; @@ -166,118 +173,118 @@ public static IEnumerable GetMergeTilesTestParameters() #region Test cases for ignoring target yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("1.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("1.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("3.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("4.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png), TileFormat.Png, true, File.ReadAllBytes("1.png"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Png, true, File.ReadAllBytes("1.png"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Png, true, File.ReadAllBytes("1.png"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Png, true, File.ReadAllBytes("1.png"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("2_1_merged.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("3_1_merged.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("3.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("4.jpeg")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Jpeg), TileFormat.Jpeg, true, File.ReadAllBytes("4.jpeg"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png), TileFormat.Png, true, File.ReadAllBytes("2_1_merged.png"), }; yield return new object[] { new Tile[] { - new Tile(targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("2.png")), - new Tile(targetCoordHighZoom, File.ReadAllBytes("1.png")) + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("3.jpeg")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("2.png")), + new Tile(this._configurationManagerMock.Object, targetCoordHighZoom, File.ReadAllBytes("1.png")) }, targetCoordHighZoom, new TileFormatStrategy(TileFormat.Png, TileFormatStrategy.FormatStrategy.Mixed), TileFormat.Png, true, File.ReadAllBytes("2_1_merged.png"), }; diff --git a/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs index ffeb3fc3..3c16c2c9 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs @@ -1,7 +1,9 @@ -using MergerLogic.Batching; +using Castle.Components.DictionaryAdapter.Xml; +using MergerLogic.Batching; using MergerLogic.DataTypes; using MergerLogic.ImageProcessing; using MergerLogic.Monitoring.Metrics; +using MergerLogic.Utils; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -20,6 +22,7 @@ public class TileScalerTest #region mocks private MockRepository _mockRepository; + private Mock _configurationManagerMock; private TileScaler _testTileScaler; @@ -32,8 +35,12 @@ public void BeforeEach() var metricsProviderMock = this._mockRepository.Create(); var tileScalerLoggerMock = this._mockRepository.Create>(); + this._configurationManagerMock = this._mockRepository.Create(); - this._testTileScaler = new TileScaler(metricsProviderMock.Object, tileScalerLoggerMock.Object); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); + + this._testTileScaler = new TileScaler(metricsProviderMock.Object, tileScalerLoggerMock.Object, this._configurationManagerMock.Object); } #region Upscale @@ -110,7 +117,7 @@ public void BeforeEach() [DynamicData(nameof(GetUpscaleTilesTestParameters), DynamicDataSourceType.Method)] public void Upscale(byte[] tileBytes, Coord baseTileCoord, Coord targetCoord, byte[]? expectedTileBytes) { - var testTile = new Tile(baseTileCoord, tileBytes); + var testTile = new Tile(this._configurationManagerMock.Object, baseTileCoord, tileBytes); var resultTile = this._testTileScaler.Upscale(testTile, targetCoord); if (expectedTileBytes is null) diff --git a/MergerLogicUnitTests/Utils/GeoUtilsTest.cs b/MergerLogicUnitTests/Utils/GeoUtilsTest.cs index 8740ccbf..02be4224 100644 --- a/MergerLogicUnitTests/Utils/GeoUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/GeoUtilsTest.cs @@ -3,6 +3,7 @@ using MergerLogic.Utils; using MergerLogicUnitTests.testUtils; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using System; using System.Collections.Generic; using System.IO; @@ -19,6 +20,8 @@ public class GeoUtilsTest { #region mocks + private MockRepository _repository; + private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion @@ -26,6 +29,8 @@ public class GeoUtilsTest [TestInitialize] public void BeforeEach() { + this._configurationManagerMock = this._repository.Create(); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")).Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } @@ -58,7 +63,7 @@ public void FlipY(GetFlipYParamType paramType, Coord coords) res = geoUtils.FlipY(coords.Z, coords.Y); break; case GetFlipYParamType.Tile: - res = geoUtils.FlipY(new Tile(coords, this._jpegImageData)); + res = geoUtils.FlipY(new Tile(this._configurationManagerMock.Object, coords, this._jpegImageData)); break; } Assert.AreEqual(coords.X, res); diff --git a/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs b/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs index dc5ff40b..389e8aac 100644 --- a/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs @@ -32,6 +32,7 @@ public class GpkgUtilsTest private Mock _fileSystemMock; private Mock _pathMock; private Mock _fileMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion @@ -45,9 +46,13 @@ public void BeforeEach() this._pathMock = this._repository.Create(); this._fileMock = this._repository.Create(); this._fileSystemMock = this._repository.Create(); + this._configurationManagerMock = this._repository.Create(); + this._loggerMock = this._repository.Create>(MockBehavior.Loose); + this._fileSystemMock.SetupGet(fs => fs.File).Returns(this._fileMock.Object); this._fileSystemMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); - this._loggerMock = this._repository.Create>(MockBehavior.Loose); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } @@ -70,7 +75,7 @@ public void GetTile(bool exist, bool useCoords) { var data = this._jpegImageData; var cords = new Coord(0, 0, 0); - var testTiles = exist ? new Tile[] { new Tile(cords, data) } : Array.Empty(); + var testTiles = exist ? new Tile[] { new Tile(this._configurationManagerMock.Object, cords, data) } : Array.Empty(); string path = this.GetGpkgPath(); using (var connection = new SQLiteConnection($"Data Source={path}")) @@ -80,7 +85,7 @@ public void GetTile(bool exist, bool useCoords) this.CreateTestTiles(connection, testTiles); //create tile table var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var res = useCoords ? gpkgUtils.GetTile(cords) : gpkgUtils.GetTile(cords.Z, cords.X, cords.Y); @@ -111,7 +116,7 @@ public void TileExists(bool exist) { var data = this._jpegImageData; var cords = new Coord(0, 0, 0); - var testTiles = exist ? new Tile[] { new Tile(cords, data) } : Array.Empty(); + var testTiles = exist ? new Tile[] { new Tile(this._configurationManagerMock.Object, cords, data) } : Array.Empty(); string path = this.GetGpkgPath(); using (var connection = new SQLiteConnection($"Data Source={path}")) @@ -121,7 +126,7 @@ public void TileExists(bool exist) this.CreateTestTiles(connection, testTiles); //create tile table var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var res = gpkgUtils.TileExists(cords.Z, cords.X, cords.Y); @@ -149,9 +154,12 @@ public void GetBatch(int batchSize, int offset) string path = this.GetGpkgPath(); var testTiles = new Tile[] { - new Tile(0, 0, 0, this._jpegImageData), new Tile(1, 1, 1, this._jpegImageData), - new Tile(2, 2, 2, this._jpegImageData),new Tile(3, 3, 3, this._jpegImageData), - new Tile(4, 4, 4, this._jpegImageData),new Tile(5, 5, 5, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 1, 1, 1, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 2, 2, 2, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 3, 3, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 4, 4, 4, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 5, 5, 5, this._jpegImageData), }; using (var connection = new SQLiteConnection($"Data Source={path}")) @@ -161,7 +169,7 @@ public void GetBatch(int batchSize, int offset) this.CreateTestTiles(connection, testTiles); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var comparer = ComparerFactory.Create((t1, t2) => t1?.Z == t2?.Z && t1?.X == t2?.X && t1?.Y == t2?.Y ? 0 : -1); var res = gpkgUtils.GetBatch(batchSize, offset); @@ -179,7 +187,7 @@ public void GetBatchWithLongOffset() string path = this.GetGpkgPath(); var testTiles = new Tile[] { - new Tile(0, 0, 0, this._jpegImageData) + new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData) }; using (var connection = new SQLiteConnection($"Data Source={path}")) @@ -189,7 +197,7 @@ public void GetBatchWithLongOffset() this.CreateTestTiles(connection, testTiles); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var res = gpkgUtils.GetBatch(21, offset); CollectionAssert.AreEqual(Array.Empty(), res); @@ -227,7 +235,7 @@ public void GetExtent(Extent extent) this.SetupConstructorRequiredMocks(connection, extent: extent); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var res = gpkgUtils.GetExtent(); Assert.AreEqual(extent, res); @@ -257,8 +265,9 @@ public void GetLastTile(Coord baseCoords) string path = this.GetGpkgPath(); var testTiles = new Tile[] { - new Tile(3, 3, 3, this._jpegImageData), - new Tile(4, 4, 4, this._jpegImageData),new Tile(5, 5, 5, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 3, 3, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 4, 4, 4, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 5, 5, 5, this._jpegImageData), }; using (var connection = new SQLiteConnection($"Data Source={path}")) @@ -268,7 +277,7 @@ public void GetLastTile(Coord baseCoords) this.CreateTestTiles(connection, testTiles); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var coords = new List(); for (int i = 0; i < baseCoords.Z; i++) { @@ -313,7 +322,7 @@ public void GetTileCount(int tileCount) var testTiles = new List(tileCount); for (int i = 0; i < tileCount; i++) { - testTiles.Add(new Tile(0, i, 0, this._jpegImageData)); + testTiles.Add(new Tile(this._configurationManagerMock.Object, 0, i, 0, this._jpegImageData)); }; using (var connection = new SQLiteConnection($"Data Source={path}")) @@ -323,7 +332,7 @@ public void GetTileCount(int tileCount) this.CreateTestTiles(connection, testTiles); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var res = gpkgUtils.GetTileCount(); Assert.AreEqual(tileCount, res); @@ -340,11 +349,13 @@ public void GetTileCount(int tileCount) public void InsertTiles() { string path = this.GetGpkgPath(); - var existingTiles = new Tile[] { new Tile(0, 0, 0, this._jpegImageData), new Tile(3, 3, 3, this._jpegImageData) }; + var existingTiles = new Tile[] { new Tile(this._configurationManagerMock.Object, 0, 0, 0, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 3, 3, 3, this._jpegImageData) }; var testTiles = new Tile[] { - new Tile(3, 3, 3, this._jpegImageData), - new Tile(4, 4, 4, this._jpegImageData),new Tile(5, 5, 5, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 3, 3, 3, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 4, 4, 4, this._jpegImageData), + new Tile(this._configurationManagerMock.Object, 5, 5, 5, this._jpegImageData), }; using (var connection = new SQLiteConnection($"Data Source={path}")) @@ -354,7 +365,7 @@ public void InsertTiles() this.CreateTestTiles(connection, existingTiles); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); gpkgUtils.InsertTiles(testTiles); @@ -367,7 +378,7 @@ public void InsertTiles() { while (reader.Read()) { - res.Add(new Tile(reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), (byte[])reader["tile_data"])); + res.Add(new Tile(this._configurationManagerMock.Object, reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), (byte[])reader["tile_data"])); } } } @@ -401,7 +412,7 @@ public void UpdateExtent(Extent extent) this.SetupConstructorRequiredMocks(connection); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); gpkgUtils.UpdateExtent(extent); using (var command = connection.CreateCommand()) @@ -451,7 +462,7 @@ public void Exist(bool exist) .Returns(exist); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); Assert.AreEqual(exist, gpkgUtils.Exist()); @@ -486,7 +497,7 @@ public void DeleteTileTableTriggers() } var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); gpkgUtils.DeleteTileTableTriggers(); @@ -518,7 +529,7 @@ public void CreateTileCacheValidationTriggers() this.CreateTestTiles(connection, Array.Empty()); var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); gpkgUtils.CreateTileCacheValidationTriggers(); @@ -563,7 +574,7 @@ public void UpdateTileMatrixTable(bool isOneXOne, int maxZoom) { connection.Open(); this.SetupConstructorRequiredMocks(connection); - this.CreateTestTiles(connection, new Tile[] { new Tile(maxZoom, 0, 0, this._jpegImageData) }); + this.CreateTestTiles(connection, new Tile[] { new Tile(this._configurationManagerMock.Object, maxZoom, 0, 0, this._jpegImageData) }); using (var command = connection.CreateCommand()) { command.CommandText = "CREATE TABLE gpkg_tile_matrix (" + @@ -579,7 +590,7 @@ public void UpdateTileMatrixTable(bool isOneXOne, int maxZoom) } var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); gpkgUtils.UpdateTileMatrixTable(isOneXOne); @@ -692,7 +703,7 @@ public void IsValidGridWithValidMatrixSet(bool isOneXOne, string gridValues, boo } var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); Assert.AreEqual(expected, gpkgUtils.IsValidGrid(isOneXOne)); } @@ -758,7 +769,7 @@ public void IsValidGridWithInvalidMatrixSet(bool isOneXOne, string matrixSetValu } var gpkgUtils = new GpkgClient(path, this._timeUtilsMock.Object, this._loggerMock.Object, - this._fileSystemMock.Object, this._geoUtilsMock.Object); + this._fileSystemMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); Assert.AreEqual(expected, gpkgUtils.IsValidGrid(isOneXOne)); } diff --git a/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs b/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs index bfc9faf4..ac94d0e1 100644 --- a/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs @@ -19,6 +19,7 @@ public class HttpSourceUtilsTest private Mock _httpRequestUtilsMock; private Mock _pathPatternUtilsMock; private Mock _geoUtilsMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion @@ -29,6 +30,10 @@ public void beforeEach() this._httpRequestUtilsMock = this._repository.Create(); this._pathPatternUtilsMock = this._repository.Create(); this._geoUtilsMock = this._repository.Create(); + this._configurationManagerMock = this._repository.Create(); + + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } @@ -51,7 +56,7 @@ public void GetTile(bool useCoords, bool returnsNull) .Returns(returnsNull ? null : data); var httpSourceUtils = new HttpSourceClient("http://testPath", this._httpRequestUtilsMock.Object, - this._pathPatternUtilsMock.Object, this._geoUtilsMock.Object); + this._pathPatternUtilsMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var res = useCoords ? httpSourceUtils.GetTile(cords) : httpSourceUtils.GetTile(cords.Z, cords.X, cords.Y); if (returnsNull) @@ -86,7 +91,7 @@ public void TileExists(bool exist) .Returns(exist ? data : null); var httpSourceUtils = new HttpSourceClient("http://testPath", this._httpRequestUtilsMock.Object, - this._pathPatternUtilsMock.Object, this._geoUtilsMock.Object); + this._pathPatternUtilsMock.Object, this._geoUtilsMock.Object, this._configurationManagerMock.Object); var res = httpSourceUtils.TileExists(cords.Z, cords.X, cords.Y); diff --git a/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs b/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs index 0706d4c7..75233a23 100644 --- a/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs +++ b/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs @@ -3,6 +3,7 @@ using MergerLogic.Utils; using MergerLogicUnitTests.testUtils; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using System.Collections.Generic; using System.IO; @@ -25,6 +26,8 @@ public enum OneXOneConvertorParameterType #region mocks + private MockRepository _repository; + private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion @@ -32,6 +35,9 @@ public enum OneXOneConvertorParameterType [TestInitialize] public void BeforeEach() { + this._configurationManagerMock = this._repository.Create(); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } @@ -66,7 +72,7 @@ public void FromTwoXOneCoords(OneXOneConvertorParameterType convertorParameterTy { OneXOneConvertorParameterType.Cords => convertor.FromTwoXOne(testData), OneXOneConvertorParameterType.Ints => convertor.FromTwoXOne(testData.Z, testData.X, testData.Y), - OneXOneConvertorParameterType.Tile => convertor.FromTwoXOne(new Tile(testData, this._jpegImageData)), + OneXOneConvertorParameterType.Tile => convertor.FromTwoXOne(new Tile(this._configurationManagerMock.Object, testData, this._jpegImageData)), _ => null }; @@ -123,7 +129,7 @@ public void TryFromTwoXOneCoords(OneXOneConvertorParameterType convertorParamete { OneXOneConvertorParameterType.Cords => convertor.TryFromTwoXOne(testData), OneXOneConvertorParameterType.Ints => convertor.TryFromTwoXOne(testData.Z, testData.X, testData.Y), - OneXOneConvertorParameterType.Tile => convertor.TryFromTwoXOne(new Tile(testData, this._jpegImageData)), + OneXOneConvertorParameterType.Tile => convertor.TryFromTwoXOne(new Tile(this._configurationManagerMock.Object, testData, this._jpegImageData)), _ => null }; @@ -186,7 +192,7 @@ public void ToTwoXOneCoords(OneXOneConvertorParameterType convertorParameterType { OneXOneConvertorParameterType.Cords => convertor.ToTwoXOne(testData), OneXOneConvertorParameterType.Ints => convertor.ToTwoXOne(testData.Z, testData.X, testData.Y), - OneXOneConvertorParameterType.Tile => convertor.ToTwoXOne(new Tile(testData, this._jpegImageData)), + OneXOneConvertorParameterType.Tile => convertor.ToTwoXOne(new Tile(this._configurationManagerMock.Object, testData, this._jpegImageData)), _ => null }; @@ -243,7 +249,7 @@ public void TryToTwoXOneCoords(OneXOneConvertorParameterType convertorParameterT object? res = convertorParameterType switch { OneXOneConvertorParameterType.Ints => convertor.TryToTwoXOne(testData.Z, testData.X, testData.Y), - OneXOneConvertorParameterType.Tile => convertor.TryToTwoXOne(new Tile(testData, this._jpegImageData)), + OneXOneConvertorParameterType.Tile => convertor.TryToTwoXOne(new Tile(this._configurationManagerMock.Object, testData, this._jpegImageData)), _ => null }; diff --git a/MergerLogicUnitTests/Utils/PathUtilsTest.cs b/MergerLogicUnitTests/Utils/PathUtilsTest.cs index 3002162c..934bbdd9 100644 --- a/MergerLogicUnitTests/Utils/PathUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/PathUtilsTest.cs @@ -22,6 +22,7 @@ public class PathUtilsTest private Mock _fileSystemMock; private Mock _pathMock; private Mock _imageFormaterMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; private byte[] _pngImageData; @@ -36,6 +37,9 @@ public void BeforeEach() this._fileSystemMock = this._repository.Create(); this._fileSystemMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); this._imageFormaterMock = this._repository.Create(); + this._configurationManagerMock = this._repository.Create(); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); this._pngImageData = File.ReadAllBytes("no_transparency.png"); @@ -76,7 +80,7 @@ public void GetTilePathTile(TileFormat format) { var data = format == TileFormat.Jpeg ? this._jpegImageData : this._pngImageData; var utils = new PathUtils(this._fileSystemMock.Object); - var res = utils.GetTilePath("test#subTest", new Tile(0, 1, 2, data)); + var res = utils.GetTilePath("test#subTest", new Tile(this._configurationManagerMock.Object, 0, 1, 2, data)); Assert.AreEqual($"test#subTest#0#1#2.{format.ToString().ToLower()}", res); } diff --git a/MergerLogicUnitTests/Utils/S3UtilsTest.cs b/MergerLogicUnitTests/Utils/S3UtilsTest.cs index 19739c8b..d239ee75 100644 --- a/MergerLogicUnitTests/Utils/S3UtilsTest.cs +++ b/MergerLogicUnitTests/Utils/S3UtilsTest.cs @@ -33,6 +33,7 @@ public class S3UtilsTest private Mock _imageFormatterMock; private Mock> _loggerMock; private Mock _loggerFactoryMock; + private Mock _configurationManagerMock; private byte[] _jpegImageData; @@ -46,10 +47,13 @@ public void BeforeEach() this._pathUtilsMock = this._repository.Create(); this._geoUtilsMock = this._repository.Create(); this._imageFormatterMock = this._repository.Create(); + this._configurationManagerMock = this._repository.Create(); this._loggerMock = this._repository.Create>(MockBehavior.Loose); this._loggerFactoryMock = this._repository.Create(); this._loggerFactoryMock.Setup(f => f.CreateLogger(It.IsAny())).Returns(this._loggerMock.Object); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } @@ -124,7 +128,7 @@ public void GetTile(bool exist, GetTileParamType paramType, TileFormat tileForma } var s3Utils = new S3Client(this._s3ClientMock.Object, this._pathUtilsMock.Object, - this._geoUtilsMock.Object, this._loggerMock.Object, "STANDARD", "bucket", "test"); + this._geoUtilsMock.Object, this._loggerMock.Object, this._configurationManagerMock.Object, "STANDARD", "bucket", "test"); Tile tile = null; switch (paramType) @@ -206,7 +210,7 @@ public void TileExists(bool exist) }); var s3Utils = new S3Client(this._s3ClientMock.Object, this._pathUtilsMock.Object, - this._geoUtilsMock.Object, this._loggerMock.Object, "STANDARD", "bucket", "test"); + this._geoUtilsMock.Object, this._loggerMock.Object, this._configurationManagerMock.Object, "STANDARD", "bucket", "test"); Assert.AreEqual(exist, s3Utils.TileExists(0, 0, 0)); @@ -227,7 +231,7 @@ public void UpdateTile() var buff = this._jpegImageData; int readLen = -1; var seq = new MockSequence(); - var testTile = new Tile(0, 0, 0, buff); + var testTile = new Tile(this._configurationManagerMock.Object, 0, 0, 0, buff); this._pathUtilsMock .InSequence(seq) .Setup(utils => utils.GetTilePath("test", testTile, true)) @@ -243,7 +247,7 @@ public void UpdateTile() }); var s3Utils = new S3Client(this._s3ClientMock.Object, this._pathUtilsMock.Object, - this._geoUtilsMock.Object, this._loggerMock.Object, "STANDARD", "bucket", "test"); + this._geoUtilsMock.Object, this._loggerMock.Object, this._configurationManagerMock.Object, "STANDARD", "bucket", "test"); s3Utils.UpdateTile(testTile); this._pathUtilsMock.Verify(utils => utils.GetTilePath(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); diff --git a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs index 5522ac56..cb85cafb 100644 --- a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs +++ b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs @@ -19,221 +19,225 @@ namespace MergerLogicUnitTests.Utils { - [TestClass] - [TestCategory("unit")] - [TestCategory("runners")] - [DeploymentItem(@"../../../Runners/TestData")] - public class TaskExecutorTest + [TestClass] + [TestCategory("unit")] + [TestCategory("runners")] + [DeploymentItem(@"../../../Runners/TestData")] + public class TaskExecutorTest + { + #region mocks + + private MockRepository _mockRepository; + + private Mock _dataFactoryMock; + private Mock _timeUtilsMock; + private Mock _configurationManagerMock; + private Mock> _taskExecutorLoggerMock; + private Mock _metricsProviderMock; + private Mock _taskUtilsMock; + private Mock _tileScalerMock; + private Mock> _tileMergerLoggerMock; + + private ActivitySource _testActivitySource; + private ITileMerger _testTileMerger; + private IFileSystem _testFileSystem; + + #endregion + + public static IEnumerable GetSingleTileTestParameters() { - #region mocks - - private MockRepository _mockRepository; - - private Mock _dataFactoryMock; - private Mock _timeUtilsMock; - private Mock _configurationManagerMock; - private Mock> _taskExecutorLoggerMock; - private Mock _metricsProviderMock; - private Mock _taskUtilsMock; - private Mock _tileScalerMock; - private Mock> _tileMergerLoggerMock; - - private ActivitySource _testActivitySource; - private ITileMerger _testTileMerger; - private IFileSystem _testFileSystem; - - #endregion - - public static IEnumerable GetSingleTileTestParameters() - { - yield return new object[] { 1, true }; - yield return new object[] { 3, true }; - yield return new object[] { 54, true }; - yield return new object[] { 1, false }; - yield return new object[] { 5, false }; - yield return new object[] { 14, false }; - } - - [TestInitialize] - public void BeforeEach() - { - this._mockRepository = new MockRepository(MockBehavior.Loose); - - this._dataFactoryMock = this._mockRepository.Create(); - this._timeUtilsMock = this._mockRepository.Create(); - this._configurationManagerMock = this._mockRepository.Create(); - this._taskExecutorLoggerMock = this._mockRepository.Create>(); - this._metricsProviderMock = this._mockRepository.Create(); - this._taskUtilsMock = this._mockRepository.Create(); - this._tileScalerMock = this._mockRepository.Create(); - this._tileMergerLoggerMock = this._mockRepository.Create>(); - - this._testActivitySource = new ActivitySource("test"); - this._testTileMerger = new TileMerger(_tileScalerMock.Object, _tileMergerLoggerMock.Object); - this._testFileSystem = new FileSystem(); - } - - [TestMethod] - [DynamicData(nameof(GetSingleTileTestParameters), DynamicDataSourceType.Method)] - public void WhenGivenSourcesWithOneTile_ShouldWriteAllTilesToTarget(int numberOfSources, bool isTargetNew) - { - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "batchMaxSize")).Returns(1); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "limitBatchSize")).Returns(true); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchMaxBytes")).Returns(1); - - var taskTargetTuple = this.SetupTestTask(numberOfSources, isTargetNew); - var testTask = taskTargetTuple.Item1; - var targetDataMock = taskTargetTuple.Item2; - var testSourceTiles = taskTargetTuple.Item3; - var resultWrittenTiles = new List(); - - var testTaskExecutor = new TaskExecutor(_dataFactoryMock.Object, _testTileMerger, _timeUtilsMock.Object, - _configurationManagerMock.Object, _taskExecutorLoggerMock.Object, _testActivitySource, _testFileSystem, - _metricsProviderMock.Object); - - targetDataMock.Setup(targetData => targetData.UpdateTiles(It.IsAny>())).Callback>( - resultWrittenTiles.AddRange - ); - - testTaskExecutor.ExecuteTask(testTask, _taskUtilsMock.Object, null); - - targetDataMock.Verify(targetData => targetData.UpdateTiles(It.Is>( - tiles => tiles.All( - tile => testSourceTiles.Any(sourceTile => sourceTile.Z == tile.Z && sourceTile.X == tile.X && sourceTile.Y == tile.Y) - ) - )), Times.Exactly(numberOfSources)); - targetDataMock.Verify(targetData => targetData.Wrapup(), Times.Once); - - Assert.AreEqual(testSourceTiles.Length, resultWrittenTiles.Count); - Assert.IsTrue(testSourceTiles.All( - tile => resultWrittenTiles.Any(sourceTile => sourceTile.Z == tile.Z && sourceTile.X == tile.X && sourceTile.Y == tile.Y) - )); - } - - public static IEnumerable GetBatchLimitTestParameters() - { - // Tests that given a batch limit size, it flushes every time it reaches the limit - // 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[] { + yield return new object[] { 1, true }; + yield return new object[] { 3, true }; + yield return new object[] { 54, true }; + yield return new object[] { 1, false }; + yield return new object[] { 5, false }; + yield return new object[] { 14, false }; + } + + [TestInitialize] + public void BeforeEach() + { + this._mockRepository = new MockRepository(MockBehavior.Loose); + + this._dataFactoryMock = this._mockRepository.Create(); + this._timeUtilsMock = this._mockRepository.Create(); + this._configurationManagerMock = this._mockRepository.Create(); + this._taskExecutorLoggerMock = this._mockRepository.Create>(); + this._metricsProviderMock = this._mockRepository.Create(); + this._taskUtilsMock = this._mockRepository.Create(); + this._tileScalerMock = this._mockRepository.Create(); + this._tileMergerLoggerMock = this._mockRepository.Create>(); + + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); + + this._testActivitySource = new ActivitySource("test"); + this._testTileMerger = new TileMerger(_tileScalerMock.Object, _tileMergerLoggerMock.Object, _configurationManagerMock.Object); + this._testFileSystem = new FileSystem(); + } + + [TestMethod] + [DynamicData(nameof(GetSingleTileTestParameters), DynamicDataSourceType.Method)] + public void WhenGivenSourcesWithOneTile_ShouldWriteAllTilesToTarget(int numberOfSources, bool isTargetNew) + { + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "batchMaxSize")).Returns(1); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "limitBatchSize")).Returns(true); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchMaxBytes")).Returns(1); + + var taskTargetTuple = this.SetupTestTask(numberOfSources, isTargetNew); + var testTask = taskTargetTuple.Item1; + var targetDataMock = taskTargetTuple.Item2; + var testSourceTiles = taskTargetTuple.Item3; + var resultWrittenTiles = new List(); + + var testTaskExecutor = new TaskExecutor(_dataFactoryMock.Object, _testTileMerger, _timeUtilsMock.Object, + _configurationManagerMock.Object, _taskExecutorLoggerMock.Object, _testActivitySource, _testFileSystem, + _metricsProviderMock.Object); + + targetDataMock.Setup(targetData => targetData.UpdateTiles(It.IsAny>())).Callback>( + resultWrittenTiles.AddRange + ); + + testTaskExecutor.ExecuteTask(testTask, _taskUtilsMock.Object, null); + + targetDataMock.Verify(targetData => targetData.UpdateTiles(It.Is>( + tiles => tiles.All( + tile => testSourceTiles.Any(sourceTile => sourceTile.Z == tile.Z && sourceTile.X == tile.X && sourceTile.Y == tile.Y) + ) + )), Times.Exactly(numberOfSources)); + targetDataMock.Verify(targetData => targetData.Wrapup(), Times.Once); + + Assert.AreEqual(testSourceTiles.Length, resultWrittenTiles.Count); + Assert.IsTrue(testSourceTiles.All( + tile => resultWrittenTiles.Any(sourceTile => sourceTile.Z == tile.Z && sourceTile.X == tile.X && sourceTile.Y == tile.Y) + )); + } + + public static IEnumerable GetBatchLimitTestParameters() + { + // Tests that given a batch limit size, it flushes every time it reaches the limit + // 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 }; - // 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[] { + // 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 }; - } - - [TestMethod] - [DynamicData(nameof(GetBatchLimitTestParameters), DynamicDataSourceType.Method)] - public void WhenConfiguringBatchLimits_ShouldWriteTilesEachTimeAfterReachingBatchLimit(bool limitBatchSize, int batchMaxSize, long batchMaxBytes, int amountOfFlushes, int totalAmountOfTiles) - { - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "batchMaxSize")).Returns(batchMaxSize); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "limitBatchSize")).Returns(limitBatchSize); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchMaxBytes")).Returns(batchMaxBytes); - - byte[] tileBytes = File.ReadAllBytes("tile.jpeg"); - Source testTarget = new Source("target", "target_type", new Extent(), GridOrigin.UPPER_LEFT, Grid.TwoXOne); - Mock targetDataMock = this._mockRepository.Create(); - - Source testSource = new Source($"source", $"source_type"); - Coord[] testSourceCoords = new int[totalAmountOfTiles].Select((_, index) => new Coord(1, index, 0)).ToArray(); - Tile[] testSourceTiles = testSourceCoords.Select(coord => new Tile(coord, tileBytes)).ToArray(); - TileBounds tileBounds = new TileBounds(1, 0, testSourceCoords.Length, 0, 1); - Mock sourceDataMock = this._mockRepository.Create(); - - for (var testSourceCoordIdx = 0; testSourceCoordIdx < testSourceCoords.Length; testSourceCoordIdx++) - { - sourceDataMock.Setup(sourceData => sourceData.GetCorrespondingTile(testSourceCoords[testSourceCoordIdx], It.IsAny())).Returns(testSourceTiles[testSourceCoordIdx]); - } - - this._dataFactoryMock.Setup( + } + + [TestMethod] + [DynamicData(nameof(GetBatchLimitTestParameters), DynamicDataSourceType.Method)] + public void WhenConfiguringBatchLimits_ShouldWriteTilesEachTimeAfterReachingBatchLimit(bool limitBatchSize, int batchMaxSize, long batchMaxBytes, int amountOfFlushes, int totalAmountOfTiles) + { + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "batchMaxSize")).Returns(batchMaxSize); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "limitBatchSize")).Returns(limitBatchSize); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchMaxBytes")).Returns(batchMaxBytes); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")).Returns(256); + + byte[] tileBytes = File.ReadAllBytes("tile.jpeg"); + Source testTarget = new Source("target", "target_type", new Extent(), GridOrigin.UPPER_LEFT, Grid.TwoXOne); + Mock targetDataMock = this._mockRepository.Create(); + + Source testSource = new Source($"source", $"source_type"); + Coord[] testSourceCoords = new int[totalAmountOfTiles].Select((_, index) => new Coord(1, index, 0)).ToArray(); + Tile[] testSourceTiles = testSourceCoords.Select(coord => new Tile(_configurationManagerMock.Object, coord, tileBytes)).ToArray(); + TileBounds tileBounds = new TileBounds(1, 0, testSourceCoords.Length, 0, 1); + Mock sourceDataMock = this._mockRepository.Create(); + + for (var testSourceCoordIdx = 0; testSourceCoordIdx < testSourceCoords.Length; testSourceCoordIdx++) + { + sourceDataMock.Setup(sourceData => sourceData.GetCorrespondingTile(testSourceCoords[testSourceCoordIdx], It.IsAny())).Returns(testSourceTiles[testSourceCoordIdx]); + } + + this._dataFactoryMock.Setup( + dataFactory => dataFactory.CreateDataSource( + testSource.Type, testSource.Path, It.IsAny(), + testSource.Grid, testSource.Origin, testSource.Extent, It.IsAny()) + ).Returns(sourceDataMock.Object); + + this._dataFactoryMock.Setup( + dataFactory => dataFactory.CreateDataSource( + testTarget.Type, testTarget.Path, It.IsAny(), + testTarget.Grid, testTarget.Origin, testTarget.Extent, It.IsAny()) + ).Returns(targetDataMock.Object); + + var testTask = new MergeTask("id", "type", "description", + new MergeMetadata( + TileFormat.Jpeg, true, new TileBounds[] { tileBounds }, + new Source[] { testTarget, testSource } + ), + Status.PENDING, null, "reason", 0, "jobId", true, new DateTime(), new DateTime() + ); + + var resultWrittenTiles = new List(); + var testTaskExecutor = new TaskExecutor(_dataFactoryMock.Object, _testTileMerger, _timeUtilsMock.Object, + _configurationManagerMock.Object, _taskExecutorLoggerMock.Object, _testActivitySource, _testFileSystem, + _metricsProviderMock.Object); + + targetDataMock.Setup(targetData => targetData.UpdateTiles(It.IsAny>())).Callback>( + resultWrittenTiles.AddRange + ); + + testTaskExecutor.ExecuteTask(testTask, _taskUtilsMock.Object, null); + + targetDataMock.Verify(targetData => targetData.UpdateTiles(It.IsAny>()), Times.Exactly(amountOfFlushes)); + targetDataMock.Verify(targetData => targetData.Wrapup(), Times.Once); + Assert.AreEqual(testSourceTiles.Length, resultWrittenTiles.Count); + Assert.IsTrue(testSourceTiles.All( + tile => resultWrittenTiles.Any(sourceTile => sourceTile.Z == tile.Z && sourceTile.X == tile.X && sourceTile.Y == tile.Y) + )); + } + + private Tuple, Tile[]> SetupTestTask(int amountOfSources, bool isTargetNew) + { + byte[] tileBytes = File.ReadAllBytes("tile.jpeg"); + Coord testTargetCoord = new Coord(1, 1, 1); + Coord[] testSourceCoords = new int[amountOfSources].Select((_, index) => new Coord(index + 2, index + 2, index + 2)).ToArray(); + Source testTarget = new Source("target", "target_type", new Extent(), GridOrigin.UPPER_LEFT, Grid.TwoXOne); + Source[] testSources = testSourceCoords.Select((_, index) => new Source($"source_{index}", $"source_type_{index}")).ToArray(); + Tile testTargetTile = new Tile(_configurationManagerMock.Object, testTargetCoord, tileBytes); + Tile[] testSourcesTiles = testSourceCoords.Select(coord => new Tile(_configurationManagerMock.Object, coord, tileBytes)).ToArray(); + TileBounds[] tileBounds = testSourceCoords.Select(coord => new TileBounds(coord.Z, coord.X, coord.X + 1, coord.Y, coord.Y + 1)).ToArray(); + Mock targetDataMock = this._mockRepository.Create(); + Mock[] sourcesDataMocks = testSourcesTiles.Select((tile, index) => + { + var sourceDataMock = this._mockRepository.Create(); + sourceDataMock.Setup(sourceData => sourceData.GetCorrespondingTile(testSourceCoords[index], It.IsAny())).Returns(tile); + this._dataFactoryMock.Setup( dataFactory => dataFactory.CreateDataSource( - testSource.Type, testSource.Path, It.IsAny(), - testSource.Grid, testSource.Origin, testSource.Extent, It.IsAny()) - ).Returns(sourceDataMock.Object); - - this._dataFactoryMock.Setup( - dataFactory => dataFactory.CreateDataSource( - testTarget.Type, testTarget.Path, It.IsAny(), - testTarget.Grid, testTarget.Origin, testTarget.Extent, It.IsAny()) - ).Returns(targetDataMock.Object); - - var testTask = new MergeTask("id", "type", "description", - new MergeMetadata( - TileFormat.Jpeg, true, new TileBounds[] { tileBounds }, - new Source[] { testTarget, testSource } - ), - Status.PENDING, null, "reason", 0, "jobId", true, new DateTime(), new DateTime() - ); - - var resultWrittenTiles = new List(); - var testTaskExecutor = new TaskExecutor(_dataFactoryMock.Object, _testTileMerger, _timeUtilsMock.Object, - _configurationManagerMock.Object, _taskExecutorLoggerMock.Object, _testActivitySource, _testFileSystem, - _metricsProviderMock.Object); - - targetDataMock.Setup(targetData => targetData.UpdateTiles(It.IsAny>())).Callback>( - resultWrittenTiles.AddRange - ); - - testTaskExecutor.ExecuteTask(testTask, _taskUtilsMock.Object, null); - - targetDataMock.Verify(targetData => targetData.UpdateTiles(It.IsAny>()), Times.Exactly(amountOfFlushes)); - targetDataMock.Verify(targetData => targetData.Wrapup(), Times.Once); - Assert.AreEqual(testSourceTiles.Length, resultWrittenTiles.Count); - Assert.IsTrue(testSourceTiles.All( - tile => resultWrittenTiles.Any(sourceTile => sourceTile.Z == tile.Z && sourceTile.X == tile.X && sourceTile.Y == tile.Y) - )); - } - - private Tuple, Tile[]> SetupTestTask(int amountOfSources, bool isTargetNew) - { - byte[] tileBytes = File.ReadAllBytes("tile.jpeg"); - Coord testTargetCoord = new Coord(1, 1, 1); - Coord[] testSourceCoords = new int[amountOfSources].Select((_, index) => new Coord(index + 2, index + 2, index + 2)).ToArray(); - Source testTarget = new Source("target", "target_type", new Extent(), GridOrigin.UPPER_LEFT, Grid.TwoXOne); - Source[] testSources = testSourceCoords.Select((_, index) => new Source($"source_{index}", $"source_type_{index}")).ToArray(); - Tile testTargetTile = new Tile(testTargetCoord, tileBytes); - Tile[] testSourcesTiles = testSourceCoords.Select(coord => new Tile(coord, tileBytes)).ToArray(); - TileBounds[] tileBounds = testSourceCoords.Select(coord => new TileBounds(coord.Z, coord.X, coord.X + 1, coord.Y, coord.Y + 1)).ToArray(); - Mock targetDataMock = this._mockRepository.Create(); - Mock[] sourcesDataMocks = testSourcesTiles.Select((tile, index) => - { - var sourceDataMock = this._mockRepository.Create(); - sourceDataMock.Setup(sourceData => sourceData.GetCorrespondingTile(testSourceCoords[index], It.IsAny())).Returns(tile); - this._dataFactoryMock.Setup( - dataFactory => dataFactory.CreateDataSource( - testSources[index].Type, testSources[index].Path, It.IsAny(), - testSources[index].Grid, testSources[index].Origin, testSources[index].Extent, It.IsAny()) - ).Returns(sourceDataMock.Object); - return sourceDataMock; - }).ToArray(); - - this._dataFactoryMock.Setup( - dataFactory => dataFactory.CreateDataSource( - testTarget.Type, testTarget.Path, It.IsAny(), - testTarget.Grid, testTarget.Origin, testTarget.Extent, It.IsAny()) - ).Returns(targetDataMock.Object); - - if (!isTargetNew) - { - targetDataMock.Setup(targetData => targetData.GetCorrespondingTile(testTargetCoord, It.IsAny())).Returns(testTargetTile); - tileBounds = tileBounds.Prepend(new TileBounds(testTargetCoord.Z, testTargetCoord.X, testTargetCoord.X + 1, testTargetCoord.Y, testTargetCoord.Y + 1)).ToArray(); - } - - var testTask = new MergeTask("id", "type", "description", - new MergeMetadata( - TileFormat.Jpeg, isTargetNew, tileBounds, - testSources.Prepend(testTarget).ToArray() - ), - Status.PENDING, null, "reason", 0, "jobId", true, new DateTime(), new DateTime() - ); - - return new Tuple, Tile[]>(testTask, targetDataMock, testSourcesTiles); - } + testSources[index].Type, testSources[index].Path, It.IsAny(), + testSources[index].Grid, testSources[index].Origin, testSources[index].Extent, It.IsAny()) + ).Returns(sourceDataMock.Object); + return sourceDataMock; + }).ToArray(); + + this._dataFactoryMock.Setup( + dataFactory => dataFactory.CreateDataSource( + testTarget.Type, testTarget.Path, It.IsAny(), + testTarget.Grid, testTarget.Origin, testTarget.Extent, It.IsAny()) + ).Returns(targetDataMock.Object); + + if (!isTargetNew) + { + targetDataMock.Setup(targetData => targetData.GetCorrespondingTile(testTargetCoord, It.IsAny())).Returns(testTargetTile); + tileBounds = tileBounds.Prepend(new TileBounds(testTargetCoord.Z, testTargetCoord.X, testTargetCoord.X + 1, testTargetCoord.Y, testTargetCoord.Y + 1)).ToArray(); + } + + var testTask = new MergeTask("id", "type", "description", + new MergeMetadata( + TileFormat.Jpeg, isTargetNew, tileBounds, + testSources.Prepend(testTarget).ToArray() + ), + Status.PENDING, null, "reason", 0, "jobId", true, new DateTime(), new DateTime() + ); + + return new Tuple, Tile[]>(testTask, targetDataMock, testSourcesTiles); } + } } From 1e5a6eb091b1cf1bd093d79819281fe8ee0f476e Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Wed, 21 Aug 2024 15:53:37 +0300 Subject: [PATCH 12/13] fix: tile constructor --- MergerLogic/Batching/Tile.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MergerLogic/Batching/Tile.cs b/MergerLogic/Batching/Tile.cs index 175c8a4b..dcd549f9 100644 --- a/MergerLogic/Batching/Tile.cs +++ b/MergerLogic/Batching/Tile.cs @@ -56,14 +56,14 @@ public Tile(IConfigurationManager configuration, int z, int x, int y, byte[] dat this._data = data; - int allowedPixelSize = configuration.GetConfiguration("GENERAL", "allowedPixelSize"); + int allowedPixelSize = _configManager.GetConfiguration("GENERAL", "allowedPixelSize"); if (this.Width != allowedPixelSize || this.Height != allowedPixelSize) { throw new ArgumentException($"The image dimensions ({this.Width}x{this.Height}) does not match the allowed size ({allowedPixelSize})"); } } - public Tile(IConfigurationManager configuration, Coord cords, byte[] data) => new Tile(configuration, cords.Z, cords.X, cords.Y, data); + public Tile(IConfigurationManager configuration, Coord cords, byte[] data) : this(configuration, cords.Z, cords.X, cords.Y, data) { } public Tile(IConfigurationManager configuration, Coord cords, IMagickImage image) { From a4b823db460f11c91f2c72cd19be81b1c6b98149 Mon Sep 17 00:00:00 2001 From: nitzanmorr Date: Wed, 21 Aug 2024 15:55:08 +0300 Subject: [PATCH 13/13] fix: configuration manager mocks in tests --- MergerLogicUnitTests/Batching/TileTest.cs | 5 +++-- MergerLogicUnitTests/Clients/FileClientTest.cs | 5 +++-- MergerLogicUnitTests/DataTypes/FSTest.cs | 2 +- MergerLogicUnitTests/DataTypes/GpkgTest.cs | 5 +++-- MergerLogicUnitTests/DataTypes/S3Test.cs | 2 +- MergerLogicUnitTests/DataTypes/TMSTest.cs | 2 +- MergerLogicUnitTests/DataTypes/WMTSTest.cs | 3 +-- MergerLogicUnitTests/DataTypes/XYZTest.cs | 4 +--- MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs | 4 ++-- MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs | 2 +- MergerLogicUnitTests/MergerLogicUnitTests.csproj | 2 +- MergerLogicUnitTests/Utils/GeoUtilsTest.cs | 4 +++- MergerLogicUnitTests/Utils/GpkgUtilsTest.cs | 8 +++++--- MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs | 5 +++-- MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs | 3 ++- MergerLogicUnitTests/Utils/PathUtilsTest.cs | 2 +- MergerLogicUnitTests/Utils/S3UtilsTest.cs | 2 +- MergerServiceUnitTests/Runners/TaskExecutorTest.cs | 3 +-- 18 files changed, 34 insertions(+), 29 deletions(-) diff --git a/MergerLogicUnitTests/Batching/TileTest.cs b/MergerLogicUnitTests/Batching/TileTest.cs index 85c9b878..6fba33cb 100644 --- a/MergerLogicUnitTests/Batching/TileTest.cs +++ b/MergerLogicUnitTests/Batching/TileTest.cs @@ -19,6 +19,7 @@ public class TilesTest private MockRepository _repository; private Mock _configurationManagerMock; #endregion + private readonly Times anyNumberOfTimes = Times.AtMost(int.MaxValue); [TestInitialize] public void beforeEach() @@ -26,8 +27,8 @@ public void beforeEach() this._repository = new MockRepository(MockBehavior.Strict); this._configurationManagerMock = this._repository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) - .Returns(256); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256).Verifiable(anyNumberOfTimes); } #region CreateTile diff --git a/MergerLogicUnitTests/Clients/FileClientTest.cs b/MergerLogicUnitTests/Clients/FileClientTest.cs index b26532d6..cfec3f65 100644 --- a/MergerLogicUnitTests/Clients/FileClientTest.cs +++ b/MergerLogicUnitTests/Clients/FileClientTest.cs @@ -31,6 +31,7 @@ public class FileClientTest private byte[] _jpegImageData; private byte[] _pngImageData; #endregion + private readonly Times anyNumberOfTimes = Times.AtMost(int.MaxValue); [TestInitialize] public void beforeEach() @@ -45,8 +46,8 @@ public void beforeEach() this._fsMock.SetupGet(fs => fs.File).Returns(this._fileMock.Object); this._fsMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); this._fsMock.SetupGet(fs => fs.Directory).Returns(this._directoryMock.Object); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) - .Returns(256); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256).Verifiable(anyNumberOfTimes); this._imageFormatterMock = this._repository.Create(); this._jpegImageData = File.ReadAllBytes("image.jpeg"); diff --git a/MergerLogicUnitTests/DataTypes/FSTest.cs b/MergerLogicUnitTests/DataTypes/FSTest.cs index a5b3b957..e8b712c4 100644 --- a/MergerLogicUnitTests/DataTypes/FSTest.cs +++ b/MergerLogicUnitTests/DataTypes/FSTest.cs @@ -55,7 +55,7 @@ public void BeforeEach() this._pathMock = this._repository.Create(); this._fileSystemMock = this._repository.Create(); this._configurationManagerMock = this._repository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._fileSystemMock.SetupGet(fs => fs.Directory).Returns(this._directoryMock.Object); this._fileSystemMock.SetupGet(fs => fs.FileInfo).Returns(this._fileInfoFactoryMock.Object); diff --git a/MergerLogicUnitTests/DataTypes/GpkgTest.cs b/MergerLogicUnitTests/DataTypes/GpkgTest.cs index e3f7cbe0..3a571bf5 100644 --- a/MergerLogicUnitTests/DataTypes/GpkgTest.cs +++ b/MergerLogicUnitTests/DataTypes/GpkgTest.cs @@ -36,6 +36,7 @@ public class GpkgTest private byte[] _jpegImageData; #endregion + private readonly Times anyNumberOfTimes = Times.AtMost(int.MaxValue); [TestInitialize] public void BeforeEach() @@ -53,8 +54,8 @@ public void BeforeEach() this._loggerFactoryMock = this._repository.Create(); this._loggerFactoryMock.Setup(f => f.CreateLogger(It.IsAny())).Returns(this._loggerMock.Object); this._serviceProviderMock = this._repository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) - .Returns(256); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256).Verifiable(anyNumberOfTimes); this._serviceProviderMock.Setup(container => container.GetService(typeof(IOneXOneConvertor))) .Returns(this._oneXOneConvertorMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IUtilsFactory))) diff --git a/MergerLogicUnitTests/DataTypes/S3Test.cs b/MergerLogicUnitTests/DataTypes/S3Test.cs index 71f3a43e..9b7a60e5 100644 --- a/MergerLogicUnitTests/DataTypes/S3Test.cs +++ b/MergerLogicUnitTests/DataTypes/S3Test.cs @@ -83,7 +83,7 @@ public void BeforeEach() .Returns(this._configurationManagerMock.Object); this._configurationManagerMock.Setup(cm => cm.GetConfiguration("S3", "bucket")) .Returns("bucket"); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); diff --git a/MergerLogicUnitTests/DataTypes/TMSTest.cs b/MergerLogicUnitTests/DataTypes/TMSTest.cs index 8ed57be9..fe9b7373 100644 --- a/MergerLogicUnitTests/DataTypes/TMSTest.cs +++ b/MergerLogicUnitTests/DataTypes/TMSTest.cs @@ -68,7 +68,7 @@ public void BeforeEach() this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); } diff --git a/MergerLogicUnitTests/DataTypes/WMTSTest.cs b/MergerLogicUnitTests/DataTypes/WMTSTest.cs index a7fc8f39..5f089371 100644 --- a/MergerLogicUnitTests/DataTypes/WMTSTest.cs +++ b/MergerLogicUnitTests/DataTypes/WMTSTest.cs @@ -39,7 +39,6 @@ public class WMTSTest private Mock _configurationManagerMock; private byte[] _jpegImageData; - #endregion [TestInitialize] @@ -69,7 +68,7 @@ public void BeforeEach() .Returns(this._loggerFactoryMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._jpegImageData = File.ReadAllBytes("image.jpeg"); diff --git a/MergerLogicUnitTests/DataTypes/XYZTest.cs b/MergerLogicUnitTests/DataTypes/XYZTest.cs index e0c10222..f87badea 100644 --- a/MergerLogicUnitTests/DataTypes/XYZTest.cs +++ b/MergerLogicUnitTests/DataTypes/XYZTest.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using Moq.Protected; using System; using System.Collections.Generic; using System.IO; @@ -67,7 +66,7 @@ public void BeforeEach() .Returns(this._loggerFactoryMock.Object); this._serviceProviderMock.Setup(container => container.GetService(typeof(IMetricsProvider))) .Returns(this._metricsProviderMock.Object); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); @@ -82,7 +81,6 @@ public static IEnumerable GenTileExistsParams() new Coord(2,2,3), //existing tile new Coord(1,2,3), //missing tile new Coord(0,2,3) //invalid conversion tile - }, //cords new object[] { true, false }, //is one on one new object[] { GridOrigin.LOWER_LEFT, GridOrigin.UPPER_LEFT }, //origin diff --git a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs index 0eed29a3..8719b3f0 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileMergerTest.cs @@ -39,7 +39,7 @@ public void BeforeEach() var tileMergerLoggerMock = this._mockRepository.Create>(); this._configurationManagerMock = this._mockRepository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); var testTileScaler = new TileScaler(metricsProviderMock.Object, tileScalerLoggerMock.Object, this._configurationManagerMock.Object); @@ -48,7 +48,7 @@ public void BeforeEach() #region MergeTiles - public IEnumerable GetMergeTilesTestParameters() + public static IEnumerable GetMergeTilesTestParameters() { var targetCoordLowZoom = new Coord(5, 0, 0); var targetCoordMediumZoom = new Coord(14, 0, 0); diff --git a/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs b/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs index 3c16c2c9..6838acdb 100644 --- a/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs +++ b/MergerLogicUnitTests/ImageProcessing/TileScalerTest.cs @@ -37,7 +37,7 @@ public void BeforeEach() var tileScalerLoggerMock = this._mockRepository.Create>(); this._configurationManagerMock = this._mockRepository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._testTileScaler = new TileScaler(metricsProviderMock.Object, tileScalerLoggerMock.Object, this._configurationManagerMock.Object); diff --git a/MergerLogicUnitTests/MergerLogicUnitTests.csproj b/MergerLogicUnitTests/MergerLogicUnitTests.csproj index bafdd798..99993d5d 100644 --- a/MergerLogicUnitTests/MergerLogicUnitTests.csproj +++ b/MergerLogicUnitTests/MergerLogicUnitTests.csproj @@ -9,7 +9,7 @@ - + diff --git a/MergerLogicUnitTests/Utils/GeoUtilsTest.cs b/MergerLogicUnitTests/Utils/GeoUtilsTest.cs index 02be4224..806af1fa 100644 --- a/MergerLogicUnitTests/Utils/GeoUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/GeoUtilsTest.cs @@ -29,8 +29,10 @@ public class GeoUtilsTest [TestInitialize] public void BeforeEach() { + this._repository = new MockRepository(MockBehavior.Strict); this._configurationManagerMock = this._repository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")).Returns(256); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } diff --git a/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs b/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs index 389e8aac..1d4858fd 100644 --- a/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/GpkgUtilsTest.cs @@ -51,7 +51,7 @@ public void BeforeEach() this._fileSystemMock.SetupGet(fs => fs.File).Returns(this._fileMock.Object); this._fileSystemMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); @@ -852,8 +852,10 @@ private void CreateTestTiles(SQLiteConnection connection, IEnumerable test foreach (Tile tile in testTiles) { byte[] tileBytes = tile.GetImageBytes(); - SQLiteParameter blobParameter = new SQLiteParameter("$blob", System.Data.DbType.Binary, tileBytes.Length); - blobParameter.Value = tileBytes; + SQLiteParameter blobParameter = new SQLiteParameter("$blob", DbType.Binary, tileBytes.Length) + { + Value = tileBytes + }; command.Parameters.AddWithValue("$z", tile.Z); command.Parameters.AddWithValue("$x", tile.X); diff --git a/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs b/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs index ac94d0e1..3c8c5fbe 100644 --- a/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/HttpSourceUtilsTest.cs @@ -22,6 +22,7 @@ public class HttpSourceUtilsTest private Mock _configurationManagerMock; private byte[] _jpegImageData; #endregion + private readonly Times anyNumberOfTimes = Times.AtMost(int.MaxValue); [TestInitialize] public void beforeEach() @@ -32,8 +33,8 @@ public void beforeEach() this._geoUtilsMock = this._repository.Create(); this._configurationManagerMock = this._repository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) - .Returns(256); + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + .Returns(256).Verifiable(anyNumberOfTimes); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } diff --git a/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs b/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs index 75233a23..dc7f7428 100644 --- a/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs +++ b/MergerLogicUnitTests/Utils/OneXOneConvertorTest.cs @@ -35,8 +35,9 @@ public enum OneXOneConvertorParameterType [TestInitialize] public void BeforeEach() { + this._repository = new MockRepository(MockBehavior.Strict); this._configurationManagerMock = this._repository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); } diff --git a/MergerLogicUnitTests/Utils/PathUtilsTest.cs b/MergerLogicUnitTests/Utils/PathUtilsTest.cs index 934bbdd9..e539902f 100644 --- a/MergerLogicUnitTests/Utils/PathUtilsTest.cs +++ b/MergerLogicUnitTests/Utils/PathUtilsTest.cs @@ -38,7 +38,7 @@ public void BeforeEach() this._fileSystemMock.SetupGet(fs => fs.Path).Returns(this._pathMock.Object); this._imageFormaterMock = this._repository.Create(); this._configurationManagerMock = this._repository.Create(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); diff --git a/MergerLogicUnitTests/Utils/S3UtilsTest.cs b/MergerLogicUnitTests/Utils/S3UtilsTest.cs index d239ee75..f428203c 100644 --- a/MergerLogicUnitTests/Utils/S3UtilsTest.cs +++ b/MergerLogicUnitTests/Utils/S3UtilsTest.cs @@ -52,7 +52,7 @@ public void BeforeEach() this._loggerMock = this._repository.Create>(MockBehavior.Loose); this._loggerFactoryMock = this._repository.Create(); this._loggerFactoryMock.Setup(f => f.CreateLogger(It.IsAny())).Returns(this._loggerMock.Object); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._jpegImageData = File.ReadAllBytes("no_transparency.jpeg"); diff --git a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs index cb85cafb..77e38c7b 100644 --- a/MergerServiceUnitTests/Runners/TaskExecutorTest.cs +++ b/MergerServiceUnitTests/Runners/TaskExecutorTest.cs @@ -68,7 +68,7 @@ public void BeforeEach() this._tileScalerMock = this._mockRepository.Create(); this._tileMergerLoggerMock = this._mockRepository.Create>(); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) + this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")) .Returns(256); this._testActivitySource = new ActivitySource("test"); @@ -138,7 +138,6 @@ public void WhenConfiguringBatchLimits_ShouldWriteTilesEachTimeAfterReachingBatc this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "batchMaxSize")).Returns(batchMaxSize); this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchSize", "limitBatchSize")).Returns(limitBatchSize); this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "batchMaxBytes")).Returns(batchMaxBytes); - this._configurationManagerMock.Setup(configManager => configManager.GetConfiguration("GENERAL", "allowedPixelSize")).Returns(256); byte[] tileBytes = File.ReadAllBytes("tile.jpeg"); Source testTarget = new Source("target", "target_type", new Extent(), GridOrigin.UPPER_LEFT, Grid.TwoXOne);