From e4be56101a1f400e22e3b864f46e0264ecacb29d Mon Sep 17 00:00:00 2001 From: amazing-username Date: Sun, 14 Jul 2019 22:40:49 -0400 Subject: [PATCH] Added functionality to save the stock cover art to a song if the song does not contain a cover art #50 --- Constants/DirectoryPaths.cs | 11 +++++++ Controllers/Managers/CoverArtManager.cs | 31 +++++++++++++++++- Controllers/Managers/SongManager.cs | 6 ++-- Controllers/Utilities/MetadataRetriever.cs | 35 ++++++++++++++++----- Database/Repositories/SongRepository.cs | 7 +++-- Icarus.csproj | 1 + Images/Stock/CoverArt.png | Bin 0 -> 24947 bytes 7 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 Constants/DirectoryPaths.cs create mode 100644 Images/Stock/CoverArt.png diff --git a/Constants/DirectoryPaths.cs b/Constants/DirectoryPaths.cs new file mode 100644 index 0000000..49ccb32 --- /dev/null +++ b/Constants/DirectoryPaths.cs @@ -0,0 +1,11 @@ +using System; +using System.IO; + +namespace Icarus.Constants +{ + public class DirectoryPaths + { + public static string CoverArtPath => + Directory.GetCurrentDirectory() + "/Images/Stock/CoverArt.png"; + } +} diff --git a/Controllers/Managers/CoverArtManager.cs b/Controllers/Managers/CoverArtManager.cs index 79f5f9e..3994299 100644 --- a/Controllers/Managers/CoverArtManager.cs +++ b/Controllers/Managers/CoverArtManager.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; +using Icarus.Constants; using Icarus.Controllers.Utilities; using Icarus.Database.Repositories; using Icarus.Models; @@ -13,6 +14,7 @@ namespace Icarus.Controllers.Managers { #region Fields private string _rootCoverArtPath; + private byte[] _stockCoverArt = null; #endregion @@ -20,6 +22,7 @@ namespace Icarus.Controllers.Managers public CoverArtManager(string rootPath) { _rootCoverArtPath = rootPath; + Initialize(); } #endregion @@ -28,12 +31,17 @@ namespace Icarus.Controllers.Managers public void SaveCoverArtToDatabase(ref Song song, ref CoverArt coverArt, CoverArtRepository coverArtRepository) { + Console.WriteLine("Gonig to save cover art record"); coverArtRepository.SaveCoverArt(coverArt); + Console.WriteLine($"tlte {coverArt.SongTitle}"); coverArt = coverArtRepository.GetCoverArt(CoverArtField.SongTitle, coverArt); + Console.WriteLine($"cover art id {coverArt.CoverArtId}"); song.CoverArtId = coverArt.CoverArtId; + Console.WriteLine("Nothing wrong here"); + Console.WriteLine($"song cover art id {song.CoverArtId}"); } public CoverArt SaveCoverArt(Song song) @@ -52,7 +60,15 @@ namespace Icarus.Controllers.Managers var metaData = new MetadataRetriever(); var imgBytes = metaData.RetrieveCoverArtBytes(song); - File.WriteAllBytes(imagePath, imgBytes); + if (imgBytes != null) + File.WriteAllBytes(coverArt.ImagePath, imgBytes); + else + { + Console.WriteLine("Song has no cover art"); + coverArt.ImagePath = _rootCoverArtPath + "CoverArt.png"; + metaData.UpdateCoverArt(song, coverArt); + File.WriteAllBytes(coverArt.ImagePath, _stockCoverArt); + } return coverArt; } @@ -65,6 +81,19 @@ namespace Icarus.Controllers.Managers return null; } + + private void Initialize() + { + if (System.IO.File.Exists(DirectoryPaths.CoverArtPath)) + _stockCoverArt = File.ReadAllBytes(DirectoryPaths.CoverArtPath); + + if (!File.Exists(_rootCoverArtPath + "/CoverArt.png")) + { + File.WriteAllBytes(_rootCoverArtPath + "/CoverArt.png", + _stockCoverArt); + Console.WriteLine("Copied Stock Cover Art"); + } + } #endregion } } diff --git a/Controllers/Managers/SongManager.cs b/Controllers/Managers/SongManager.cs index 7ff87cb..8e16233 100644 --- a/Controllers/Managers/SongManager.cs +++ b/Controllers/Managers/SongManager.cs @@ -354,8 +354,6 @@ namespace Icarus.Controllers.Managers DirectoryManager dirMgr = new DirectoryManager(_config, song); dirMgr.CreateDirectory(); - var coverMgr = new CoverArtManager(_config.GetValue("CoverArtPath")); - var coverArt = coverMgr.SaveCoverArt(song); System.IO.File.Delete(fileTempPath); @@ -369,6 +367,7 @@ namespace Icarus.Controllers.Managers _logger.Info($"Absolute song path: {filePath}"); + using (var fileStream = new FileStream(filePath, FileMode.Create)) { await (songFile.CopyToAsync(fileStream)); @@ -377,6 +376,9 @@ namespace Icarus.Controllers.Managers _logger.Info("Song successfully saved to filesystem"); } + var coverMgr = new CoverArtManager(_config.GetValue("CoverArtPath")); + var coverArt = coverMgr.SaveCoverArt(song); + coverMgr.SaveCoverArtToDatabase(ref song, ref coverArt, coverArtStore); SaveSongToDatabase(song, songStore, albumStore, artistStore, genreStore, diff --git a/Controllers/Utilities/MetadataRetriever.cs b/Controllers/Utilities/MetadataRetriever.cs index 35cc66b..392c5c3 100644 --- a/Controllers/Utilities/MetadataRetriever.cs +++ b/Controllers/Utilities/MetadataRetriever.cs @@ -103,16 +103,21 @@ namespace Icarus.Controllers.Utilities public byte[] RetrieveCoverArtBytes(Song song) { - Console.WriteLine("Fetching image"); - var tag = TagLib.File.Create(song.SongPath); - byte[] imgBytes = tag.Tag.Pictures[0].Data.Data; - if (imgBytes == null) + try { - Console.WriteLine("Null image"); - return null; + Console.WriteLine("Fetching image"); + var tag = TagLib.File.Create(song.SongPath); + byte[] imgBytes = tag.Tag.Pictures[0].Data.Data; + + return imgBytes; + } + catch (Exception ex) + { + var msg = ex.Message; + _logger.Error(msg, "An error occurred in MetadataRetriever"); } - return imgBytes; + return null; } public void UpdateMetadata(Song song) @@ -154,6 +159,22 @@ namespace Icarus.Controllers.Utilities Message = "Failed to update metadata"; } } + public void UpdateCoverArt(Song song, CoverArt coverArt) + { + Console.WriteLine("Updating song's cover art"); + + var tag = TagLib.File.Create(song.SongPath); + var pics = tag.Tag.Pictures; + Array.Resize(ref pics, 1); + + pics[0] = new Picture(coverArt.ImagePath) + { + Description = "Cover Art" + }; + + tag.Tag.Pictures = pics; + tag.Save(); + } private void PerformUpdate(Song updatedSong, SortedDictionary checkedValues) { diff --git a/Database/Repositories/SongRepository.cs b/Database/Repositories/SongRepository.cs index de8b3d3..e628b4c 100644 --- a/Database/Repositories/SongRepository.cs +++ b/Database/Repositories/SongRepository.cs @@ -36,9 +36,10 @@ namespace Icarus.Database.Repositories conn.Open(); string query = "INSERT INTO Song(Title, AlbumTitle, Artist," + " Year, Genre, Duration, Filename, SongPath, AlbumId, " + - "ArtistId, GenreId, YearId) VALUES(@Title, @AlbumTitle, " + - "@Artist, @Year, @Genre, @Duration, @Filename, @SongPath, " + - "@AlbumId, @ArtistId, @GenreId, @YearId)"; + "ArtistId, GenreId, YearId, CoverArtId) VALUES(@Title," + + " @AlbumTitle, @Artist, @Year, @Genre, @Duration, " + + "@Filename, @SongPath, @AlbumId, @ArtistId, @GenreId," + + " @YearId, @CoverArtId)"; using (MySqlCommand cmd = new MySqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@Title", song.Title); diff --git a/Icarus.csproj b/Icarus.csproj index 4f3ca44..cbdd51d 100644 --- a/Icarus.csproj +++ b/Icarus.csproj @@ -30,6 +30,7 @@ + diff --git a/Images/Stock/CoverArt.png b/Images/Stock/CoverArt.png new file mode 100644 index 0000000000000000000000000000000000000000..2af8c3026ab7c17ba9555b33b4ae7fcca61456ee GIT binary patch literal 24947 zcmeIabyStzyD0iDT0jNqP6Yu$q)QM<5h>}EMp8l=7AQ)W64D`|lz@mdDBWFBinMg+ zI`dur_PP7dJI1}^jyv}8`vxxFn9qFX)3pdueI$PwpBf*6pv#I1GU^b7?E(Mb;eb2T z1QkLMgb1>^e_vJc{(VL#XGcpLI|~S6kMWI>Q1~uI`D!-zf$YaCTI|1~GevcY$es;z zkY-Bflj*tLuG*8g9*lnfRT#e*8`qz_;0kwdwdhy;z`3izVFhop!rmSks#_D!)3r&| z9@g==&myGjy7>#t2>V@sJY*v=6|7`_Wkf8^gJUgcVM$dU`!;a%s9GMm>HaKj!T4}# zS#6gb6N7o1kndr#N2GCATUvu;}sLp?I}>vU6?B<}ybsoapUyMX#cqmPlm1{oJqWoSWW_3s;DI@0e>m&tbfksS3^XEhjrm zp>Flpt?n0jMh@XJ-miNw4dK3SREQ}X^O>0*nW^-*O*%hC+@o`T!}1|y5by=ZR7qY2 zLc#xM)aAVacP=?8=(<1TM$d{7H0u3j_X?xl{{(Kx+RU z!({kJmVe>^#NeNn{2yu^1e77@uyiAt7=n&!)`TMm~l?BtDX5zzSxBhba9KE%=WOqpqVF8oAqbBvOZ3A z>VI_gf)d!EIYQMfjBXYh`tX6uTHcS@ENX=#%$&*;Ukzy#1T{@5!qoB~XNmVSNUV*u zE-xg|dn(M>$r(AynAvf)y01qXqSoYNHm8@OE&*8a$Uq84=8qJq4Bsh?N#in`*dKGm zkd+;zf3w%n%_P#zAqsjR()j{&!2clr1H*66-#y|H`XLE%WJ`UfJ@_*asFH4w)3Jnf!r-{gC zxJ!$hK11)_aEK`aDBDO&S}P^5>wT)Mrprqkq~2lf@T<&}xAXj**Jl75{vr0H@9~nj zaquU?3bkX40eaa;K)p)^Deex1KIdy$;=(4Pl{DtMq@4@-MMh*+zN_`YiAg)DQoI_;_S_|+?B&YQ09l6Hy;DI@ncs|0^Zi~;&KH!Jb9^vXAI z(1H_H2L@7D+ZH&~-t`(S3X!g|>%e}*&PkRnDtbrYXY$fON=o>5vGg#Ci$(o!0D1IMxrM(fv-*!K@*wb=1qY9v^|taR+kT|OQ51u~{4>2y2oyq9EPd^^Pl?6Qo9 zZ!{N9{0-NX4dsv4E8%{Jex_G28 z@Z+3eUQ&vq$Ob4GqUst>l>eY+C5Z{a>-LIG1YFgHS`nAsXRhVU7}>7Iem1S3&Q37A zmR;hjJbaZd)QbN6>2I_7K$v3o>>dHK#&df@m~BY z_Bh~axB*9Ty~5Z$PI@QCsA|fpJ=5fz0f91Url$qkExPH|JV2gHPbnJ0F;Pnl*kBf- zkt%Zz`%y==m_uaevVwWMNk$kMN1Tr5f(5Tvi>;aI*v9zr_`Ed0!9*7jFo@xH?D8K@5;EsRyzlT*E9}g&FsXV`z?j!OI9eu^xzT!SV(6J8Bm;C*+&-Ykm96B zm1;#qY&P88kz=_cULo+@cejS%^z~>l7}}X51qYnhb8qWWqoWJ?M2MO4xlkuOz@;xT z0EL>NlpNT(93(9RRP-lSUxoOg518JVV+Z0uNwZPK0u&$+*>ccb77q*w^0_fxZy6^}N5mX04ZewRnY4~BC?XSTOJ7Q6fFGGc94d+ZCO_$9(hp;RxT$K9755PW;;s-MRnOiP}Q+uHAJC%|!$#kq4q z+@Dt(e7Qn3Tev@mN#|T!n>jwPe)O>W9J%sKuy41$jBCe|53t$^V9xH5nQT|RxxqeK zSV~}jvoBkfTV6)SrHnpEM9`oMKj?$vw0QdA;X{dWe$b|n5>nlgrWp6=OI2IlB*FSz zu%a#)70mTZq3TEBShi}C+sEEAVB5_S%&mQA^g03l$l{E-petWCSSsb*T0SY>wYK8x zoSw+BFPQ3~iTI#?D2zJzy0)9N2$F?m4}7C#DYUK&Ifg&{fVp0>FK#cGr#~Y?f2VF{ zLrr$GyJzIr!pdy6pWrE&?tw%j11Urm`f@1RR)vhHbUQR?)cH1ZZHBI|`^Y+yZ|{&g zuFZElkD)P_AH=x#dfau>Q0>nOF_vp!RlI(%M^$ZV0b!cJfEe2XH#l9J+LrXMQNQI} zV8T9p4R~~?yfF2As<%vdRjloY-MUA^u15pV10?HB4<0w6NX*gcq-ST^f# z;23%Ko+a}lR&=eKylO*cMh~sX>-dCp`8t5S^p}#>Mh7b&&d{}_B{62`r{wud67T)W48@ zz9VUD{miF!(4#mVAky4{7bE?$O!v%zVPDmoTg)U2gUDpDbhF1V{SvelE!3^Gbb`T&WfrR)4)E zc~u*yTU;GjW`DnlpojmEDn*=%{FB=q4;3|D+5 zL9pWUWo#a<%n_jm9cC{;YordtO-o!w>x!)GwU;O71*!2_)wA@1dS4eA}V!xbqNc?>U!!y~VXgYjX*EL;4!~7Fp!h(F#eVPO>jVCymVW__lGfgS zt?BrcnYjy12Pu8Pdah*D(R>VA|Tagz!)Lee#5UY zQsEl~2d~O5$#0&x{k;QxaBy&iqkp;b2>gaZWMD#ZkJI9jNx>n3wUJHU3NR@%Bq8|UVXKNeq`_aI(8`?~#R{mdDXlxC-g|3asxVg%p zxx=c`q%<~h6hQM54M1LXYfy94?`X08!S#F4=W_7`z~@Gcn;t716`I-7khQyDBRG!E zZ2;J8mre2p7V>%gQm#9A>rw3C$00Jg;s!zdxKKuDa-zFqT5G@-wk#$__(s*=8mp`b z5E;`wTyA7FU^9ZOxt#f;hPC@KWQB4V{RetE8-FaQ-@K-SH5N*loHlLdkWHUt|G<<|yN>GgvOyZik}9Md4mN-T7>|1@(^Bak9k#CCwW$ zuqD?Gj}--$go_xk<(=&IRFMy2E}@k=MV%nHHX$debxmm!YG5jh9pi>#`CYOrv{uBj z&r+xSrR2cYeAZ3N!kib&(oE3%+zS5h;UUwt6XKR{DxCe(3&C^C+f7RHD>c6=0PWQI zUG&^fb_-QKs-{wTTf`2&h3x?LCFaiMWQW&pr~?qzt#2JgYCJZmfuFhp;PX@K`XBop*Ds~BCnrAywka&ugfcNfuA!sVHRbhVAX}1=DOC>%4o07M zj_{qwMi5JSN!`LZuj_(^G(z}3*MQW{tJ&>E5urr{X4~dC z`{F1dtH+soB4v+!guD(4{5h{8`8?^bAwJO5&c#VX%cN}M=C?}5qPz@H6Z+;jja20) zm}BxX?0i->3#BKo)?Ok$5t7!vN6Fh|(;<6#U7Uq}weM}jFi=FL{krwGmg*96LDNXY z>-X*w>O>#oUEA*L*+xng;?q~sT2}k@*N)^EQhB1iH*CxEJlc$>u5&{1Q%T7V!NI|b zOQ{-zokejhP?&s^(%{EzPC$f^MZL7lfy9%~0u^G0khWY30i;7MVdWSyvgxlPBO`uT z;fQZe{Mnhd`d7s_NQZT1OkuDraEu)i-G%)B+_068w@PGk6ifxn?z~2Axzb*I9}3jL z;5pw*e+hk3m?DlTyv$H%hzF%UEmj_7j(oWN<#XqBN5Vk|AyT$C)&Bf3WWGFx~)pMY7+@MP*wsc_{sN?=2 zjGQfP(9Hod$@J=-WW|C+Uj-)cZ=Ob#p(N8|>3}y70Bp{2pN5eMtIB;waXWL(0BDUX2{w<-d6S+#F_Prrwx~8x zglU;3CH1mENnK=d1yXr5g%g+^hxseP=H}mD06APGY5FFl>e36|tPToHFfa65`T>ry zPX4JQ$pwVJ{mNjc>@rgwJZRb>K%=&o3Y@o6bt|@)!8V5(3rgVwD=lYG!N|wvvi`-8 zp?yFXpRg6Yar5+5DEif#ar4XIH2UB)^J(>3WEfB{H~>@*uD`VlI1>N2YiT!g89YeX z9X#&Nn!A3fWhRLTa@qiwiLy;f)c*N7vHx}LyUBtvc%-zShmUjt8Dk@F2*7Bgo;wkn6L7KfY`yPQ@#Gky?A7feqY3ik=h{tREd-t}3% zzqTtL1?+xOPkS;bWXS#Am*ZdCZ)ao6=DkZCQCgbMAWS)5bJ%)R;x~`-gt%^^vA24- zpS7E9HJt>KYPk=UZ0JJJ!ph(mka-a{Y`a!d_FDSatB%!PXJ+29bXjfiVo7@QW`LF< z>Ll|!Z%3fKo6$HKuHQjedt2){FXA>E5XAOf z4SyvvXxe)NGC6kO7IF-}*fpja86eY;b;zOCt>UjRz#tgp2q0K+1|b0`L0kh>mKIPM zl1W>NQ5ntV<-J>R_Pto**<58q*vY6B7H9GYvwet0Y0#Hc)AEzj;Jk*2VPBjjQzGrAtP^60_&tA_!N!2r5Nu zTIw*WGwTuTr6}+KgQ*Q{FY9a_gy|Q z;{-LPn|=Po5p;bWml*H$&agi5Io!w(CnUf?z7chYoC;&sN+Qxm3bKaB3i{Wbbw7|U zGzGww84%+rlhuPF;m;-G;OW_uG$eHGr`@A#&n34TOy|g!@csfI;yqdvl9^qMP@|_! z)N@8evT(*_iStte>QJ5yS7|7T{`tXxTj>zxt8$?u1=$0lT-zyq#stkxAwEG9TPET4 z`>XjydQ>fGdgg+hi=<>63;D&gA*-D+I?p-^vY&ZywHkTwK0lv(4a$LRj7ULH_W%K< z!MXrNOMlRkyjzPC2#W(gErVjo1K+xV*-DX<&3XyA{#S41Si4u!5K-!XT!Dmo8L@df z+G%>)Lvyb}I^!ak8AJQVZn}iEzoyu)UX^RotL7>PY?ZLplJ83z8SoieGjraoA4f4X zL}5xES2;oP?+T#Uft18xQx#<*h-*0o(H{Z}98RB@5Xb!&f(qI8qz`gfltjXf{A?c9 ze&#tiKi!<4lVtZs#J}Lgh~+J{a@^Z1B*TITM6E!4v07kE#%biD_E?KBc{pd?B1iqP zyu9hin!M?rTS9AdT3zXqu^-)h!$}0#JGcNdcKZx5@P(wS zH?Zppiu;;NE$tR1A)TQ=+e2jo`X|b`0P%VEKJJ=s)w-CO_RWl+@A`*q&z{xTL62er z6W;T;wPlYFvEV_A657yv6Hw2Sna#ai?6{(*TS_?+mtDG1T`51`Qxf&!M_S0V|KUp$ z5Ql?xw3EjMgeflZj8NjC0iwSczd+7xU%)Y96;!>h4^{W8|5*uX+BG5uSvuW(&GWWh zl{3a9or*Vo#D%KqmvactUNj|6 z`7;`wRL-^pFrXgahIYZJ)5P7?2phNih#`A(G{Qj43rAie*jTziNtTGS#KXSuD4Sq@ zZgf4Y#^-y;2IsUp#wFPQw;p{ZFoz<&BOz38=;2{v8I_9oD>cpYJWXoYP#t-Tw;sX{*D^bWk{RnsUKv z+?mykGhHv*OrI1kQjNytDg{Nlv66~&O2x2hSxMC#b;b@gOXF^+pnH! z4Cg-fw{~5#m_beB^L$P)o`Twpbz&$qm*|4o=-hd7YPx;6E}iEZd)uPc;vhKo*&!``il0X+8IbjTNF9$XI&Gr`@soD~ zlA8V-K!ZPW%A4&@SGFA$OUR>~ESZumKa;p1s-J!%%|*%S`b-No>4f?dpM8yNPjSUeq_$;uQX5UmIs#FaC`Pzy6EqR{-^ZEJVkXHQpN)eZ!2PkZMYN54y( zvgc>!jLUs6Gx~Pp&%S$9RljgkAEFoJj~yR3C5aX?@7;rl_Rn!&LR=vOYqM0qeaU93 zljE@7;3Urro$->Oo`0jZTBICTQ=VWQEbMhYZRQtaN@4BT%Ah#PXMCgtY+?#n3sSMW zAlcU@tlgnq;AZ6p_H=lR#Iu}g|HbRvT=%e+1U46|;>sT!UM!?FQghJ= zEI0Nsz=L|RrJ+Y%p=&ebaJgbxw^FW(AeF0&*_N!X$I_fwqwjd7gr&=f+c}THz4^}$ zMMgy8+;z{Mj*jD5JxnQiP`7%dd7N^q^rT2z-qT5nvj0|Y*pJaL5zlO1P&72$(~CtY z0Mqe%{S;{BRtp6_Mut)!0?ISp$8`)&bFVaOU_5MCCJu_H;K8F3m^rp0uv%ZCXV*rNN$luOs?i6 zeaG-gYK@x4XS9yfhHq-5qzxAOdB6A`JYj-_7coI*43}M7ReV^zM&C_hlUpzDZFJ{Q zLz5|&j6@%}IN!lvC}V^~&vdTdPS+GNVgQC)9#mE^brRnVRhK8&-0mUxEW%?kr1t!L zp64Yrr*qZy1E`DdgSt3q+^KJ1uvsm>-}rOMXo0(b@!{5>+LepFbkha0l8D0JDl{1^ zo8bGQ!bd~?*RY(zGb;`0;D`d$LT)492zduqYVP!&QD-Q>1Eq~W#||Pe9OT?_hcQ zQ?K09MjLw7vTVt8kvf9@#oDOU$j_$~C?PrHLp`u+yp%4(VlG0v8Hj)^s4U`q`fBM= zX6Z$tfJ~@bQ8@MA)2J!Lbd6s8ZT<%}pn{E%k!kKctml+7I;CFV{>1-q3nN5rYp@h_ zIZmY^r-!(r-IG5YLodoJWzaP9y5SLkrIQs9DR6w6m&Gec-lC^W30<-U5#8_2^lMn? zmco9e|83A={07pGCQxm#|6#>Ij)622iT;|V#1k3eKAk&-4JEz+?3rm!OUNoSRUm>w z=)VVS2<{ySwe({zp=|+Z1p;bsKNsK0X-`(Z2eIC86f|pNF$SBI4$u^b{S4z)1@*4( z`%OyP{>b8=5 z0f3g=Wr07)kRl7mXU3R@Eo3ByW@}dT*8rk|{fls05GZ(L`<*8cmrNQ@5ARTzT{K~z zR&^%`6JaU2{Q1Ma`!xB;0P#I2rM+8vjKH*iACyGmtQw9ye(zUNgSGZ>9uN@OiLc?Ft#z1%+bwK#?#iPRR`>%IaMjvTYg?z_BWB^PGnN@86{($DM5 zPXUa{UH|Ejx*$v<008uBKnE(z#Jm@4v#ptQV%UgJ58?j$e8WW%V}?@UNuz&Anm_@# zov7Ec{wJ!9#^}y47M)TP!BCq284a)J91`F%{yPA3`)q!e2+K7j#@(0%*okCDOdUJE zv6)oE84j1s0#G)7Wkv791?U?H=`aK1?6KI?hJ`RRom(w1otr9W=KQ)2={#=Zbh4^X z6g=hC%{>abvhaYwa^hsAPkzP@pj^6nKdEONToPbZ%N)lo!HO!U#c>JKq|{=fbTiyK zuF~b)uDA_B2f6?*9zWY8-3Bpr9(vw&v%{`#O{%Qt4IKe>*7(7Y_=b13p%lx)_(qA} zGtpcAfpz~gEtWD>#t@ma)B;AB7&4YRJ3k%D-RXc5Ev>q5wLA_FENC*{^SMf@xJwE zsmJ1O)Fp6co84EG)pH;cnlgn_cwNZqhKzqaq!mpl;L$E?bO0l=sXq zCW5-`i!G=u{Y!upS32;(Me&rEMd=qlXx)rtDH$_c%ai26TV}rRSR?v$Z4?|V+~{Qw zhl5poZBd^-1CZ8da04Q(9@W%NbNL?BU0-6&|7+!xffUR2T_!83MK`{#_K{b7kKtm{ zuOQHVdqOPki(1OkEg`^IrUv5|fG942+Wb2k?lKl0z<%GfR^IMCtDbmE;7SRaQL#mb zl9Xsx(v^Uj1N}{ZRigf!lRgn8JZQaGpeT7Mh74arqn0n%E9#RtrYja$lLa%B+RQ8v z64e5eEnoZ=neIs?p!?x_G-2fAy5vt*%WR z=I44a*?^{-sdod)+|Kv65|}yq2E~GZOZQ`VT4pvSZxSv$+d7;gBSs+gx?Ed9mYuW2 zn=`fV7&I|3ZGbp9r#wE~2+Kq5xqz^V0;m6g+H8J%FWrwDh}KJlVe!}JVBV>O6iX`9 z^5Fu#Sc{nEMz8)R`D3|g{5~xmxgU2=gA&J2V;PZO1WFHc#t$ZV@GwBJTVT`Yv?~XK zRuW6a@83Olqkm=|>;5#fQl#Qa$xS1Lv;qMgOELNj^*^Y-ycC&$FEy9OQRylzk*^zA z2^g8d_)!`|9NG6kXc@Uy+g{dQ_NRR?Kz{UB1fF|tbbTzI$?^J0tGnspmWf^cJls(Y zfUFLZ8fJjb__o9nHmb>$)OP2JK_8wfFZND7zSWflDuMLGd{G;^%`xeiHg}o`tQ6|q zjnP8sw;X*N$(QT5tSau?u>U+DdxX3GHpdIhKuF=dzPzGCZ;eKm+_UcPJYuM&*qI_0 zj3w~dou;E?X(#Ky$6ju{W4ylf%=$EP{9?(UiC~VBCBgWYB?F^d(XZ!Tp08NecF4oz zB`r@TwwTTnp3-8OEJYhqsA$Hi;Oknasg zIk%A-cR&yingQ(uExO6M7P`%QHPXA5^t!yDs+y6)_zd4jVfd%<*`2hD79O+p*AAhR zt8wJtUvt-)FnC|IcpNAhzrl9WngVPIlgNAl}Tg|2@4KTxe~31sUm@qCA>46UlKDu?Reemdt zLJ~QisDkapD|DumEF@<+fwN5MnbwwB^kY7#;W+*_vZan`dH)I{GE&gR^A%Sz=zqDD zBw7s6rU#o=FtaHfdp*MH_teAgua26c9wGZax)k(w!83ewf<_GWi?a+OpYA-Y`{9Nm z_1ajex2i)go=&%zi8GG5j0==_4E72QS@;y9!7z3Sdi zHLOouptU`^LkLZqw3gOaTsUYYp3HP<)V6?$QBZsetG|_Ojsr3#X^P1MtE;mAdpe5U z>*qt;M-Q71fJ5k^czy{}M{raZYx%BjrqiB`W4x?UiAvFT8e&k(lMciJm@5ewkCW+3 z?y8zsJheMpUI+b;AdId;-n;Za8nzN*q9TBaxS$EBHv)aD>WSn+Ss8lbiSBf=FpXJ9 z{%q?NdWGF;K=*~E)6(tn11n=-!okGN`pYX_8K5eRj--Hz-0bX%ti45nydv19E^iY<2Z)25XA zaZ}5_48K3l@>bt%x9Q37!XxJa{m;ZgtRRj}=?Cu!J(rbPDO4`qFdUO9wY)DVoYp$- z@#n0UWE(YEGsIT2dfGcb>+P+rROD;n@{5wjEYy_pg}vQtk1gS*g=VZ@K~!VIXWF~g z>dleN;VoH|9STUfC+1ke#FjDDBTx71r_NJ6`=u=|DO#^Aq`4TCa6GV!n#nk= zS<23KNn-G0#_5mOns!N;O~q`S$gF(Kow_?lOq}g_@%nBw6OPebnSkUO>)m7HT^{ov zC$p%V)ng@Mr}~~5(Zrk%Umsy1nZ;1tGrRr|hjgBue@WEBzw^D3z#vZL zbz$7>nHNZqzObL#i<7FVm$Z$8R@Ck!jVbi*=R_!k{d{Jgs<+?_A8h?pUhjI*HM~T zUHD9&&ql==e{JfTuqIHfqvvDryJpt6NsifGQ5Fswo zQR+T7<88XHUC)oA#O?cI5mMj(8J2^18V<|v7^u2>w!u)m$x<5Q`22!{%Xq95&49d+uAky zRuKIYD_q!f<=oDKZ#x%`%d;nj@g~pnp24)%E!_vq+88M~e|m@Ft)RYIdP;bv@!cCZ zjh#yKKy1-&yE;U9*wgKuJ@7yuVDXLzZ*pg(GoJ zkrsb$?);vuqs;j-NZ`0Ltp|8Kn&E#;by>W~f%U9*2TIM{nXJFCVsIXm3=UuMM zTvSSu8?=-2^SqjJ}>%S-wU>#5#+ z(HkgyY;ezy0%)Z3bx?8n?x zeiV91a!K!FhSvaXLPNeg%CD~{LTH4>3epRjU`r~P&B--ft;X;$N) zDK%w#72VWV!vV7xpa&m*=WjFL{A~c3mIAYC*@S<){8Scj9}$Au*)jjN|K+IuerM!P z=ik367mWtN9>@=-wybb}N5kv!pG9mi)4`W9@MS2YB0tnPfe%TvpTu%INiy=No+G~ja zjYVk2M7V+m9rRV)M%4c~WZwrPj2-h;6}RynqRI@$CCi|2Y?T?B>qe&V!r0v7x3rXj zz+(~gAhOdGv}D3Iv!KSS^1Ioh`@wvNJ*wIwz zMTuHP+~DMR?U&Fee`w~c4o*%SP4f5Y%GJB@QL%o%M8mK=Xlzn=113RwV{RyR(+jg> znTMkvAG?<{o1h6$`vT z86+VeOxS>kb+4O)TFh8d_i~C@fsJOxGEYP!SbSIHCI*u4KLSQN)%=qMEX4dPky1^X zSLh3Smr74y5Oq$`^?bMAKW|bFl(BZ9gTuNPh7*uU>vmMl=I&W zB#Op_4+CeUdGfN**1M~JDFVWypL8m6NvzV)Z-XRO-r9LZCPp^+WR1EJA&SJ1&nPC9 zDJ=B8qIIaAV16h)*`mtEy;2SCtH8kN+Ufq@ ztYF!c_4Sd)L#E_MsmQFidrM1Qfi(_EKz%XY6>|g3V^JmCP$WccSTHf>p*O&;coZqK zKWxJU-6{53b^ZJ(5)UDQR$K0;9&K-8_^G8K^T&hM&0CRdK}cGdA5a4SX~!jS)>oMJ zXgxLru^4w69-qESWfY4rRqmS{BU5~{i zsK1M)UBfssK+{1H$jmkne>}vN2w*1fUO`(B#0_FoaM(L9qW%Q8{(egYQ4A!egf_`P z$3qwhqDl1r(b?{S^+TYUPHC;ft|>=L>(Y=mTF|(vn$}fh(Cp%)9^&KudVYxs$%*D< zyn$X(%UrKjcrEnIa%%ec;ro#!%0@CySs4y6Xa0$cg0)Vfbp7Y+EL)Q}N+~9R+*~uK zQ<7H0xzz@hAT&yrW9NOZvu*d0L{gdjH}b??D85?4=g7Eacgi3c212Bl5Ps&}yTkx> zB8>k$v$s2MQON?a6%*2+0H{wt4+9B?4iS1?k=^mJq}*n11aVF*rBwZUo5v~<%^m*U z>I5cDXx@D(U&(BUs<+qAddwY$_${5pszxPFm6zrrM`&^nZ7sfhzL1v;2JtWN13Eg8 zDa3!#)d)%v@uBoqOfq(JKW zM^84s-V&VJPtVFOQ6Xg1(2IMJ;&+acS?GVliQHq^AeDr z(7~U1@ToGP$+HGFG>zJWZ(Wt7tfLWZHTx? zcG%hx$XI`0q}A=WrtPfZ5qzJL12)uH)MUlZ6~p=Nd>J-fYrF0Obc{;e^Q&9Tk>5lQw>` zi<|v}g$60B1wu-uD066XK};3RAKHnd#;ay6`#-XV2bgd^WejR@!m0tn_z=Wrv=@mM z^L3vhUu*D_cP-WduP`RLxbU8|X2Kp0r(X+A69@Z?70iJe&uofM2<=(&bf2F5sXoMiRlo`y5ry~gM7VMv%^j}`;z@w0N=EcZ7xo&kNp zYrt}}b;W%hV;yb6N##(}?yZwQ8pu;QPnsd_d=c%CZ7|wcj(a5(VIBxmgFQw0>N)$# z7l#ma`PYO|1J~4;fB1!W*_iDWxpY5hb(ft_nl&Opnnw9NB1q z>T7w^BQ+j1%rZ2pPI6<$Go;BECuwNj{(fxc%<<^_^lp?H{Ev)50zw0)lQ`y&)g7Dv$fq|iyEKqs!eKXX z)=T4i{ZZgcn(^#z&w~+EF(8)`@x1d$V!M!1su+zY_t0Ycx!In>6j9C<9@7`k3TsgH%MIHn%ggIzn8oS^dJz**QElV9JiweIU{i#Y{j#I)-m+Ta zbF*5jD4abGE1>U9?f`Ijup4_PSzC_iq{1Bv6(4HE^4+kal&yJTjweI#Nlgo z=c793BRrt?ETFb=&}~F+tX?8-@56i}s+MA;a)unsgbFQsJFYR6mW-pbr|ZkpUztQt zyg+6f_Dw+P4J%On$MTQbmecBD9z6`f=;yZbN8{jZJ6AIsdO=eXRU81OX*aID?1~?z z8Awcugc&`&iDJZ)N=B!Cr0vxVev&7G_Tjx3WJbfSB7>HEa7rm60LmuogLNsF4Es6l^Y@)XRD00G1Z>NW2zYEU{^m0f_tTctN_iB8L->Y3K{m*^J5%Z8W}heI#_;P8 zeALRm%S%uGTqT-~sAc0T*jTtG%;^M{JG^8F%kH@agUA@mpDD z3yRY7ZPqdLM5zR0sye}3g2*?s$}8ElE|&Osob@Ld=zQxyE*`2bFaNgFBH-d-5^KyC zy_l3LmP%0c8HpK4^xRbifrJ!fa8!sk_)ypTrBNRF+0mW>f!jpD-eye=@kv7Ny;mDO zsRD*r-=VTaB;e#s5K9VVxHVOP+8`uYP literal 0 HcmV?d00001