From 74b03a7bd01a8b871aef39e7f1544c193fce149d Mon Sep 17 00:00:00 2001 From: evazion Date: Wed, 22 Sep 2021 22:48:44 -0500 Subject: [PATCH] posts: fix incorrect exif rotation for PNGs. Fix a bug where where PNG images could be incorrectly detected as exif-rotated. This would happen when a PNG contained the IFD0:Orientation flag. It's technically possible for a PNG to contain this flag, but it's ignored by libvips and by browsers. post #3762340 (nsfw) is an example of a PNG like this. The fix is to use `autorot` to let libvips apply the rotation instead of trying to interpret the exif data ourselves. Note that libvips-8.9 has a bug where it doesn't strip the orientation flag after applying `autorot`, which leads to the image being incorrectly rotated a second time when generating the thumbnail. Use libvips-8.11 instead. --- app/logical/media_file/image.rb | 21 ++------------------- app/models/media_asset.rb | 2 +- test/files/test-rotation-90cw.png | Bin 0 -> 27176 bytes test/unit/media_file_test.rb | 12 ++++++++++++ test/unit/post_test.rb | 9 +++++++++ 5 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 test/files/test-rotation-90cw.png diff --git a/app/logical/media_file/image.rb b/app/logical/media_file/image.rb index 9d77c3e33..297c84cd4 100644 --- a/app/logical/media_file/image.rb +++ b/app/logical/media_file/image.rb @@ -11,23 +11,11 @@ class MediaFile::Image < MediaFile CROP_OPTIONS = { crop: :attention, linear: false } def dimensions - [width, height] + image.size rescue Vips::Error [0, 0] end - def width - is_rotated? ? image.height : image.width - rescue Vips::Error - 0 - end - - def height - is_rotated? ? image.width : image.height - rescue Vips::Error - 0 - end - def is_corrupt? image.stats false @@ -81,14 +69,9 @@ class MediaFile::Image < MediaFile file_ext == :png && metadata.fetch("PNG:AnimationFrames", 1) > 1 end - # https://exiftool.org/TagNames/EXIF.html - def is_rotated? - metadata["IFD0:Orientation"].in?(["Rotate 90 CW", "Rotate 270 CW"]) - end - # @return [Vips::Image] the Vips image object for the file def image - Vips::Image.new_from_file(file.path, fail: true) + Vips::Image.new_from_file(file.path, fail: true).autorot end memoize :image, :dimensions, :is_corrupt?, :is_animated_gif?, :is_animated_png? diff --git a/app/models/media_asset.rb b/app/models/media_asset.rb index eff8737f0..f432a7095 100644 --- a/app/models/media_asset.rb +++ b/app/models/media_asset.rb @@ -49,7 +49,7 @@ class MediaAsset < ApplicationRecord # https://exiftool.org/TagNames/EXIF.html def is_rotated? - metadata["IFD0:Orientation"].in?(["Rotate 90 CW", "Rotate 270 CW", "Rotate 180"]) + file_ext == "jpg" && metadata["IFD0:Orientation"].in?(["Rotate 90 CW", "Rotate 270 CW", "Rotate 180"]) end # Some animations technically have a finite loop count, but loop for hundreds diff --git a/test/files/test-rotation-90cw.png b/test/files/test-rotation-90cw.png new file mode 100644 index 0000000000000000000000000000000000000000..622964780ed0e49fb6b83eab0c7f117b9ab395c8 GIT binary patch literal 27176 zcmeAS@N?(olHy`uVBq!ia0y~yU}#`qU`XI#Vqjp1l6Wh}z`($g?&#~tz_78O`%fY( z0|SFXvPY0F14ES>14Ba#1H&(no)-)Zr3MTPuM!v-tY$DUh!@P+6==i2z`&N|?e4A%_Y z{p8Bx@4m%{Q+U{#O^jI_CU7uI^$5jINj)`fb;PukslL-sZ_AlDMKkQ8TEvu)DGW?J z42~%Ri47-z9^1FE*v9hBk5+TN|37}k75sl?SNqMb_Fj3dw$1Cv^M~Fp{}+7DQb{O~ zr?Eqzu{b11iH&RFx^98FQ(`#y7$)u!Xe#Douu~E=4C&dZ^Zp2jp+k=V=brE9Sf9`7 zPBf4x*&XY`qbMNA&?2zq+S%}=p0#1CFTbpKzx?yem9mqaR=RK;3{X&FU}`81%RFew zf3V`cawP*31It7ePKM3bypCNq`D*94{PM0fpKQXTBC=m61zsSsq!zGO^@kY2m>=!+*G&bUr4o3dCdXzFq;?+Q!1t6o0- z{>Lt7PAc~>@V=0DI*)Jj$ccNQ;S)m1EQZP;Y&=cU`B z5#*5MV0i2qlK^7?ry`5+oZ^lY%k&<@105?YpU){)c-EQJo6gM&|7BM{FkxcI35uBZ!{l=L? zP{}fVFFy~bpkQUs#0invbGa2;cCB0b=){(-+jLH^TGg}Cxg#|6h(v3PM-#VGTaV$f z8Q=G<)9t=z9Xyr$`I-<+-f|y zX4Rbat8Yq9I(eywA-&r*_m#@oqLm@D8rK&et(bD$y}GCK>eAA+LX0As0t)P094!)( z$xV)nb_6*U^h{({>v2rp;N*GE(wUKAo<@rRGjoEX5W`{*MV4$`!A#w)*XAibx7qi< zs>q)~vE`X%#@46~3%UO1pDS6M9w@Rrmthe2znS~TgF?YaC)F*Uzq*x@d0OK5!Qyka zmB~FTvy*#DOJj?BQeJIZwQ7-uQvpLyQ|HBMdCrtcS|=@(j&U%xYHCMYXJ@B-H%(BV z>6a{`t}}a!sKL9_pL8xh{1p89`E~oBceZ-3bl zagJI{UQS=w^swo_JoO)Ig_YH;7I<z2E(N`x|QpPg=|pT}eOe`de!p87v) z^Y_&K?Ui<|JY)Fu!8ZN5{+rKj(MXOBJLe^4^|t3b`*~%zHU(C1;h9UVyhCT5D6_sk zso2kfQL(_SN%{F4L&gJ)6F8D`Y&>}snHCi9TeoJb*hEjwr6E0r@)~YT4(C{(Gfh<7 z^z7|iKXcDZi!_cu?lhccc&}of!$b~-2E%if={<@{$sPiX3U2Y&zt$LTzQ(ZN(XB{% zr=E#PAFfF}_vvXAj10aSn&~T>%+S@lS@eX3v+B-ELF!&woeGQkOW!V=YsUCzkZECK;+eXl8h3Jb{ux+aq< zoHj{iVo;kv*CLJ6pFCq23+`2SbqF#nQ8;ppJF)m81B1Za;%m1A_FUVu?zMnMOM`&r zbB2kAYzN&tu1N-8?KoknzDPp3RbtWAD0MHbrAsI9wDdoywXvQ%bC=vV_U1UZkj&0W zJ9kBWVPAZ9DsN-S=c(qVo6pBu-WUA$HhLHh#R-qnIpXnSbYR zeZ{XipVi)G+MKViaO)}VaG5Bv;6alyo1livf){HRN?0w~KC+|Mlei+O5^*akY2n`P%<|Q>f$+_tCV{>-a zX+OQ_-`_9(I5=F?rp={$@#Mwfag|^1J&u)btYC6FD<=BBe;#uO!vR*UlS>~tF&H^? zG%#wkJz(tEc#N|^ekT9Ln*udFEG{Cco@39mo>WN#dy@_{HCx|tsE2Ae07Z!bG>^iI;!j9g2M;p z2P_pZ+E&3T-aJV{jBG%Gc2=<4oUT8VYp#Y$Rehxp!B?{gJFVUTLZ&`z1dDXHctIMulShd za))(hJTpY*XiPb}Mk6igLBWmSuJT)JeOB+%TD2*GBd9~-&ZUf$wVJ1d1g83NT!_eD z`?}OxhNJ1>nWvZ5>pXX_E}yph(ag1sqU@8>I@gqiSvT{oPG|4jz;ov8?dv@nNQ~(#xJjS<}Uq=6$^Q zsl8K!MZe|5C70}(PczqF|9Vfvb)yE?xr%A23}+;qCo*TrFYqi?I>>&F>%^3x-p>=g z%%+`|*nY11zY1$okEiBkldDnZpMO@1&YiUMyRz=-Pd*%i%9ZbvRgOud`?@UrUc92C zqeCFMN72ZMf$L)BdnLsfi1HxcJ%Ay9-4_%@TIm z#)c>f2o|I?c^{pc*2Mhy$OMK{tD;0$nYQa0s7*M@A=h|R!l~n2rPDdf{By3Fs!L1s zOwy&C6gpfEN}QjWv*`!_xm!`uBCN?inpb!HQ{%9H-oU{qq2SJTU{;M`kP91+pg^Ml z#{>pOhR(tU2?33ZHl9{4d?$rjR3{_{2wig7<&&&(%)+(DV~(NPg`){s!C_`@0x{oi z>-H?uI{r1MK3zFl_DkI#cl&+!eEsrc>!0q9|M};8NJ~Pc@_p9H| zww8X~-_IvEU-nyA+u^fYB^Ya_1T`vlG=08OAw2heZ`)tS{v})6557v+y)5|fD`odN z#~Hd^Pg?&KpWU4Cv~u-aW?RoEYs*6;TLm~J6u1-{BLX9iP5pdO;&E(`gM3BVG1lic zZc0je^Frb}cy>PUF1EBX1HjisO6&ROQ$8M|cbiqA1r zS>!Qq#m_wsb~AP@laORz>pD+8a^0jB?W2-x4IUy4PD-x#PFcjwn)e~#>@G{&^4!0V<@eP*eRQf>dj0*%=X1AiO?CQ~U;o-%-}dVj{{Mf@ z|M%bj!T-AX_D^NcAKv@7XqEZ4bGh@Z*?YpLruK+_-f0|HbT%+jctYXQpoBfkDy(!3 zPO@u9GftZ9X*xerN#um6@ElGDMb65e2XmfZs(Qb~uhr|-Egi4Lllvx|I?medAlN9u zz^K5GZ8ZOx!0e>02YIA!xEF{jn=l4*9Gzis%xC#$iN!%jB#v+>20V^nc+hNK7qFw2 zLEiM=+rLJ=PCSOkR%vW~(&Ww7#mLdtqwK*cF>xZxsbJP9ZpEoS6INciSP?hv@=Q)S zi_0^EVmuE&-AG2@M=EAz#(wW8|U%V5%EHl-?^|bWeQ(`kthh0lM<9}?k$x^@a3Cih3 zm%=iuH+=bVVS)7&gEF+y8yLc)0ri zKkfKPf&NVEmweOA%Ql6`zp>Rh?YjNC)Hh1@x%zW`ff|XIZ!$m-en`NRB!%YF@4M&p>&h*(F78@LD?a=RYgn?m= zWHQRoF2;(q&`{eG`t^KvH9xn(vacQge^j)jH?SFrc zpYiVfauGH5>N!WRCT_oaY8PkxtJ40{o!WO#o;>;EOHOw7>g`)Z=B~ZN*!1D-HWU{Gc%Xk(bO(WAxC zP3aqpp|jE=4#OZG5y20hPg}h>7X@5x-6(1l;3b*7hy9%N{^uPY92-}NIT@W(NnW$D zc9Gf~0iz@d2_Yv24jzq70!_vDS{^KM>XMqtAaIYpLym#vv6F$~1jXkuMS6RTpD-&k zwKXZGKWOSrX#+?T0^aKUU428o6PX<-V$Sze`u`OgJHFB&X!D^!MG1Cr?&fi1*uE7AW!B zM!c(7aY>X;)>`4YOYDxU(pp>Y;J~rB&iqKm+^=@WIDF4ZDjO!;yJ_QX^;YM{t(#q& zPefkv@;WFnX{B#$n24vgZY$40Wv1j47DdNqF-<5Ikm;~t2C0`RK_` z@%fCJ?`-b9)_p(W)TFxihvn-HTQ<#J?Q-GG$H#LFjb|=3ijBJ^G2idfl2onjzccEq ztnS^gF`v70ce$MX-!H+pZ_ic=Nwu||EyHUTzU=Yli>GeoJXBKqeZ2cOfB!fB^KFY& z7hY~Dezv#Y<=k-(6$i!Z(yyPN$})`CnN!?UxYR;{IiY*g155J=DU&xH)fDs_n{VFO^*{V$aUiT$ax1u={f3 z8r!-Z-B#>st6%=P6ntLy`|bSwf1f?PsS}vBb^n(CFD~A@xcBt+vT1I%#br7I$viFs zN_)N?`&t?J!bW?oaMW_A4ZGI$8XmhLVB=zPjCa@GUF(|FyF421xx37J;i4&;yhb~D z?cW85U0viA3VGSuJLWJxpOp0E#FPn9o-G2-X%+@8%M=(6xh&kOSmDH?;4ZSo@3Rd% zL-0+BrU*w6*+55a>u!db(h!NJ?P@N z-Q3>pb$|5tp!ch|rE%i&0STbcP*ukA~o-U{FMgZ;$YYd=Gy!?OKjKV5d+ zep_2-x>M(x+KPgdHCbDy*CaRUDIWL42M5Nw!jwe9xbmy6PTvZj9AT5LZ_ZRNF25iMWil`82mUaW#WhK54U zZW}$hCKjJ;{a{!1ULeqevEiQe^O(R8#TK^0j0OMIUnYMLnJdy`$aSx%FLTk9M+_}D zN){?Bna+)G(ol&PIhthnyoZ6i!1UgkSzGe? zs$FVHUg}<{QR#dC6-nF{PJ<6OXgH$iOs04AarSz`U4xV;2 zWsT;X=*Vx!WaQr#cX-aa@ghBS;La&czEdN+ogH0udc7D zOuy3pLN90i`gOW@caV@IVbsqq_APr%C#HC1UKvWUY^phW~(8aVvFIo+QaEh+2<@7oK)7T zJfEQw<-sQ~^^xZy%j4fKDhf1Z&Q-}=H04Uvym|Ao*8ct*xBPZ$M`^5Na&pg}%v46h zV=T{kU!0Ygyy+oF!8uF8i0s$5EMG6Z;xgg++oxBz9xM>y?AlazZuf)ap1XPG7ca51 zUu62}!@YJ!%9Y%ge)Dcr)ou9xqM-h|*yqG$=kwQ<|FVrf^Lo{Vl@~gbf+ifenN;`v zUaW45`BCokHfuHJ+0~g$5?b}>`2RcUuXk1a{dzs@x_Qa1L?dgta22cf_bUFh*MFLO zsl%butE&6b$Ah<)w+h^2eI3*674>*dX;fD7nyq?A4oK#&ITQ7`Ie!7uF@vDX5#pYc z%o2qgOnJR?c+6TJ49<@ZJelmm@cI_Rr?TCLTTVs4&0BvzYpdn+ zMkT>yrm1O82Y$W!l(BNXg&|MWqZRk3*=!M-_nfO~qRy6RO{bEpThyNhZ8yFXk-L17 zlj>HXD1}2ef0X1_Ru8evllOE1V?{NCS)^<5cdBd{Lw-Wxj2vXvq_A@S-;#-hZf6bpwMIqx(;F{H1Rp*yZ2(o&b_L*UpMo9$frA&v5>kW1HE_-!+(?v4|3Rzwghfpli3@@R}U_ zYrXyc-ooPC;_NNEBqNxN>c3xGyk+mFcXR( zF#$*Is}D{(EebMnc|IqVXR?a#B$Z~l7@X)-!^buH5BSaJRJ(@L>qg$^&RgEub~+<3c1K*`A?=xSbirFUQ3%cb0} zy$@f@m@vDlEhK*(@AtCzF?+Y%&0WpE|HGN5r*D_P+w=Qd^m?w&*{2sjdh_Lb{qybX z_W!dLJbP)yaL0&$XJ@~|%r7Etde%GkcW>GG{^z^P-`(3=?4JI1^2s;K_rEi{ zUuF%S8_m!6&F}Qx$Dj6Evwx17;&&yiBFJf(9>e{epM*EA{3j@x>>|+2&Tw#NP?Xn2 zhkyR3?x>yZ-&e^kDB$XHjMY8GSL>+d^B7aVotzKmFe)hsCEo~%XAoh|oU5>D*S4Nc z$NH7GWeXJj{m-jit_%(3X?-9x(eMdx$CWK+$vh(V48K?CaJx+S#QBKVp{ZE!=CNa3 z$ttSSeAdm5?pzOSQaIzR_Q!}WU#|X}z54svM`uDdCsl3Pb|qf6^w-=iI%?ZyJ>O|{ z=zucbB-~9g`-M{1KCHLu{^rYmur@P3B zUA@@+x5_44b?w7Tx3)fyvzU8T?8&{CkGAmee^XO8exCY$%YsX%PZSAQUe8U~WENL* z;A-ZAUzL%}h7Ex^mi#=T#Ob&iBd9k+m?Y5YC_Q>x5DKl0P1`fp*0go$l>YA_A2c#G_I`o`SHd-X0 zZ1Tb1SwTffLClazK|p9?7+2$-?dRHetxMZ1u$cd1xs|TVyyv+GO6eKYILxZ+u-Y?FJCI` zEFZ`yE_>o?Xz69L<#yCjk&cj4UpL6UwhUj}Z5_=J$WZ%8S^n&8NrpA+^K5FLI^X~E zD!lGv{J&TJf4`iMx7+@${@?yT_r*8QFYTdcmxFZnx1Vu_G0c< z-`@g)I|a^J%I7#=%v?~ZsruZg<%7yv_r4Pi5`w8K`wRtG8YE6yg-b`bKDhPvTZTzg z^zDqNbB`{vva*?ZezipHJ->VTcf3_PK6(nzU&P+g(a>YS_Pp0{>((&UOb(Wd>YXuC zyxX>2-)mlB=DilRzd z+Ov*De$iv=Z&L5f3r{sMjTGMEw}<`MgTL+l#s7}jw%zy><05wNJ-<6cM%5w@jTQ%$ z;IsVS-hND!_!d3wcjEryx2K-=eto)Us>V4McUeu}YtJTYy2k5uoqP3(`@GH8Tk?PI z?*Cn0|8#o&&&~7yzBym_kb7?4`;wYxJ~MQ*MBYxF>%A~;iNvXwH~rF6lil}zzSn!` zv()C9{CW_Nk0vufrt zD6=|D@G8_~P%2VeQe?L!YOYDHrF;70n>BHaTq{MAoM${`I1ym*?a6YEb5br+4H800 z%|*uY0jg16E0;*^8cS(|8I8vVafl0`s?1U-G1*^_5T<9wU<3rxBvQg@kOo^Uk?6T z$$s%v)Op+AIiX?s`-_!NT5Y~{zpmiGXFJuotQ%)+i_*@X@_e~#uCjRM_fy9DwqO6a zuRihp{Ilhst2XR;+EJa<($r8X&tNcVy|1d>f(@qrwt}XeZPz>xKYtj*wUEK4fqS8% zi~BhSLDtC=4+R^eprm(!TUJ5kWW|DOA?2$nvL)tBZ@Yrp*R%uR)* ze2N+eCAt{|lbZbulo}p17B6Cx(v}#*EPc8hl@U->) z?;FL%;B!-^=S>POtmPZU1?*{jZ(p|6e)(_s`bV;`=_Il1}=3=iiQ5tTpcszPoqx z=E;vGcIw94JcX@66!54nz{FJKF*x9 z{r1~MTB}$2O*(QjVNdq<+t+4yOh}FF*%)(Xv(Dt8d2{CQur;6k+Pg{T`?qfb5wn(c zXoxmPgnwmHdKx)RJ@fE+XQp#I^H+5C{Peh2{lwS1`F_^gi?=RU zy8c~$&(`k`rp=$<$|SaYCGXpF$DVzgDtq{RT;*fw*NYcE&~$oV5;OCbn}dA7D;ITL z@#fDP@4gIMXJ>0&e9zz*!=j8izuA{ORd?s-VBoP-@LcHXedNXkZU(_!bHgI_PHpN@ zrVM;qnz?yCR) z|7U%y6pyxW{Wtacve$R6UOJGHXTEK_-OrW$^QNoMGCz-}pFAbTuJaX0YU`K&do3`95kYk(?GH1e!1TK;1caC@P zu&!!b)a2tP-{Il)c22WEbmZ#WZ}r5wcdfI0evM6Gij!r$`PHxw8&~x(@CmsvEBp{h z?h%=&^n8w{CW~;>^imE*p5K3yf~=y?K0CTJU4QSFz~B1!DnIA{RsTO*{?9}E;}M?< z{+slj=FZ;xuHehB+3ziz`s*GA+s!!s`*-E;-?zS+zqhT}vvq6Wl)_ih$9+SeLmcO+oQYn4zychgY&AsQo{k+=uNPYSGR)-@2 znxal7-#V)&cxBF2`Xr#?mKAZ|e^bxf)Arx$l&)+zFSVpw!Xb9LT|`6M=LeHr%Bpn_ zNVS_Ft6eD<}OwZ2$l0_IrD`?%KL{$&t5#4!f<molsk2)E2{{ z;E=J$UO~XDx1__v$Eefjtck-Hxv9^Bj1(quP4?NoTQ}jw9ATqCuj|LIl%8GMq|Otg zw}b0km3%9M%Q?yEJ|1e9O=NrBLIbZYH9Y2_S;?GptYhMg5Furzemj?xi3Sy260=%F z6qE#&3j0oIu&E0w30Thd+PHbw)_wbSMfj}S|M8i-{hveA_x*W#FhliysolSm@-l04 z?(M4o{{8<4{@u;zrk-8BcAh>#=4!OB0zarGV7ez7Se@yxE=qm%vi{X5hC=j;*n zmmg2zS~`VkW^o^*kh6Hr7su?oH45SyQ!hkub-Eb-*tNP{=b`B-SgVN?!WrHx@S?#FIPREyM4;D&ZuCc$SA3OA75$zF#m6* z6c(E5`^0Id!2R8Yzx)4vIn7vd?QPdVjRdK^d8(0an{V~mo-5Z|vp(+Dy!PLhtGn;s z-CPy7*WUU`qr_yd6%Be-^4*)wEm+Xe;PK~V<53A^8%yz}Th48{ z(8TC9)sU@6@xuugwUvI8mRx|rq7ZoGMX(4Q&|@5(rIM>puu8tlhK8V;q_wUX#z{81R1!9$XF;V$j2^S zB)Mf%g19c@=f{7y^XK{Y$%}Uv?wnB(?d7-fnc=nOx_d8s&C1Ko#UmwL$=+^;v7dCoif zKtCojZugE~$9j)f-fLs(@AuQrwrV!rAZoa7GLM5`#{)x`M?MNg=Oi0ad@A!9C7wH( z9EteDAIE!af{N#?WnP+19UY#FCaXMTI_KwSdEDge)@yT$-zz6iSeChaZun9`r<6#s zM(gJ+;)chzT-|i7PT={{M?D))K3TKwwT-`W^R9Ik&lN3RXK~(S?;!P6DW zHpx5|k9!I`<~4ENYp-hD)^lpvB)fkn#jSt3s~_JT|NE2tyxz>p3ym2@x~#vBK9RWc z=S9Z<7e78eKHje%V{!j|%G@xe3-4`rY?qMN>^NS{zr%y&LXFY7*O%S<`M=4%uaZ~4 zylCr|ThTW^%<%D-S>JQ)#DsHm)5&in6_w{o2QZe^)fMp-3AC22c0L$(Rc5h?8duxuy=Cnm%j153 z`(FD;xqI^8-g{veRzz;;KKbx*ySMh~jq|!)?p7BZXL(>{c`Mx7+Ip`K(~;fg_v$Ld zV}u0?uD*T!GG$wR!Iq8tj3rXi)06cUN-h#}GD+Z1Hwu(+ z7KnPS#^9mJ`q)de!-pgA`ceTU&yqr;c;1*>kq;d-&UQ z?@1L;j@TYS4J9T)1!YAQhmvy^=>m!@;>v9=1U$XgO>sCT@%+T1jAN6M1!P=jX`MTj zB)3#MMm*}FoKCjB=_58~1Dl?Q;{;4zl`T1Ox!f)rY@1G0ax^-h=%?|VV z=k?~@fB9r>h*(*d#2nM)#9-%a$nQu_Dbj!KrUo<@NfFU=)WdcA*bZVYhH zTzVq%@cQ-IuO&QAmM*e*evkE>WfPC0h5P$*;fkIEGZ>2OelTnmkz(jzGGc2mbUUVS zT1an3v6Zkp)_5Po)`#*h-kBE)l_x*ufdPz~4n#%5f->hHH&JJH^Tl;gRsQZO?-{u%^ zzPaXVmTldh>Cb=GnBBW|r>5fn#R7|%xTv}3pYOeQ>fOJRupRIB{rPq3R@(aQcjWa# zL#L{0GUx5xTE-Xft;%bAc)7e?>o<1#cxbv;8bmObD3sQ6OfLijzk0ZIzS1{yt?Pt>k1nCZH*B#6!pB38SKsg5boP51RTpoU{&F zWX4v@$9CMa{vs#%`1e_vV+L;LEz>&FIP9*RaQd)y^Ra4f3Be22&-eD<W&iE& zm9E#)d^q?}%<{F9+4*~(>+k)rsPs<6r^|+(6JLpWYNmQ@Ua-h9e|=2Fw`dA*Ry8GIe-{C%mkh^dExdbxHP}f(`MFQ5^hfzG%A6hh=kG6GbRzO_ zmx6;57sm@`Pen zYTq6Dx&LGM|4-%nKd-%A{;uY$cKxqgx8MJh|M&g>%}6gYHLqjV~m!5eIu3UyrJr^Z{MO7UQmVG*?#Mr+qj$~eWo;gytzbg*=z5=@<0DP|9|)Wzk9b%ow~mN`>E>f z@BgL$|9StWW&OV=UmDccim#9Td4>Pqhv)zP_{+)8=bIMJemeX9uW#S~-T(hUK5kEq zso;*yTg7S$TGqZ(c+Kn4#y>Z>@LK4jaQy0WpzdTYW z_i=8xf7D5{<4XQVPyRS?ONuGn>$XGYEc3Xzo==r`?3xhd)Dy(Dbmx>gi5)DN(=^V` zw_)`Cpu%vh;xLE!8|F^oB!Ta$rW&xZeJ>wowEJN^IH|8IAS&zIghxtP8D#MORzd%x(nCsQuH?N$5y z@$~w->d$|I&nkG{%FE5Q&+V#RID_+Pk{M&s%dWWCn-S7;g|p&jor`AIcNbH2R!vEr zV|dK?N~Bye&%A&{j>abcO;@f=6_}wmse9SeM?0ScJ^QnAdfmAw>DnnyCMqH-k9a03 z1*CL%dFgHy5n^ms?|L#{qsZlbZESdGY)gXXF9DwRjwimht50jPX;&IAdG~6S%$HxD zi=KVf4ES=-?fvUjL0(yFB?I^0kCo~b=wvi(`&+ku)hicOj|G)YM}!u>TD2%6+j{P~ z@2QUhrsl`|e|NO_`Tmbj_5Xib|Hr@nbN%1z`~L^uzyFF)UHJQpk0*aUvz)u!xOm%& zq>4|Hu1(?*DzzUlXUA8GHTl$D7~xeSdrS@7?U{dh6HfgqCjIxN+g6 zFVXk^Z1cK2b!zFsrNvM8SnR5OfA?caed*G@CRwclCHHRa`Eur9jbZV(f~vBLqC0QD z`iibPRJyx)$<)wwWokuwtX$`IB)r(0`Mjud<<-|q_fAVov25|vUMu$5jY+d+!M)G_ z3RqZvyTmjU>s2_L=B%<1J0x8HsqQO-%O)Lh0VU@InPAnqDT*u#>qWmeN^~1WJliub>QyK1NxJvWow!;$&+Fin)!7Q%_a+!$6S?NU zw)AS!r`P+x>BrYU{mQ@p$EEoHtLu9|rqq|$e7^Sf<)R+}lZr(3;%coX{XJ~|WAfzU zk9T%1xBu8F|6}j{zu)(N%l}_$Xzy*xSDncc6(tv2`)lR)`&G-=oeo>37jGG^x6J(B z?sKl%XQz6|ggdQ@5KBMW^nC5LJDYa@cK>-vBjfh2x#HWqUh!;RGJkpQ+RLsQt5sg{{V-CCG*;rYeAY1=WrfWbnQD}X~fpS zA|T1kB)_OvL?YQsHFMH(PiaqwBLa)QZj$qpG&+9SIx*%0 zM^l9P>olXu3#=oxQv;oKGw)q;+icjztb1Ola@vZ{1Dro3Z#G#@2wXWM`_#T)Q`hsb z?Un!grr-G5rA@oHZjGHHywv&HqrGwY#eY9d-}mEH{-0mr|KtCk{r~>d(&z8)?)-oM z@8A99pZ9JzGrv~%?)knC<^RszXKbkdo4voRq-M{qeP(mdPty7Q!98xxsYpxd?Z$FB zQ5QN*C$mjul$spO0RdvFc@x ziSrePjh^kZ!g~yr0+fG$Zb?5gW6CDY;~lfsnHwIP^{xD{_veEg2N`Sw89I2EOF0U# zo-{rPkB zv$k~e)TvX;mMe$+_W$?dYW&~ucv~wTr;h1yzi#aRb$x$D&4(BNKlA_p$6xy_*lxzl zCo9Zl?$j3ij{mc|{%f%PS7Yth*_Sg_C2!w}C^b`?)b_XT%8c)~oHn^eM)6PmxV5wU zP=xX0MW%DFHVEx>&=ah9o6{0-JvFxdLf&zSMc>6LdV)B5E=tR*GBRY$Ewhq6Cb9q5 zAAe@S^d947O9O%w1dg5%EOp);>SW?m_kPj#BRY=8D~?(yvKE+Gyq^2j;fSCmbIJjU z!h;sixAl1(ikhyaE3sb8xW|#}!2{ve7uk(^R}UQUc*iEY(JJ8iHFoRSe=j<$)ma`b z{r9wZ*z(EECto(M6x+7upzG1nL&l6;%G?L9UYo{U|M}V3@c8=F?CPKFbuWJ3dRw-B z_qSiG`Tt+E|1sVD_rl9j)eo2QOPl{K-~aJ+{d4>Ox8ihZ>h|O6mw)~Vp8xMlip@+Pwb`q)JsuW(|M=&|%4wwU(Y< zy<7eAPRC_S&R9=HNAlShqSdo8wZP?+IX+4TTJ&JDfCz+%Y92K0K1Qu<*H!JPabx*xZCV{hx85;yo zI;wCv89eR1>{ZxsG>7M4!G@ev zH(mE`-}`NL{+@3y4nE#xBA{@wa{1lt)ZDYC3cDUmjh}h0Z~xc5`CgjyD}OD% z|MT12`fuF(e}3r8-@dK-@57rv9`yhJay?4-SGN8C;&pnjvo`MAS7l_k`}YGogP6#8 zdrRx+sHm*1w-3jizZM!RcG%BOTP(7E!WOH@TR~QWPCpx5AF5q0Du18y{y~nJvD356 zThDw1KMEX9sSCTN>OL=R<}|5>B@eu~6&Vbqf~BIbhq?+*z2q9$VRN--qr_sv&|KT2 zX^Z9vsm`0=&|IywLc-QbVUzDhFTtkrb7uejcsw}uSgrgIUcES-qp{f4$eH)pFPyKQTVwI6?6X+0j>YRkPO3YnoM2t0Qa+DeXx2_o&-t^juYdofHQoNS#q^g?_OidX z`TS?;{$HQx|7Wj%|NrC3{@PFN_P-DRc5e?~7qheS`?uTg_ibLWdj6l2^XKS3TdO0l zyH-a{SnPFnxL*AJ%Jp}%SLgY!-V*4hw26K5%elMz`}>X`Yn(RM!~X9 zH4ZvBsAR7d=;>&GAl4mKSyIO6P#P;f)iI^pRr8Zge%g*TjN&@QfgH;mOdel0{J~$e z#AD*3)I-H8E+rxdq>JPli`7J)H?>RDg!-L2nyE55P3hvS)&n!YcLj+yI4RYpCD>K)uG{@| zp8xa0?E95Jci;baZYQ_+y?r0w9ou=fzvju}@cFgRZe6}^_wQoA$mgHZ>-U7|KbwAj zzP$WfIeFWAH{)zKgdMrT5Fewl)+INy{JqBcsvhoh!P!ocSLbMJnmA6FlelPNO3%ex zQVvHo_VzRC2-{RRxhcA2-(9q3`Ddq)r%lCIqRKzz$TdIFnb?%HW!b9NUPTL+=&Wun z=VMr8-hK4qwQs+Y;Qr2C=F_=FU*xME zy7&7}I+>EzvvC{Srn!mQljhvD&-*&9x@zevv6xe5d)FSdsVp(~dbM_4tn0M0T`%vl zujiR|eK_J~pLe(Yn9??iH@LW}39^6L0G!31w9eO-83& zt@pa>OGSl>xE^|5o<5^ok?C5hs1wVS%axu7SdR%PTQFs3XJ@BqvH6SiXwKctG4Vj_ z1BnV3o{L;P`}CUDT1B36dJ<6VFt_t)PQ2Db=aZ2)Pp!BtIM+{0#jf~k)}$2|3pVWC zYx$~lb&=n}p0>Mt+rQV&%{1N2{eo>h9%Gzy0#c=qWL>(>|aeJU4FnnmcE$`}6PAeR**4<-v!MuD{)X`TIYg z|3CG=S6wa6w8iw}lE(p4%NR9ozs(Ci|6KR1M339zqbZyI7nG-FKD~3)TfO!5^hVbug(FH6oHyz=zUZDUoY zWz(EYqv9;<-`#n2YsLNdYAg8;N?Kp;{JO3wf=yfV=^SfSC1#uboBvLjF^!YeQ1<%4 zsdw}0Eh1c>_51g~dvCYv_lJ+t`FCw(ryqX$Ha)H)&1!YWf;HW1mX@8H&mS>wo=wiy z>Y4Ap?!Mg_GkfQ^?H5~H`Qgze!4*5ozdL^5aGa9bW5;!@iM=l( z?CTz#O**9q#k*H>hiNOOXgy^=bS7b~yW5=R?~IW-5uqHt3|S%!PxdYsQ2x1V6@!v@ z(6IzF$!uNKrl3U{&lm(XmvG*?wRG_{omuYR^L^FTQzLEuo|*b^Mft-!%cjJ5_3=nt z5s+c`5Z!T0scDkdgF@Z{M|x*(ufsd))S}4coLh#A@!X z%);uRJ-`3BPk;VwuYUbg>BSc>{W|t)?ahifu_MOEBO*oSEO$*j5cK8XOe+}MEdTC~&3ks%Rwfsi>95~kR=aP86?dv=r-zqjtB99=!aJY0tU^@>om7%y zy!0dzz8JC{vvfN0f|FsmTbK;$x~Ch;G{(O^r@!HZpRAAES>T; zML}Wq)%3@gXPW2brq-61f4}&c{o1X!U*BHLC@K2&VrzK(zf1G~989?J^NM=ho^OAQ z6`t-{7nmBfRr~NOEuCkXv7tv}lv%U0b=%iId9?Vh()lX!?dvpI`{mAl_shGM`2Fzw z8!I#GT4omzIkx9#ub$*v#lcFb5Vxu8spVdkSIWsB&d&Y*?bPD>sry6`w0Fv#4J z)!g5B=y$W0gNVkWDV>vobe;t>WNeL^Q{1CCDW9S9>(;H8FDEN`O>!wRoBKgC-#Zx%S1EzuQz_kQ1BOc|HDj*u1UN+o$vM z@tsb(^!D>D#pzmX3t7B3UwiD%9vWJ{`|jbr)pL@RLOGU{-b#G=?c7gSQT6WDt=sON zY(MPyp~jGVTiJwD0<1eVzYo?YZZ5Z&qUp?{_@V6t4OHV1?1byOIWqorM!LJR2Ms?pSQE-L#_5|J*nKKC`dW0)nzy_hfb4 zIcGcbzSrd~vbXO=>!~R5%T0DEUMHdDqPX+{)7sLlrag?00}VOnG=CRSp76k@>+0Gq z>sH^A<#*k*=}xqd>jp*tl2bP?i<@_f8T!p!VYY77!%GV;``&)L=4!5O#RrbBN*ZcW zH{#{OLREKqr7UWBrm)9dOu%^w$I?iF69*b3#BEBy-u!y~Ue(j5>+kLOxNE}4U(zR9 z@=_0f-MakOU*5i2es3RswW(g#%FB)~P-SQ`KjyPbSL(~7*3Wad$Jti@NvN;3UaMZW z>vu)+PcN+pxAo(v&t<GHTA*cgUP3VZiwqR+uOgQ#AyDlUEAKq zoJ~9aR%iB^TJ7$+54|K$&0IY>#POJD=gTW=-senuvU!t@O#gD%g`a({g~<8!tS!A% zT>4VkMP9IU(wAqc2R-t0?L(!vM@;bwnx}s3R*~KFJq!0Q>ORP-wv+7%%RJ77mqRiH zH|0(9aNOtMw|Jh2ji7+|XZO3?q;!}6jkEUkRCUx6U`kPYcKPy)*E-(Uu3Zy|n6=%{ z{}|7XwYh;(2a~iybJ(IZwU(xRt}F?d{QK9}@cQTG^?%Qr$N8D8>zS5%szrct$pqcC zzn#9MUYhP%zh&dkjPKU_f4#o{`^E9~DLdb73*THez4@Wntebk9e%x^n*Ne^AIHUHP zd)=EBXSYl3^ON4{LyR_HCJyHBZfngHI&s%RVLk2`3lMzkDpCvbG}b7z@LJlVR7m&*`Oc zA1v5$C7s2+{kO=Y729p>Y^^Ike3*Uz&ok@%y}7h*QA3(aM=&98gNbwKB>&Y_aRA1@wUy6o-V z{`<>=C%^5!&b;bv-QVx}GD`8*o0|2vW#7EDeOH#f(s<&M%Gpn+1@dT3T(%)n@3m{8 znccZfpBXi(?t9*vd1A6j`MI46pZ09sTl;Qm_&tV@wR@&7UAwF6^2;k$^VDV)%O!_i zO^uwb?AEf< zuaDiU1(LVlUU&M{ui5MCU!T6er~dc1zwFyt+m|j)Ty-fgy}0=CqrdF!ov(`LRTkN? zEt|Av>X%=clPYvKY&Ei~fBDkp<+%{`q#k{I}oP z*KF@u*gG9{Ei;(s8#BXOvw_9=3|vZT^^OTXvFDFzbj ze4e+z4fAv9%sZR@?McbDdIL+_nfZBnva<7|o-;BzPhI+R(U)Tq@)Hy^R3(yQyw-{; zU0s$FbnyGuS|z;Jm^C>}D{R{2mp@o6KI?HT&CV{Df1|g4P28=WKYl!XxBvIm`+sgt z-yarw^;S{-PeE#j`%bL`;cTRo!cJkwu$TOScVsE?ifA8x*zV++cJ=wV~DV~cu z1a{_xSiHVv>df!k{*if8qO)z`xkAn8wbR00mRR)~rbViW*av%FI+r?6G5ioaPuvyN z{O`LQ?o>OrFdR`;vlQ;Mvz@u5(rDhCg(6-nf7aZ4`DN8ACxOR{o8Q;GeO>>Dz5dIO zkN0k!s@k^8$j*Ak)uYAd>oaO=uLke=|Kdqb){IxHYgjyQvu1L3oL+MKT)XYvyyC0h zN}o%||B5o5CiwK@y^pu^W8QDyyh=m=ZOk!+w%ETv&OLg%{X5&-txuP7FAgkEy-_YR zJ?s)ksCQ?i=hlx-O`l6U1Sft9b8BL>%6=`7ynC|al|+f89@FXN@8ADBC||eq?n#EX zv-9untN;J+-oJ}AVa(pszWJ)e=!jMBHkIhv!+m}I{^AYwA`DZ{NE@lA>l~A4a4NZW zH8j+CnbcbLV>1{8oHS;dSPM-Fvhv-mlWq3FBqnX*Rt?X96B#)RCDbC#^S_r|>N>$P z-RY$ICX>W{2BD!-f}S0lal8EfZIg#ptV_E-J? zlCW>*##{2G_TMHhjV|B!_pN^I*PYMx+Ft!&xBq-Hp#A&0`}e9}ER*v8{@i}c&rFYN zDv}xL>iqn=A698GEWO6G=4q3mpV!6%i?0c(EVZ$Y&F_HF)sJpNDA zq~)Q8xuwzT%=8wRUc7Sj$CHaCcAxJ>y`K`a_uhjaFScBLrE@B4W5koSev9V`>(&Sq zIe&=BsEI$<&784TcrKTs(gqXX%Qn-4*!<2;6P4}^Mqd-H$mpQN&q*Hv)I1NV0Izm9Somu=qi{?^Jq?_FLK zVN>zJqT)^Ibb+Mho8RPSJUt!icu&=E)yrt#9Wj2 zT#GuF+OtsS^dd9EW4qRMyQ+$Eu9I?Cner>4**j3|`np)}&o%k^`BpQHzqv#^Y}uWC zdbRf9i<<&gempRxgvC95xz^cFDi06L4R+#)zP&x~-k*Ehh*W` zFZSI0y7gfFAM<~oe*Jpz;=#qQ=KDXtc(`}!)TQb54^$Oz{N3w(HOual<)H7TpRv-Q(Zi%Ln${V^49IVvurg;pT%g1T-t;_b%VG=8_15 z0*h9c)60yt(}Oq_x3n$N&`6qex7jAFjV?6uLlrgQz&H_tR&Hq$GA&LoTS zkII$vm={;Zdi&0;n`h#rxXi+0-m}c=E77)AGW9RJ<9{9t-@kGDZ;#D05@xFMDbKUt z{zcgSo3i-1{CV?a_x$>_ou99K>$$o=>h;TRzkT=qy}X=kXG%uIsV@s=m(O@{a!Gzp z$GS&cOnQ9&-{;ryFZ2JXN5O8(yme%tzghmM)=`*VD5-lt34;-#-P zADmtUzGR3TArpQ_W6^9_n?2@RD_7fj~3xZ7gxnYp|@ zhL6`2>v`G=rbXU6WzFy)r(@zI6=SoaW73jmf9zvx5m;m{aVBl^%bImt-)$*=zxVsR zV!cf{EOWed-DFE%JabLm%lYK8%Ki=8Y-j7#{V%V7|2qEPwUZYmS-Kv#*4CBZe)7jwf2(x(_TuBgj}oc7CYMj=k^WSo zc|?W9bq@1_NuJk|uH8uAKL4ymw4BcEnS1}uz1|XD7l9D~!G$D_+7fk$a(7_oj8($&H0~&)xD6yujVbB*`3iy>xNnqOEE<;h|SI zteg@wZ&9&c(8--5G2#J{@_YGRBn}H7UCk!scJ8x{f62GT4gcA#d;a;%U1{Q$tkfVW zpZz+g!}D6!_S=s?{pztdwM3TOiNQ@Tgj9)S50whk=RCRCxTqcjbP3-^{1EYd4qK&R?giU;F0h`I;9=B9Z0(L>73rPJeze}J(3@kigIc(yJ_B=+7(e(6yml? zv1+MnyLR%56*Y#EuUizmn=0j%7Wf;V+i4cYcHZC^f0?F`Ap4^^>YmF=g=`{U$1-RJ zos)iA_$T4nx|t@qE;f6=M^1Zbk{fi1-zAGhd^1NA=iE*mmdf|f4z6Cm=jXB4`Sa(> z&A+{?B=zy5fA7{FefjS4^>ek~+U{@2WY{PD+((y!`u&$y+h z>(@V*zJGhJ*xs$hyRKWW<$lkmr=yxY)Ux<7nG~xmhLl6w1eb@SoP9=BXrg%uty3^Hqst-yTD=tVD)IJJp}h zxwh;6`{k8#P6dh{n(WPvyYIT4>+~qNS+J48VNT!quGT_7$;EPatapCAR~xcJN` zyRF@Sm&@O;+pDTUF}wUuv%ee3B-1kfU%6DhF z8%n--_|N+9(tq3cef*_f{~-CAU)}TV^~b}e8UK8@_PX7liQ2cVUq3&;_ro*kr#Ejl zXI|8L^{!%Kz@^)DS#LkQP&D-IR=N>sxcYQvq)*!Cqf4}U`?+Qc7)=!PecK)RP>1^? zr|30v_1Rr}jOX~Cm$*EqIom5zab~~a4VAMsJX%S!QhQ4G@aqXAAKDcl(rOy`Dx~1c z!8U;^a>%aL6-JR$2XEFQn zZ7G$rwwZ)S%$2*Vk=DO$JKOx2&F__cez~E~YPtG-OUAL{wjcU=v`gfwUTOj^WhZ)KIxRH&Er_}OPIHlGsi8Qav}y?gJy zka>Y28^a`@^vv$!nM?0JEYS3hb`3lu#@)8)^2?`{v%OP$x?4Oac`oean8>MkBq?v* z{<_&3v2nK!O#4>4F+#@QUw+PgpZ|ZJ|G%?hzD-5N?`v;=PhV$uTmIXz50C{jL|bmA_GHVz83*-t(LG1nNGC@lxH95UEwF)!MR4 z@Aza^C9Zi~SEJ6HtuRW|u$cbmZ=l#Y!$qoHsXG&VX52E3E}X?1bk6dz4Z~w6)6UO^lJ^c6XuJ!iID%G!EW_zvP+kD*L zzWC`;@%T@Uwm0V5RM_ZhsZL%vK~_nWlR;9*OL3}D=OrhPBneUH-b|%4Nf)QxU3>7{ z$-^J-mgjqBwrN*wnfN{?>R^kZ>{9{p_V;!*U!>Tz)L(sBqUZhj%4PXWyT0z7{$BL+ z#gmaWzh;W>{}5jH$XP!2X;svY+*`k!C^m{U_#R#jG1Wj0gSOMEkE zMWb@ZEmnCCj-`{Q3FInCGI1(S-m41+d6Gcmq}UKyov?u zE}7(){?5GhN$=X$$xchxhD}S2(q1}MU`}z{fj#`^s^o3boy>NfZRnVhRyi#-b5_wg z$@D1o%vl+0kN(Q2G_-rE&p&ON@blH#*Vo0|xMyQ~qxR?4>C<<;6_5X6k-kqO{r$eb z$8LUkGjsk=&gVzX_x=9#b^E*TZqKKg&D%8Lwv=_|ewq0}OBe)|3e}c|#BlV>3B_96 zek9;+93q=~*=37O2HR5Cfr#x`IXBno%uR9K2Dio zBYWOAN#s$ z!^#IUSI*^ES^7or-u-{-3T*;Rl}rh9)X#=6IA&b4R$QERb;tK}7TH$Fi`wL())~~htR^94(c*-fO#8~OhjX0n|9W+uO)I$e z$)A$HNzq!5M*(57CDl1Z0=(Rrvl9u z7rj=GOKVEM-(!CLDr}lkQs}J9A8o3vB}#VfwKH6mYw~rGR&3y|qkHtcgQM@~tWZ#r zkLBnq)@ymxHLG!v#9ICsB`(FO&%6wu=j5&_ZY&m5YQ1Io+-2SeormZ5R``}btv0`3 zurTg^+*FOSu<}2L8kR4eD*EZ`V)lOj{_|PY>uujvN)(+{zkJI^Zo9Zq_U%2_r+I0p zM(y;A^71|>!Q`%4A@IcO+n=lavps)YzW=NC>B~dL;*Mc|w_ZEy-Q1C`WPJ4CUH9$z z>%T;w6YH0^yLYSN<28YI_cUAN_}rE6o!8S(xBqJ#pHaTBpdstv4t?&|uQE;<8QjeI z%ONsz!rC(Nz}M4uSN;$6DW3V{;^#%%TmvH?CqFo+l`zTMvEx{4f|Kztvzcd>UEVm! z#!Wuv?1WpDx8Cth4`Xv*-tPXp{c@yZpwPxuMX7?$=?xA?t2m95*7GO@7dZgzf-O*FHZ_VDq&!^6L zzjibbnv)*nA;;rbpjhR8tfFn+MhT^mYgdn1KCk6Ct-ac=?S-?cd~wR%y8X8^d)u-@ zW6z0QEeSi*H7oIfkFe3q7wUX29EvQ7Jc=GCC#!s2=Mk*C^xHkQ1Rc#e_#7y zlD~F+u1cqp(m78r-E}cH=Us30dRlyb-;5HYiC#xp+2(IwJaf9pg8R~U_P@@%TWRy6 ze^u1J;?EzsGcki7lHZ)1jsLW{p*fkI=FFn$Np=tmpKK zbsOD{srr0O*X_{G2hI;@k&EkH)l3ri) zbN1@RW)G%he?IxX`qzVR*TeL4rk3aHJY#=u#XRxp@!gwmebc)9@7?Kq5mzaN$f%R` zZ_@2PpYeXZ)SAQMHP4reCF}KaXKj70<=USdIb(Dc-^Gq+q54(!ouQD`}Fc}-vvmm-6k;!-wFk7E+=Yh$M$PK@Vh)sc~x zPm8?vwk)~loaDzd?ekvohQC(Wd4j{puSwCBBVGNm#N$i9UL335?x*hRQ2Y2>;qvWs zd&BylU0t+h%Z0^Tm-=m=n(C!GrF6>1?j=*pZ_QjO7F9AmJS_b3#gDy*?SF2)Z@v9W zU(&Wcb7~$5TUS@-+y6bp_jcdsd)oJ7r23{!-}Zd6N1?#RudkxN2k3kZiT``y+i|2QCBE&F>O@M z+j+p}HQu}?$&g*B2Rz@06(v}d{SmWNd%2G4MMyN7hIiN5~ z%r#I{HF?eT*Nk6QZPMwge0oZN^+=lij-(i)i)-X+l|Fp_7sj0AqqTH`bI-(u8BcW& zB-zMmPvvPpta5&n&C{TQb6cnNFdI$r;X2>)S!5#j)FT=bc!XG_Rs5S)@Bg><{oQ?^ z8%}=PGfzKvuKuF=^JPBU#K*=;>gqn9Yo_(2Yx%CFM$@$Crg{|_O7VuXt^UpbegC)L z@wEltpIv?X^zox!@8|PtU%eE~@85O!$?o{tzqh^x={QeYFE{^He%+tDt5L_@#$>8J!N7bJTZfkZcT@jlQ{n|pj zyE5{4#+*$Pj~`%kVkwen)a2)5;5g|1$_aC{7LVs770*Rmzuo&@wKs45{TDN@lxD6Kcj`Ft zSwLCSttrQ{eBqUt9aVz9dn$jwd;48ZoLhc|d5=cw=a){~s_(|-S61%4`r2)Qm4w4Y z6{}M>qNTPid6Tks?$x)O7k}Ko|Igmn>-T*-vvcj_n{z*3zh(XW($~`1IgfVd@4fey zXY;pbH?FoH|8#Bdr+*V;cPu$vJU8{U^=hB&o5_5uts)d#l6JDQFA#7^5!7UA7Ff)F zT)FSO-&}69;O?7W-n{8ilJ7sh^zrZC?R=XZcCs@r>F980VQ~7Hq7z&2U{R#Kpx`E( z@AoFFclBQJ4)MGtt~}Gj`^lV@y{=4ZOCA^{ZTWw2UKztlOYs=bh0-@SNG#M?<#6TY zmrpk8iv*aT$Glwf@~FO8_s0sEWRbot-DXNvMrtBaj>=G7AAY3z-XS@ z+dma`lS%~2J^#A_lo!d@?vLx~j$#`A*@Ka20T zv2@(c*{T>@^XsN~uglSxZM)Zd{IP&j->S@6p_i?mw;g_%Vs!GZ z&fXkDLm{^?*?`A;!#3=iHFy5M-;<_1&X|#V`D4NEEmH4g-n`GtFO~hah-J#QwmD@> zFS7C;JNVPla*odGcRya7ynI+(;_b7ti7$Sfe!u_LylLH=uU|cC_@Su&ec0_~ub)1% zuMgwiv9<8}9;@n|_0``e_uFgzdGX`Xo4L)lAF8fiQ@F8a*Oe{zHkh4|Nq(ceT;+`C z_me8`7&1bpX{JqQ7kIRQqqKCU_b<(*I^JvwOBo!x76ov)EaBKZL8p_Wqp+>PBx9+F z`^#VZa(`*8S?ieG%doIhAhJJqwF?951l0EK=&nWD;w?San43kI`t?<0gYwYFvbA0{srR{F!dbzAQVreede|SL*KWC)yUR|eW zpPzkNQT)zcDAoAy#j94Y7#JAlq(*qAd3tIwa4;}1urdfSGBYrO?)qV1V31;D1+%>v z7#O6X>>vgP1`VhhCI$wE%yt&AnkWVc&|zc%^IEFfD+X(!jvLzzk(4Kn!GXpOXo4r)r67L`h0wNvc(HQEFmIDua=Mk)f`E zrLK`th>?MniG`JsiLQaEm4QL?v$q!+7#I*5a`RI%(<%`f3_}bJtqjerj7=dLCa^wK zVPIeo1=)~Vk(p-YoS&0l6kL#)oXTKkYHDn1T+NWjz`!5`SKwNandYCCR-9VGU}+H9 zb8j{S1A{z@Y*=bhab|uVgNcQXf~kRyf{CS$f{DeY`5n6$7#Nh{O5Ji2i!%Z;E0C2# zl!BDMzsa7>z`!5@S00dAk(v|Xl9`*D2R7Z%$fD~0s=Evf4C1J2A`xmV%~tG~1d37y MPgg&ebxsLQ01jx;C;$Ke literal 0 HcmV?d00001 diff --git a/test/unit/media_file_test.rb b/test/unit/media_file_test.rb index 6d0650332..8b1cd8e90 100644 --- a/test/unit/media_file_test.rb +++ b/test/unit/media_file_test.rb @@ -359,4 +359,16 @@ class MediaFileTest < ActiveSupport::TestCase assert_equal([33, 50], @file.preview(50, 50).dimensions) end end + + context "a PNG with an exif orientation flag" do + should "not generate rotated dimensions" do + @file = MediaFile.open("test/files/test-rotation-90cw.png") + assert_equal([128, 96], @file.dimensions) + end + + should "not generate a rotated thumbnail" do + @file = MediaFile.open("test/files/test-rotation-90cw.png") + assert_equal([64, 48], @file.preview(64, 64).dimensions) + end + end end diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb index 44502e4f2..7c95933f5 100644 --- a/test/unit/post_test.rb +++ b/test/unit/post_test.rb @@ -1336,6 +1336,15 @@ class PostTest < ActiveSupport::TestCase end end + context "a PNG with the exif orientation flag" do + should "not add the exif_rotation tag" do + @media_asset = MediaAsset.create!(file: "test/files/test-rotation-90cw.png") + @post.update!(md5: @media_asset.md5) + @post.reload.update!(tag_string: "tagme") + assert_equal("tagme", @post.tag_string) + end + end + context "a non-repeating GIF missing the non-repeating_animation tag" do should "automatically add the non-repeating_animation tag" do @media_asset = MediaAsset.create!(file: "test/files/test-animated-86x52-loop-1.gif")