From ae32d1afb87aafd420a8495b50dcc567164ac098 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 12 May 2015 06:16:08 -0700 Subject: [PATCH] Remove unused file transforms Summary: Ref T7707. - Modernize the file transform endpoint a bit. - Delete transforms which are no longer used in the product. Test Plan: - Used Pholio (navigation, inline thumbs). - Uploaded images (embed thumb). - Changed profile picture (profile thumb). Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T7707 Differential Revision: https://secure.phabricator.com/D12807 --- src/__phutil_library_map__.php | 2 - .../PhabricatorFileTransformController.php | 60 ++++++------------ .../files/storage/PhabricatorFile.php | 12 ---- .../PhabricatorPholioApplication.php | 1 - .../PholioInlineThumbController.php | 46 -------------- .../icon/fatcow/thumbnails/default160x120.png | Bin 1006 -> 0 bytes .../icon/fatcow/thumbnails/default60x45.png | Bin 762 -> 0 bytes .../icon/fatcow/thumbnails/image160x120.png | Bin 1459 -> 0 bytes .../icon/fatcow/thumbnails/image60x45.png | Bin 1179 -> 0 bytes .../icon/fatcow/thumbnails/pdf160x120.png | Bin 1654 -> 0 bytes .../image/icon/fatcow/thumbnails/pdf60x45.png | Bin 1378 -> 0 bytes .../icon/fatcow/thumbnails/zip160x120.png | Bin 1383 -> 0 bytes .../image/icon/fatcow/thumbnails/zip60x45.png | Bin 1078 -> 0 bytes 13 files changed, 20 insertions(+), 101 deletions(-) delete mode 100644 src/applications/pholio/controller/PholioInlineThumbController.php delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/default160x120.png delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/default60x45.png delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/image160x120.png delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/image60x45.png delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/zip160x120.png delete mode 100644 webroot/rsrc/image/icon/fatcow/thumbnails/zip60x45.png diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7056c0a3a3..2db8ddee4d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2824,7 +2824,6 @@ phutil_register_library_map(array( 'PholioImageUploadController' => 'applications/pholio/controller/PholioImageUploadController.php', 'PholioInlineController' => 'applications/pholio/controller/PholioInlineController.php', 'PholioInlineListController' => 'applications/pholio/controller/PholioInlineListController.php', - 'PholioInlineThumbController' => 'applications/pholio/controller/PholioInlineThumbController.php', 'PholioMock' => 'applications/pholio/storage/PholioMock.php', 'PholioMockCommentController' => 'applications/pholio/controller/PholioMockCommentController.php', 'PholioMockEditController' => 'applications/pholio/controller/PholioMockEditController.php', @@ -6311,7 +6310,6 @@ phutil_register_library_map(array( 'PholioImageUploadController' => 'PholioController', 'PholioInlineController' => 'PholioController', 'PholioInlineListController' => 'PholioController', - 'PholioInlineThumbController' => 'PholioController', 'PholioMock' => array( 'PholioDAO', 'PhabricatorMarkupInterface', diff --git a/src/applications/files/controller/PhabricatorFileTransformController.php b/src/applications/files/controller/PhabricatorFileTransformController.php index 248a6dddd2..e3a939d45c 100644 --- a/src/applications/files/controller/PhabricatorFileTransformController.php +++ b/src/applications/files/controller/PhabricatorFileTransformController.php @@ -3,43 +3,36 @@ final class PhabricatorFileTransformController extends PhabricatorFileController { - private $transform; - private $phid; - private $key; - public function shouldRequireLogin() { return false; } - public function willProcessRequest(array $data) { - $this->transform = $data['transform']; - $this->phid = $data['phid']; - $this->key = $data['key']; - } - - public function processRequest() { - $viewer = $this->getRequest()->getUser(); + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); // NOTE: This is a public/CDN endpoint, and permission to see files is // controlled by knowing the secret key, not by authentication. + $source_phid = $request->getURIData('phid'); $file = id(new PhabricatorFileQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withPHIDs(array($this->phid)) + ->withPHIDs(array($source_phid)) ->executeOne(); if (!$file) { return new Aphront404Response(); } - if (!$file->validateSecretKey($this->key)) { + $secret_key = $request->getURIData('key'); + if (!$file->validateSecretKey($secret_key)) { return new Aphront403Response(); } + $transform = $request->getURIData('transform'); $xform = id(new PhabricatorTransformedFile()) ->loadOneWhere( 'originalPHID = %s AND transform = %s', - $this->phid, - $this->transform); + $source_phid, + $transform); if ($xform) { return $this->buildTransformedFileResponse($xform); @@ -48,35 +41,26 @@ final class PhabricatorFileTransformController $type = $file->getMimeType(); if (!$file->isViewableInBrowser() || !$file->isTransformableImage()) { - return $this->buildDefaultTransformation($file); + return $this->buildDefaultTransformation($file, $transform); } // We're essentially just building a cache here and don't need CSRF // protection. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - switch ($this->transform) { + switch ($transform) { case 'thumb-profile': $xformed_file = $this->executeThumbTransform($file, 50, 50); break; case 'thumb-280x210': $xformed_file = $this->executeThumbTransform($file, 280, 210); break; - case 'thumb-220x165': - $xformed_file = $this->executeThumbTransform($file, 220, 165); - break; case 'preview-100': $xformed_file = $this->executePreviewTransform($file, 100); break; case 'preview-220': $xformed_file = $this->executePreviewTransform($file, 220); break; - case 'thumb-160x120': - $xformed_file = $this->executeThumbTransform($file, 160, 120); - break; - case 'thumb-60x45': - $xformed_file = $this->executeThumbTransform($file, 60, 45); - break; default: return new Aphront400Response(); } @@ -85,16 +69,18 @@ final class PhabricatorFileTransformController return new Aphront400Response(); } - $xform = new PhabricatorTransformedFile(); - $xform->setOriginalPHID($this->phid); - $xform->setTransform($this->transform); - $xform->setTransformedPHID($xformed_file->getPHID()); - $xform->save(); + $xform = id(new PhabricatorTransformedFile()) + ->setOriginalPHID($source_phid) + ->setTransform($transform) + ->setTransformedPHID($xformed_file->getPHID()) + ->save(); return $this->buildTransformedFileResponse($xform); } - private function buildDefaultTransformation(PhabricatorFile $file) { + private function buildDefaultTransformation( + PhabricatorFile $file, + $transform) { static $regexps = array( '@application/zip@' => 'zip', '@image/@' => 'image', @@ -111,16 +97,10 @@ final class PhabricatorFileTransformController } } - switch ($this->transform) { + switch ($transform) { case 'thumb-280x210': $suffix = '280x210'; break; - case 'thumb-160x120': - $suffix = '160x120'; - break; - case 'thumb-60x45': - $suffix = '60x45'; - break; case 'preview-100': $suffix = '.p100'; break; diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index 5bc0eef0e6..0d352f20f0 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -784,14 +784,6 @@ final class PhabricatorFile extends PhabricatorFileDAO return $this->getTransformedURI('thumb-profile'); } - public function getThumb60x45URI() { - return $this->getTransformedURI('thumb-60x45'); - } - - public function getThumb160x120URI() { - return $this->getTransformedURI('thumb-160x120'); - } - public function getPreview100URI() { return $this->getTransformedURI('preview-100'); } @@ -800,10 +792,6 @@ final class PhabricatorFile extends PhabricatorFileDAO return $this->getTransformedURI('preview-220'); } - public function getThumb220x165URI() { - return $this->getTransfomredURI('thumb-220x165'); - } - public function getThumb280x210URI() { return $this->getTransformedURI('thumb-280x210'); } diff --git a/src/applications/pholio/application/PhabricatorPholioApplication.php b/src/applications/pholio/application/PhabricatorPholioApplication.php index e56f989630..801a2de4e8 100644 --- a/src/applications/pholio/application/PhabricatorPholioApplication.php +++ b/src/applications/pholio/application/PhabricatorPholioApplication.php @@ -49,7 +49,6 @@ final class PhabricatorPholioApplication extends PhabricatorApplication { 'inline/' => array( '(?:(?P\d+)/)?' => 'PholioInlineController', 'list/(?P\d+)/' => 'PholioInlineListController', - 'thumb/(?P\d+)/' => 'PholioInlineThumbController', ), 'image/' => array( 'upload/' => 'PholioImageUploadController', diff --git a/src/applications/pholio/controller/PholioInlineThumbController.php b/src/applications/pholio/controller/PholioInlineThumbController.php deleted file mode 100644 index 624ce3d3ea..0000000000 --- a/src/applications/pholio/controller/PholioInlineThumbController.php +++ /dev/null @@ -1,46 +0,0 @@ -imageid = idx($data, 'imageid'); - } - - public function processRequest() { - $request = $this->getRequest(); - $user = $request->getUser(); - - $image = id(new PholioImage())->load($this->imageid); - - if ($image == null) { - return new Aphront404Response(); - } - - $mock = id(new PholioMockQuery()) - ->setViewer($user) - ->withIDs(array($image->getMockID())) - ->executeOne(); - - if (!$mock) { - return new Aphront404Response(); - } - - $file = id(new PhabricatorFileQuery()) - ->setViewer($user) - ->witHPHIDs(array($image->getFilePHID())) - ->executeOne(); - - if (!$file) { - return new Aphront404Response(); - } - - return id(new AphrontRedirectResponse())->setURI($file->getThumb60x45URI()); - } - -} diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/default160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/default160x120.png deleted file mode 100644 index 16d6fd4f907913415c3387189dd1129385865575..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1006 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$SgAGWQF8Y}dq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfdQ>ba4!+xb^0)ZN7**L&L+Fd--z&1!DvpMYu8)R$f}l zP$l5f_w$AD6sbT*$3_9sDSsNjY)s-2TGY5-AWEfa!li})A%zjxPd`XfkS|?iBw9-K|q0tg%O!*IkwgJptj+$ zZ`X>iKb!yc(ZQv0AJzK4-aoN%>d_0lf3@r9{{NQo>(l(HeIMB-GSy5!skBf1Ip3OB zD(3aSldFC`y>q@>oKN06{+rKghSjqq*3>A*?ER~7{~u{+r3@MDOsE5 zx|#p6>M3~lO?|F+1+ z|17+J=E}^UmDlg)Ij!>biMrS&Jt4yI)wI)> znUw$84Gj19v!-8V*7PQucyC$-NL{c@ltAoUqhtTw}Xee3;w_C zF8UfB$IxE=%l!6ox7*bwyP4K(U`l(sEo%L=AJ?+gl@P}*%tBj{OnxDbs`DNBUmoKSa)%K#mr+#vp%bC)^+&D z{wLXr$)!QTfrW!qs)NC?fkOZoY)I6s@9P2w-fDjS&y06{XpDhTGIYQW*a16W2ke0VGhjs26OUeYw?mxmhdf{L zIX#6?gJ}8d<15$ca&NyeBI58Q!#dfa=7U#eSX){BY{u>d0rQs?s}{9}vStJTp zzx3eJ=_3R^-EQ0sI)75y2H@O$3S1L~@8MrP9;a0P$j0k6c)Ru;W~Yvp1}zTkQ7RYp z%vudiUV}F&bg($nrkWOo76Z=ur$@?h$1UP%K~s7wIMF-+lg$RD_ZD2F^j^Moq20RQ z?a~O5exs!o)}$CWEFAD5Wdh%rJ_UH^Ipja&n^6=uvcB>!(^Z3f(>h>QY*1jfhz5S# z*oJ2d=VIT_!YIz4x}CsS3|P_F_1-S5ZSKbE<^rcRa(=Rvl?z&#(jL_zV$taEx3yVW zOJ4aJ_E1C)BO~a)Nog5isEEQUNlyu2tct>;0c;>&ON*PSKn>e!rPZ*|7OXloJTkzV zia1_02y`thp*+NaYYaRRT{?|!<^894eJo)SWy;*yk@xfEn!8iLAZz+HWb+FB*5}7C^29^-4!M?A5wWJ^xx7rolcUsN_c&8fZxbJP^=ra0Q)R5uRBUw^Zz8@ sqFDP@09VNzumg6$4%h+PY`+8;0Iwg8LNtyxvH$=807*qoM6N<$g3|6-kpKVy diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/image160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/image160x120.png deleted file mode 100644 index 90cc11c02d86c9654463b2148399cc4faa998ed6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1459 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$SgAGWQF8Y}dq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FtCPtx;TbZ+>mA-6Y;H2|ZxX-lEqbt-_3=?Tk(P$`0PQZ;g;F`py+1E5xjA?4 z85^J>vs08k%bPk`f7U$Mn4eyD|Ip*f@4wgHf0NQ%?8hJ{GEI|#1qd8~fIP>RRpBqqp_5zT?_brwGI?ewX zztObaqDp4{+>Sk;{=MP;wPtayEaSpuZxrb?9K*`iV0f; zT)p-dR|Y;!6b^6n`yF-k7t_+vgqL5M2Z{hDk(6T9esa6b=#@M zi={U1t9i3%jhcVwmv=4Ce*c?cKi%!;rI022|I8Fwr|f!j;+|?}pZ{(h3%0iC^+g*U zUGhN9wIlqP`+=C>;mh;wW9N__tbEIPG7p;aQ)wpS+y_X7pi`` zd-U|A+&?<%ezkhr)*So%_z}>tx7#LaEO>KbyLX7~#1##%>uc3Le+N!I^G2)ww9(X@ zm$wVvhIfF1jN`@8B4*daaZJC&f0@QA%4&X|HzUmCQn1LZs%k5@<&)OMF{`;abWKp) z@s=aQS#V>1_icmobN+=+nwa@AE!(KH)Y#nU^on&#Y7BuK=PTnGRYgSAB(kj+Pby#i^3Tg(JyY(+-Ppjl@%*ok&r0uzs);kUKVE-d z>i32(n+3lf=j)GLwu|rj{^+$CIpOou-)5}iT)IVGKasJc!FP3nsoSO;ZLS*)djyIf zro2d#uGMv6Tf#g2lTN4sliB)~xl=Cfy?*sU+HBoh-+mi8{YdkbJa*WgB}XS=TKQ#z23#-Zpdc)GSYkrNfDm0w z7P9V->||%Ud%DW^s;W1$(M?vSmT5>AJf^05`b~Z6{is(pL&g|9NloDiYYlJ%+yFPg z4R8ZoqZW^ALwUFt@mx9ky412`S$Dcub<>%X)rcmZj%|qe(~N3Q#h~0b?sZQi z_8R^TMxSoOKRy{csr1%zS&B*Aj;z+V zi!eQsOfxxP1G5(XNrzqfSTefdT6F; z$j2WFaizjrI4E$HofBa!O6S+)qu6ktv#cbvxNou^znu^zT}czFd=giHA)RAYc6wrD^jT+eXp53CeF;52>Jy*Q;w8!{mU)!Ugv) z&s;?5-7zw5SyINuxX9YAkJZdt}Nn)S+XnlSx4JJ zRxuofvv9DaWwtG>Y|`0P{Ic}Y@!t@&X3@(wFmq+giuC20+*3ZeiN4BnYGdJQM`#NL znnaqo;$pWmesSwo(!#4JzDG0(T)i@5ug{%cLV2Ivdf=XoygpThNbO>nwN2f69=}c> zlNw`JVAv!?c7{}Yf|nyVjO*9tpnH8=pjg`~(YMHY*XmhmN&QReY2;ap$EzN16LNKB ze$Pdg>hb$5^)p2_)r-EUwzae!ze1J`Jn&vNyd~(uQQOVBIVY~6NwTG>s_*8(#hFI$ zevgf(_7-%zZ655-OIv**PmF>CXGIrl8+RP=$R{b<>Z=`am7L`K>65do!O!qYUu}i> zWjCmWr44lWQ%kB_3~wLB@T;c4Ge{4rqY&UhfMcchXM_ES?-?s_8lyY+!Tgk*8}G+I zDC~xVVNHMir%?+o8udROM09{(W?7~KNAJJV1Ir4_pFHNxaRPJYj7fV+x4%sW%5^7t tqx`l+&A)gW;0Cw>Zh#x$`m}!p7y#Z%ch+0IL<|4`002ovPDHLkV1o2xKfV9} diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png deleted file mode 100644 index 20f08f955bf72d402ad77cde599dec462218ba4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1654 zcmbuAYd8}M7{^CjvYt6DcHB#9>23ujhHrw|>v_zW?8+_rv?;pXTA_1Oe-S0RRBR#TkWB zWQk%ZTQ)0pbm?-qBDAld@mIXUFJ8GyiX;OZ{KNgo1}>qb05XP5@~1`!$j1PH%~~!f z2P|dq+x_5FELrQ#&w#EEG2&s|KZCjL9~w+Iv(tnJs#ABS8ye-kawU0cq%wBWQy1u{ z^T=&xst?RL(x7KS*BqQRXE0&uMn2Bik%OX6p)ad%z~;+*k)@?{N^Wb(+%B3{>F&Dx znKvhqG+8px_tf{|~e#-aBZVWhMkSh73RJTuJGoQdn6+ba4T2F z%0^f(DbK~q*FZQdHZYbj+|liG)-C@f6mvW2W{t|G@-^|fY=pVim%MlQQvriNF=R43 zsIt=3I&36fLls&_RN9(hR*y%aXDP+WnSG)=hjO>6LJuZ}3>BZLUVF)1i6srGRX#mh z1BJtBy%B^^nO5%@3x(v8BBRy4aVLVHFDbxN!i3*Isw=b2g(1jTn26GAF4zRnMXP?geC_VdQKa+ zxbAJT#s!==5t47Wi-E&0`B=1}!QLm>?X8XEH>Ho)Ls_Q)u$i(m_Ptc+QF+eiZhDy* z2=m-nyz^A#2-3ToR94ABQg2P>-t>9PP9s`QX@+F%+$TF> zr1-;rV$6dv?NF7aj@) z9n`hr-9#lq-FK?VE6qNvEvHc!I{c`;NcJLu=s&=mYI^S2mU3129e((!XIL@`%zx)q zci(rFkU%T<6XpT)#^XOun`IO1&}nJC$&FUW#dhVManDQ<~$aoutQtYRpeFC zgogXZeI7V!DT>gD`-Fr0;!ETeD&rj#q*rrubdV@H{2Qg=RlbfZMP5;#$gN(yy<52z z*Y9}1JTIQB-yRb&i)kAT&RSiC!o{>QQRXT+gO6LJsbkj!Qza+Qj>`!s# z(P5WlvgPW(s{HD;`R`xBfyqiN){QBk9g z@1hYbJ*%VLt@s$<*`+&_0ik})6Zc8GhtO>kD>y55ak}nhP1i(YFJrbEce1B+bFNil zRe#kZmGx)ea`do$^5pk>?9{3*P4~0sGs^iCW4fDqPwms2x57{s7JoWrn$CW^-P83q zn0aK(<9m5={PAr6I{jYqM^;*l`j^vt1h%l5^n*oW4ta>%Gq$+A0eidUtD~Wb4fW)2 z2}|W_N6at_trIJf8?ciJoZ&!`^u*dBe;lMp-%Ti%n(GSYlXy|R56dHWce?hmnxcZ~ zf^nRxi_P7kfqR#^@|A@L7Czc-qL)ioM z8s<0_-ywU6O=*V;y83GU0#5I#nLJXnucXo;MpJ-L{yY*Zn1`-cT*yolK2u`0kMB^r z7OG`$4*)8#SMUo0+yhEd0NA47zhZskIYs`C diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png b/webroot/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png deleted file mode 100644 index 8a16eaf488e00f922e2ce0d77c0f6ec43ba311da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1378 zcmV-o1)chdP)OP7(~*v7V$+2foPG6FPdZ%n_GnlQoKMf z+L#hrq7+e+wp5a?O`6*#o!y!7KeMxI+-{m(XVab7{o!MVGv}Y3@BG(u5~k}qZY2?L zi%FJnmT;Ev(iVpmWyYAJqpPc%ZZ_$fhSc&spUogJ231v$JYQ8+MFZiaG_6z?uKZs? zl1qejt1>b&qBr~fo%B9&vA@}2(L?0uY7Y*b=N30oqoOrpP)0ZAbJBdFemWZ&i#=!dCoH5=gUu|>N>%}< z&wx!%MhHh66Sf2hGbWmuI!SPyRYgE=KXBWMIDOInF`T+p%*JE=qyJbn3cK!ylZQvYo$d#EaU$64mBlz042EFB*nqJNKKDklOdu3cx`^*!N3=%ep@`JhS zb~$qwAsj~d%m8M0)gjma30zyANqm43>%qt&rh;fx#`_xsF+B*iFClY~)1fG|c-GMcoQu1|J$cjp?%F>@_Ugf&Tm z=h849{^&EDt=omtoqO@ahx?#>)kB{h;)hrBdW~^*9U&XyVV}0pv$EMHD=w!?adl0N zPf?VAy(p}z+Qdvy?K=MJ$MtvR)xWLh>_0ko`QYL5wLd#`-RPQc^lqoq$y%D5Ptffj z@rQVpzS$ySo;=MCR0{4)3Q-3+k$X3?1Xs; z=MxIe%*w5Fg%FI(O*bN}C2HTSd~-U=6907-iT?mLVUF{~nBfhUm8K!%F}xHd`!5e! k!db#u!db$0mcIoU0Lp_RQgVwEW&i*H07*qoM6N<$f~#YcIRF3v diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/zip160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/zip160x120.png deleted file mode 100644 index fbe19e59f601befc61f4eb320229d6748236e536..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1383 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$SgAGWQF8Y}dq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FtBoZx;TbZ+GHcZz2HBP z;G<%v?Dmp-VdokV;irx2$w?Ix#pN%|S6KMcNt&bcW&8y8dIlz531(Hd1n=#knnGgb zw$IPKx%BQ_TKP$V+8_I#JV|?hX4}cL(~IBjH1^$_wpo+mzo?xz0|yW^00D&zoCZv= zlAQK{bKdjT`)74^a^-{wC1=t;Z$*S&>VS*JWJ9z1ZoxxM`Tvh1r_Tfe-x@-yDQ zrs{x7&5=z(P3);_rq0c~6EkVH_x4>$FR$enmH(VqQ}m=G#YFgAs8-STU2oP&rayna zG(zW8`uq1YfBgFW*}O#S^d_YT2VP&)>I;k0ZBlr_G57M%Q)han=4h_&SX&+2d2Qpi zU202%JXLGNIR!tg{NC)RB|UkOjqTfatLND5jdbWWm_B(`+R2X}3sqbWEEhMhRMJcj zwRwEu;o-8)v$H3j?)9+axh+(;FaP|J&R~y@2IqvO*S_yvcR}mTu}z)J&tz%xJ<48p zxb*&6kA(uKiWe__TU7I<`McV_nL87tk50I{l>43Uot6sO$hDhIW>@^Ix!1Yl*EZUHnH9>e{xY;vY>*IS%12JZs(5)8L$}FQH<0F!Z97 z?X%j`CHE3;iU<_E5V~`&#ZzCrVlRJ!fB<8=q5i9k()#JwqIGf^1qB&@Kg_Qv*MEEF z>E}2Frf-Ya?LETJ%{{NW)^6?hACJtFUR_&y;MvlLsV9AxehQVncX31U)Ge=<>VA1I zW&d)P{>EDzGgJ~B+rv%V=3iVNaXsRiY5jpLWraWT-|pxzDgXfk6A)0yz-55Lt3TQY a7@{7Uo=|XDd>vSFGI+ZBxvXK@`B>%r5P=fTAX~ z$jJop3t;fZAHC_NhL}Ji6*zg|WK8@D`XL}Ke+nT&y%?_Y5fEs^1Ak(o1zKt-npoQP zz1eM3+O3i}tGi(*c^UT2>~?>_JEz-R2dIpjHz#y zmy`I%1HDuNtIW<&6jcSE&j*}yI4u;QfKoE&bH<=pEWUj_I5>!xr&hlsrDmXq{HghC-0=#SV+psD5^A4Gib3ItJS(Xfd&Er0bV_~tFsf(noz!zo<=F_ z$?!0xvWIvXKsj~}a0QH80vpc6g)1*27=icn+{L*H!GsuFh}lTs+g=q0i%zO8GD$(71A>!U8$xhHR8z9 z^1K$Nd^{72frgQo(i125M?EW9?|C~uKgmx^3Ns*Tgk$tpeVBFvK~ZVVO;6*sD)d(K zg(%GVz}zASbJM!(Yaigt*8@1r6PC3_=9{?Ja zmgKsrR0=M&UWVr{UW%TsN#D2}WiE))+&V(j+6gX`%|H&HuNDO&z79qg)RBnqTyET^VPtwXkBA{%7lJFu!SKvk2_dM6Z~@ zMnr}NU&37M($}uGVWeIYu1rz6qvOUOT-pu5R2|h+ggVoqh=8wNy{?;2dK$M1cHo96 zO$P$Y3K+pk4fLEW$a&RLJK@X*~YczoC4g0T{DW$rUL0F w$_cKu;0RzhHSZtd9OV07*qoM6N<$g2S-(b^rhX