From df2ef0ed99ce61708b35de82d1f67028c1b29427 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 1 Jul 2014 17:54:37 +0100 Subject: [PATCH 1/2] Tweaking gif frame creation and fixing unc folder access issue Former-commit-id: e0a7b73bc547b65651a848695000c26072401e31 --- .../NET4/ImageProcessor.Web_NET4.csproj | 3 + .../NET45/Caching/DiskCache.cs | 56 +++++++++++-------- .../ImageProcessorConfiguration.cs | 2 +- .../HttpModules/ImageProcessingModule.cs | 2 +- .../NET45/ImageProcessor.Web_NET45.csproj | 1 + .../Imaging/Formats/FormatUtilities.cs | 28 +++++----- .../Imaging/Formats/GifEncoder.cs | 18 +++--- src/ImageProcessorConsole/Program.cs | 5 +- 8 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj index 2a149236a..d830257ae 100644 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj @@ -95,6 +95,9 @@ ImageSecuritySection.cs + + DirectoryInfoExtensions.cs + CommonParameterParserUtility.cs diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs index f1cefc657..6a23d48ad 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs @@ -22,6 +22,7 @@ namespace ImageProcessor.Web.Caching using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Configuration; + using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; #endregion @@ -212,37 +213,44 @@ namespace ImageProcessor.Web.Caching /// private void TrimCachedFolders(string path) { - // ReSharper disable once AssignNullToNotNullAttribute - DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(path)); - DirectoryInfo parentDirectoryInfo = directoryInfo.Parent; + string directory = Path.GetDirectoryName(path); - // ReSharper disable once PossibleNullReferenceException - foreach (DirectoryInfo enumerateDirectory in parentDirectoryInfo.EnumerateDirectories()) + if (directory != null) { - IEnumerable files = enumerateDirectory.EnumerateFiles().OrderBy(f => f.CreationTimeUtc); - int count = files.Count(); + DirectoryInfo directoryInfo = new DirectoryInfo(directory); + DirectoryInfo parentDirectoryInfo = directoryInfo.Parent; - foreach (FileInfo fileInfo in files) + if (parentDirectoryInfo != null) { - try + // UNC folders can throw exceptions if the file doesn't exist. + foreach (DirectoryInfo enumerateDirectory in parentDirectoryInfo.SafeEnumerateDirectories()) { - // If the group count is equal to the max count minus 1 then we know we - // have reduced the number of items below the maximum allowed. - // We'll cleanup any orphaned expired files though. - if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1) + IEnumerable files = enumerateDirectory.EnumerateFiles().OrderBy(f => f.CreationTimeUtc); + int count = files.Count(); + + foreach (FileInfo fileInfo in files) { - break; + try + { + // If the group count is equal to the max count minus 1 then we know we + // have reduced the number of items below the maximum allowed. + // We'll cleanup any orphaned expired files though. + if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1) + { + break; + } + + // Remove from the cache and delete each CachedImage. + CacheIndexer.Remove(fileInfo.Name); + fileInfo.Delete(); + count -= 1; + } + // ReSharper disable once EmptyGeneralCatchClause + catch + { + // Do nothing; skip to the next file. + } } - - // Remove from the cache and delete each CachedImage. - CacheIndexer.Remove(fileInfo.Name); - fileInfo.Delete(); - count -= 1; - } - // ReSharper disable once EmptyGeneralCatchClause - catch - { - // Do nothing; skip to the next file. } } } diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index b0977a962..9d3ea6be9 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -22,8 +22,8 @@ namespace ImageProcessor.Web.Configuration using ImageProcessor.Common.Extensions; using ImageProcessor.Processors; - using ImageProcessor.Web.Processors; using ImageProcessor.Web.Helpers; + using ImageProcessor.Web.Processors; /// /// Encapsulates methods to allow the retrieval of ImageProcessor settings. diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 33877e15b..d70e71867 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -359,7 +359,7 @@ namespace ImageProcessor.Web.HttpModules IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]); // Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal? - PermissionSet permission = new PermissionSet(PermissionState.Unrestricted); + PermissionSet permission = new PermissionSet(PermissionState.None); permission.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted)); bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet); diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index ac434afe5..2f5e77f23 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -53,6 +53,7 @@ + diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index a72485a19..53025bf42 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -131,40 +131,42 @@ namespace ImageProcessor.Imaging.Formats if (fetchFrames) { - FrameDimension frameDimension = new FrameDimension(image.FrameDimensionsList[0]); - int frameCount = image.GetFrameCount(frameDimension); + int frameCount = image.GetFrameCount(FrameDimension.Time); int last = frameCount - 1; - int delay = 0; + int length = 0; + List gifFrames = new List(); + // Get the times stored in the gif. + byte[] times = image.GetPropertyItem((int)ExifPropertyTag.FrameDelay).Value; + for (int i = 0; i < frameCount; i++) { + // Convert each 4-byte chunk into an integer. // GDI returns a single array with all delays, while Mono returns a different array for each frame. - image.SelectActiveFrame(frameDimension, i); - byte[] times = image.GetPropertyItem(20736).Value; - int thisDelay = BitConverter.ToInt32(times, (4 * i) % times.Length); - int toAddDelay = thisDelay * 10 < 20 ? 20 : thisDelay * 10; // Minimum delay is 20 ms + int delay = BitConverter.ToInt32(times, (4 * i) % times.Length); + delay = delay * 10 < 20 ? 20 : delay * 10; // Minimum delay is 20 ms // Find the frame - image.SelectActiveFrame(frameDimension, i); + image.SelectActiveFrame(FrameDimension.Time, i); // TODO: Get positions. - gifFrames.Add(new GifFrame { Delay = toAddDelay, Image = (Image)image.Clone() }); + gifFrames.Add(new GifFrame { Delay = delay, Image = (Image)image.Clone() }); // Reset the position. if (i == last) { - image.SelectActiveFrame(frameDimension, 0); + image.SelectActiveFrame(FrameDimension.Time, 0); } - delay += toAddDelay; + length += delay; } info.GifFrames = gifFrames; - info.AnimationLength = delay; + info.AnimationLength = length; // Loop info is stored at byte 20737. - info.LoopCount = BitConverter.ToInt16(image.GetPropertyItem(20737).Value, 0); + info.LoopCount = BitConverter.ToInt16(image.GetPropertyItem((int)ExifPropertyTag.LoopCount).Value, 0); info.IsLooped = info.LoopCount != 1; } } diff --git a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs index 612a453bf..662ad314c 100644 --- a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs @@ -193,13 +193,6 @@ namespace ImageProcessor.Imaging.Formats } #endregion - #region Properties - /// - /// Gets or sets the frame delay. - /// - public TimeSpan FrameDelay { get; set; } - #endregion - #region Public Methods and Operators /// /// Adds a frame to the gif. @@ -289,13 +282,18 @@ namespace ImageProcessor.Imaging.Formats { int count = this.repeatCount.GetValueOrDefault(0); - // File Header + // File Header sinature and version. this.WriteString(FileType); this.WriteString(FileVersion); + + // Write the logical screen descriptor. this.WriteShort(this.width.GetValueOrDefault(w)); // Initial Logical Width this.WriteShort(this.height.GetValueOrDefault(h)); // Initial Logical Height + + // Read the global color table info. sourceGif.Position = SourceGlobalColorInfoPosition; - this.WriteByte(sourceGif.ReadByte()); // Global Color Table Info + this.WriteByte(sourceGif.ReadByte()); + this.WriteByte(0); // Background Color Index this.WriteByte(0); // Pixel aspect ratio this.WriteColorTable(sourceGif); @@ -387,6 +385,7 @@ namespace ImageProcessor.Imaging.Formats /// private void WriteImageBlock(Stream sourceGif, bool includeColorTable, int x, int y, int h, int w) { + // Local Image Descriptor sourceGif.Position = SourceImageBlockPosition; // Locating the image block byte[] header = new byte[SourceImageBlockHeaderLength]; sourceGif.Read(header, 0, header.Length); @@ -435,6 +434,7 @@ namespace ImageProcessor.Imaging.Formats /// private void WriteShort(int value) { + // Leave only one significant byte. this.inputStream.WriteByte(Convert.ToByte(value & 0xff)); this.inputStream.WriteByte(Convert.ToByte((value >> 8) & 0xff)); } diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index b08b9440b..248fe1d7f 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -1,6 +1,7 @@ // -------------------------------------------------------------------------------------------------------------------- // -// Copyright James South +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. // // // The program. @@ -58,7 +59,7 @@ namespace ImageProcessorConsole // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) - .AutoRotate() + //.AutoRotate() .Constrain(size) //.Format(new WebPFormat()) //.Quality(5) From bab130a24d849484e6f766f40ce4b836ef3a44e9 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 1 Jul 2014 17:55:06 +0100 Subject: [PATCH 2/2] Adding missed files Former-commit-id: ff28d95a611a40d91daa4a103c2b4fae209c3b1b --- .../Extensions/DirectoryInfoExtensions.cs | 56 ++++++++++++++++++ .../images/output/120430.gif.REMOVED.git-id | 1 + .../images/output/4.sm.webp | Bin 0 -> 12162 bytes .../images/output/Tl4Yb.gif.REMOVED.git-id | 1 + .../images/output/nLpfllv.gif.REMOVED.git-id | 1 + .../images/output/test.webp | Bin 0 -> 5590 bytes 6 files changed, 59 insertions(+) create mode 100644 src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs create mode 100644 src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/4.sm.webp create mode 100644 src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/test.webp diff --git a/src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs b/src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs new file mode 100644 index 000000000..2ec477257 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs @@ -0,0 +1,56 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides extension methods to the type. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Extensions +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + + /// + /// Provides extension methods to the type. + /// + public static class DirectoryInfoExtensions + { + /// + /// Returns an enumerable collection of directory information that matches a specified search pattern and search subdirectory option. + /// Will return an empty enumerable on exception. Quick and dirty but does what I need just now. + /// + /// + /// The that this method extends. + /// + /// + /// The search string to match against the names of directories. This parameter can contain a combination of valid literal path + /// and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions. The default pattern is "*", which returns all files. + /// + /// + /// One of the enumeration values that specifies whether the search operation should include only + /// the current directory or all subdirectories. The default value is TopDirectoryOnly. + /// + /// + /// An enumerable collection of directories that matches searchPattern and searchOption. + /// + public static IEnumerable SafeEnumerateDirectories(this DirectoryInfo directoryInfo, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly) + { + IEnumerable directories; + + try + { + directories = directoryInfo.EnumerateDirectories(searchPattern, searchOption); + } + catch + { + return Enumerable.Empty(); + } + + return directories; + } + } +} diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id new file mode 100644 index 000000000..71ce555c1 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id @@ -0,0 +1 @@ +30ec5c05548fd350f9b7c699715848b9fbfb8ca9 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/4.sm.webp b/src/ImageProcessorConsole/images/output/4.sm.webp new file mode 100644 index 0000000000000000000000000000000000000000..90a6308640402286dc34d6e178063681eb985089 GIT binary patch literal 12162 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 E0HyKO%>V!Z literal 0 HcmV?d00001 diff --git a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id new file mode 100644 index 000000000..6515d65a0 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id @@ -0,0 +1 @@ +fdc62fc2d056ab885eb9e8fd12b9155ee86d7c43 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id new file mode 100644 index 000000000..c07be0b0f --- /dev/null +++ b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id @@ -0,0 +1 @@ +77cce70db3722920d60f4b17a45a5e390a09838a \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/test.webp b/src/ImageProcessorConsole/images/output/test.webp new file mode 100644 index 0000000000000000000000000000000000000000..549fb9c6bfaba16b8249fc25324416aa3bfa02cf GIT binary patch literal 5590 zcmV;{6)EacNk&G_6#xKNMM6+kP&gpM6#xKGZ2+ACD#!rH06sAmh(e+vAt0?6J1{^7 z31+-HdnP~HuQ6F({mw>(EKT6o){)eTP zqW}B8fEI#VQ)<1$v~?u8ZUT*}9$p=Rb_Vg*0KZV$squhw9=0Q~@Im>%=Qv>aqQ9Bh zh2UdK2r5(M+{4UE zS~{ z6G0l3!`hsXpkSM>#o{!OR&Ubsdn&pc(riB6%nB(yzB4Fxsfiwpz1?ek3v=yPgRIe7 zyoKsE?*-QCr4haLQ487(rZ#9DUM|yvEoaPuAT1~R2m6L!NdBBA>k*@ht6KJv7e*A5vhVNiC{4f1Ao zL>)4>PrPBOJa3$`M8)UAaY^d@a!LZ-(@NWOj!Zy1X67R94Pf}n$RX@L(E{%i`m}J?9xxZg(&n4di2PVcJc~j- z>5j|*HD3A1d;L2MV?EN^tR4OBu!JIv+|S;%&N7^m_g$pY`MmOkV!hediCihYL><}X zI|iv4UYeB}N4vz*BLSfs5$F==24FLm*2nU?!P;e#OG%?25vlRH>8A9VE5N+L<*L5_ zK5Fbiz#Q=61O@(_upVRkC+Hl?iRjs%K@{^*+{S@swm25U!ABDOcI4@7yG z@8ub{9_K6HPD`mujCiV$jF93-|4=>63g7_#{Wa@e5B*p5ck1kL|Be0E_g#5%Y@KVn z7IanrCRC_sx->~DDRPv>pFio0Mo+Q>m&K82iCx2ph7HGluolklzmdoys+pX*w`f>l zp_cHQs7{L_Vczsl5GU{`S~Qy7A+*&bFqfQy$*3CynK~}n4nrs?@Jq2>cBzB=`F07V zDKT>bP}fVn)5sOP;>FqxkS0@@VZAoy)U%8^vBi`lY>tyv)=lvj65HD8#36P##(^q- z`L>m2D0#S0d$kU$I4-{a3S)!jc|RbPORb{=vOxU{l@B{DPAv^$GaXIqRd;M&{Uq>wy^(o zn;mr{x<~5Ed^W^11a#aRf`x25p!mx70Ng)zrG7rUBf!RS>`+kq$*)gHf&aPmSHuD1 z&`YV}a9WESB<*r44JlnBrV}t^J+U$;9kmaZa>m!>o%#Ol+IN?lhksq7qpSMjBZk52 zwN^QTDkZGW)M5^(&#bMkCOj8LT>cU`+O|N})wsJW{YysD)<_x>ktS6XHo)XHeXMDN z$rJP8u=vqBR_WSQEK}D4*j^X?dW?{PZt;SLW5kHW1_f(Ab>)qrB$KWYYM|xb$bjb6 z{(dsDU~e)0n0_pZsh~xJSaM-6Ij?S?$&NQ({mX` zy@ELaVEKiNqA@;S%7AH*l)f&B_aVKfDSq$1m04=Cbm<&_6oI|B7$BfwZ^)!yzIx%nR}-9^!S&q7E+it8A74g>@wV*J+Byj^g}JHiF8GA<#xf+ zZaMzV_2ffP`jei)-JTUE^L*->JDTrOH5uly$UrQ6G+O|jUoyNR-iHjN%{b_?B;#Cn zu_L3Qb6qlhogyru;q&HVy+?y?0qh)a{23`Z?XXTDSjqzgKfdTrGjZt#bBdK!&##D3 zyKnhq@pm}R;&Za9aB~dr+y_bJ#Iq|auiGNh5%7k~6ikasl7xuMF!l@{ zqxjIfg6_2zD5D_y@D}z*c391;ZJsi_&lN$;)ls*`m4P@*G;tLB^oF0|<%ohcsU6g7 zvmg0zD{Ssni2em@_%%)H`Qnk&Z}wU-D@5U5E$z&sQN2}hY%kmPntgyAQ)R=v(s(*$ z85g2C#|H*MilBw1oGOsp*I0m^!0>4< ztFCfihm4~%yeZ=vk{%W^@EF!8-m;JzF-pHe!PJ^W$m;CUoSRHD3q(GX?BH|fg$a26 zj**RNY3|d6yJ(o?LXObjfSpQB8f>VO=&%X(p7O383Pv4e%7XAX0jS@Nk`Bj1{Bh3Q z{ry;$(yt-udHy|lisu$6 zKwYhjN`tk^^L(#nk|(>Yh4nBYX55)+hM-9sIiM$mR$k;GeAz;kT3$ZrUo+jzxsoR2 z-MhATdLt*)Rf31~iv6#o0V{QRdY3Q}6#e1|o$9;Ukx?~feU03ZpS~6WpDK5vq6r!K z@|3tfBAUu?y7~q&k_C&jhv5DNGTf3SRHGtvUmhF3v``?$8YowViPuYlGX9j-yf528 zM?)>py9EoDV?6sqfL?o09SD3|fK5S#8z}d4(vh8ZQj)X#Ptk@?rW!6^wqQuo9lTde zH(?vGoS}7l7W@{{l%$;h?H? z*{+A2zLLg6S@EG2XzO$?8`a&U(J1FhA?)ANh6Jb79& zx>hwP&QAD;!~@&$D-rZXOwc?WEE9nrIoNk0HtcRtH2gs&91w9f3RwQw>R$%!-c0|N zEs6KDC3D8STJC~1%+RQ95MRtZ%r~Q1FU*4C3C;$$cZL@nhZqA-v z(SFqUkWlj=e5|9I>je+*v%$aXl1o8m<>TUU>|4p8!u7=V^Q0KoBVARv^t8QmJ)9e- zU+Qm1O*LIT2I4|`IC!GqWq^-|d1=9X!bLkY(g}JvbNM+N=L0QRo$m&GZmN-kO9Pza zl2ne0j_eIduCm<^uLN9uT`%e63gD$C{=%QFrG)w4?$kHGq5l;wr}H3i2A(hb z(bg`@aUfFa0>^mUVDp%X0~mW#*ncdg`Xz-u^{D(W#%l;~-7qnw-#fcE27cE{Wo zno%78n6OENcr!ufCXz4&PEt9=U>p}{A)VKv*#=-7?({La_vjO@fW?-1BxD(z^Vg+p zn%-^`j%7Jj^|z(G@uBmrw_tO^{HtGqWq_iykz_+?B%HfO?W+Jd59^=z$Cg*;6}8^vLo+u@Gtkyb{L>7tGr*8{klE180X0}`|C1ePK zRU|(rM|}BRvx?jvDg-oBIzhxTJjPSlG`MB_n;Q2oNr=jk;;?R3Y!egd^2t= zL$OmPyJ&F|PtWCla~(DCE*%Ble1@KN z6Sf;`%;Oi#c}F_N(r7)Mb6Lfz=3Znw&qGc%i!U#C3&?kA``%;Cet1#A0d=YCuXHLSaV&%;svPQz~4GMY&P4vpxZT5orRbo;eRg!97Aj&;*FmE;lkVmqF%ln)PN_-euNLQ* zz2uO}X39wL7WC0Z#}Yj~=4)@4O7cEUfe< zYN+qy*6pfVqpq(WG&gz}MnUS87#FGC!uzG@ynp?l} zUbvKLoz`tFR~r6g6u;9Yk6%0-T>ZHWtq1;`=H>*qCFgzrjt8!zmeWXo-FCqIXSs?Znzv~~!F zl)8Gx28J7Aq=R)O&W#d>=zH9gy|Hd3XbUv@=G)Mqfna{V-}XkkHh9!857Z6e1QkL| zd8*M9HjV%FLx1QQrRX$&kmyoJk?xVa-xJgc&W%{lM5>mwNo4T|v;NLbxu5Mw8M0Un zJG6ea;QAsA;Yo4{=WnO*jiwZrOx~)S6b#Z3#VHFGk+(onrhZw>-LiK2jQvL{c3(9h ziRl@fU3pvnJpdKV%nrbW4#wi?zLU6G11ux345}>6<6DJ(UE?-dvJZ~}q}D?^uk$bf z-fyijrmP=C;4eAqhaV$)gUq?AN9JlVXS7vfwMHL4K|%qZPLETs@`44?thY&jr)9~t z>r^+AnSDfGr2Ya7&>4w1+PO%)r@~6!_)I(bCcvXf;CJBx!@$y>}ESuJn+N6OF0-O3d%fCLJ;^-E@#odj{@DI{F3FSx~^ zdK#v_N+ZrAmgd}&TfU*SWF$!ZWPc7~7Ib2rxm-XC#_{6p%>mJD9xBRXonW1fzuh05 z{*SR_V1Td}6B??_x zUHR_+yD8e#WKrc5Enx3@-lwOuglXNoeBzU$uO>j_gZ?Z(fo=Nl?rGBf_rINzk zp3nYBm7$zqc)!3w9imXlB^Yj@8+g-Z6l<$`qbN%9&O+1O}%Q-Y`2hixt5X z3$Fp;X}#W24r&-Nay8C5`Ft*g-JrzM*@Xu;hO)}&Jg_>%KLS6a|E(0&14t2xJu)e0 z{B7i|EO!P_8^7DSOI)PNQ(A|IW=R$x(ZYh~#DePErM0N%90Igs#8(^uF6(N4lPwK1 zL)6rb0%*x}3=T*VMxB+G=BgWkw{X2iI4o;G!u*G51g8oPGJ^kez8B*J#gS|;CVQh< z|7|bhhg+{2Q{UBX*s(BVPzd4~gtRq~U_Sb1@+7KQ1q(OKN16sXGVgRm*{V2uo;4NJ z75Ii>|1$zpEt+8`F`99RxW`>FVdlRh)r$V}k~5zi1!E}-Modj$Qshs`;ba`^hw8hQ zl+WCN8wq-T8SRTAq;P(e@uJQS3#OAs^b~M+iSljUFblQL=H5lnFy}~^qG6(ce66I3 z3t!eb?9;c7fm;s`Vw-Kw1lIC1xZ~|jya|xJH4de7RlURjkMoW*9_0|g4v5h{b_2a} z$B838I}_!-4lnXtCbf0QfzD03%yiRKNr0_#KG}vN%MDBV9VQ^J-hypW+3Au~@rma6 zWI*<4t~UzQDPitcu1AqrTBC#Bb^Xg7HsAPbHzus1v%fq(FLt-jXw@HKl_+Y&gRG3? zv<^5ABodaY^W6C65j=4Mu&#=dhUj(fVag~+t$AxI=9?8x1_L@Ukh%jn3%s3oK@E^7 z*6TYehg0R7_YpD;kq@`hj0b%uS`$oT+lCiQilBh#1F|B3M!H6x6zdZMe@;Q7H*lc1 kr<`&Y$OD7KxCQ$kv+@{W5}@&xEP-vPcVmq1Bn2e^0Jp&C8~^|S literal 0 HcmV?d00001