From 4059448dc634b4cb58b0df86a7382988f3202394 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 20 Mar 2018 16:21:01 +1100 Subject: [PATCH] Add basic comparision tests --- .../PixelFormats/PixelBlenderMode.cs | 2 +- .../PixelOperations{TPixel}.PixelBenders.cs | 2 +- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 2 +- .../PorterDuffCompositorTests.cs | 52 +++++++++++ .../PorterDuffFunctionsTests_TPixel.cs | 4 +- .../PixelOperationsTests.Blender.cs | 88 +++++++++--------- tests/ImageSharp.Tests/TestImages.cs | 2 + tests/Images/Input/Png/pd-dest.png | Bin 0 -> 2563 bytes tests/Images/Input/Png/pd-source.png | Bin 0 -> 2393 bytes 9 files changed, 103 insertions(+), 49 deletions(-) create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs create mode 100644 tests/Images/Input/Png/pd-dest.png create mode 100644 tests/Images/Input/Png/pd-source.png diff --git a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs index 7541be7893..4b8f56d766 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Blends the 2 values by subtraction. /// - Substract, + Subtract, /// /// Multiplies the complements of the backdrop and source values, then complements the result. diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs index 154ec73738..2c225ba4c4 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { case PixelBlenderMode.Multiply: return DefaultPixelBlenders.Multiply.Instance; case PixelBlenderMode.Add: return DefaultPixelBlenders.Add.Instance; - case PixelBlenderMode.Substract: return DefaultPixelBlenders.Substract.Instance; + case PixelBlenderMode.Subtract: return DefaultPixelBlenders.Subtract.Instance; case PixelBlenderMode.Screen: return DefaultPixelBlenders.Screen.Instance; case PixelBlenderMode.Darken: return DefaultPixelBlenders.Darken.Instance; case PixelBlenderMode.Lighten: return DefaultPixelBlenders.Lighten.Instance; diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 3e7f3648fb..0ff0b85576 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Normal)] [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Multiply)] [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Add)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Substract)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Subtract)] [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Screen)] [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Darken)] [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Lighten)] diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs new file mode 100644 index 0000000000..90b963f5ca --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs @@ -0,0 +1,52 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Drawing; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders +{ + public class PorterDuffCompositorTests + { + // TODO: Add other modes to compare. + private static PixelBlenderMode[] CompositingOperators = + { + PixelBlenderMode.Src, + PixelBlenderMode.Atop, + PixelBlenderMode.Over, + PixelBlenderMode.In, + PixelBlenderMode.Out, + PixelBlenderMode.Dest, + PixelBlenderMode.DestAtop, + PixelBlenderMode.DestOver, + PixelBlenderMode.DestIn, + PixelBlenderMode.DestOut, + PixelBlenderMode.Clear, + PixelBlenderMode.Xor + }; + + [Fact] + public void PorterDuffOutputIsCorrect() + { + string path = TestEnvironment.CreateOutputDirectory("PorterDuff"); + var srcFile = TestFile.Create(TestImages.Png.PDSrc); + var destFile = TestFile.Create(TestImages.Png.PDDest); + + using (Image src = srcFile.CreateImage()) + using (Image dest = destFile.CreateImage()) + { + foreach (PixelBlenderMode m in CompositingOperators) + { + using (Image res = dest.Clone(x => x.Blend(src, new GraphicsOptions { BlenderMode = m }))) + { + // TODO: Generate reference files once this works. + res.Save($"{path}/{m}.png"); + } + } + } + } + } +} diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs index d77c42086a..10a34ec313 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void SubstractFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Substract().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Subtract().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Substract().Blend(this.MemoryManager, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Subtract().Blend(this.MemoryManager, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs index 524747afec..d3956ecd5d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs @@ -16,53 +16,53 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static TheoryData BlenderMappings = new TheoryData() - { - { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultPixelBlenders.Substract), PixelBlenderMode.Substract }, - { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, + { + { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.Subtract), PixelBlenderMode.Subtract }, + { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, - { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, - { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, - { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, - { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, - { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, - { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, - { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, - { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, + { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, + { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, + { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, + { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, + { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, + { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, + { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, + { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, - { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultPixelBlenders.Substract), PixelBlenderMode.Substract }, - { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, - { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, - { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, - { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, - { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, - { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, - { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, - { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, - { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, + { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.Subtract), PixelBlenderMode.Subtract }, + { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, + { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, + { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, + { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, + { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, + { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, + { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, + { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, + { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, - }; + }; [Theory] [MemberData(nameof(BlenderMappings))] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index db469f87e1..4e9c3192d0 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -36,6 +36,8 @@ namespace SixLabors.ImageSharp.Tests public const string SnakeGame = "Png/SnakeGame.png"; public const string Icon = "Png/icon.png"; public const string Kaboom = "Png/kaboom.png"; + public const string PDSrc = "Png/pd-source.png"; + public const string PDDest = "Png/pd-dest.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/pd-dest.png b/tests/Images/Input/Png/pd-dest.png new file mode 100644 index 0000000000000000000000000000000000000000..8db8ce173d75e4e458a7c6c7005ac5a46d07f9f4 GIT binary patch literal 2563 zcmV+e3jFnnP)^DTt$%^h4-?5t6$bqOnq_ zXlWBPGf*Iqx6O08cZ;D1a!Duymb|pFFwuBYBy+N7@KeUcPqH zwQHG`0EYq0btw!3I8B6lB0idv(|^37;SW77#d1Vi2xA!GB>;8-xXt6xdn_yRh{rLL zLi0NT!>D=;z#H&h6adKfA!bqpe2h(oQCSD@!#?Jqgc(gJ6#fwaKScpRS^mZ!A72h- zq0ojRB0TFy?3>}VILD5KFTxPf762K3#J-vI6~^;J*A5&gWo`_k)eZ7=tY{?IVO8A8yVx{i4OuVltD zj3bn$rN`~USa>cB5iPQB&Go_Hu1}gY@V!K$j72QAzq7eHvMm_Q`3f^01#oHjvvfX`c`ghyebuJv;S(qJ zU9%gvv2lBMG#dGBFgS1Zi%rXOGU7KjK6lBo>b3wVV#Z%(_;dq5 zZZK`#)DbbuOv17v?*VvErcaspagK@GF=EC%*@>hxJ_y4f+cf;PVT7khO(l)-K^W~n zHVr2eVZGE;(ik63{`{6*TV`xEjPU1W=98}YaJh_Q4$P+lyhBW^9qoBZ8 z1>j5eJkZ^Rh35J8cI&j%#L^7ERxr0aF=pmHrKOd{vXV(hd=bX73Jw5V@4!X25OnCX ze7^B%kEs@#mhljPE(cC#G2>u)`PxacvPvg>5oY1S^|?aCcL12|#19d^+0_+%sl2?} z&)x-B@LU+f2+!&13A_cMLWVzPEWdiSeIL@K6-ySL{xYUnc^@;q2xkjr zcrc7`K7ivGyjsmmu;~k2^t+!Hf zU6@cP{1iZsyB%i;V&>;evvP$UVQ)@H6Kf(|6~-{aPZHr5ZpIjc05iR4nj6bg zH6%jHH?2fyN!2D9TocALE7t(n>X!crn8Yj&my}eQ$r@BtROkRoQw>CfXsR~J;EFJ& zxp6)-MI5-eAYs`zPt*7{!w4tU{BiEww7E$AzN$MXr|?YbsZES@Vdl@@{5fXvCjfTu z$gc@O%X@nRs{lUbFrDcDjv7XI=0qE68WyDLoCr+~4b`?*WGBo=wnHKM9|thQu00X0 zkHug1FMtk*sojy0AzmMEX?m#Mwm4O%MB4v{FuI=4_tSWPa>oVQ&#rFJOE`j z%`fHU_0=TWpt-rGfruUiAZ*4Mf|mibAE?%V!AiHi=>vYvSssazCd|MJg z%=B<`bM3*Q=5UAb1E$%&0|2_a_0>qde#e>?IO05y@sTEs5H#C??O&4JHX4om9^j|! z#u|nhn++rUq^40gb!$4*)U@Y)r#U1-nlMC|X4h8N#XG5NZ&`J}1hCg`yb)|=M$*-R zVKhxVEg^Q|7_uBW5k?3~wTqu~a|<>x;}yFx?L)6NHPtn_9Yx}yEaAdZLYPI$695ej z)$z>CoYerIup8F~y#oXIi5Gz+?lElp(ve8F)rvGY#6(L0wAziG8uXi%mfEvkM3Q(P zqg}RZ$;>HNb%(L6$Q4ZsECcXwyFQZSY=8faZ7#?71etrxf9>0%!bvB8Q`7DXLeM=J zF~%pEIDj>7-cXK4;vU0J>RGu?JNaX=+INYx6#!D2(M$#+Y_qJ$N!flAA@StTj(UlQ zI{7Co&nKd}x#k2j-w&I^QDZ|EGdw$l4I@pMyu2Cj0HvV?pD^QBhEe57t<05O|Ki1#8~OPqF(O(Gf1kVQ28#;|L+9JuqpsHH zTstOrbVSb=6d3OS_&(C$X|)m|fR^XyhhiNaQKzj{iGsLGC{(qai2n%J#xH!M8^99F ziX3;tx$EELXteeSfQ0}&DVHZfFMvIo#^rF_t@Z=CW&d>`eG8FRUtC-z{bAmo&n=qf#<_raf*Gqk zihmhEtq}2@vDm)$(I1wUR(@Rws)w_OW1kBI#3Gsh(80HXQo{(}jlr_X14umYXqSHi z^t+xOeScfq?u29OL$jfW;jCH^3j{LDPoCU))q#&s@O{$PFv8i)bT1LF0I&o=z702V z0OtTc!Hna90Ny-xsxGA~Cc_Aq0dTbJ0O0MR2h=&ncVR|TQu6RDT@REBfoVjT%FMY$ z$i?6@EaL!O2dIxobTZRPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;2FkAZe8V00_xRL_t(|UhSQ4a8%V9he-l41R@cNkXF%w zh*~kt-g}c6a4fZvn0xo8NolNAKB%1z6=rapYTI!-ZLPJX&Zr$m=m-DNfsUiL^n+5h zGipT*uzPQSR;@E=TPx}qK(Q*-Kxm&APTTGFmMq!b>}L1<%{)W??cICc-#zEN=j=I$ z2`ZIJrBbO>DwRs5QmIrbl}e>jsZ=VJN>zG#sIRX=FyE?*Maj7RdAKa;I}4!N{8&|J zB|SS1t1)M75Vx)hJ?ng!YJROMl#;G}F2?)_Q~n0KK)&t_Jo}8`Qv0N!!`5c55DIL& z3S%y##=H^4?L&qaFy@w^%bpi3v1|C9no|g2OdG+!AKt^1BXAI7_CP<}%+K3N5Gu`| ztHw$+XAPM16%5#eDZ}s&W6($N5~ z@_yi1G;h|OAO3^)f7$Z|WYcQtk#lG`uK(n`O#AyFC_$s_*0v%<*NXYACdPi!{ zX81maU(9%ErgZ1@OMUWX0zL0_jPwT8Ym9khu%Q4z!$ z@Kbm-BGB3JS8C4&@Zk(hnv!r^)Syg-A(NpKo{R`?Hjq$Q2jLC)ImRr(n3K)hszy@K zWmUoq0=JG}zLOT*Y@z?L=zpv?x&HGsZ)*~s)3f!`w)&?RFV@By-uQ8?*W`mlOE{v%lNQ(*9qmYZ#ITMC>&jYXb zyLy|Zf%ZSCqTN3eR>ELJ5c7pJo023*?Rf_7pug)4-Pq~7yBgIXQPOj2F~x=ff<>wu z8OVHch{5hYcm#89gwOG{%uZ+%#}hjf?uOSQ0ymZnV#sF9`5K%J(|B;o*B}g;0==*$ zB3NU|Fvfh0A=Du2F}M$cG>wF>J<^RWJuiJA0$BXTi5&Z$wav4C@^T;Xb%JaP9d)M~Nl~ zWIlBi`a<|U{QW;cC|ab+mFc8sNwt3n-PESD`uz(^Z=)84JQX&8Y~P3qMzJEzuk=4R zCE`wV!gFQ}xUtePh{8<;S?1IaQ2{7cB$JfSfZl`c^p~qJrqL8@{43GzRKXkyC$**! z^Jm#|EWJLqigXj@xPcnfxZQ89F-07|>hEi>qCnrGfG?&Lcsz1|anClm3Qjl08{Z0i ztAlJuYK@tuk1TjGBlr9+Y$YjJ0dq~!#ex`52_Xu3R1 z@#NvLelie`%`Jjtni}(6*c}m^!r<9&GHCo2_p}UVVoH^{-SSexcRT{{FhMcngot2` z3IATSz7b=-C|elKEtaPeeoF(!d=rMC5XKzgePyA>URaMY?Ye^iVa!AV^97LAD>54p z6})^R#>nX%w_?mW7&F=2nu-Bu6M?xMa=owScu4IW#)xNu8tX9V)e{TH>`$*7&67YttwLyxTWw&L~uuoEQ1ZX z=56$2joZ4~^sKbeh^KijP0jZRrW{`~>H#O$knxEOS_8N-=&+~i(Zg8?W8^far36=w zbR6~MCf7I!&m`i`vh8lmEKJeSe6}K>Hv9|@LOSY8n!IX8$ zxO1_&lq%Q4lvCh481q7e5$VY6uxum$2F%A8?N9Qhz_qHu4m?Xz=i_a7l8vwZuma|V zaclf9SuJJ_xUmYTBiOeQ{HPrQ$F@p%mTVPY9=g^X(0%-4C4zn>{5H)L`LuB#{D$9s zIrOYk&7Z5rN?}**T!Q~&%#iHt2>s4s7{rt(!g%b09r0%UPlXDhogGcp7;`zM$O#*A zR