~n8CR5x(&EP|=agcI`9$4A-
zr7XpQG^Rj4w|;+uwtX+$^y^`mE0;ZLcn@4C4BJMbB*9G^1K%%(SD48vG2~#^uj4MApa{!xie_M#SSAWG7gy~M6
z)6+d6Cg!bXBRDTGY{I4_iY!-Ti+MhYAS7c*3CFUOpHs0&ORIw`C3~c#%1e&_5tjMyvD@wJ=(Ub1qYi#J|4(+o
zP3G-ApOyD#$lYGQ9d~5hEzI|AY(O9OFJ0ZrvM*KmyolO?btkI*i{F(
z{6LXM_-uHtS(xU$I>lol^>dxuwj`Q+uw}JX@O`tth2KUG%1kXUKvP;ww(i}CZrNsztvSzD96KXONUSxuhI
z?jLM0_jT1E%w`0+$|v)xfp(>kkJYP@*1wD$J9hC13`lM8E0guHL(Mg@?|p5#oaWY{
z=#|l7g(9kKJ4J=8x5tPwvsM2(HXn2?C
z^~*&5ZC2+;fwbyqZZ?Rqiyz>0ll3DveNz}hqZr<)Dk!Locb-arvQa9TgSK`o
z`t;aXQ-1tlUvzoOuY}pOwMIYVJ>5r$ksb2B^vb`5Is)^`OCbc(-JACF!@}0NV`(`^
zKOC!9uS@{+`MXb5{;v~yOZLsPEbZKE1)`h;q+3K5;py9~<#p@LJ{)4t%2sw5q|L-!
zOmH!t+1m8U?M?gS@^Jw6qc1Vap56iRs|i&7_(hDl=mc3nNDG;w&?C$*Kit08=M3j=
z#adpzVz?{n_kO|p0@EL`t5TUs#g{pe|1@aEyY0>@)K)hSL%1)8%MWO%Yb;Y_oG&s%
z#G9INP%@`sk;O^*y!2f8i8;iJgeSDajxnkcwi^!HDl3ywNEwa_;cVl~k1%Tc4BAXl
z*(DE>srrfU79RddMJasN?}7r)I!ERo^WelURd`lCPq)lakH{=u3ZX8?49;NIW`=f&
z{?R@!*bI2m{SAZf3J-tjfGU^9Jv395qSs#AZf=84*f^
zogyCYIO745H9P7fKTdgHIX*Qy8ofn>Zh75<+Ve?_;F*K8n#P$9%S7fG&&CELl+Qu_
zr~aI8vR?g~QoDU)>3JBXu6}kH{7Z=4Qjp_R_6x*%z082E2`_pAwas*AOaV`*Z9wU^
zNNu%BZ^cHhB^|>(7WKI_G7Ewx!INCFbY9*8x>>}Ur+oh*2%me^7Lv~>_pq2K+it%Y
z6?9q!xgk=(_y?7j62T!yN4K`PiH|QN4uti3KV0{}5+j$Iqc^FWYk-`$_JQNR#dOZO
zk_9P=GYeCa)Vi5en+OIxAt6|7P6>xe
zNbQ&tM@>aUi8*a{kZ&k2^EUA>Y&dT*v@d!3@o|0r}RTuN3|RYjA9c=Ag-z=~}pL$)JeP9uMXknvQx^lbe+
z0%KQPO4g}47=XvG6NyO3qL~8KWIa4?E<>*bPn2z+jG9#DPoYpmS5Ycbv|QR9
zF}A)sBPVw*H1c0u2l*GY$=VGioaQ>q4;8lSouRqEDLm}A-%HN_7hb=bRviq8N8leK
z`IAwUq%;jCnoi@X+D|g-gSRJEoUQC38!nBJZ5Yk65jh7YRQ$9*PrOV?B`USFG@|07oLN+GQD~n9km^~X;f~hE*
zAmZHcC`v2=>624q{4ZTToT_YWzkQf$3h_VNG9MM`dD_U>Nax;^hKHs`f{pd|!#~>Z
z-}gbTqJtwm*jL)X^oMJI-yGCcP=T6-v!&(Nm*1qXjV-SaDqM*^yPo;o4BZu|s?^jU
zlvZ-i1#+K*&NDX$0*S>2Z)5&`K5l?Ig8#ZQR%t90Nl&+*fXh4#vjftg3zqG`>whNG
zbwWGiwUxm{usO&Hy$j$g{tq$$i?WaKD--o$A-t6_A+Imb*n^U)T&^OkY*ZC3n$Ll!
z4y3P{mhgFmVdkDuzgIZ8Er4S*-IoGA(M_>NPPBeIwO85JGl78!8C}
z_jmA3TQ<^VRL;Lb2?w!+(lA858B;G9^biT$C)?|<-ZJ8aS;?yE_No`eDhy$LEn2Ii
z9|K|2V)=~>W%9Z)xpJ9;`X;4%U+FKsH6k@(5H6XAw>yd@oNbAFTcb9oTTRhl@#Wkj
zcK}-;;<%uZBcGM;SI%8QsI|D-A)zHQ1eShAz=KY|(5^=rScZ?o_}$RzD!T96t{<4;
zBU6=KBxfI6!%QI!DyD6&z|2lCwNckW_fG&;^pj~e
z=bgvjyarRPgQ<`Bw>C^rtI1I3h`J^YNwjRK=45||oD`Jj1pB3jDZ|J(
zQAek3$)qaYFfdxwOF-zI|5)<`(RJC{_|<|$$Kf;75<)KiSj0nMFM}D|>VLytL4oI}
zd0Tkx547Kf1Y>A7#gtdR`4qbOR5+t_wSkUwcb%RJ{PhBy*?N|nZ3?y
zD2=!~AL}GE?WIz6o-M@byd}X6qdUaClvyu5i$BKQ;_CNDi?|E?uzJ3Swtqvdw2HsW
zHEDpVy8ncCd_n8!xXdfX;|`98z~<3|YhPWh&ydwMT=kzknTWTk2zVUF3x?g8_!!Th
zpj1~aY^~{RuQk-H&&DNq_g$(ftJ0d*0^7<>*pap~#<6i!otj=Azs~UTT_=P!f5`Pn
zSh06;=RfIN>GAOulSRIQ2TVU>kW=0_*{1jBP2!jBus97D{m*C3J?&Qe-c40?dA{pb
zSz6(^ju%!=jf-dT)>K_<
zg_ZP<)sM;Emu4MJWkE~ylM7);-44I7L1|2BE%^8Q#f&&Ti>u>rgTj_Zs<5zn{Y;aF
zitG;>>xdCaeckK2Ql+8u5;%
zmUex_LBRi^WW7a0a
zFQRKieCyBceYbc1H*$g%$159hkln1B#7IP^r-H<1!=R*Ez2gtAb>
z%dx&7m*jx_2i*_zzy4VeeU9bIp*0a?h?XPoseC+g4d>n1d*=mh1tI%tJS~F$z2P+$
z%0ggE!D#mjTKqq2(cRTQV=;RjF^Z9TosZPksM`53=CN^^w<511;(f71e~p9^+HU(!
zR=U2BX*p!_qxqU@7!}O_bBZ+NVTU=jad(Z_^({A0+i=mx@zq(cCC|wk8J2&EAB+ap
z$eahcFa0|r!&2Seq&N^uCbmDwrC5q$0P+I}ITf>SUOsq0)r_&9(*4_Y>CJORlacf1
z&N)S%<;#>f*pYO4y9|r>E&Wki8a~$HUBQke^2he4?J#9@2Pk*3s;RjRj=ik|O7}ip
z_^*hPL^bqX=totLF6u@vP!4gHSUA_XnNac#clB)r{ZVyWceG36WkWK=!u5
z(l!6){z>0>;N%+Yv5y6Euz-OA&W)K4{LQN-1WSQ((!a?D7_!bNJdFg^yhs%|2Ok^V
zNL4bt3*}7I>)uMEaXvjR;%4T?6tm{v{N1~(Uaxse)Osbuqon(?D*?|nt=9NKpj`4M
zGSGN#L+Ldb6;o0QulxQCRP!?ryAvAB@ZlgBqN5{sw%ZLzr}l>S{xad_Kd31cU}$~q
zBEI_yFsh$IydG&UgkeR_pl17m>Hklffro}S-rY}>Rd#GbuJ;;HXm4P=0Gog`jb=x5
z_4m?tQt5(zX}douvsV%i3fR+^yZ`CvOPEb>Fu&Lqsfmf6P7=N;DuLU?{}a@(R45E(
zAOYBbA>l>S=~G9UOGFM5{{JQd+CWS#>ecr*nf?NjMPvRf}6hx6Yf)osn7wg173(4o#_V1GnGOg*`A+
zxr{YS@`mMVYE+ZjusNdt_4!=V0+^Fj-8C{I8>`j1V+5d15S^52tx0_K*q6Bs(#8iN
ztN{GnQh=l;Q0JPcf7E7}X|Z%?T-i0_YvAqwa-p>ha?{0rpV`;Xl%h$ZNsepA!p^!Q
z|Ba1Y)6LI^&c^2gjfmJ&37~FmqRO4v%fFk)$W5F5NI0~0gIlwYpYi6qFZfS`#SUZ-
zP8cecY#E3zZin{x;fK*+-l+Qrgr2>fb&vyAXYQ63msKFw&9ab8%yJ#kj-F)_7DK{P
zZQz8GVV1Qy^!vV`Z2kh(+jTAEXO0p^OI-muzW|)VgPJ=R&dT4=?T3BX(uT)aibM9i
zlL=zIivZxS(qmmYl+uh3Pf|Z%yN|x5BH3XM#3F>Q-=T)H7945&`|x!avAUx_6Eay7hsseqqWCwRIE~*&7a%*2rq9j#Z?|fg-eHgiNNYOr
ztI5f=>qs9n7(1#4q_@Ka9bM&=7;0w!1|0}DAj1SbEp(E
z$*NaN^i&2l3*C!N{>Mzqe<@4)zRrIg=v|SgCI#I?`1Ek$jMQ!88)qH~N~jPx?`
zs_QMw+VPk40l{c`>dt_w$djZ|&u`sdWvLFwuhO5?Ot1%7)f%e=?^hWW)`jI4G8cH2
zepm}+Huf`37D$t3{4`7!!t~6{1&%;MSFjJry}P^McH-V|>2BI|g}e4wD;u)EuiV1-
zGe0Qbr6YS%BAM-e_AkbMXBEgY$2i!~GwJQ=XGgN244LK%FfOYs_idkcM*>vTaT#IQ
zQNu%aBdKd7Z?AU&UcQe-A5w>^q$HtFUd~nVy>zv^_d6Q{x22u`R;BgMvbyE&6lv6B
z5J-S@wr@PW&?2EZMwYsGxeyHEmR?-Uxy-hZvl{fXXFMq3`I#z~IqWYLWO}D;CR<u3_^TpUX3?L84|+T?x8YGsF8l}L@m4l|4e{!7yq^CT=q(^y
zn?30V_GHA^s0XV5s-x`V`OU>h5J~*=;FN-~QF-{Q*Tl8nt%QIb-B`3z!0f_Wb(O{q
z9fNPXM)v|%=6B*N@6C>4W#0LZ1~AWF=GH~gpbm_d5qS;V!WkGDAXGq?2A(s$>g6Ls
zZJN`cF#@!F9q2m4R0iP{blKBZK$;`X@qgzNeGR)xyKy{6EgFmSHB>BS1y8wpAocu5
zYNZvscW=yjCQ}`U$E5Gu{=BJT(=fB=gVqCUt&X{x@+$mL%=>~5Zq?$6Zmu1?>H~mc
zlxX+v*UX?3$~XSKQ$O9)w#QRYUyb?e4+goqDUrp?;gPDe==Hen0kwlH{rA=J)a=Xc
zeiToo6SxMQ0FwxtDRIFr>9*F`%&Qv`!~?cLhf1Rl{^LjPWCc8{o-^%J)#`(
z142sSWHKhuoJD&SdaZzW_cik?=?%xXu>xx$V{hc9(0pBPBEex|Ku*C$Tamps@Tn~i
zJY~JRTDk8m|KpXQO5(h5jsP0ma5jKqKQ}1exPTms8Tzge|6O5O?Aq%&B~w7=BgnPK
z9^2V}+-@UpDwI!+r@7`7sIf$EWq-{csh<$hB$&A~fLGxPV#i^2E~Wc=E%Chdb)Z;%
z@Lv(>6{cO3Nv-)O-R1$~?WxiSHs|rIn7jXS-^x#7w*}bJCs6y~3>!&PZq2K9zu13u
z&LF5^>1n+Ef3n1#Vrui$#uf~K7C&Uzo9F@<`#9@iuG>ZG(b#H@2lLF%k+Ol4g_FFh
zf#Y0(kgnnAC{%%_6zl=zy#6NZ{5Bx*ehH2DFD%&KHnZuU$TP9k+G>J20D1+v`DO+<
z>bZ8xn`iH5TUx6-$UtY70S~I(kdVE
ztlpbhYqOU#21hW+HD*0Kj`z2L+}W^S%AGp^@ua>et~}woseWyiwz^fnf|`~ah;;#6@zgpOcQZqy_dfT#HAn8
zoU0P6IjRF9hZXs*TB&5G577TwZ+7@;YXv&{8GcTwQo+x9{_eurFZOe~Z%G|{SXkYBf#k&>4hQo5s2484Cw3rX}ot*{8ADn_qPno=b
z1>vao>oXf+T2{JC`qEDx#6USUZ3_g?jYYTriYPM}MUOw_)~^=Z8KOrTx``wJfXrP42tu|AI=W3+Fic&BG`
zhh3*bmmaEV$S&*}SGsUvqTSnjBK9Mdz&E5OY1D7CSp6*bI#hIE(
zOQMRXZi-I7@t_*6E|^CkN_H(&!l=U|{|{#MP4?+86A6}wfkc%l0|Gr9l>0xUV12r{
zyo@Vdn4jPIuy~&FY@V_IA@lG={x8bP%3SW&RvhThGj%P)KVj3@*w|&}*w`58K2C8c
zDpEKo>y*w2`u(b1h{8m|+=Xp@K&m5MrU!5?&!?uQgpO$AvfQk!EMbG7cIRj;K#^R9
zLZQe!h#r#Ne7ErUVG^{S=1VHk;eaF4d*ZF7cINp1wjzzDPE{g!}`RY^Q+!^ymobjuQag3NX?)i`j
zFb03oYXb45yQ5B8+t>_`;8i6j1kE_+0=SQ-}
zA<%{VP-a6*^#`yIT%rxCF$JD19p62Bl@^e$c;dw1d8v`-TP~`~$|dlHuLl0LE!6;T
z^VkdOKX^VZu{WWlbn>@?T4jRvW8+`{)WEUFDvMmb)SbNljv5_bi!wottVfXqlhOob
z;QU#9P-7H_0EbcWKV+TkBtZs9mcW?fX&KA{tmQz5%82*lY~YM7fHZL$NRf5=5z=L6
zE_8p+GYs=yJroyKq5jUw@UR|rq(Ao$;KhGX{XR}R2mfRL=-rBK?ohEES9NP8feO)B
zJN~=n+4XF#>vLC!lpetlFK-z;(*aWa@!BCtXPSn>NEEdTfkL4`IZ(-iz5;KLw9#12a|3GKXy+J!pJvv?2ax??d
zxPpM=I6F-O&I(``5uiWeF3n~{$=Y<4OJgApDdy(lO$Kq&y|
z*$07LZaNnz2!x+HK$iR1!6}^}lw?aFd=;nGaz$>oa$qDb;I5W)eE`Duacr0`+uzd*
z+!EV&?dwsgPgjEz{qH?X{QC84>=9?<)|Tt^`Y@QYw&JVxg{CD%hE?dhTuWnbpOGU{
zpPtRk1gCU$#j3oqWtsDO-9&}w_nx84RDf_dZIuL&hrq_jXzHiZ6x+{^cUq-*wnR(_;?2EXzk(6)Y0L%(c*JfKT=
zx~{9Jx8OV5nY>3@TIwMl5Uh`$U$gpb4Mpe*j{o2LN7j^f*B`m7t0?~ve|TcY@2*9B_Qb^WL5H{kvPf@@NI1VSGVz<(;E8XKU#19L4?I2Uri$xZPP%
zT_C*%G}`s^Q00XxC*I+@qktg(*K0n~1jytL&{H4VtMcOs{wd#NFCDJv!q9l9tE5JL
z1KMq^P5nC?cC|N6YtD#OAKTO1dK}nswW1#qZl(;af
zBY^6^>i>lH{}CHBdXkD{`8Zp*7#wOREPrVO|Ii_yU%L3AZx%!Ab*45C
zarT1rYf}ZcKmm`o=V;iM_@xEO7!%)p;&HlI00%1_lF&8cXC-72mEkNM4bs<+ePVo2YJ2ThaZqq>~ZJ3YEO6T<5m>ktlX^jHCZR~;N2CJK4GouS__H
zM@3M2R;*s8q+WA~ikgU6V1;ac$iSf~9t0s{Ya(uT`>3Sb2tt|W8NW4wT3A?!pZBG%
z{FYaWtrfiZGX#Q71r!jO_?j^~T@DN;o~!csi(NOv1N}^?oAstUJc=B)CR#i0&AfFp~4IVXeWiR~7)^64@GgDK=1&TVpf9lSmUoc2smQbSf`_{=O
zDg}^Zu6(R9gC0EY%EdY1D5<-fuLBl8`p@~_sXaZzZiX!zt*y~kFVQqU8l6H*=N032
zni}fK+oj1tg3VmO-sjufDa?MxBu#OILn7>-3^S|htx3f-VBAQJ9_kpwA9wYBIrakJ
zJzihj*s5G@7$K>*_t^p>F%|*CUgW4gw*!=$-&+!A*o~ZGO-@)o{nybO|GgAR)Z`JA
z>5!AdNJdu@(eO@$Zf0IyO0mog8cHaoj-KBHl$nH{*Ww3IAMjagb*c_F7^
z+xppDn)w1TWuWJuO6wf#T!bt}+q4b&Q8GirOrVY(-OJ(&;lp^6NWf!w6s2Xcq{Z{Def+WkEuJ|{WP
zIC1&5nJeTQr;$U_tmD&m#PZpbkZ&pcp*JY5g9*FW*%q1v;%^P=vsOjS`t5h-VIrT(+mJi(XlV0ciDK+l8oTSj41U
z&b4O?0EbE2fd~(;!bL_|L`95|0-c7I>V-OHm>ieA-=w6(5y9jjDyD(u1?W~J<7~`S
zCI-;p>R>-=ZB#-|Qae8k>JD;QaaI=c9buxzXNevQgzu_V<
zc_a<=o;;qo)Y&kD{6281LF$A>uykGf?Ca$3)+T$ibFlcGyf1e$WWH7^jJstY&2Z*=
z<@?3ERc8uRt&DoNsZ;!|I9X7|aWX&zUW}5&DVfDLu@kX*ofv*sTXZ65V&yt4<c}*cxskgF+52i`RL}wygO!yFSS$IN5KxZgHq&1N(wXyp~WTT&DLPXAjy9
zCNpucS5)>|z4{R4iVr6@2bvp~4H2bLQb+Q^Eu#7`wbfP+bbI+S$vMy4FSby2(gi{T
zJ0y=a!r>F~6yxq*K+|8h6OH`dX4FAAE#j`PU6Rk#JyxpU41<`oY=(*@mbJ)guWQ@uWbTiO1oG>&
z7wZ)R`!K`P&6U#Ai(d;OP$EkUSDcgMdFP@}@2OB9^wOdaZY_*kk*YXVnFw~kDvlf8
zo5U33R%TWwIdR6A*tMhvTcqgQLzw`E$`i=9z8_|G2lt15Sbk(Xvz|!PfkTJ(n0|B0cAyyG4r{!=~v42hUI;DcB3L)X#a?E|)JH#eUto1q%1(n`J!)4A>HJ6q1B%W^ZdEo;M&JrkZU#%a2C2)&xQx
zGS1zz{fo7@g43wAv9@jVlxI`=&_hVBj>&f1
zz#P#2L$QxZ^Tc(<%1!5>ney(q((ZI98`bMyP)a5fs#Hxj-DNma$}Nr0W`rk#UgF}Q
zr8~3aTq`N+BhRTcSg2yBNxhxv2%wZ&?M+mDVL+ZMSse#L3TZ9fW3_a96=4m5-QG
ze7seqPRx$c-}81fKkNEIa!$6~Gw1AqtnA=nQe;^vPm?~HUA%dh@Jm{T_Zz=KCs%&+
z!Vxt0X12OJKLUYY-Xg^A&Vpg$8wkUU=o#w}kxP^X90d)x|86Q8Z>)qA7R0~L%){WE
zph92{ge~LJ%CX}wGSDh1YC6PwwvI$*pRq@DdHljP+ZXEWmd1wfeGJR!SrK&!K77)x*D2!*^bs;M2I6cLMNrbHa{
z*YyH!_6it0c`l8}DOdnR{ViL4`O4*i55NEUsi50$WBf$$
z#gVxl!HJ#1s#2?mBT6+gT=#OuS}+=JMq%?-N@gMNO_K&$QBx4Oe$Juqy2_@iIxe`8YD@v##PXJ+XGIJ&2f6+A;vM9~V14jf;Y83`
zwX6|ygwgh3xJFpZ#{Kmh1}Q
zr`z13HN8#t9S$Q8cxfuw5{CA7KZt-kG~`gdw5(kLN$^lnV0NZbsc3{kX`jh2Me6mX
zzHGf0ff)G_jJ!Ui3$vlLjtXMkeHWg7ZeE#)BX;%7&R*?-qzh%(NHCbD-@Y7~oq)^6
z(gWVUw{rA)lv3yn3eGy;pU*2XLn;pEG)tZgXQf(gB!d?fzt}37siZ+RRg{!ou4-3f&`wBlia8dW-#^r~a-mY!l*w|>F-LMMh!jrQEeWUgM
z7Q`WsJ)*IOYVYq>IPn8tMs<;}&e%1Asr~iNZpi`$Q9gbhCIdlJksWF0y{>Yaei_br
zK?DN-fA;-Q&yDA#^{M|&iAG8~j*lOUmpw_SDryRhZu=JR2SIKyt97j5h_H$eO;saN
zaLp-ejws1PhtiowVV31(u-TYnizlA5Ai<2r#{KiOk%P1Q@{Ej_)l-RyrTE8NeTy6x
zx_Gr5XT*?)*B}v7=Ac6H)zTqM
z#Zi>R=@9fnkM~DcU+_j`Fqz|0dsdVw^BJhpC^PP)*d%Hxtu1yetVEF9dATcg7e6xD
zs^-fqYyPxV%uVY|>O-vdUkiO$Gz=S4v;P~Cdou%=Y_WVsm2%zUeNk-B6j@w|eC_Gv9>{7Ln&lFbgiZ}5+`$i;7;F9LITrXM)w>@bh-
z>pI_jeN9KU?92rD%ikUF?Im5U_+F2axnnvG_N``I=Ap9y0-FyW(Svr{io3+gwP8n=
zZ@CGmDCP;RXMCA~pOvON*d<^f&~)V1cd$cyXF^Y`Z|TBR+(cD(m2Jb2)v;bGz>a!E
z(8NM!DcYs+8D3=M9_N0ZBqCZ&XGu}p%hQUcXUAS&M0%gT-j|0iFW0QIwWh&tiiJ;5
z%4!Q#h#MI<1g9Sbq_=j&w<12SG%ri=wI-A2`QTB?JBsq?kqURB^CPi6gw=;(Iis3h
z%dg2`6^wNk9Ze)ppM-3b+eM5bxlfyOH0-)W4sR?ko(11}#Vm*2fZ9x9>D}^9!o=9+
zg584E*qV;5AEYL?HZc_tzU;DwH~lzH7$#LY-N{b(sOXw>ogo&t7Hv&*s##1oG6XhT
zJ*f4{kP$!-$tUxP4KO67{~_SNFQlp%A8l#m52e{RHZ(5N+}r!mtsAqRz{IF)DEZO#
zK4W&Bu28gRx|4!^-U28y*^`Y54&}ZWg9ng3KTE)}GoC)KzTzM1K5Q~7YSI#u&g1%|
z`F6j}9i(0Q=7c{cBclT_A@R!&>_#6@P+v{M;R+XZKJ3FS6lrR1xDcwtQdx^c+|oT&
zRoq}e+nf&(td5X*w1z}+3Ov?sYZOf^CuG{%yrghNe2Ndm4V#tq@k%s-s`7P^F6RP)
z#4r3HEHfAIXvBZTDJdQX2>*Up*~%dku)5N_V|-`Bybjpv`T$it;GDE)z+};&7UB7u
z%ev+vyoaSxK2ZEm?4ilsR?_C$a=lyZ+-tPP3|zu#vnu~R3r6@3Ze!Mr=*|_yIjwDO
z_v()m@IM7%cTs7d)!RLhBJTJ5C0!y2HBSl!%O*#3m8Qzg{qrQM~c
zd7bEjWV+n4o=TjX@9=XOlP8QI}FxB*UAOQr?wYRr9szXg5|Z^
zJv*SK)q@#bBm6`0{Gw$sRa`%`?wQ={H-doPM6h^;?=fyoE>Gb*!)i)BIWg-ItV#mr
zV#sf#tu~$315`5w{zMpDxj!*6k(q=~NyY8QYWNueIe`gqe07me{u!e`W;}A`!M)OfO-@Q$ZJ0Zg@gz4-{5dJx1_+`>Hkg+{imJ(DO)3~ngogz%YD!G=2kKvk
zg=}q>UkqPtTNYl`+nf24?f2JT_aL)&XEo{p!A@+bA7=EA79o#CXNpH%4(^Ox89fX-
z@xjCOiAwVsuidEn&P+vbhTXv<_sukH^Bnii=vJOHJx98a#FirHx;O_KXBbKl2yg?g
zldqXIwl8g41z*1|`@@cEal&W|3*HOMe?g%*R$niKwpF|&oVC_fP{+=L@(aS;0(k^N
z-*O~ugU_Y(xftUgnI1zDiQGr0usZyO2F?CM0Vkg4z)5F7`j1~2gL1ksxQ2tx=<|m1
z|6i>ga&d>;&qYVt{
Date: Sat, 6 Jan 2024 05:56:17 +0900
Subject: [PATCH 7/8] =?UTF-8?q?New=20:=20=EC=88=A0=EC=83=81=EC=84=B8?=
=?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=82=B4=20=ED=8F=AC=EC=8A=A4?=
=?UTF-8?q?=ED=8A=B8=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/app/wiki/[alcoholNo]/page.tsx | 16 +++-
.../wiki/detail/AlcoholDetailPostCardList.tsx | 76 +++++++++++++++++++
.../AlcoholDetailPostCardListHeader.tsx | 69 +++++++++++++++++
.../wiki/detail/AlcoholeDetailPostCard.tsx | 69 +++++++++++++++++
client/src/const/clientPath.ts | 7 ++
5 files changed, 233 insertions(+), 4 deletions(-)
create mode 100644 client/src/components/wiki/detail/AlcoholDetailPostCardList.tsx
create mode 100644 client/src/components/wiki/detail/AlcoholDetailPostCardListHeader.tsx
create mode 100644 client/src/components/wiki/detail/AlcoholeDetailPostCard.tsx
diff --git a/client/src/app/wiki/[alcoholNo]/page.tsx b/client/src/app/wiki/[alcoholNo]/page.tsx
index 0c4bb1d..58ad3f3 100644
--- a/client/src/app/wiki/[alcoholNo]/page.tsx
+++ b/client/src/app/wiki/[alcoholNo]/page.tsx
@@ -1,9 +1,11 @@
import { HTML_TITLE, nameOfApp } from "@/const/brand";
import { getAlcoholDetailById } from "@/queries/alcohol/useGetAlcoholDetailQuery";
import { Metadata } from "next";
-import AlcoholDetailPage from "./(components)/AlcoholDetailPage";
+import AlcoholDetailPage from "../../../components/wiki/detail/AlcoholDetailPage";
import CustomAppbar from "@/components/layout/CustomAppbar";
import CustomContainer from "@/components/layout/CustomContainer";
+import AlcoholDetailPostCardList from "@/components/wiki/detail/AlcoholDetailPostCardList";
+import { getPostListQueryFn } from "@/queries/post/useGetPostListInfiniteQuery";
type Props = {
params: { alcoholNo: string };
@@ -41,18 +43,24 @@ export async function generateMetadata({ params }: Props): Promise {
const page = async ({ params }: Props) => {
const initialData = await getAlcoholDetailById(params.alcoholNo);
+ const initialPostData = await getPostListQueryFn({
+ searchAlcoholNos: Number(params?.alcoholNo),
+ size: 3,
+ });
const searchKeyword = initialData.alcoholName;
return (
<>
-
+
- {/* 포스트리스트자리 */}
- {/* FIXME */}
+
>
diff --git a/client/src/components/wiki/detail/AlcoholDetailPostCardList.tsx b/client/src/components/wiki/detail/AlcoholDetailPostCardList.tsx
new file mode 100644
index 0000000..8116600
--- /dev/null
+++ b/client/src/components/wiki/detail/AlcoholDetailPostCardList.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import AlcoholeDetailPostCard from "./AlcoholeDetailPostCard";
+import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
+import { Stack, Box, Button, CircularProgress, Typography } from "@mui/material";
+
+import AlcoholDetailPostCardListHeader from "./AlcoholDetailPostCardListHeader";
+import useGetPostListInfiniteQuery, {
+ AugmentedGetPostListResponse,
+} from "@/queries/post/useGetPostListInfiniteQuery";
+import { SEARCH_BY_ALCOHOLNO } from "@/const/clientPath";
+
+type Props = {
+ initialData?: AugmentedGetPostListResponse;
+ alcoholNo: number;
+};
+
+const AlcoholDetailPostCardList = ({ initialData, alcoholNo }: Props) => {
+ const { data, hasNextPage, isFetching, fetchNextPage } =
+ useGetPostListInfiniteQuery({
+ initialData,
+ searchAlcoholNos: alcoholNo,
+ size: 3,
+ });
+ const hasPost = (data?.pages?.[0]?.content?.length ?? 0) > 0;
+
+ return (
+
+
+
+ {hasPost ? (
+ <>
+ {data?.pages.map(({ content }) =>
+ content.map((data) => (
+
+ ))
+ )}
+ {hasNextPage && (
+
+ )}
+ {isFetching && }
+ >
+ ) : (
+ 작성된 캐스크가 없습니다
+ )}
+
+
+
+ );
+};
+
+const ButtonStyle = {
+ backgroundColor: "#F6EAFB",
+ color: "primary.main",
+ ":hover": {
+ backgroundColor: "#F6EAFB",
+ },
+};
+
+export default AlcoholDetailPostCardList;
diff --git a/client/src/components/wiki/detail/AlcoholDetailPostCardListHeader.tsx b/client/src/components/wiki/detail/AlcoholDetailPostCardListHeader.tsx
new file mode 100644
index 0000000..13f91e6
--- /dev/null
+++ b/client/src/components/wiki/detail/AlcoholDetailPostCardListHeader.tsx
@@ -0,0 +1,69 @@
+"use client";
+
+import React, { ReactNode } from "react";
+import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
+import LogoLarge from "@/assets/icons/LogoLarge.svg";
+import { Stack, Typography, ButtonBase, useTheme } from "@mui/material";
+import { useRouter } from "next/navigation";
+
+interface AlcoholDetailPostCardListHeaderProps {
+ totalContents: number;
+ href: string;
+}
+
+const AlcoholDetailPostCardListHeader = ({
+ totalContents,
+ href,
+}: AlcoholDetailPostCardListHeaderProps) => {
+ const primaryColor = useTheme()?.palette?.primary?.main ?? "#7B1FA2";
+
+ const router = useRouter();
+ const routerHandler = () => {
+ router.push(href);
+ };
+
+ return (
+
+
+
+ 캐스크
+
+ {totalContents}
+
+
+
+ 캐스크 모아보기
+
+
+
+ );
+};
+
+const AlcoholDetailPostCardListHeaderWrapper = ({
+ children,
+}: {
+ children: ReactNode;
+}) => (
+
+ {children}
+
+);
+
+export default AlcoholDetailPostCardListHeader;
diff --git a/client/src/components/wiki/detail/AlcoholeDetailPostCard.tsx b/client/src/components/wiki/detail/AlcoholeDetailPostCard.tsx
new file mode 100644
index 0000000..c30f0a2
--- /dev/null
+++ b/client/src/components/wiki/detail/AlcoholeDetailPostCard.tsx
@@ -0,0 +1,69 @@
+import PostHashTagList from "@/components/post/PostHashtagList";
+import { USER_PAGE } from "@/const/clientPath";
+import { PostInterface } from "@/types/post/PostInterface";
+import { Stack, Typography, Box } from "@mui/material";
+import { sanitize } from "isomorphic-dompurify";
+import Link from "next/link";
+import React from "react";
+import UserAvatar from "./../../user/info/UserAvatar";
+import Image from "next/image";
+import { useOpenPostDetailPage } from "@/hooks/useOpenPostDetailPage";
+
+interface AlcoholeDetailPostCardProps extends PostInterface {}
+
+const AlcoholeDetailPostCard = ({
+ nickname,
+ id,
+ createdBy,
+ tagList,
+ postAttachUrls,
+ profileImgUrls,
+ postNo,
+ postContent,
+}: AlcoholeDetailPostCardProps) => {
+ const hasImage = postAttachUrls?.length > 0;
+ const openPostDetailPage = useOpenPostDetailPage();
+ return (
+
+
+
+
+ {/* 타이틀 */}
+
+ {nickname}
+
+
+ {`@${id}`}
+
+
+
+ openPostDetailPage(id, String(postNo))}
+ className="line-clamp-3"
+ flexGrow={1}
+ dangerouslySetInnerHTML={{ __html: sanitize(postContent) }}
+ />
+
+
+ {hasImage && (
+ openPostDetailPage(id, String(postNo))}
+ />
+ )}
+
+ );
+};
+
+export default AlcoholeDetailPostCard;
diff --git a/client/src/const/clientPath.ts b/client/src/const/clientPath.ts
index b51e157..496eb13 100644
--- a/client/src/const/clientPath.ts
+++ b/client/src/const/clientPath.ts
@@ -51,6 +51,13 @@ export const SEARCH = "/search" as const;
*/
export const SEARCH_BY_KEYWORD = (keyword: string) =>
`${SEARCH}?keyword=${keyword}`;
+/**
+ * 알코올넘버를 인자로 받아 쿼리스트링이 추가된 검색페이지 라우트
+ * @param alcoholNo
+ * @returns
+ */
+export const SEARCH_BY_ALCOHOLNO = (alcoholNo: number) =>
+ `${SEARCH}?searchAlcoholNos=${alcoholNo}`;
/**
* 유저아이디와 게시글 아이디를 입력받아 /post/@userId/postId 형태의 path를 리턴
From 59edee428cbce06eedf037abf72b9f4c70d6a095 Mon Sep 17 00:00:00 2001
From: Jungu Lee <1zzangjun@gmail.com>
Date: Sat, 6 Jan 2024 05:57:03 +0900
Subject: [PATCH 8/8] =?UTF-8?q?Refactor=20:=20SearchParam=EC=9C=BC?=
=?UTF-8?q?=EB=A1=9C=20=EC=A0=9C=EA=B3=B5=EB=90=9C=20AlcoholNo=EB=A1=9C=20?=
=?UTF-8?q?=EA=B2=80=EC=83=89=EC=9D=B4=20=EA=B0=80=EB=8A=A5=ED=95=98?=
=?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/app/search/page.tsx | 6 +++++-
client/src/components/post/PostCardList.tsx | 18 ++++++++++++++----
client/src/components/search/SearchArea.tsx | 12 +++++++++---
3 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/client/src/app/search/page.tsx b/client/src/app/search/page.tsx
index ec5e9d2..7d8195a 100644
--- a/client/src/app/search/page.tsx
+++ b/client/src/app/search/page.tsx
@@ -8,9 +8,12 @@ const SearchPage = async ({
}: {
searchParams?: { [key: string]: string | undefined };
}) => {
- const accessToken = await getTokenFromCookies()
+ const accessToken = await getTokenFromCookies();
const initialData = await getPostListQueryFn({
searchKeyword: searchParams?.keyword,
+ searchAlcoholNos: searchParams?.searchAlcoholNos
+ ? Number(searchParams?.searchAlcoholNos)
+ : undefined,
headers: { Authorization: accessToken },
});
@@ -19,6 +22,7 @@ const SearchPage = async ({
>
);
diff --git a/client/src/components/post/PostCardList.tsx b/client/src/components/post/PostCardList.tsx
index 01adf81..0a11a61 100644
--- a/client/src/components/post/PostCardList.tsx
+++ b/client/src/components/post/PostCardList.tsx
@@ -14,7 +14,13 @@ import getTokenFromLocalStorage from "@/utils/getTokenFromLocalStorage";
import { postcardContext } from "@/store/post/PostCardContext";
import PostCardSkeleton from "./PostCardSkeleton";
-function PostCardList(props: UseGetPostListQueryInterface) {
+function PostCardList({
+ searchAlcoholNos,
+ searchKeyword,
+ searchUserNos,
+ sort,
+ ...props
+}: UseGetPostListQueryInterface) {
const {
data,
fetchNextPage,
@@ -23,12 +29,16 @@ function PostCardList(props: UseGetPostListQueryInterface) {
isSuccess,
isLoading,
} = useGetPostListInfiniteQuery({
+ // 검색중이 아니면서 AlcoholNos 가 있는 경우에만 AlcoholNo로 검색
+ searchAlcoholNos:
+ searchKeyword === "" && searchAlcoholNos ? searchAlcoholNos : undefined,
+ sort,
+ searchUserNos,
+ searchKeyword: searchKeyword !== "" ? searchKeyword : undefined,
...props,
headers: { Authorization: getTokenFromLocalStorage() },
});
- const { searchKeyword, searchUserNos, sort } = props;
-
const { ref, inView } = useInView();
useEffect(() => {
if (hasNextPage && inView) fetchNextPage();
@@ -59,7 +69,7 @@ function PostCardList(props: UseGetPostListQueryInterface) {
) : (
// 인터섹션옵저버
- hasNextPage&&
+ hasNextPage &&
)}
diff --git a/client/src/components/search/SearchArea.tsx b/client/src/components/search/SearchArea.tsx
index cc97ada..4f28980 100644
--- a/client/src/components/search/SearchArea.tsx
+++ b/client/src/components/search/SearchArea.tsx
@@ -7,12 +7,17 @@ import useDebounce from "@/hooks/useDebounce";
import InputSearchIcon from "~/assets/icons/InputSearchIcon.svg";
import { motion } from "framer-motion";
-type Props = {
+type SearchAreaProps = {
initialData: AugmentedGetPostListResponse;
searchKeyword?: string;
+ searchAlcoholNos?: number;
};
-const SearchArea = ({ initialData, searchKeyword }: Props) => {
+const SearchArea = ({
+ initialData,
+ searchKeyword,
+ searchAlcoholNos,
+}: SearchAreaProps) => {
const [keyword, setKeyword] = useState(searchKeyword ?? "");
const debouncedValue = useDebounce(keyword, 300);
const MemoidInitailData = useMemo(() => initialData, []);
@@ -20,7 +25,7 @@ const SearchArea = ({ initialData, searchKeyword }: Props) => {
return (
<>
{
>
);