From e6592c0fc50d7ff1ffaf77ebcbaf3050104bac04 Mon Sep 17 00:00:00 2001 From: ErfanGerami Date: Thu, 1 May 2025 12:17:02 +0330 Subject: [PATCH 01/17] adding folder --- DockerAssignemnt.pdf | Bin 121993 -> 0 bytes .../Problem1_PostgreSQL/README.md | 1 - MohamadMahdiReisi/Problem2_Redis/README.md | 1 - MohamadMahdiReisi/README.md | 1 - README.md | 35 ------------------ Samples and Hints/Problem 1/README.md | 32 ---------------- Samples and Hints/Problem 2/README.md | 18 --------- Samples and Hints/Problem 3 /README.md | 24 ------------ Samples and Hints/Problem 4/README.md | 21 ----------- Samples and Hints/Problem 5/README.md | 0 10 files changed, 133 deletions(-) delete mode 100644 DockerAssignemnt.pdf delete mode 100644 MohamadMahdiReisi/Problem1_PostgreSQL/README.md delete mode 100644 MohamadMahdiReisi/Problem2_Redis/README.md delete mode 100644 MohamadMahdiReisi/README.md delete mode 100644 README.md delete mode 100644 Samples and Hints/Problem 1/README.md delete mode 100644 Samples and Hints/Problem 2/README.md delete mode 100644 Samples and Hints/Problem 3 /README.md delete mode 100644 Samples and Hints/Problem 4/README.md delete mode 100644 Samples and Hints/Problem 5/README.md diff --git a/DockerAssignemnt.pdf b/DockerAssignemnt.pdf deleted file mode 100644 index 8415eebe634902251a6055ea81934d8eb6556ec8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121993 zcmeFXW0Yl0w>6ly?L2AQsI+a{w(Y89rOisS(zb2eww;~N_uls#_kMl*Z}*SBXN*`o zVx4tjpEYBTm@#7qnSzKI9TPnp3|ZIHpHCPT762o_-pC4umlwbwV`*n<=w#_-Y64*T zZULB>nYg%E01OfUZ2$`!6AOTui4C9&V2}r}Z~_=a0UV4htjqugIly;I<)3IaW_AD{ zAB?G;$v<5J{$KpSu(1B8L{vN-OaTlUN~UJtX_(rXyI27J$wSQ2#>Ld>`)Xt8Vk%;4 zY;W=%^{=afp_8pM;2#i#?QL9b?VJH@00spoQxi*L7kj7g+`jVyFsOe6!31FWF5f6f z+L@So{DaIlE{vT2@|f9w*T4UW5`aO;-rnUKwSP5~zd;2svwoxc-KX2XpyK#H;bD*z z0ci6wvKVui8MB(OahWh08!|E*8#A&Saso1ZNi~Q$t%Ak4$4D6N7DY10w?iPH5s4{y>RAJfx9T zI5U07vBO}A$zVXdI)+GkNYL;xIg;fotOWDu1xQWWLr(#Hs?SJw|MQnI*D@HyprTVE zX|jnX@3kEk*-t)bpkHN(wEv9sf86K)gE9X<@%x|l{~+)`2>cHM|NlS$=6`X^zo}c! z(ALx$z{315x{-GFC?-3}9yd zk01VvIE4*e3~lVq{}Yw7uz&aR?|c0#NZ!aw*~RvM^D7ezBm4gY!^#1;SpWIT$=Ld<4J-tQmA-epi!WMq}|KcSRLF&_fEsRcuI>+uTix1KUU zJ7V|T@D)XWLFwOSO*ubdF+~)_)y6VA_Qg_?kxe8@5u>Bf6-a?oj^mimO2L2qjZQaY ztj#PHsf_@pMaJ?OL(Yw70#Oa&WGg00j;b-Jz@n*PR<^`))MAQSED_r!4yS&WqEYEl zcP7Q_X@J=wX$4Lltoew&RzysAT%&h ziz)ZUNir{@lOWhf$1{6$7gy0dOO2as(s#;OS1^yMZ1kGXU zgv=4t2hB0;L6-Zqt7a_Yz&j+8mdCu8I$p(iKNgN(kvdLJpXhuqIUw?09v1$h4)M45 z@A#!&6XbX%TTkvZ2WAs3UJ}h4*f_eL8H97F0-UZhszyf7x&g#s&q{4@kB!|kn&h7` zP^EBsL{{{a80A5cZcuI5KI*94_(WeNMo0caDMlu51B2bTxF``ob2(kmwP7X&NIsJf z5j9Y-5SpFQF*z9*)_5KFb=~->3FFj%6b_ER0WB?_J!FT61N3sSQ`tZA7hqq(SBWWN zEL~lgX8zW5=Pis~oYCRqjsNPqIB;`!^7U#QO!4~pe)w^JYr>u7L$l@Iz9F;!OfnoK z(X|zd1;?;K*N^yh$0(0fv-LU~t{mw*NT63j6ReaM;uZwrrHbQWUK^x+$8JE_)+YhTN66oA)sZnKs@UgrM>_V!tOgnn_i1D)D#l5XA44~+fLa< zYSh9?P>TpDF~&f(6r6E~GgP#8tov=44{;SDR&DW9NQ8ksM0Ng!c{qbE*B!U7C~9~m zKf`@cP3WLTLclXtbihkz@M}u4Dp;}#c4PVtye8W=Wf?@cpc&73JRQT%xxCZYh+M4Df8(`no4rzQ^>j#q2Rg||Y)5_q`KI5h$muehgn~v>cgBjDe zEt#Xm+JExUa$uai;E&Z$hGz#YkO?|2@=qbj416y z*IlVm1__>#+=n$GuvG}FfE}D}9xJ%B+rt_tX=Kws(Ijvyl`@t5XzvqoQ&I@!3ouxAnsuvwPk>F1xwR@`r znUG6BfJ|GcZU39JIR8^x!uED9rgkphMD`!7CHpPF42A6fky-!9D)w(3#=*t>kJkDY zY~PUpCboaeEmLQES103dGW)mZUo`a(!To0<`={f76WM=@;(zExW+rxy|AJqGhIGPO zGjivfdWjRXD%+nIG_ozTi}68v`+>H66>9V&ptx8lL{TSbr@`C5@?FpIX%mZT2gD%J zV)-+_|Ki@N9VIor-Xyu-ee7JHJ_tAKzr^8+tr@s-R>m77d4%JNj-19;ejc=!FJ?@; z&$7Mq?)dy9O2^quFwP+T0XZ+_XZq5v-ny-z;mrz=_`V zIf|X@b|!#vHJdeOc-$l)*xtKSYDGYyP#4V`t80`|?f_D*3eK846)UXt9IT-&SSZx9 zci2o{R4FvQm9E0&x{X*@9dgk|pWCREb4*SlR|QWvy%ZQQ9CT6Ep$ zVv?tgwnHXYex7g;+PHgVKJ|MvYN%y|nGt91gE6Q|oUn4gK&DCsG=2pJCLFoq1?OyQD7*GLoJkcla8+;1Iw-lbAI)sz@0LE7 zcP)yBe)fe6DbHFdyNWx=>c#cZBpzJhyMS$`y=$N^yo{bBF~dGd;Z~9(qlrzz#*Cz@ z^Q0RcLChpKwKELNwGgEMJ;lOdCAwpA_RRBy-x);&i4RSpVcV0SS`cL1&Qq?j>r!h5 zL8`plwkomb`pn9!>0QJ5uHz+{ijyB>5R|mi1EStYb6F}z?&HxnYoJFgw;Zs3*3Aw)dDRVPIi8jvRNAU~}9)$O01G^#7mWKi$!p}T|AaX#r+E!S_5wR}g z@o6RRE%{`f+G++HjqKD|l`Dm4mbX+)NsKrIx5ah{l@1h}Dx}o!Mk0zahZ$Tk*!(YC zD0WBKfhX8UbDEU6o?k9XEN(1kg#P#L;fz|)>$ui%1+Q~P=?+s`b<+AA-BZFt1hMA z%6J9|;*t{iY32|L_#t^mmBPIP(RMnE)iR_8z@f@WK%oZNGXKGKVkFdM%P4asm=;GxKoiJ_lD zxl`W@sc6=sh|RHZVQ9gtw-#vjfpfq%T~4Ahz7{6v?fJVXlYohPpF{ugCfw(A3-eoGLg*g+HmhdG=Hw{V=jc5*RMJmp7Er22xJ6$28@7oi4=(3 znWbVKFcG0a3~L`ij{YtvNO)r*a~Z1y060tXwW3juFP*9vV8auGa9<&;rSU1krqpmS zNDrK76-Q_VOtx&0xjEfT;isq+cCb*cI#b=q#{Ct2)Az>RqFGTHvF!sP;SP~@S{wqs zzi4ZLZmgC!8zMWlNVpGI`}}34sx52YlO9E5o9&^rsxtt#;(lo@pwjYH48(GhG3Z*R zcdaTa;{?5*#_oI>exs$}*D%o&PQh-y9HaI8VUjD}IK|I^W2dZDiOg3N;MyTXl3rU5~ir@xD($&GPi{N#xH8K8(QTose>tJ#(U{d<_i1#+1e zI6~-%d~4);9+ha#OY1DwfIWgV0w5ua#r8@Nb#r5V!;8_pcTC`H zvW?@&Uu~!C>K&rcQA3st@aVMVKJ+S|J$vfX)3Nc0f@Gz3k_j>%p=p>jUJW~fmmBEr zh27g%$Go4wV;yJKeMr^VWQg$KVt=ES<3clm$yP|@wYvoWD9{L}3h{~lY+#8d=z|HL zXOFcYLlfNqh6|&xRUO6H>DVr)>yD+Uja!})@uoRT}Y^P#@z$5uGAOJ>u>xV$T$!j76f?c2k zE4w_g>1&AyNK<1%)r?R6B3!bB_F<1oR{Jr@4G%*7sp0Q^YuCVMDHKVFf*C@bMqQs+ zc`|9_8Z9f>C3>v&em7#oMIPRUgGEE6{rmaF;^2o2|+T9i9GNgxeILW8fYl;ei~)TS!?rHglh9<3}52uSv-1 zmNm7<@oZhaX?ID2*T0P7lE8k8o*JlgG0eZ#BW$L0fvc3oCH`VeCo=OoZASVaGk(lT z)Z-JO7M74<3hEh`iO(ftk~?SRclLI}H2Ni58q3C%9CH-fm_;``{_5r8W3sHOBjW7N z@_|{2q6&aP0!yfcXPwLGYgfy{sLOuh#r5cml8+2!_BaMbhSP@+y=Qk34sz9b#ijo+ zzIf|&{(25y;&UnbyYbsobxV?;O)Na{Nt6h0N{mk26{VF2FwuMcY(kHzoX+b10gkvL zK%xD0n9n1(KD-v3*wMCjp%KBqc9YUq{slCYxsUjNUoWx#v)=jl0_ML};w;Q;-<$IP z?b_yBiGOd^|4WH;aBMrk-+}oJvvrXdcW%a@-mgm4pjjSz-i>_^Cg89-h2Kjs;_jrem zUQ8Su^!WKz>NxLIdvop%W2NBUDk-(sWtr##4ZlWNN!6pes*KK`&lnrrY1kEML5k-Q z*r4#(kDPbR6&AKUCla7KmD5{DpzcMD@>_ns2fU}2aDzx6A%8}Jf=x^6QJR(Z4IKws zE!eL9PkD8fYC(UmrmX2t2sCt^c`-#00yx3YWs3~>-rCSN>fTz}SP>032oD44HVf#y znQXmn5pOSKLoUic!3P3eB(&m^rW!HHC>k-)@nB;k0$inoCJX^1fS> zom3LLom{?4yon0?A|-PfPDU&>j+dOa6dX=>d6FoKB)iUDDmxCE_jRP0MZ54lQtY5O zXydlzbV!~lXs^rU5K^58hhn^qZF-4EOQY<3xNcSWV%-?W%o*MkIRtZ=F{oQ%IXY(^%% zMQFj-q5L+e!96jCXftw z{t(#e@_6Z+(+4^RgI3%TR6E}b_x89KjsEQMa;n*bO4Gi1K!a0 z5uj-IX7=|ECS@H+`lFniQjHl&MX1lBp2DIt?5P=jZ{)?-w(|5aa)&uZ=&P>Om_zIZ z5Pd%?{KdUrjz|7=e{-{^4|RO+f{9Xg%U5vkd0!6t0#MHR92>a3_wr&ND|hTX-6>wk zpIdMdjXSwbA}{gJTsoWFGhWPkfa5ZIXtMN0x%Jw}>TkD5F>EpoYYV8jHfrJI$*OdM z_Huw*u9GjfJ@5qbG=E%}>dNhH)Dg|Ps~o6kes%ElEUt>P6=@+TELRyT;}csVUxGO2 z5<3xFaiWizeQ10rdB}IMwHiuaD1C4$sH&~(CoqYkZ&a;p1GUv_F^Uvo8zjbP#UPEE zYiNYu%TyX|B0o?6fGrM~&>sEj@j14#$ivV^!_+$Gg^(yg=fMDB&h#Eu9Oc{T!i(sS zb?Sy7fe-bNSQ&MrHTkQQQLTz!cpe{ms~`qPWn9L^6%S`Fi`zHtL#U*N%!Dlo@isLB2ocUNtpTC!MoV5Y;z4I|# zpuk-(_1gsjRpc^{vJIzWWx-|1)w{-VE#<3sLV{m#6=`s4Li z^={Qx%|*4&$|aTph3pq4+o*dtwP{=ejJl^s(PD?DUA3|98uVs;sbgF`TJPcNrG_TW zMRtRattCx3yvC_u4|&}}^iF?(Fmk+W+g0Wqf~RyH`>dE{8*eOAXWJhM*CK%-+6g-} z$#F1Ob-Vhp852CU1UMSHRo%advehopbf0=8tbA{ZF;w~V;t40ra*Bjw_m>Q>D9JWl z;87?nov9=F5N_Nd0lvg+kv_Jn?0j?DgMZvC7qk{ ziNl#;KDz6cIv77z*f*9O3R+jc(EXdKEne4OWbKSx^+&V7HLBwtS2A4G{XneEVp(9T za%>1MqqWIFb@f0)fpN}h^XuzLvumkvc5WiqD364=#w?n*3EBrJ8MNxZxR)E^NH#W=j%9;S_AJyC?QAYP?rb`Ls6w zivc&))`NSkkF9w}`5tLw-4#rh)ak@EZLp`84gQ9$Dw>J0E^C<^dPl9sJkx?Ut}dmH zew#(APO%JCH5owF-Z8g+tR`ywJ%YUkU^Eqmj7EcVhLh5t8mXp-B~Y-#;$x(y*6eVV^!Ksq& zLe9uJe3umz^QDV1 z=nMnDcPVb9-f4?=qd8H{n-5x0><47pQLhenb##73@>emKsTB~*o<7i)|$HZXdC}dt5 zHhIajOue-J#{O)*C!At%%sFUm(wr*3GWSMI=+c#CI5OYT$r8pcE-qhr^Y2cq%;{8{ zavCU)p(fq;(&mnrX4drZ(PMfp+p~jceWkTM0m3FJWh@W^?vnIY(P)q!m@LmVq&9hl zEn#dbUNAKmCf|;Qd-(dYv!ho zi)r2v5~1iuyv8xBPbA7SXLF94SxQdUQiQ*z-bgx*CaUsdQWDKA2LJOy-;eyeBMJ=! zCNi(8WnJ~h%{>I};Q5w0>=l1{tfnb&T~EQ`DTY>xU{HCGoXM>zb(OE(p561!6RXyc zHhrJS9qsc8^7e>d?rg2gyY8 z>Ubq222*)*9$lCTtug{dZy9JSW!WB%zYHXi zZbhj5$58)NesxH4%@`O(tW-T$Ydr+od-c+gPj;CIr}!u4+qlIAQ;{GF-DQY=$0(kw z6&>~`kj;ULC(Ha3QzQo_pDZ&a%5B>#=#XKF6NW)?|C$~z5HBMu36Lx*B8?^07XR^W zyoY;K+{avLYA0q{6K&5A+$WM`o%T<|k%r^Sv7z@%nkHcPhZhJ02MDvF9P9W7@*cuB z%G3u*Bu`bVB;vj5SmO)y#KhwF&vKnP{VY3xpX|lFF0K9>am4hW#L<7Nfc~|+%LHKJ zWa9ewRyp(czBw1;KPR64*HNK=PDK6t)X?`^&3_$f`roH%qVK^Ka91C@VfPf;Eox9I zn%ml>sq}aS0suW54Wbb|XzmP`mzQemh0U1Wcr8zvZ(p5hPvk6;eq&3U*0$8lrmA9! zsJJAtiSYe#aY^B!h=3}}qJdEe14Bb|BSS;sqCZNYJX(RDB;rN0Kr1`}wg8{6TBIgO zV0?X36oDaiVNqNtfyoh=?okATgI(i;Lt{hW>YD27&!OqTY(xOC3q%GGS{jfOJ5nqt zb5e73WyX)?@%0D5&7ii11NDz7P;&tO1TZxKGPZ+d80=bn42Ue3?f7aj zHMSJU>d@e47g`y6Q4GC+H`2DM0XRE^AfBFXCV(8^-EHj_P*wr5olggKn^M!O4*?g@ zg$UU_+W)%c;P3r~3(i})+2Bch#4t1?46*w}p5C;qtlKO54Rqs^o z`2fic+M_0ruO7@V4GB^p!Vetq7yol3C%ERv^5RV32(ZnA`0sK55YHcGlE1>6qZ`$z#eGo>ykl?9TH2Vtd|Q%{a4~-k`46MPF)@AQ!=qAYo4GTp4L;ui za)AKGyT}sIBluE#XCSJp1(E3+tukrV;pg;QFosOzZFS z`6hqm+ACuNP_z3={qh_bhlww{mC8B!vU};0Vq(Ho4}c`0;0cI}PC)M-9i4>TJ~RRL z_^`(_1w3DIYkb}$g{H0od3;enJ!F0=*WPWh2;4mdO@n-LB*#yj?FRv|e!;cU!%{@v zoME1Q9XWo@9eiyiejy)xxlVuCiz>;fsrjE;elkCQ&45<+sM+~zx64%}?44myuC`x- z?0=@)MSqjoYKlN3V7=pEy`d(vdlc@ug+wo%>KJCCY zaha0~n4seCnFWZ`hjRq*xC|2RkUD0!wX+_OGOqVNzg=P^YB%lc&tryN2*$`SVO}7! z@Gle&*Z|E_LL+cS=`Z1PAhQ+!;|2MXuKv5z;&;T3SKrs4%RuAQU(?oT3;w@AyDJ_M zI|k=p8E!fkq2GV%xr%)uF$AnUclE!vvW@5Z?^q+$eVe!KZ=*BzZ4Ao4jmepR>_Y?7 zaMv|k+(g%P1KZlSljHHLcc~rWONbt*ZtvR(SN!e7p8Nu=S?eu*SM{3sZ~P(pmPa-} zA3WckUG<9(`QMMU;Xqn~qT(=*Y@%L3>B>N~FR4Ytb+FtA!HP@WSQ9L;e_&i_XZhum z49=+)y!>6+`Zb8?W=L-@Ija*%8^`B~$F>OYvyAwdf8TzwK&oVJnTu*?3|!*K_9oTZ zkiHE|Rg^VZx*M5P?wdksL~hlMp`M!zht%c5eVZ&4Uu|e@dOni4UY{)9fT8zH9NMKC zv_IWx^#f;7(G=S<--;vQWR3^S7-qE?jq7a57@J0Q#g2;3k$8W+4rU+abxdM7@}G4o zl?@(F3kpc)e#C%1;#iy92LD|43&Q(s7dP}P&~eb{qzeDk=}@47n2y_5IOZLJ2Z(s)2*>= z)dv1Yp*GdWFsFcrq`twE9vHfr@1~sX5S2qufd(WicAQZU#S(NNZn8gAp@H&5)qFV5 z=?A@82pO+Z8PtV6s>Xn>A{5vmd5DQJD!UI;8+EfP`3`P*8g2S(gp+|1kr~P!7nL@z zBMNE$)vYRWe!B^t2oaIv=xaxaE(?1xNr+ih@R1hrU6P@WV@m=yHH%`3$ZhM@iutRED0Nu zSGz`u7L1sd^10|w zpDDf8Bi}l*grgwB?asS!L^C&}nlvyI znBw=Tv_z|8ORuM)rrAnO+Ua_HzQ-JCW8s%W8V88zy1bkI>4@59Q#P}Y?Cm2rW;T5s zW!3v>t2qzv?S=+r$%-G*H?|;M@4s$w?^6~U5Y&QT9>Yk7@GtT5H%(Bgk5PEjsB?=} z`{>4d2AZCI&pmI%w6w5)#7NMcbq9nU{6r|g{-d`__8@)E`hgtqIGkx-k%k3`oBt9~ z7zV{>yw@)LEryxTSZxW%gIi_pSoY%}ZuSw5C)p+_)8r+-iCYI8FkI=oqng-=S19hk zj{xIU99WXTdmo0>)0$ipZD(6c?pq;x& zZ951<1q|Wi6*|*psNP2xM9}cvr!uZ+E$CMab4BNlFwiSpQbHv9q&2F4+V^r%#CDVo zD8g-xhs$DkhLw?JM<`Ie=v|WkDX1h+b~hB0r-41vRqlODznvcvrD+XILniK=>Tie= z>Te8Q=eU7~kws+tfL%TL*xg+CP+NLhD$LWEARnn{$@lrzTfk-}aGW2*m1BBawbT63 zGdV=JwbmX$tGoQZb?H3u^nWYYME1gn_b5UG-RknUmg%^}Gvdp`pOAk9iF?$Y`B?YZ z@H4d~V&uyHiIN;swB#25no%3uF3;x(U=gHH63tNR=2iAtAS+F}e-9MaMB|wpSTETS zKg`CbJwZR#FAt70{}}sV*8_iwi8pygRugAV=mX^`8Cuj0)x7%z%DR!Q(Bg zUtHyF#4_;`+?d^ND>hEi(humr_m#^W2-o=Wmb|Zi_H#EY2kuXTy$;sM30E1F`dvs7 zj&lMS)u`$V;C-S<>;dY3dN+q(;^SIW9;9z)3ac)YJPypAfiTP&&?ydKb{@8?w?&AFmArch09u1+7ej zu(3sUov~D`swZT0*E&Ca>LVWI4@j>5h(O4_^>#^^R;}&}%hJn2;B3xlq8~tEk z0%nzBVLMesk7CPBQS;7;x`w4tNs1S1a$u9D;mspIeV|U;vz%Aml=L6uTzz|lEG8Vr zm%HawV_u}tNuQ=p+U_Z) zfGJ8TQeqhg@1^8YAaP_*H70@RR;(R2t(UD47Vofj_uo)^S9zXY;6y((@s3%~{~+NV z*b0UAs8cAtQ=;bsEe6P)LUq9A;9MXa%se%MP9xvlxxPH2_kxZpc6SR#F@W~jM()oDakuk z?MRha^A>tNdnmx?7_M{p<^lc+Cq|x|7h)>|SEt~cn4xtEDZ63GBI$p+FPg?wUVAPz zKS-CLdRUBY5h+MT9T_EbfMc?lVCGKJ*mFym-dP@Tzj*r)814H}1h+pne!j`|1N|M5 z1A2XBd_BuFsE<9$n_8tauk9=r%!sRo+X#7>{vI}ka!fGA6EY?O&E7O@6|YPjP4@9; z0n2DZE+t{-4$Ylg?^?>4!~kYw%#Z$FxOwnD`YMV_jL$fM4AT0A9FUo3AIKr_sxOPb zpZ5hCseMUYgR#C}?6;SaDeR>6(SYRGy8=MNT}{45w1Y40B}z>MN`tJ(hcf7o(A95e zG~gNJpj|*?B9PHo`T6FkdXR2Wyos8>#_%PBnhVCmm7~I@$6(q29Ix=*m~@dK61_ z<4xNQgs%TOhy}1)OJ6rdB%@BP(S+NpE z4J{^kR53AJ2%R`8#ZetwL&lq&flaJO(X;#Y^d6x`*H_{vQ>DdGN_Wr3YNEm$41>A# z%}+#pPvawARN{^gA<0}*(VDH+bo(9&ikTXRq?7F$AoOK?bcSU)5Au5etUj>f#ET?b zX77k3BONmE9RiE3RMBuZj=77 zc4%bG7Cg{BqK$FPsWR-1?P^k4&}}54SY}^t*+W@{rqbcx{8J|@=@>QW%71d>6LGIm z+oY*iOmpB<`6-5lbj?A)BIc|<*ZZ`F%v{v=dY!Qw|n}NSCo|Z$zSCK4rgrl%t z{-n^JBH%3wGZ_%(wm&T=I~|ZdQ@06yGnX0`q4)ZXbatfew;^N=0q$of(wS=%5~qAM zHqTV4GPj#;Xhsaj{27FK__F}vDQRah^DR-FDZ}_Z_Br~Ek6~+3;vsCHuA$@3wd__E z3_M*yhCDv*@0sXba*wU^XSI;KuslSBwxoljjljVIC&gev1XSJ6lNpK|=f5Zkc?bo8 zFSu8sbZ@7iwJ;hnhs9ANC1-~Y$_IEEuf|($1D0OCR$-*~sPv$RIq3w4u=&Bo!Q(^; zR6j{Dycf#!l&6NA^w$;1@q>iT&l-g}4r#Bq(5lqD+lr|@mcvhlN@dcNXTxqhCkBguBABJM*g~T6_yNa`vGOn{@m%`8oJ}SpS2v2?kildHXN%kk&Uh;VC7h0T^ zze4e-fI6caA0jc12;y?NDrOV;6`-B-%6^^V(!3vLvVfe`rqx|%GeD}dHRX)UvTh=; z+?iI+E+`j^J|2oA#P_OY4zTAZrDUxS+E2%5Dq-4Twk_~19TCd?px5O)nYR8pI$*NK z2AJcp`<0t%rzwoJNQ*`kUsPMNNEu2!ONxH#V9J&=L*vn^beR}*4ePAeIc6Moi+u91 z9}$QCv`Yj1Ho6m*eW^GV$-JTA<^e^C=t2f_rNE49YOjc0KK~4EFQ7HNeGJk_uT<;d z=-?qFnUchq2{+$KSX8~37w^ZJ7Yunoed15)5dYBLiCEyDW=vH^CcYya7{lD7F3L+o zbFxdV?%wh#LC^KIEzIob=15A3zCt%Go*vFrDon6H8U*^_b_PxMqP5o7_oe-`Kux8* z%`Pkrq$#AoH{hdz^7zO;mW*v%&#a8vs2G z{X9Vsm87t-r?(PzqbBD7$@`-&N#n491EIounr_dITq*;_C!L(WvB9(o}SF#uau-FT?!IChFHG1pCKmY){#tUR2LlezN>g)ESgiq4pdO9S8soRKO& z=*xF(77p-nMemSuj;=*um#h|fe~$Z_ZblV;v^3cO5=}(19~QG=Y2k5o`2SN<2JSKA=)HusnKTF{^0zG@ybIfC%3R= zGqFF^@ZmUl&s^O0Z`H@P-BW+1P({H{TK3Q8o&2i=Q#oFe-+#^1yEUfHQ;+q zqOsaBUfVpldcdAwY9xG>zPkLAJF`(p6GI4WP&i&%6JJchF{cK)fO#vL2T9J-hbzQH zfAV9$IFO{~`RO+(xfX?D1LqQQv{t;H0{?7GaFCl|y2b>=8@8HSPDFJ}Hc~fxXrLdH z63BvL$T`c%@73xlnhYrwkMbO(d)>j!O0W=D?*hMATG*qpMl>*k5Im%;Vx&m)&ytjf z@ksH>>ug=AO2#Ax5bf4OU}E`oo=R(6Aj-M(F3j?d%HMQxs!mvUKBrCR8K!=CT%@$2 zv_Gsc&l53NdQN`0pYE8$#xCrn&&2?>{!o^6HF1cnOb%Z0e}zA(@O8WrzA}XXpk+e% z_)%NP87y<8z5nrEnKZqlJ83pD%QNnZQ>cxEl=4!8bcVs*s4wc4?N8B`ra(n!fy24! z29r)mFV~c-zZQJeig`f`oz>1H4XQAkqd~PD!<19(#1XC6%eW#>$gM=B<6a$vH80RP zRbHglPqpIIv+1a9p(fs3zKnO?Q;zULXvRq|-rtzDgip!-v|Ud-mvEQ1vn%H>Q!}oHYDpiP({@QX_+u+ z4ZaIPUrSx~bX(qdHUmecjkG4${sgm`j&h%kAWWVp!A=ubRMlBKa^ zl6Iilp>BFvv$N-_yhpx2A|nqNYD3Drc#b~iKTIAO2Ub|Te5=+%Z?y03H`!}(R0&sH z!5hMSe7?49>^`FoC6<2;u%OEfEXmfB1SNYknw}^`&v*G)!%az;K589-0 z8ckK_=Y2`^hADZV6QuI`i+U%P{k%ik4M;{BOap_A7A!X~IY{|a^4Bv`1t3*{Cj zCiBWLINfPHm61Yo`weVoi*;(l@7F3?&Ty)SJABWb2n>E82hpzlhq;Fi(h(IBu~)p^ zlXns$Up;2j)E}45?I-Zzr#{n1-1&!NA}n91FPliSg^LfrVJGQhtXK$H$si{a9Csd! zaSa3OKr>#n7D&u2!jhyRT3CB6dC*Wn0^KSoj+{evDU)7tniV0lRie-`@zgO1wp{cz zY@We42{l4!4j{1cTN-HvvUIRKRVwxlWa1w|SC9|k%AzAR1?4B@EcG8V7y& zmC{gNn$sHbr%L#V($7TjMF!>9ZB}PQBvoKIpVRSc0@p#{+FY5}%T-<3192C1=l7CM zW&gYr-?K}~A>uBTf)a@tPEdT1&Lmx9t$lbzaC}r4iR$L-P(K=6im|>G_PwqT=l+dr zz2a{8p`_sUJMLW}%54pKdvt;JQkLpPnVkfSq-La~bihYdyGER8)Xgc-Z5NJx@Ge8> zMse48N2ardPIf^m-g6O|?sr&m;@gPcExeG|ZZNpcL!$O+w9vY3DWlod4?U|>NXXgu zPz+$I^y+e#PHmjcl`G;@E^v58>W-Gvj1ck&W{kP)Z_Lp=c4&^ZC|xVx%~=cf%RJBqnXH@5@p0(j3b;eo zRR2pDh!XmRQ1g!@7TvSG!Vmbd)zitVx`5H&4EBD=ssj2t7bJ<~-CdzE-BR5JqiUR! zsXB+4l2Tj>J7Zrf6-u`|KS|=U=nHK)>cqySUmhia9vTT$SQVqK3RtxB-4HNFkTUUS zOO4>>2TF4l@D7GYh2)-O2<)TUh>AAkGli;BEfSa*m6{{|9&nfu80JrrM+j9#Ya;7p zF(jSX;7{@!U0O#)zdsHQ4joAv4O4skVXablHs5n<>(d)<{gCXs6eCpV3pCl=@0cwR zrGE`nFVV<|(Xa85+wKf`>^@O}n`6m^p`N3@N`B+6NpZPBI;`K;>0Z;TSFb|=3%xHC zf393rNm?u?sgXJo$o+#>;?|#6lYhE#(j09%_#opEm-P_MA-?(Jy}-@A*x(_?kaX9? zJ^IfW@~|_L;X7amY8Ky_Bw8Z)*o?Q`IGBU%VQ6FF68K=~uyDtlhQpgfM%v@98#T*L zW4CAc?glY$+$O$59ng#T%OJ6e2_2DA_AbCWD`YbU7b@RIqXTY3+<(L%dwFy3cUTH; zTdoLDGLB(IdF259i~!8B>UwYJ$8I-}G{vV@(r(6DV|FS1p#0csrYL4J9WaIdh)8e} z25os&cKVNftRS=qFZWme*enX)6D~rl*F(bo@pe#*mem{xvqBL^ul)Yuo z1dAwp0VB8eXl81G9ws(etUgWHV>^1g6shdrptk#^4sC9q5*0>zX4=*i+PRmNUKHie zb(T7&xwI5h5`B#D3<-ubpOw@chyknu41kT`GP%T=Biz&Wt=pC=rRtzJ-Wg(?ar;Iv zAD`b&7q~ZSzm8cVQ{Ue72{loen2}_78(qmk7(wa1))rle>C9z7jo2sBCkYaVg}*j9w1g&!=N%VA6EOJt5+Kh>LWBhk`_U z`M`)1bA|sq<;!2pqLCqItp%@1&%xxpE~?f(RF^B{N?@Vlhut)hn3zC3;`TCT9W=q) z+?@Sm6|_=~xp{pEcRuz?6dt@h0F+ep-qMO{RuO(iK7BJNRk+1*i0Gk0ch%DKXIRVI zDV(=kSf0V6RU3v9kZ(H;`TCm|i5=MCqX$e#8#qebXR}ipe)uaP`ZM^i^;(Ef3nV22 zxoogQsyDW@SBJWb>Oh2a9 z_3ttac@8Gmw3>-Nr=DvT5m^x_SPgT0%5L~R)wVc3o3nwvh?YL3`Az1)vpu}m?Aj{f zM;@{@UhJov=3mFc;H${tGa|HXS18!va)L})#hIK#MnPh8Pd@id+rEzjUeQg-v_Fc# z9ZY-6XeAcUg|?rw$=L{Au!x19#C~%0g5+-7J)X;QSoqJ+Yyzc-8XCUmm7Xu-v9iZ{ zBoe)3MtErRuXDD$blkmgx;m87AUHEn#w9AG{$@6 zS*9A@Vb*3N5!>Qu=~ljw1rB~(+4@)P7@qNfgqRzpCeV7b)f{CM;JYq3>^OFm%T*B7 z*oQ)VVwb~zmKLZ6ML>{SVKmeU5h=RyP~VmjZALt3n5>JMDp%1vW}xb`%Kto}>bCoB z+0cy4uUwifX4c2U>c(6{L)>0Ba$>Y6g8Ak(${^LO;h$`!5@&m;O{wSJyclYk>Nm+> z#KQhnRar*6OH${@UvMK^o2RO->o1OUmVzqxvFo61|Kz;+%XvBACV0+4DHHZ-*8w4O zN&0=Lf=3IwO%k&mgq4X$i}=$BWt@c5wN$H2+<5^Bzp_6{Pe0M-eJ|N3lcx-nsoV88 zroJ1b)R)4iq^FVL@m^oD`li4|ff?c;fxj3fqFcfX&z_($@{|f1Ea3;28_~@lUG#RJ z5RXq=VTy$MA#|E+pjHK;^A;pCx=+Ks2>BMai(3TPtQh5zqR&`~ZJ){WiNFk!mtG~B z`Uo&q2dy(bx*Abc5nk{I&X*;NR+cOlp%+HNbVEpdf?bU(`qPnd zv!bG{vG|;Y`=h=_1&t(gj3xra+YAc!G>=rcsF9)_O-Y|yF_Qg#O4|)ZkaXKpKcyw7 z!LHz7_A-+tWVZFEd|U0d=RnsF?Cz>|7answ z8Uf|tOM%W5G-*xf%;-o!-?2|59e(VfCJeDe=j_XQ>WBQB`!~6!g1VL5d+;Dm`!AW7 zNp2_4)D|T@1#P6TQj*BLgwSxBrKf4IC}@u+S;#Ubq)gZF-&AGO}%hvv6eeYr(@#>iTZ`9$Gu>|3WqScJVkfv06=W0xG2-jc;9HkI4w^qohZg;CAa_j4 zd4TB(vB6hfX5|NNPXwSuN8|=Hmd}x^e-Y2d6LhQJsEU^$A=BsS%U+g5XrH(SyLZ9d z-*!5=9B?vt^o>(s@yCUj5 z07t0=Y;22bPA0)jPI$!7K;r8KTovc+UdvSxLKpwl62Y+5!>}*Z+Y8EkXg7^dWejoZ z`#9&kl=$)dkKk*Rcsk(cbQOUvxa5E1CJQWGF#`APG|IjF`kU9zIaIA_Ie;b_<9mmP zOK^k6k>7WEBG6{^U&M?C9z-xYXzAIl9Zo$W)-B z($kUvJ7MOJse*6ZQ%|PE%!qzlNotg%WKG3hXp&V7_+Z8?n@wljLU6QzZZa68xYuRa zf3=qS!$3t?5uf~W{>Y!iK)3B_7XqM>J#hYw=6w&D@ z-mg>&6C5?vZ+*SXchLiwM%Sc1=mI?2d4oK*>n>w0wiH9elZy1wOtKxYF*R7ex;h$* zANs{K^LdRMAI}qLZ5<-B21F%Gizr4P6y);e2ZJU)bTs;d9$w4^ z(n9@3h|ntM+HF_hLNkBXqX((qPqvQM*UKgPutGz6N29jXad8iS$(d8Etyy(MgL9ve z$Lu4K+jMZj*NsT8JrxF~w<#63;g}*VaejtFHd_bm#iTYHWMn7YAy4A7N%{i1diHVN zh$8`uK6u{eQNd^7kjZ_4-HY_(_0n`Bm7M5dmpoXAw!NP1d&=rmd0>MTUhVZR&f|h3 z0+|7LKwCp|OVj!lBNo=MWZr3ZV<|bRhL*b~T{mmDuqBK{fb7p= zaS!YHMk+ftS5KgkfwX7r{UPOYueOHYUAPpv6uRGK?q{;mf}66$xnJie?3yNpBfk{{ zls{#+_kYwlM|XolJ00Jues$&OF(JU+;}?z-5OzuyaZRfLD=&bZ6cKjsVTMyR1d6v1 z_h2??1i{Bfj^p`Qn#4k{FB-cJtA2$_+AQdo+N+-vuO;z;3U-2WJP&7sYGwHnSksA; z(^w@BV3hE~3QgV(P8mX)4e|q}rP5IJ>%Z*P+!Bq$&Tk0W@TgIoOorgQ-FrZ}#^@#` z7ML?*&D2t1R#z^F9*Sk7Nz-6$wRdK9yj@O3vM&a8P*U=ES|_V|y18*a60 zLI6uJY_|XMmrSpLs1zDml!O=gv#?ywo4{eP=>E*{mA;P~Gi!{<%;#5Lv75h-8~de? zYU8maPBqbG)_i)8B8m`Yr@6~e@K*|};Sf0<`zxk#3eb3>un1jQ&>C-FBvC_|Sq1vC zx1fzcC_H8iE|eGIxQ5<7d(lTySmGSG{%Dw`_n<+xfjxBOgob3pq+kC20g;OIoYk0Q zFxd$6!P+g9K$OGzuxU+j?1Ius`~*y>eE3VhGVk=3A^lwVb{I?Z z#DsA)QR%CBkZ?_j=qd!F)l9H-Kh8S)s$wP(Lca)d%B(2E>ZSHML%25A-B9v4SMHkm zr(EUvu9IgfRE(N#jQNb22?O;8g8;877aB8Q%fo&e5n6=O>{7%wU?+ZQ; z6Mr)%fUBIO`_o>_et5`>UQMnK+%*lPF0f*L6nr^tPP6tV=@(AsU%->EvMItOmU5TW;2!b6cw+^GLI(GSvv29 z`?bgqoSrY@VO8nbW5RyBxm2!~f5NGZVP!zpnZOpfib~Mmg)o3iJ4H69b!0NGmkC3^ zA!4vbi*Dz-!CNd+QFH!E^YtnsVNTUZqe4p!3a%tR)bZ)kcj=<_k4}pv#qJ34GAzf` z+V8C3M|u!=(jI;=CY8$Oo{|7vzB7YgYJKr}{<%AstAYfI>Ad0liR<(JhZ;lfv zaJLlURY++rI^7UUjfWnoP%gRzrK>Q_$ zGUkLC$$ad7-^9nLw#S_7N9S*gQg%bRdW~xs$$L?u$VGfMVBi>4^mb>F9KW<3{W;5Vs!3p>_`#0*hM|NDsR2> zWT#gvXX+V(dd79fQe{F*)gR!mDR{(aDZJnd#;HLN4!o?6l__T%N;UYmh4P-QxD<%I zsz(j36_rj1^tEBj#{~}eYVHiWCF&C9nrM4C%KmUCdVJw(0B{ofHalW+zNtt`@rErZ zN)ha0S%PkT_k=}&?*N6~ZzH$Jnpt)SRATH(80K5zS9pqA?c*#|`*a{ZjyUDUMMZu2 ze-g}{7l}bL^R{2OK7H3w{>_@d99b=*>iKTgai|ijo?fY=r@0*Y3gb1N%???+QvB{e< zv9_HEuI%K}A<^cb{8xRWi@ZmPOhQ{NiJnGuTZ2h2)WyRZ@{6|@zsMhPj?PT0Qz@EV zaUvk&3%t~0ax9gZFHRSZ<{y<*KVitRP+lH!u&`M(jrA z{ZNAksOVMw;^ekj5?p*jg5)9A(<@I~S*@nH!(XuWWUtq?P1-;KkXXNfgR+RMgs6E^ zNs@fpwBAt3UDYyv(K00!{Mc&Ano#!HA@ai_ON{Jtp70vrh-ni4HZTYcTzQ}|fQiN~ zSAOBHU^@LGWY84c3fJ68KNT!09M&3al&43h!ixw>O~~=zLz4WVOAYru;~NaRG$n_3O4$dZs+O>RL&>X=pdPvUhzxDOt%;?G4+4zOEx#)$Rg#%D{{(;%4 zb(A6yHxQmKkXfL9SO_YtP2k_EIOJfEA`9!|r$oKwovroRHDo9+)HR)K5Mc#J0tO=1 zBGNs2ZXtCYgrYMbuy0ek*F<3cz1?2mMyBR3%B}w1K*(m0@9FimrKO#@L98QV@MfSa z-E|P)7!;SdxtqBsAk(CEM^RH<%1_QfQ%zG^UDH&~(7?JaEF$7sIHmyFyWL~%Y#tqM zE?#CH?e!mq@LmSy-TAfP*y)W@KX~DWZ$>&oePTxI7lA8evp7cAni{sl9m>bg+|335Nc64I@G@6 z6DRZEFT#LLKS^58Acn`yt0thVz~8S^>0kSvnJeLTg20*Iwtl%78Jj5=9=Bh$FT(t& zs9xTI*x-EZfq|((IHPxdGd)K{fnR)y$+e5!>9=W395V;Ry?4ttNBfUL^zI*Dpg+I< zTvkB8__BjP_BO#l7lNYo<1>SHA1|@Tzurr~#}B`p`~9U~yAfZ3j8a3RD=&sN7lG%$ zf;OhSw7Q9bxIOT7v5%X;Nq|6Jh@xNnYUr=izf+*IwR%@S0F90Hw`(G(P&&KcMG0C; zXj;#r?3DDDs$;>$heW;aSL&8F5a9Hy{MrCRTA&C(-Me8Ipw!&v(ZijqH~y$!Z2*w^ zxJx}MT=8PjpNK^ZNjb2#u&@TYZ=bpw1-du-;DIq4bn}a20)$FBvGYC)ey34@IIy*Y zy#Jcu;sTTv78v_OtN@fcL3jYd6#YZ&0F=5$cmT{4{Ttbl1uTaW7zI8+_8zGPET<9} z1wTOc9k~W9#}ar(-@QfXGtKZDxzkMhRSdX_`6a#qT*>@T@bF(y|L|W>^YdR|6L?mK zdhtK=lmD4N|2Mb&jr7`~i~s$bTRutnAKLeg=-hKIcWuAh{t-xab=6Pq;Su;1I1iM% zZuq7Ff2SA*K=@`23WVE%VfzhrJUIy@{&Z~p819e%C4$^^bo)jvJO&KBB>n(8dt(m` z*LUFPeue;V8G+T_mqq1~q2x$UnWMQ^4PP^k;99@oj=e4Ku)8>BpO}5_^EVCuc6c5& zk9Ny9ekZ>zK3`J4Wxv}!A_Xrv4I=@V_!AgbKb78BbiWxqKbnf`yBOzp9_;JCZHWE6 zkN5L^ec-=mCbw{GtWDnyQFd2>XutSr@u#~vzZflFJ0<-%GY>0_m4di;xk2@T>}iLy zTj$racjNo^O@Twb`i*jP83_aZ5+`*omYkpccso8f514(=ThEMsx)qy-j}Ir`nk*}T zJA%M{U0lB3)@%9{%D?x8YQOH%**4p;f-dO*MDu?H6`c5rB&Gve zIbIwuz(M-;mY+O!xR`ZwiZ?y4IZBbdAFE`E^ce)ElB!w$U!}9OaUM3*zSY9~mU3mi zBgF#ixIwh}!5NZYLdn`guiJ`N>1`!{=Jb+QKF{66y_*v>al=9+B~`E33yQguMQ_YQ zrqAhC?%QKDYw~$&2G$PqO;d%2PL)^?PFJ;lH1Q(n!wT~L_s^$E#z9Vbry$%^zXrdNP}Ah;Z{tuDa_r-u*!N`M{#)|Gh&yu3{x zt`*kS)zbnU+7+^&jbT4uE=KlXvHsv?w%mNpkVi6#?7lg>Bzgw98S2R{$%$@=T{m|&+~A;e4H z0=+TRc$eo4tpq*ul)6%=h~(a`pn&9}B!>drmfrZ>e=5kJwf?^GpDiu`rsUu=clP?d ztNCl1pKN@E80wTEWF&Av?xOx3h1s|bNj;edJoBF%8xX`?QhablhbQuXCTME!j}QFK zpI?PNr_ZM&58ZdwU*U~{hMaFLE3MQ!%Av&Ny}Ah%Qk&XgWUO|$R)4ty2Qi72)VrsN zAN4>lbH3S|rCHdTq;Jf1>oq5KwxRY8qvV2H<4ei1x1WAJI%$OPv42bmb~;LKDD=AT z`gq){F*|&g1mVauqpz81p6LG-q{~ByUp5J{xqcR>2mF4sFRP*WWuGaLxXW^Fy+~7 z$2nSQ=Dr88ktLrH>jXPh_*x-58RdR0s%3q%Ge@7&V9D4WtdkAG^(jIk31u?ZPIvZctqzunNKoA$n?MGn;fhAVMfI+(tQ$ul3_!qccgyucDfkn@|{K( zcjd*C?=h;zZGttJz$1$+214dyA$O(u44Hv>?Z>B)GoW0{>72q4Mu z-*SNUGz-Jz0Rh}!w||FH2va`Tk^bw8^QP z0ylzb>?~w^wdWpt1PZ{C5F|Grcl&o{k(Sij)O3AWYCZv7>DXhk#hy*C>5Qh=W6yfd z(TbBFY@^bjb>Zzmou`y8=OeW9i3=s_gExBXjB6Ea9ipayOCL*&?78E#kkQ-)({0T} zBCIx1Kzmre#seKIIRC=fQqKbTXl^!hv7fw#=K=psBAJUtKMe=;6{0^ti!F=fQyeU; zx`7};I_r?Pt>r&QcG#?1Z8$F=98bx5tJ8011Jn-LVU2pg$Q98mUGG^VtBH83Ql^yo1_3#FF2t3 zjs9Z)RO6gdHav0zyMbQZ4M>Iswk)saycHj#Rb5{g(p<3WYav)4pcH!IX2tDb(7Bxg z4gToI!gd|H01#cfxe8kbqju z)9r(4C`J&oX+Ghmw@Lz&c}J^UP0oC3%=P%>Jj-LkVEIJ8LI@EiV%^7f=H#K4B9xVH4l^yt4T_B0^vF!l<*q zU|9%Ji&juwWXfrB3TTrOdlt@Ur7mZ^X`2+5f9u{AM&HA^NU*UEE8c(7H=wpuC#j+C zHRy&g-zEiuJU_%Yz_<&=`=&!Bz(Lh(oHq?6jX$&Nz1w#Po&vBoMTnem<=MTd)X0q0 zqZW8wkZMJ!XOm|2@|4qwwUX=lE1#t^Ke+i*Ap8{j8BCK8-vJ*_*{%8F;P|<&*O3~h zQcawp$Hc{8+iE=3ZEcmaiU~{V7ZYP-gZO~hij<+)A~vIV+N@I~PC8%X057yJwPT>? zpTko0PnBj!A6OELd5RCq(VPbCV0#!W38tMqGFNO}F?YDEK^1Qrh1z6fvok$L{VU7Vpsd!zo zK+S*|y|i|-YWM0+0y_tC&GvrL#P@D4U(hn93g^r~CGU)S{?58MZfJQ}AbU_VN=v#R z5tuHS&#UK~vO9l@Si(3l%<(D%9USWPVdB54rsqslqZWb+YDlM9x`bixgPR57x8T7R{U^!55A4t znRhMn2mu-FD|ca^#&0gj8%=8px)kO8MaF&`7u8BQ;E24*z6{mQt_~o> z*TN^sqpZMJI8YVGF&&+hh=<8`>y6%bMEJ}rZ}94GO@tA`j3^?*O0=YhP;6%IDazRX zEVe~lXtK;V`o~!p;hbOPh}nB~n?jv#Vgw6s;i@EEXw}eyhUtMSTCF|;5%;a6^6Qy0 z7|eb$B^~F*d#NB8WN&PSNppvaicu|HHsuX4K;(%K+lQG#cwOJT{@sCQf8oN8;fO}fFgmU@mY96%< zzyNiT$1T>XqlvKa*HFiw!a=B}+sul0MLPIr6D59t#iN$4oEy`&r zS_F!{TU+#S7isDe4XW3S{6YhB9?nihULzm`!LKPX{)oo)c^@PGaj9i6*Qcjo=&wGf z!m&nXj;G5SYQ0v<Fob8p%o(>f<;30HI>ek_{6g zZ_f9M6_;CnCImOimBsAD7jGZ5P6*@%+?6OV4Y+_QxLy-eY})gk)=Fbv?E1Y2DY1KkNx_1#xKGE|cCubmYGGmCyY-~uk@?ewts zfCgf{16iVf4;RDIO>fmr4q8R;`6;~J{c2Je8Lz;#C#v+jC1eY5C%pD>DjdnQ3GdUD z`Q7f+{Qo9Z^s{&~Mi$acRT08@3s52vYxP*@|5JmzE662L?muHJX^!4#O+8V~5xUWG zbV#C*<@?}(dPS>Gct3G7Qx6kd@zGe-Ufd1oL%!4n?pR@nPq^1aVIfsVVQv0!x&1n1 zvDf6!=?)VcYC*Skxi&|6;~>N$Z>uEeNbYGqO_=3lHm|T2${)0tJRKh?#i=~@1_n;9 z#5HT6a>p&%>@!?6wzwI1)AkttvK{uke7Y8MBWYBb9`Fv=kp5K}P~}Phbocd?5w4a+oF`Sl3WUBNwj09bgVA47+1?X#YHH_yQWN zi*i=PP*(3scJ*l;hKm;a~K-pBf`A8CL^NemA!E2MJWi%FqQ`KQ?2{A)jijclncN9?dcAQPfa< z7#qn9DP$n6+wA3&mly>}bI~iHb`O@of#o36{kE-<98vjsWwR9_SU%uIc$ z$bHL^--y=)vYm;7?12>+poLXfRXan_B3-T3czseTS4(!dtN*6q4jfm`T)38UC&zAc zW{Whlp2h)=s*+wJcN7@z5HA=E(iJk$!3^?`9Ax*>-bO96@mUWi6E@Y$tJUG5K=Gfk zMOMmDSD`Q^L{8jf|BRo3CCjU^uDl#S9?jV%SvsA980~I3OQvT|P(I1ZKefOY@2)Ca ztEHRzSQeqD!kqF(f^*Vj8^L&`G@o!>tY`|3o`%G|%}+H}pM6XK@#0xdyb5YjzgUEj z0HSV4mlU}THP%4#5Mgc1r`(zgpW3oFLz+@TF2e6@N9{@>Fsu05JR6_e?ur3wk4C`< z3B(w3ZE=#_f|Une*|mAE)yRoG?7oba@sb?5eeUxWKtsM+|1-^>zv{{LZsJlFAm2fdp-wiLHppR^R z`eX4N5zG@`lIr5=c<*{nn~hhaM+H;+I)->Vb_qQ~Xf()Q1UmjDGx3mVjc`iuWu*(7 z%zJoczMDUkMMS0C?TN}{DN+BFXCNwRoSzfkX*EKugpcYAeTf6-avjWxwiRI&O!u0} z{NT0`n_@l05xS1UvOFxq1axLRq`)3W9Sc#lp-{i->+=e0p-MuHGccwNZhq5;5BboA z+~}0Z+HgK9fbq6zvw`)$3y<4AQ<_|OZ%wWxwU?N?MNFQEpLQ(H4wtBw>95|b3IYtP zAKK^MA&@A*)WBrWR9fLpX$iER(Tyh1k+B{$}?-_-Afn6J!#xK#@^^p;&+_8?LtC{tuMpkK0g2UHNo_ywCTIE zvgIWw;uX;uD5py&YRJHA1Pw3ASdKQ#X3h7CZR3En(@@$z^SzasUq-ya-$cB6U2dG8 zxiihrMlXpQMb0mUGg4C$kTSb@{2Ey9LnAyl!pp(xZQ$bZtvmZd0zuEEeAQVWtF<)y zzm%0{W)?{FF_<#tbwvtIr{*K8!cS3%@!ebFBM5LVsA=DwiAj~s5`;h!ZQ^Kx@hGke z8G&$I=};Wq2yIU|XZ-#Z@#8t(8U%WbDoo6X#kzL(hR}13l;MdvjB1gN&v_lKT#Z=F zJ246FRp}EsQv0_9O$TVBfX03!_NR6-sYG~CdyeS(WbO(%ux~C-EGpOifi>ouFC4k$P$aK8= z{;gbzod`?oKM8*|OFEPB9137-8z^Qhg4Ls>F>_3H?OOSBP-9){PoX5Y`l$KjuxjE`FM3d?_smp3)L-(V#3C`{W>VUl-s^byZAgXqP zO{Z~17dGMnEB2d_(@7~v`81dlVYv9uO16*vYWUJ_ZlLCt$LU&2RL)|9x2jVccG|3+tKNEU0Ians zms2{5U2BYvWzJtSw1`?OoQf^RG(I-OP<@BQhE$?T2=tOKP+>c- zsqN>V=$}GYfdKCXgHxuM!Q?x3IrrN*m=Lx3yM&^DF%6fWXmr$J)dG(RsyNDtT;yJ! z=O@Fcw?Ps6q$2~7=O6?+))s_UlRW$?4cv4csvOVY^E;2gne@?Yt`qz3JxR9Z%O%1% z_iIcJO9Pb8U#*awIWerTad*VEiK;!e7At1&^69c##u<%-pGc33I{8=0*g0Vb$Y#Xk zohBU8)4l2Ag2Gp6e0HF241D=Lq9Fb*-NzNS>dZrr-ruvb71uhjfiNxkV>5YGB+VYM zd!w^w0i3p3vR*0Di@F~P@@hXnAe&ECz^lLK1k1P<6P?>R<|Ul!UaR-ycr_)aB?sV+ zT4T?Yy>v~STwmh$6Kk6B>1%6jVMmo}$9p>4<>&#=3iLa#O2M$PAr)?%Xtv9D<1qBH zB-MC)#h$|XyMv`NEK=PTU5kCXS5?;l21o2HG~1VfK{}PyzbT+3+eTA2FIJ61q^KOC za7^e@c+=gj{EzRCqSVfKsc&JkW#Z6rSwkRxNLaPNdwB&uqV1S}hUfRKo3GwlNr9W; zyjrGn-m5odkV(;p$WzpWx7W615xI891L0!}o9E(Xsh!;q)KKtk9jy_VmZac{VyDMv zF9I(y-+Pj!6A&r_=VS&Owpv^EyFsn38x>kR1^v{HGdCsM|DKv_?Co(N%RyN@8@UVF zA&wtrF_qkaKj1y=t1b7VDY0zvjUl}0RYF*)Yq%=SX(}zy!}Y7T&ik&Y9nl%HUFtKA zW0I`r%Wt4^3^WX^r;FEWq1f-0IvL;;KwBG!>?oJpE?tSO*pEy=5D}8B$H_z|Wy`UU zB7Ms2kj6ZUXCggU3Q?1Nr&x_%bZoG+^mhZUkaHh_Fzu5}R3Yr`NZ~#m7Z6LeE=*!o zNQPHm%|f)zefoR!KwfS0HA4kbn^?t?)Whmf)g$cFW}?Kf3(6*2$-ts+kSQcm`ZJpa zX1RH*atR7Lg!A>zLZr!}ls3_t9cE0Kn$;834pzQ|p-8t*an_UIiXZbmI_m1`gV?Js zz)DLzHPvt@K-ryzlIj;9T*L($v?b3YB=Faeh|sWCyPzUS7M-pa7|3!#4~l-13&cB* zxWSX~9p=RPdOH(o2-bBlke#_)V?LbL%mzdwp0M9*Hnctx_eXf>_%n~Pwb^E%58YQB zK-Ap@q9B|K1ps>^(L#_fJWIvA9Cg-&=$*YZJ5Vzk><2YhgI;@nY zWZ=6`lCxTv%EuWMPu)Uv>}GRQXfwGt6jz^K67m)O*ujz@b*VFw=#P4O$-Q=NX%g=C*(rMRAMDnVEC<|8o;d)ui?_RH-m1*e1=om5YIG5_v>j&t3X3q2`o6- zs-XP(U7=m*Cu!P&nt>dINz?O;HyJDx+QA*F*B;$~Nep!$%g6NODlGr$JTNrIuf({A zKtGb0NZg?W8AffRk=771inJvW6H>uW+4-BUBcwP$GgDULl+M83k=Hy51~#n^(7}EN zbCbP1ZX+_!ye6=T(XXuubnjjuN)ueUB}2*%;lU9htVo9jVeMLtj>p*4JU_Rx>pt7v z9pn#*b)6-arzhJ=xF=|pt!DI7sUnxH)tE0eL*kYKa0U|_B=N1mcBBR#Hw|_^w566G ziPx)K%92$0q_7cUH*6r6Qxq@~lYRb-tcJ&+%~ymz2=Xrm4AM2<%5wQXsZ&oRwc zaoms;9n^Hy7nr3#`Xd{s*PsZ|%45`S*HcY!>0qEVE!b{ITJPTJZ-$`mJHBn86YDVB zr=QkW0xR%BD@lhr>|UzKWmaY!{gvfU&7_9^Jk1&3b9=bBiVK+Oxx>UDcSrO2*@nWQNeZk;$wq#;$iQQ2SC4RqwIC1?FJ;#5j4!Q zfi$J~P@_aq<)Z$V&?@4qgJqor$+clKdva>Dz>NK;O=b-on2qn`=rG5Jg#>t8y`kc0 z5YUT5%m%}W8!O~d{wAvKDRsCejJt zp2EnKkC`SQS~T&d;UJ^xYC1$4Yd;A6+=aNCLn5gjeN#O3H+MYN)ZL?&ZQu z01{jHW-6+#JT+3^*h+)f}jBuZib9v>BsY7SN{J z_Hx=CiepCeu@is+)sxrebs&*n#Z$H9>v=?Eiv3rGP<^=m_Voc@Pe$AKwnTsTDfDR$ zOs_(apP9|)k%v*DsR9dy$K5F}@l)=&!3$F76sAk5q4n{0z3YYCQ|>9$_{ngWPcezXQ5;Y*MjB;9;Ak0!fRtW_+4*gBnH{VCd&%-oQO(NntC z^R}zn7d`Vd2Ii73)uZuf&j=%WEf<M6Mn3=#zCSI3&YVV$}U zjeSo4uoxxn`~I@U4K_dUH1maLscWZPH@w;KEh!r--;Szdca;@swM<2Nq@>D%a|~({ zcL2Miu*=}uqG|v)vxb6;u~eGyNa}X%%KQFlYTm@lx)@4E0Qv5(u=IkFq5JE;q0351 zkPo9JG>bML>1t26*L$0FoX1)}K2%myFE_%4tyEMw$)U^;%_bDgX+b87t5!D#%7EAia*s=B!074Wj{L@uHp+Ng@fZT?E4^gW2G*(J+3K%o zVj=|a#=Dvu7-uBI^6h?<;6v1}_AqyBIrck5)A!Da=$3$#$x)~&txcE_mjYfKBez^N z7qnzxOVj8z8fP`>ax`kK0pr%w^H1Lb2FQwB=d9_60oXaW!o?%|yt7R?=mTZ92mYYi z8tHI?6cLmp4Zq2s_mL?L(a=@bH%aL`TS^8dX}H(ei(=NIYBQop+n6;_KQCA^K~|56 zGv9S&IY!mBLtm|f6$p|GX!07}0~+urZIFH2q720FTa8U#)(pK!9Y+v=REcr{>X5yDfb2GsCCi7!HXDWA#7FxTCI>_pr=ydOJ3K*seH3azOvbxF!%PdupEYEL%+K%9 z@`u^52}-sl-_Uf9-1eaN9HqrvK1*p5tVg zY2>Qep%g!PHTC9(yR6AEYyn&vsP)_f1kMk^}Q=iS8D3|&+h zu;1F`^e>it?F6BnGrf9J(nJ(*JvioQdsyl>A#^R**gB=+wzIsL zVLVG;c>`WcA)t$Q-@toJmKvRPFk=zB5_rN!YLCM4v7C{(?j0FG1>s++yf8uMs74?Q zd>(xH(#A$p4$U#HH9{j!?K~joNtk9oQ;B!0|D*~lCR7TKPszNoCk%i)_{RV zUXoye(kIRSR()T<1n_7S8g{AnIT)6Lz4~>>nKu0s#^rcPgzL%FoW`~T0q<4d*Rpo( zN=(8|A?A*q(Z2rtyPzWA(1-<2$(;(tic7`uHsViCEHMAca>?nqrnQRxqf@=QbCKfK zE2hf8KgM!EZs`kk9t0`7E6+a1KwzQ4!f{GlJCW49Lx!_wLnS+1H*FV!$EtOS{yGWl z?9k-+byQMAPeE8q6Hd&KZOjkfZh%XC;SV^1Vm}&{FjfRaZ>bFt*N=pW3Dn z7jLt#JNsJNI5A8t_k19q#MvrDY+j?1oLn(pFDo>6Eyy2rHJWu^dgTJeZr@+PoaI;i4cyNiW>ZMS{se90s; z%pO)lJAV@4(sW{e+>-=6uASm#s$8Tzm~stJiK_gTl1YkQhTIeWxHI*rkXGP1OrUS* zN{|9QnF0one%&AP<)_8ae;2>3Y#OWNUWXZGgp1^fOQ3!_eAw(TCqWCYE|yAw$pQxdVC}G()!TCKIXa7Mn8u@p}kj+FaQ=)ID(pzNpV{6(Xfy@FZM`x@DyTB}) z(yfyF`sq!xF!jvp>V{eKl3!9*?70ln7YV&T25XjHx{4uR!O8-|q-k%Uly6L}`q&O6 zsDcKMK52n_%}(T2%QZZ*kraH&VYqFBdeQcYuAPQ$T;JWf%1A?`PTrv0Sk8^Tmk8Hg zy8|bZb6~-ivYi3*?zI55l#4+JS(S}(eOh?lsAy{QhP==|-2x(2ZP)ENhj5jj_LLUg z&A4v`Y&hb3a3k(g$a~3IC9SnU;ZWUXq66`Y#mD)@X07+ySE|E$pMFRJr>`FLfd!;C zc2+l-?fKB9Vc{~-BA|h+#W~WXQtd7?xG_#jH^q8J1(9nNm2-HbnMzclsr5WKvQ`AW zOC~;v5VEyhL95g}vbN*N-0LC7MXui_rl1%k@Z@Xa_ob7A7Xf%C-!xh(|KI%Z)mY{6 z>Zh#IfhiT)P1JdG+H5237^#iw5s zw~m;8Lq5#*x;n*zoi~Ayb16#*9PbVziqfIN$trm!)Zl!bYKyWi4N@N5@k0{~3X%SF zX6*xf=D)I9YyerFu>&til?I%8-%+`t7I&Ld>IwNQz71`4ur(;oa+u|AU)2-pY?SO}g`N}k#{24b*sPcgR zd$8Ryn0`^FRwd7$W-xsu{Vj1vzpK~*X2jropmZ#x_=74Kdm5Y#DtJf^7{f+NnL2@K z&_$uDFMXUUI^S( zGxovSkGpAIUB#^OXmHz@yA|?8)VdNamZ$j{Yamsgmy){UvpKCL9(SDKB$L@s$(3tp zVBP3QzLPjNOq|pD1V0t$6>#aDJE)hTQ|{UK(eeq8d$;BUdJtFWma_sqVR5u-W)PkP z+|Cw{f+u~*mDZ-HTUE8xrW8ZId^Y*L!Y}R2X!F$IW3Yx-+9 z$?~D-Bsb;7gV-)O+eBhA1a?456MUh9$L5sRbR2TItOSaNfFyUppB5&A-0#yK;@_~R z59^$&f&}sLh&hLvCnlRsTqW-ZNWO6_jX#)#DyX><6<>RULbKxAo=vdZcE?CWhA|3&@A|NT9btR(mO~E$?ZJu2}$AD?g*Jb}8>FE~HPz$6N zE+tqqWX1i$cXfKlc(vgz0E^_Y3Gq^X4EJ{nbd48VulIV+x`Ikcli3(B&Od76YXcTw zb`4!}L9hDlqDKwb_af_ls|`w5L&S4woFH<@CE515*S#1-CGo^2I)okh051VXGqSxD zR=WWDg<7U=G>x{SIP^GipR6`o;K~#C67#67vhYdJEIQc&_$1mqS<{#QI#rc*{;p}q zP+^{C!=xALAe;po-C+e@#mv>bVpz7!PFV}N>{sak`gSU>U?T=Ym)^z0Q^V{pYJq0@ zRLY@ksc3o`Qb=g4Kz_s@Ir$*-$GRVXmbx1lnM~YwKXGy&lS#=y&c*jTFRbM0!)9xiQv6;4DQ{0!`n0RUs*gSYQ8U_ zrA6IZv?=77$d2*K88$&IJ5hcAD<*-5_K~*j)P_II6DO|!i?MTv6^04A^tEl;PNl2s^mB~b1bm^YY{23QEgMr3+;X*RB1_Kd zt8W4Cg6tG15BJ}oZwrcRfkcBE?lUL0PX+CUe`)Zdx<#9)+?G+vr}ggnt}k?-`{oq( zEdfvGz#+nMgi;>Dv8a&4Aii=syg~T?9P$>OCnEj+ObSGe@W?O$O+JyDbz?+&ir8%l zIrR?c05NzMtSpWfH^6~H5tcMjbXRq@f`Q4oa>`!Sj|n^lO6sDn%<9x*C@T+v5OXhQ zV&nU^0Q3LYtQ0dwNhX; zR__^{ODQ%oiuwiqC1jB;P(7wIR5lSC6w$h z)cO8iSqTJQdjjaAdtW+}Zf)>0Vt)XGLLE7p=`e*n5JU~#>kWxeVn4kWdw4;aQEUw1 zJIgASaD^_d>wgL|aezPWz|NbtLAy?#POKL4 zl2YaP4cK(#<5EY2esw$HsIl7@;VuX`J06PJxh$fQyHi@1gzJCp3rug<@`Z+x&>)lp z>4zlcH!v1YQ*K>}N(jakcFSyJU-as2ZWlvH-e!Z{NHc86^~n-DLMyTn=W(bi}NA(^Zd`xq&@_ouyx(b?HJKMOGnrUz8nxCo{ za_;Aq>n)H&`sHohK?!WIhPIp>!5cA&p1^cy02I?at z)_;q%>YmR?HQ~NeHhfulA3V#l1wBVKXGRe4I@jX0GmK6U6xi2;X99S%_L7RqI$N-j zx*oWrjHGqGaFMHB^29EZ(=AW9G^Ig_Pm?hN%g}^UFjYqe9x?}s@|F?rX17aPyq!7| zKXCoia-61)COr7`pyO~l{01TtGn82dB3GE++Ck=z|A`e+0YjFk$@BaT`IHSlZ`(z= z*j5K)wU+mK9%$C%<7%hma}tss<{O!r~AK)cg~1pOVp`){oGKB{nDt4iAj_U;F`izmY4j z_!v-2%uh=aG702jpbQqKR5=rMt$JaTTWcdN5P!TBfl*1tXoy;vytpy7Q$)aDB*C946$uT?{C3p(8xWDrJK za9s9y4@EIo7jo;V7M7(HVx}PljI`tAV?i*#RYMuvx{@PACECI&ov|o4^aFLfAw9j1 z%wZhJnvnQE^f?U9r4MOu=;_A`4p_Bmn9~v?)|X?{jO{^k`tq}#7h3*PN{J!2}q;x>RvZM!s{MA5rQ=SO$3kad>cFa~s}FJp>wyS$G| z5tqo;VjOgDagyEr4D6iED*$X1S`*}VCjwI*`dgLX6Qg_Lp zx~os$IkJ^S9R|^}^HfUxE?{|F`|(UJOT_24VRc2&nAPsj2~6MvXb`D?)WV|ukp4Y? z6W#=$>rNCtq2KF%@v~SO1cPmnDQkt%qnlSkr=AFcdmb#fNy$e7RRMVbqJv&YJ7+_j zxJ^qm71gJbc0>0;BC zL>Hg>a;bra-4!=ANYRA%L%z>b)4b$R`#`4{9+->CfwWH8YrXR#(7H&dihyF54#@Y9 ze0{(pK?G_76Ggf#EQ`TLjU*)UiNlu3*)(ee$-{=~PZxDQ-S|;eCb1e6=ZA_jibSpY zMbYBp?e)KehwmcSO|m1I88_xX0xL^ zEn@w(QB5@ZOgICWFU_EAEA@uy4S@oE(UTzw{P2CzW9naBIgY2!08r^emGSc4%c@Ex z3lT2;k*O_R%JpubRJ03rn`)vPw#a%gf2L2on;*_aAo*b#`8e)aAt^?MmGF9UkbmLfDT&?*eOgHctliwZ0CK+bAt1z;Q0w|_a z`N}e5TE^Cu<^-8x2?K?DgEQu(yx}Ol6F0?zmiQ43rr?>KyGDd1RB@)Tboa;Q0D(Ei zx^q6E^@nD-upkqDY0GE6s_nQx?{LH&k+?Bi!l#AlDt@e=2!fG(jxUv7K@3WRbv&sM zrY|Hjib;`8zry!%UA>MgKT`veXFHG^)v7uy(Kc`9KGyi8>l(-69A4wXoj2vp9W>iWX{VW;i7}(B~vW>1cAT8sgRt z4KVbIdVmDEqnV568@!s~tz29# zCtmvy!W1F!zd_Bv3_x2E|x?tYyM-~e_OMBD}x;vc>K)k z(0Ow3Q4g-32=X5^Pp>fG$5a;TKcSD01;Z45>+#+Zw%_Jy!@p~$4hLA#paE*z;{JBJ zYf^=g&!(t4A0Q~$Q0(K5N4LXpaWgF z>EgxID*@2|+yzfn@R@?Ii;jTAyg2%ldt%OnicsasA9G2w5G=EX@4Xf4HJh6Iwe&}v@`o8WS^HbIgHL8;l;f~ z&FGQdeg2i5vbZ+sYx9k#;}fSI4Vo#Rj%Pg(Gqm#m4zXLfgWQcW+S+^Jw*wMahXtBdc0x@JcYR>-itJkdh& z@GgAg5#Be;|ACPv#*_((ZH4x^|3Eo}q5t`_@Fgu+A7zTLMUhL=XkOtqwU&=r-X6?T zT!n;g7NV_S#=tLOSb#G={QCKBi{|Ez6|8$R?sAew6;Tk7%jW=XeAM`I5VsJz!6vAS|I!p6d!cjxmH@VX{MB%&n%9B}ibAUBvPqo3HJXApR%`)UaY z-#K~2eJ!7uiYxcJ;M!Vj!og_VYTkpfvsM8mOQ{D{jl34ha&Q#EFVWAUbueaLtpOTg zc)-TssaR>UnpEdsplc*afjJqp-~;3KNa?M33tD%RnG0p?wSlf7x+B-09#%I*&cU)^ zMDLHWkwi-sf4vf@hyi_^5L=nAl}dukX99&E^NIE#c(Ke3_~qRgF)nX4g2nl91`voX zLW&L#Wf~r9W${lB*!=4g4#>9so{a9XPPMg?#&%^A6Yx4QWC=FVtol-Zw|A9-nVs8* zf=5O~>uPFG5Sb6xkCKrDN^mibxd@7657-HSz;8bFHWmPLtM5h%1jl=1A~WWY`RQ4Q zECNK+toM|Fmk&+KcxsB9W>cm!u7!RMQnZlKb}t#5cHsq7_L~V6!wS|jN&=Mk48lXg z$YV8uHHnXc9n8&Xa$Mh*snAAYu``QTRvoDk9=Fg5Oi9sujHJE1GpsC&EMNDy`wR9n z<$!9YIE2(Mj_1yeaI=kBGE$^RV=cp7$LE=Wge>LUSJa=*SQ!pAk4H^C+DEYP5 zKxV`f<;p3!fKYEqI@bntl5aa(^1%u2j^G|>80}Isu{MiTYVo}J^#Di(=0Q^jprV{QAtOar%3QJ>G1{Ad?VX|nQaMdN92 zR{C{sBc`votq!+Hp~82KahB?cyX$9k|H@lrm_+0C5;In4sS_o&sKvum3n{L{YVaDFaXZ>7JZzl_}1Ife*i8&nJ;DGJ@&r}f8V1z0<6L5tk7 zOV#K@L2?#|!W104?$BtUU{fwIn{@zS1$O_WD}$9U9}6w4iGs}QzY(?kNSfFCPljc+9ORE=BG}uQAj|eP2a!b_;@(+@9?i{s~)|nkVw$U1nyrZh~{Kn>CtV50TBaJ&QG=iHhCV z%}S>(jjgPmRF5ca$o6{AEx9-y_^pNVw*|M-`zu7tu||MoGz)t{B$jQ z(2YEDHlR&#CxOHtgptV`XbMSZyEYHu5)fHr(0G}NH3mf1I5)Jq5m(S!;c+qP%Jq^# z6%>o+CF{B1)F4n}P`_f6J8~e&yV%4ide?k0&WT~P_G=t(7s(i11%h`0qrHQXi)Fg} z8Xd&z>OFKf5IVcm%(u3_Eo;GXAs#E7%MgljcESd<`aK}5%>JyQ9AKSF?Frt|si>6Y z)(B#z_PdJZ(zo1{+MCiiUXH(n!Vagu?^x;@G zB@s0mGo8g0^FUmUzMz z-o8`VRS$CL8Fhsnv>T4LBptc1gSP+u0$nWgFlex?TXeT)Sgs=5DtR|G2?ik6jjqjJ z#8!@MED8J>l9fE9n4za~h%?X({8ss~mfzu!0|5umiU@eS6UT1_6Ot2Wx3r(fUO@Oh z?dma+JQH-C9}|wzgepmn`SI2FFp!UDLi^Zb!UqB-a4Jo|f>k&t1Smv~oK(X$b`>6? zI-vYO1cM+({!CDUw}=2pd@<#H)?Hjql{X#iXx~uCANF>;>5@8&yr*W%uumchSSwzf zWb4g)Jvj}&Aip=&MuEU_B8nq9!mvMR62|WXNErsJm(Ve8oLFd&8^fljQ22Q7Qj#Cv zv^+q@Dj9fn0g~m%;Z?N%#-{@Ec-GlE9D~ z4Jt$zS04INv`7r?0HS2$c|xL8Ph~p_X9-$bRe5Sk4k(Qy z{?E%zox#pvo9(K$VyVkGuGibu@5&z+-XMAB_=`^~fWlO;WD`@4mS?NV&p=5mzU{?& zLxN8Q@ZurwL$y>wnC^4Df@MML3(zDA_-b2yhV>J=*>vC#TW%S|ACnDM&9T_U zqt^o+l}j?qlH>DDm=LBzbt0!b2|V>fwdXNZ2$MWf(?9BFgH?cxFdt;)zM`PD}c08?GWn$*-ow^jPcT&coq&_! z;nYzO?N+3(R=O(i*omqJK(Qy45Zcw?ioYz@Wjs13RS@~`l3HM<*i7)0;GnvZrLFPF8r+>0BGk}#g!gZ z2Obj1!6wzw_;J?bv4%@E1s~pAT+sU8%Xd-Ih_Veyflzw?#$Pwjy!HE#(vZfyi%SzQ z3~;Il!o16@RixFLGo0QTJ!mgp97W>h(FFXuy2;U@q%_NIr~0nR)G;7M;#*=T)y(TH z8Kk@2M;qD>UNjWyRqi|R#ta%9y#e9P7?-9`2Y1wRs9w=f@Q7!5Eoj?G%Yp?j|3}N~ z%H|01=7WbYlSg&~R+-&lA$8-s;ID>lvT=BoZtN^8GCpYikWn$+tqal+nD(;V@M7s7 zD;){vwp90z)5YaS)@~N6>TpDf?I)+U7a4J`JMsJ>CGH-K4-&UyRO(FpVU_}i*}tvN zTxB;;F3x*-&Bt4OTokb)F$|K%e*2;NYnsQ1ZL4zt^ljp*e}D&FLtJzm&xQiIV8A$ksn}6!P6^dv?NtXyUON0%xcpE6L?#6V zj_&3X+pP{&n4oBUwA4f7?-Ij>lHaH61+_X$(ziZ4XB;Z+W-OT@MXG~YaA4%WQZfHX zXq!iv9$;N4l=VqjU;CCRHpgE)>~kl}vMU80&U$!M9G-tds&pcAmLGkUEaKZ={?pI! zGR{UzGCe0&y!0m{*V%L@r9;}MRtzRBFi}{zWTA+)Ei1@;(R{{p1}%|%bK#8B`>aAL zk#frCjbraRr&jS5nySjtX5}@iFi9V_$WJ4f5lBTq&lezv^E$#Rbopub++FqNNOhtj zs;{8AbLakNKGE~t_Q6_b^(hctP|)-=P9bq~1RCj&eriQ8HM5L*PdZ95)m?Og%>CHn zC-2j29}x=SV9JvT=g5m%FHc7&kKdLc(VBHkW`=sGAc@(>Y*;pA*`{!kP&fzm$<@2b z+PN6RReI_)GN!wD0QMq6JlE-hQ_0Q|>*4M6Xfn5;oibrnic6LJ>t=}uykD+X@#2w9 zh2%drB91sa+3R?Q4jb<&od5~rx6*ZR)H1^_5XnNco3Xm_zn z1g9ljfAv|!vnYGI_Dy;k1l}HD9D@uHTB3usHJQq<=eI~&b<3grF?{g6iaFZCu%$a+Fo~D)RdY;Z84vx4AE-5OTeTdYf)h+-ME>xU9m>8 zO$%H&s|rYje~$R?YIr%@fU*Rm5BTOU0}N1IQ!ij(YJ8^S8ah-Z z=u8KNB>;_uX!ToS*bwEPPiP_L~`>gF5I5 zq|G*(5V^Ock*_&`hjECCPleqjJUXmm^xoLpAo6lYD6(M**BHbw!2K1m-YRSea9@2r z<)bGTZm0HNVuV4F-+qH^e_=Zv37IKzW8+BHLO>@XY|fQD$`Um%?~)KB))UT#u$O%n z2;VH=fe?sqDgVHM#uSpVeik^SVo7qP59FH_<_~z-hwU)?dum$Jxz3q2PrCz5P4?Yt zPm+zr^EN6*cFw-y@H?w_$R9WOCpbyX$Y2%GfD4s3?!?Ej=lfk* zYsYZP6Rv+8fUQ^0Lyqc%_X(!zgYt`5RmsX!Ye@_3q$ENfUfK;Z;8W)~1l9G50T_F) zRm%Zp{Aw+TRp9MwK1e1Kos`vKt}S5!JjIny-$w819JELXj)sWxy=#KKiNyUL^Eq+P z1q74GN2i;RHD-r{Ai$_U6Y1V*yMOcYV6hW$_ad{cy;psrF}`u~#6C2q8_R_CE!8ILi-*ARNYLxXlK7 >RdsCsq-i+ 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 sT*49RL6T diff --git a/MohamadMahdiReisi/Problem1_PostgreSQL/README.md b/MohamadMahdiReisi/Problem1_PostgreSQL/README.md deleted file mode 100644 index 8b137891..00000000 --- a/MohamadMahdiReisi/Problem1_PostgreSQL/README.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/MohamadMahdiReisi/Problem2_Redis/README.md b/MohamadMahdiReisi/Problem2_Redis/README.md deleted file mode 100644 index 8b137891..00000000 --- a/MohamadMahdiReisi/Problem2_Redis/README.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/MohamadMahdiReisi/README.md b/MohamadMahdiReisi/README.md deleted file mode 100644 index 5fd544e5..00000000 --- a/MohamadMahdiReisi/README.md +++ /dev/null @@ -1 +0,0 @@ -Sample diff --git a/README.md b/README.md deleted file mode 100644 index e6388ed1..00000000 --- a/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Cloud Assignment - -This repository contains the **Cloud Assignment** for containerizing and managing CTF challenges using Docker, Redis, Celery, FastAPI, PostgreSQL, and NGINX. - -## 🚀 Submission Instructions - -Please follow these steps to complete and submit your assignment: - -1. **Fork this repository**: - - -2. **Create a folder with your full name** in the root of the project. - Example: -``` - MohamadMahdiReisi/ - ├── Problem1_PostgreSQL/ - ├── Problem2_Redis/ - ├── Problem3_Celery/ - ├── Problem4_WebAPI/ - ├── Problem5_NGINX/ - └── Problem6_DockerCompose/ -``` - -4. **Add all your documents, source code, and configuration files** (e.g., Dockerfiles, `docker-compose.yml`, Python scripts, etc.) to the correct folder for each question. - -5. **Upload required videos** (demonstration videos) to **IUT Box** or any cloud storage, and **add the video links** inside a `README.md` file within each problem folder. - -6. **Write your explanations and answers** as a Markdown file (`README.md`) in each problem folder. Include: -- Description of what you did -- Steps to run your solution -- Reasoning behind any decisions or tools you chose -- Screenshots if needed -- Link to your demonstration video - -7. **Open a Pull Request (PR)** back to the original repository diff --git a/Samples and Hints/Problem 1/README.md b/Samples and Hints/Problem 1/README.md deleted file mode 100644 index 386d0523..00000000 --- a/Samples and Hints/Problem 1/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Hint: SQL Commands for Question 1 - -```sql --- Create a new database -CREATE DATABASE ctf_db; - - --- Create a table to store team information -CREATE TABLE teams ( - id SERIAL PRIMARY KEY, - team_name VARCHAR(100) NOT NULL, - challenge_assigned BOOLEAN DEFAULT FALSE -); - --- Insert sample data into the table -INSERT INTO teams (team_name, challenge_assigned) -VALUES - ('Red Team', true), - ('Blue Team', false); - --- Retrieve all records from the table -SELECT * FROM teams; - --- Update a team's challenge assignment status -UPDATE teams -SET challenge_assigned = true -WHERE team_name = 'Blue Team'; - --- Delete a team from the table -DELETE FROM teams -WHERE team_name = 'Red Team'; -``` diff --git a/Samples and Hints/Problem 2/README.md b/Samples and Hints/Problem 2/README.md deleted file mode 100644 index 7c683334..00000000 --- a/Samples and Hints/Problem 2/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Hint: Redis Key-Value Example in Python - -This simple Python script shows how to connect to Redis, set a key-value pair, and retrieve it. - -```python -import redis - -# Connect to the Redis server -r = redis.Redis(host='localhost', port=6379, decode_responses=True) - -# Set a key-value pair -r.set("team:red", "assigned") - -# Get the value for the key -value = r.get("team:red") - -print(f"The value of 'team:red' is: {value}") -``` \ No newline at end of file diff --git a/Samples and Hints/Problem 3 /README.md b/Samples and Hints/Problem 3 /README.md deleted file mode 100644 index 9f0462e4..00000000 --- a/Samples and Hints/Problem 3 /README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Hint: Basic Celery Task (Without Redis) - -This example shows how to define and run a basic Celery task that prints `'doing task'`. - -### 📄 `tasks.py` - -```python -from celery import Celery - -app = Celery('simple_task', broker='memory://') - -@app.task -def do_something(): - print("doing task") -``` - -### 📄 `main.py` - -```python -from tasks import do_something - -do_something.delay() -``` - diff --git a/Samples and Hints/Problem 4/README.md b/Samples and Hints/Problem 4/README.md deleted file mode 100644 index 627c908f..00000000 --- a/Samples and Hints/Problem 4/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Hint: Simple Flask Echo API for Question 4 - -This example Flask app echoes back any JSON data sent to it via POST requests. - -### 📄 `app.py` - -```python -from flask import Flask, request, jsonify - -app = Flask(__name__) - -@app.route('/echo', methods=['POST']) -def echo(): - data = request.get_json() - return jsonify({ - "you_sent": data - }) - -if __name__ == '__main__': - app.run(debug=True, host='0.0.0.0', port=5000) -``` \ No newline at end of file diff --git a/Samples and Hints/Problem 5/README.md b/Samples and Hints/Problem 5/README.md deleted file mode 100644 index e69de29b..00000000 From 0f01dde08156ac3e106388c99945c50273e72a85 Mon Sep 17 00:00:00 2001 From: ErfanGerami Date: Thu, 8 May 2025 22:45:40 +0330 Subject: [PATCH 02/17] adding readme.md files --- ErfanGeramizadehNaeini/Q1/README.md | 0 ErfanGeramizadehNaeini/Q1/client.py | 75 +++++++ ErfanGeramizadehNaeini/Q1/run.sh | 1 + ErfanGeramizadehNaeini/Q2/README.md | 0 ErfanGeramizadehNaeini/Q2/first.py | 15 ++ ErfanGeramizadehNaeini/Q2/run.sh | 2 + ErfanGeramizadehNaeini/Q2/second.py | 18 ++ ErfanGeramizadehNaeini/Q3/README.md | 0 ErfanGeramizadehNaeini/Q3/celery/Dockerfile | 8 + ErfanGeramizadehNaeini/Q3/celery/tasks.py | 42 ++++ ErfanGeramizadehNaeini/Q3/docker-compose.yaml | 21 ++ ErfanGeramizadehNaeini/Q3/test.py | 21 ++ ErfanGeramizadehNaeini/Q45/.env.backend | 10 + ErfanGeramizadehNaeini/Q45/.env.celery | 10 + ErfanGeramizadehNaeini/Q45/.env.database | 6 + ErfanGeramizadehNaeini/Q45/README.md | 45 +++++ ErfanGeramizadehNaeini/Q45/celery/Dockerfile | 11 ++ ErfanGeramizadehNaeini/Q45/celery/tasks.py | 86 ++++++++ ErfanGeramizadehNaeini/Q45/cloud/Dockerfile | 26 +++ .../Q45/cloud/cloud/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 185 bytes .../cloud/__pycache__/admin.cpython-312.pyc | Bin 0 -> 559 bytes .../cloud/__pycache__/models.cpython-312.pyc | Bin 0 -> 2086 bytes .../__pycache__/settings.cpython-312.pyc | Bin 0 -> 4719 bytes .../cloud/__pycache__/urls.cpython-312.pyc | Bin 0 -> 1944 bytes .../cloud/__pycache__/views.cpython-312.pyc | Bin 0 -> 6781 bytes .../Q45/cloud/cloud/admin.py | 8 + .../Q45/cloud/cloud/asgi.py | 16 ++ .../cloud/cloud/migrations/0001_initial.py | 68 +++++++ .../0002_problem_port_teamproblem_port.py | 24 +++ ...eam_peoblem2_up_remove_team_problem1_up.py | 21 ++ .../Q45/cloud/cloud/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-312.pyc | Bin 0 -> 5162 bytes ...blem_port_teamproblem_port.cpython-312.pyc | Bin 0 -> 961 bytes ...up_remove_team_problem1_up.cpython-312.pyc | Bin 0 -> 784 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 196 bytes .../Q45/cloud/cloud/models.py | 28 +++ .../Q45/cloud/cloud/settings.py | 187 ++++++++++++++++++ .../Q45/cloud/cloud/urls.py | 32 +++ .../Q45/cloud/cloud/views.py | 111 +++++++++++ .../Q45/cloud/cloud/wsgi.py | 16 ++ ErfanGeramizadehNaeini/Q45/cloud/db.sqlite3 | Bin 0 -> 184320 bytes ErfanGeramizadehNaeini/Q45/cloud/manage.py | 22 +++ .../Q45/cloud/requirements.txt | 27 +++ .../Q45/docker-compose.yaml | 48 +++++ ErfanGeramizadehNaeini/README.md | 0 46 files changed, 1005 insertions(+) create mode 100644 ErfanGeramizadehNaeini/Q1/README.md create mode 100644 ErfanGeramizadehNaeini/Q1/client.py create mode 100644 ErfanGeramizadehNaeini/Q1/run.sh create mode 100644 ErfanGeramizadehNaeini/Q2/README.md create mode 100644 ErfanGeramizadehNaeini/Q2/first.py create mode 100644 ErfanGeramizadehNaeini/Q2/run.sh create mode 100644 ErfanGeramizadehNaeini/Q2/second.py create mode 100644 ErfanGeramizadehNaeini/Q3/README.md create mode 100644 ErfanGeramizadehNaeini/Q3/celery/Dockerfile create mode 100644 ErfanGeramizadehNaeini/Q3/celery/tasks.py create mode 100644 ErfanGeramizadehNaeini/Q3/docker-compose.yaml create mode 100644 ErfanGeramizadehNaeini/Q3/test.py create mode 100644 ErfanGeramizadehNaeini/Q45/.env.backend create mode 100644 ErfanGeramizadehNaeini/Q45/.env.celery create mode 100644 ErfanGeramizadehNaeini/Q45/.env.database create mode 100644 ErfanGeramizadehNaeini/Q45/README.md create mode 100644 ErfanGeramizadehNaeini/Q45/celery/Dockerfile create mode 100644 ErfanGeramizadehNaeini/Q45/celery/tasks.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/Dockerfile create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/__init__.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/__init__.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/admin.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/models.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/settings.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/urls.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/views.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/admin.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/asgi.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0001_initial.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0002_problem_port_teamproblem_port.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0003_remove_team_peoblem2_up_remove_team_problem1_up.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__init__.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0001_initial.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0002_problem_port_teamproblem_port.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0003_remove_team_peoblem2_up_remove_team_problem1_up.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/models.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/settings.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/urls.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/views.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/cloud/wsgi.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/db.sqlite3 create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/manage.py create mode 100644 ErfanGeramizadehNaeini/Q45/cloud/requirements.txt create mode 100644 ErfanGeramizadehNaeini/Q45/docker-compose.yaml create mode 100644 ErfanGeramizadehNaeini/README.md diff --git a/ErfanGeramizadehNaeini/Q1/README.md b/ErfanGeramizadehNaeini/Q1/README.md new file mode 100644 index 00000000..e69de29b diff --git a/ErfanGeramizadehNaeini/Q1/client.py b/ErfanGeramizadehNaeini/Q1/client.py new file mode 100644 index 00000000..6d01f003 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q1/client.py @@ -0,0 +1,75 @@ +import psycopg2 +from psycopg2 import sql + +DB_NAME = "newdb" +USER = "postgres" +PASSWORD = "ERFAN1234" +PORT = 15432 +try: + conn = psycopg2.connect( + host="localhost", + port=PORT, + database="postgres", + user=USER, + password=PASSWORD + + ) + conn.autocommit = True + cur = conn.cursor() + cur.execute("SELECT 1 FROM pg_database WHERE datname = %s;", (DB_NAME,)) + exists = cur.fetchone() + + if not exists: + cur.execute(sql.SQL("CREATE DATABASE {}").format( + sql.Identifier(DB_NAME) + )) + print(f"Database '{DB_NAME}' created.") + else: + print(f"Database '{DB_NAME}' already exists.") + + cur.close() + conn.close() + + conn = psycopg2.connect( + host="localhost", + port=PORT, + database=DB_NAME, + user=USER, + password=PASSWORD + ) + cur = conn.cursor() + + cur.execute(""" + CREATE TABLE IF NOT EXISTS test_table ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL + ); + """) + while (1): + print("1. Insert data") + print("2. Select data") + print("3. Exit") + option = int(input()) + if (option == 1): + try: + name = input("name: ") + cur.execute("INSERT INTO test_table (name) VALUES (%s);", + (name,)) + conn.commit() + except Exception as e: + print("Error:", e) + + elif (option == 2): + cur.execute("SELECT * FROM test_table;") + rows = cur.fetchall() + for row in rows: + print(row) + elif (option == 3): + print("Exiting...") + exit(0) + cur.close() + conn.close() + + +except Exception as e: + print("Error:", e) diff --git a/ErfanGeramizadehNaeini/Q1/run.sh b/ErfanGeramizadehNaeini/Q1/run.sh new file mode 100644 index 00000000..5f4526ff --- /dev/null +++ b/ErfanGeramizadehNaeini/Q1/run.sh @@ -0,0 +1 @@ +docker run --rm -d --name pg -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=ERFAN1234 -e POSTGRES_DB=postgres -p 15432:5432 -v pgdata:/var/lib/postgresql/data postgres:14 \ No newline at end of file diff --git a/ErfanGeramizadehNaeini/Q2/README.md b/ErfanGeramizadehNaeini/Q2/README.md new file mode 100644 index 00000000..e69de29b diff --git a/ErfanGeramizadehNaeini/Q2/first.py b/ErfanGeramizadehNaeini/Q2/first.py new file mode 100644 index 00000000..52837e1f --- /dev/null +++ b/ErfanGeramizadehNaeini/Q2/first.py @@ -0,0 +1,15 @@ +import redis +import time +CHANNEL = 'erfangchannel' +r = redis.Redis(host='localhost', port=6390, decode_responses=True) + + +for i in range(5): + r.set(f"hello{i}", f"world{i}") +i = 1 +while (1): + message = f"Hello {i}" + r.publish(CHANNEL, message) + print(f"Published: {message}") + time.sleep(1) + i += 1 diff --git a/ErfanGeramizadehNaeini/Q2/run.sh b/ErfanGeramizadehNaeini/Q2/run.sh new file mode 100644 index 00000000..c2eb3c86 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q2/run.sh @@ -0,0 +1,2 @@ +docker run -d --name rds -p 6390:6379 redis:7.0 +# redis-cli -h localhost -p 6390 ping for making sure it works \ No newline at end of file diff --git a/ErfanGeramizadehNaeini/Q2/second.py b/ErfanGeramizadehNaeini/Q2/second.py new file mode 100644 index 00000000..8d06bfab --- /dev/null +++ b/ErfanGeramizadehNaeini/Q2/second.py @@ -0,0 +1,18 @@ +import redis +CHANNEL = 'erfangchannel' + +r = redis.Redis(host='localhost', port=6390, decode_responses=True) +keys = r.keys('*') +print(keys) +for key in keys: + value = r.get(key) + print(f"{key}: {value}") + +pubsub = r.pubsub() + +pubsub.subscribe(CHANNEL) +print("Subscribed to 'mychannel'...") + +for message in pubsub.listen(): + if message['type'] == 'message': + print(f"Received: {message['data']}") diff --git a/ErfanGeramizadehNaeini/Q3/README.md b/ErfanGeramizadehNaeini/Q3/README.md new file mode 100644 index 00000000..e69de29b diff --git a/ErfanGeramizadehNaeini/Q3/celery/Dockerfile b/ErfanGeramizadehNaeini/Q3/celery/Dockerfile new file mode 100644 index 00000000..bcc9d086 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q3/celery/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.11-slim + +WORKDIR /app +RUN pip install celery redis docker +COPY . /app + + +CMD ["celery", "-A", "tasks", "worker", "--loglevel=info"] \ No newline at end of file diff --git a/ErfanGeramizadehNaeini/Q3/celery/tasks.py b/ErfanGeramizadehNaeini/Q3/celery/tasks.py new file mode 100644 index 00000000..8c8d1d06 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q3/celery/tasks.py @@ -0,0 +1,42 @@ +from celery import Celery +import os +import docker + + +app = Celery( + 'tasks', + broker=os.environ.get('CELERY_BROKER_URL', 'redis://redis:6390/0'), + backend=os.environ.get('CELERY_RESULT_BACKEND', 'redis://redis:6390/0'), +) + +client = docker.from_env() + + +@app.task(name='tasks.add') # just for test +def add(x, y): + return x + y + + +@app.task(name='tasks.start') +def start_container(image_name, container_name=None): + try: + container = client.containers.run( + image=image_name, + name=container_name, + detach=True + ) + return f"{container.id}" + except docker.errors.APIError as e: + return f"Error starting container: {str(e)}" + + +@app.task(name='tasks.stop') +def stop_container(container_id): + try: + container = client.containers.get(container_id) + container.stop() + return f"Container {container_id} stopped" + except docker.errors.NotFound: + return f"Container {container_id} not found" + except docker.errors.APIError as e: + return f"Error stopping container: {str(e)}" diff --git a/ErfanGeramizadehNaeini/Q3/docker-compose.yaml b/ErfanGeramizadehNaeini/Q3/docker-compose.yaml new file mode 100644 index 00000000..be40f5e9 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q3/docker-compose.yaml @@ -0,0 +1,21 @@ +version: '3.8' + +services: + redis: + image: redis:7.0 + container_name: redis + expose: + - 6379 + ports: + - "6391:6379" + celery: + image: celery:5.2 + container_name: celery + build: ./celery + volumes: + - /var/run/docker.sock:/var/run/docker.sock # Mount Docker socket to allow Celery to communicate with Docker + depends_on: + - redis + environment: + - CELERY_BROKER_URL=redis://redis:6379/0 + - CELERY_RESULT_BACKEND=redis://redis:6379/0 diff --git a/ErfanGeramizadehNaeini/Q3/test.py b/ErfanGeramizadehNaeini/Q3/test.py new file mode 100644 index 00000000..1366fff0 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q3/test.py @@ -0,0 +1,21 @@ +from celery import Celery + +app = Celery( + 'client', + broker='redis://localhost:6391/0', + backend='redis://localhost:6391/0' +) +# initial test +print("Sending test task...") +result = app.send_task('tasks.add', args=[3, 4]) +print("Result:", result.get(timeout=10)) + +print("Starting container...") +container_id = app.send_task('tasks.start', args=[ + 'pasapples/apjctf-todo-java-app:latest']) +id = container_id.get(timeout=1000) +print("Container ID:", id) # pulling may take time + +result = app.send_task('tasks.stop', args=[id]) +print("Sent stop task, waiting for result...") +print(result.get(timeout=20)) diff --git a/ErfanGeramizadehNaeini/Q45/.env.backend b/ErfanGeramizadehNaeini/Q45/.env.backend new file mode 100644 index 00000000..1892ea75 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/.env.backend @@ -0,0 +1,10 @@ +POSTGRES_USER=postgres +SECRET_KEY=wedewdedewdwefeqqfqfewfweqfeqwfewfqwfewqfeferoopwenf +POSTGRES_PASSWORD=hello +POSTGRES_DB=defaultdb +POSTGRES_PORT=5432 +DATABASE_ENGINE=postgres +CELERY_BROKER_URL=redis://redis:6379/0 +CELERY_RESULT_BACKEND=redis://redis:6379/0 +DATABASE_ENGINE=postgres +DEBUG=True diff --git a/ErfanGeramizadehNaeini/Q45/.env.celery b/ErfanGeramizadehNaeini/Q45/.env.celery new file mode 100644 index 00000000..74a567d3 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/.env.celery @@ -0,0 +1,10 @@ +CELERY_BROKER_URL=redis://redis:6379/0 +CELERY_RESULT_BACKEND=redis://redis:6379/0 +POSTGRES_DB=defaultdb +POSTGRES_PORT=5432 +POSTGRES_USER=postgres +POSTGRES_PASSWORD=hello + +POSTGRES_HOST=postgres + + diff --git a/ErfanGeramizadehNaeini/Q45/.env.database b/ErfanGeramizadehNaeini/Q45/.env.database new file mode 100644 index 00000000..c07642bd --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/.env.database @@ -0,0 +1,6 @@ +POSTGRES_PASSWORD=hello + +POSTGRES_DB=defaultdb + + +DEBUG=False \ No newline at end of file diff --git a/ErfanGeramizadehNaeini/Q45/README.md b/ErfanGeramizadehNaeini/Q45/README.md new file mode 100644 index 00000000..ac8242f5 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/README.md @@ -0,0 +1,45 @@ +I wrote django application with 5 apis 3 of them is for authenticating and registering.(ignore get-ip and token/refresh ) +swagger is not implemented instead I explain my apis here + +Start-stop/: + +Delete: deletes the question for the loggined user(authorization header must have the token) +{“problem”:problem_number} +Response may have 400 or 200 status.if there was any errors it will return something like +{“errors”:”error description”} +Post: +Creates the question for the loggined user(authorization header must have the token) +Request body:{“problem”:problem_number} +Response may have 400 or 200 status . if there was any errors it will return something like +{“errors”:”error description”} +If everything goes as expected it will return something like +{“address”:some-ip(or domain):port} + + +Register/ and token/: +Request body for both: +{“username”:someusername,”password”:somepass} +They both return access and refresh token +{“access”:wededewdewdedewd,”refresh”:wdewdewdewdewdew} +In case of success register will return status code of 201 (CREATED) but token will return 200(OKAY) + +Database schema: +cloud_team is an AbstractUser means that it has everything that a normal user would have. +Like username and password and email. + +cloud_problem(name,number,description,image_name,port) +Name and number and description are obvious. +Image_name specifies the name of the image used for this problem. You can create two problems with the image name mentioned in the homework document. +Port specifies the port in the container that the image uses and should be bound to the outside port on the host. +cloud_teamproblem( team,problem,up,ip,port,container_id) +This table implements a many to many relationship betwean team and problem. +Team and problem are foreign keys. +Up is a boolean showing the status of the question container. +Ip is useless because I distinguish containers by their ports. +Port shows the port on host to access the container. +Container_id is what the name implies. It is used to stop that container if needed. + + +Setting up the application is rather easy .just look at .env files and configure them as you desire then just write docker compose up –build and hit enter. + + diff --git a/ErfanGeramizadehNaeini/Q45/celery/Dockerfile b/ErfanGeramizadehNaeini/Q45/celery/Dockerfile new file mode 100644 index 00000000..24e5a00f --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/celery/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11-slim + +WORKDIR /app +RUN pip install celery redis docker psycopg2-binary +RUN apt-get update +RUN apt-get install -y postgresql-client + + +COPY . /app + +#CMD ["celery", "-A", "tasks", "worker", "--loglevel=info"] \ No newline at end of file diff --git a/ErfanGeramizadehNaeini/Q45/celery/tasks.py b/ErfanGeramizadehNaeini/Q45/celery/tasks.py new file mode 100644 index 00000000..a643b67e --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/celery/tasks.py @@ -0,0 +1,86 @@ +from psycopg2.extras import RealDictCursor +import psycopg2 +from celery import Celery +import os +import docker + + +app = Celery( + 'tasks', + broker=os.environ.get('CELERY_BROKER_URL', 'redis://redis:6390/0'), + backend=os.environ.get('CELERY_RESULT_BACKEND', 'redis://redis:6390/0'), +) + +client = docker.from_env() + + +def get_pg_connection(): + return psycopg2.connect( + host=os.environ.get('POSTGRES_HOST', 'localhost'), + port=os.environ.get('POSTGRES_PORT', '5432'), + dbname=os.environ.get('POSTGRES_DB', 'mydb'), + user=os.environ.get('POSTGRES_USER', 'myuser'), + password=os.environ.get('POSTGRES_PASSWORD', 'mypassword'), + cursor_factory=RealDictCursor + ) + + +conn = get_pg_connection() + + +@app.task(name='tasks.add') # just for test +def add(x, y): + return x + y + + +@app.task(name='tasks.start') +def start_container(teamproblemid): + try: + cur = conn.cursor() + cur.execute("""SELECT p.image_name,tp.ip,tp.port as hostport, p.port as guestport FROM cloud_teamproblem tp JOIN cloud_problem p ON tp.problem_id =p.number where tp.id=%s;""", + (teamproblemid,)) + + row = cur.fetchone() + image_name = row['image_name'] + hostport = row['hostport'] + guestport = row['guestport'] + print( + f"Starting container with image {image_name} on port {hostport}:{guestport}") + container = client.containers.run( + image=image_name, + name=None, + ports={f"{guestport}/tcp": hostport}, + detach=True + ) + + cur.execute("""UPDATE cloud_teamproblem SET container_id=%s WHERE id=%s;""", + (container.id, teamproblemid)) + conn.commit() + cur.close() + return f"{container.id}" + except docker.errors.APIError as e: + return f"Error starting container: {str(e)}" + + +@app.task(name='tasks.stop') +def stop_container(teamproblemid): + try: + cur = conn.cursor() + cur.execute("""SELECT container_id FROM cloud_teamproblem WHERE id=%s;""", + (teamproblemid,)) + container_id = cur.fetchone()['container_id'] + container = client.containers.get(container_id=container_id) + + container.stop() + + cur.execute("""UPDATE cloud_teamproblem SET container_id=NULL WHERE id=%s;""", + (teamproblemid,)) + conn.commit() + cur.close() + container.remove(force=True) + + return f"Container {container_id} stopped" + except docker.errors.NotFound: + return f"Container {container_id} not found" + except docker.errors.APIError as e: + return f"Error stopping container: {str(e)}" diff --git a/ErfanGeramizadehNaeini/Q45/cloud/Dockerfile b/ErfanGeramizadehNaeini/Q45/cloud/Dockerfile new file mode 100644 index 00000000..4626c034 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/Dockerfile @@ -0,0 +1,26 @@ +FROM python:3 + +WORKDIR /app +RUN apt-get update && apt-get install -y \ + build-essential \ + libxml2-dev \ + libxslt1-dev \ + zlib1g-dev \ + python3-dev \ + libffi-dev \ + gcc +RUN pip install --upgrade pip setuptools wheel + +RUN pip install psycopg + +COPY ./requirements.txt . + +RUN pip install -r requirements.txt + +RUN pip install gunicorn + +RUN apt-get install -y postgresql-client + +COPY . . + + diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/__init__.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/__init__.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b48a0a22f7368d2f0a6998267adae8f13a0409c GIT binary patch literal 185 zcmX@j%ge<81leK286f&Gh(HIQS%4zb87dhx8U0o=6fpsLpFwJVMYveSc!q|=n3ZJ2 zBu-qY z(q9pD3XEdNQzvhNH&4yDN_nhzc<=kZ;d?*kC6zKkhUlc7Ct1G~nT0k5qh|^300TxY zFjPeda13j1>@g-0VBOW2Ueys0)S7ggHHc~}HP00zi3b#^e{v=NmrMpay4= zh})P^Z=m*&3~ef@;d2(0vZh$VE!%7Qxw`L#oYuJd3t=!H6E_e>^vDe*>H!UjNOIDo zK}fhroO8eC5+?LAv6)y@c`Dt*NIGC#DePOPm9n)LI#%8F+t_kC+t!gnTZchFn;s)x zXdUy0?G*{P8NISGaY{C!9hA+!j-|$v^761SM literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/models.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6f60cd49b1038b48053da7002380daa2f0ec012 GIT binary patch literal 2086 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 literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/urls.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e6cf7fd5ef4b08da4c3c692aa7a5c4dbf76e127 GIT binary patch literal 1944 zcmb7F&2Jk;6yJ5$U+X$a>yV~Os0K>vIK;c5X+W}oHch__RTC1IgJsFxc*pj-`(e$D z39-0v>#;qBKLL~?apb_A0~cG4WOYTwfdlHTQN^X=z?=QRp%PWu!|t0mzxUqn{pNZ6 zOFAtJ@I3x&uDKZ%gx~ohe7qf4JpV})gndC5%7QNH5mU4x<%r1bF>}n4%90f=N4>RV z#;kZbZY9bISV#4knf%^I#!cBul~W!nVV(x3d@152L?m7r zacUINhygl<)2)Rt@8}EO#nCFX9%aJbyWlEM?@i_2(7poc>6j?4cF}m9!W?N$n6Pw;era>7ZPKRNNAO}UvL0=enmn!HwB(NNU zkzqqF%g@?2u|_eX7#Cy&Pm{4WEvTyQ)TpAjG`r!1_nn&0x>m_|pL2J5>G#eRK+aaugP@Omyvi7Q4yB#=vnjZc_fae|X z299+Iq0nq|A)8$a`f55BUP88J;g7Q1&gSHGQ=>G$1C8m&vi=tfhcz+bL==y4NarTx z`af(qUeRckCt1k7#HeW3%#Lo@4G_Vr$6Mp)8|qW^gh46C6NpJ&(857k_geHVb{G_`v#u=#YN$*>AJSx>TaOsZwTf`@#x@jL0tRX`h zX1ilyn^lS9u-m!QZoFCrU$yFv2NJ`{Fk}*7MCnf?h;RKS%>N;5{whp85f+~a=qM&c zllNyHtnL>c7WOYayfl!`J(d#p-~1*$oXPiR@`D+5AT4v(nFqz;)O>$xelV3CNDJIG z+nYW=oL2hN%3yl=hwhhddV}r*_GbxyTjR) z{_M(NcJ;@NL+RGDbbKOmG%kz*kzsPKpPc*l=5Xn9f9djJWbJ4oK5<3-Iz{+j$=`{3 BCE)-7 literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/views.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a46695fac9dfbb220f4ac939ece6839c685d63c GIT binary patch literal 6781 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 literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/admin.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/admin.py new file mode 100644 index 00000000..db42b2a7 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from .models import * +from django import forms + + +admin.site.register(Problem) +admin.site.register(Team) +admin.site.register(TeamProblem) diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/asgi.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/asgi.py new file mode 100644 index 00000000..9525683a --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for cloud project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cloud.settings') + +application = get_asgi_application() diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0001_initial.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0001_initial.py new file mode 100644 index 00000000..084f6e0a --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0001_initial.py @@ -0,0 +1,68 @@ +# Generated by Django 4.2.13 on 2025-05-01 13:08 + +from django.conf import settings +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='Team', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('problem1_up', models.BooleanField(default=False)), + ('peoblem2_up', models.BooleanField(default=False)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='Problem', + fields=[ + ('number', models.IntegerField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=100)), + ('description', models.TextField()), + ('image_name', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='TeamProblem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('up', models.BooleanField(default=False)), + ('ip', models.CharField(blank=True, max_length=100, null=True)), + ('container_id', models.CharField(blank=True, max_length=100, null=True)), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cloud.problem')), + ('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0002_problem_port_teamproblem_port.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0002_problem_port_teamproblem_port.py new file mode 100644 index 00000000..da0661d6 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0002_problem_port_teamproblem_port.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.13 on 2025-05-01 13:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cloud', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='problem', + name='port', + field=models.IntegerField(default=2000), + preserve_default=False, + ), + migrations.AddField( + model_name='teamproblem', + name='port', + field=models.IntegerField(blank=True, null=True), + ), + ] diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0003_remove_team_peoblem2_up_remove_team_problem1_up.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0003_remove_team_peoblem2_up_remove_team_problem1_up.py new file mode 100644 index 00000000..920af7c9 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/0003_remove_team_peoblem2_up_remove_team_problem1_up.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.17 on 2025-05-08 19:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('cloud', '0002_problem_port_teamproblem_port'), + ] + + operations = [ + migrations.RemoveField( + model_name='team', + name='peoblem2_up', + ), + migrations.RemoveField( + model_name='team', + name='problem1_up', + ), + ] diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__init__.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0001_initial.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0001_initial.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1691dfce29c3234f93cf7e240bfe76a0c1803933 GIT binary patch literal 5162 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 literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0002_problem_port_teamproblem_port.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0002_problem_port_teamproblem_port.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8493a3e2fa26a5a672e7d8cc6585a2a7d50cc70 GIT binary patch literal 961 zcmaJ<&ui2`6rM@4*(A;C8ij&eMM^8=U|FqtkWwhtmWmdH)k6pj>CWtK*8Er}S*41g z(1XX``Y$NEi2sKd3xzIo_2g|~D?(4sWV5st>KtCa_wv5?7@u29`%f($>wTlgg%YPfHCeGKIoh^qmze%^vK?QwP!HlRW@fcoy^Z|H zPkk?7#SV?P0unN%6VufHQRJ#XR>Y*?b%S)xR=7e!6%=_PVM=BT4W9&9h#7H*!wBbeToE-XZJxp4g9^o>%&+gvKS!3?Wi*dP>cTm1C z5(1)A3S@zW&NdZ~F*5=rZEkkJPzCzzP?oN!AD#>ipwE0V4zoOZVb&csdN9Nu6|1otfix(!ZRXx&89oZ@`_5 F{TFLe@SXqw literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0003_remove_team_peoblem2_up_remove_team_problem1_up.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/0003_remove_team_peoblem2_up_remove_team_problem1_up.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9888d6572a4f5ad7efb4b5a544a7a72a9a5c74d3 GIT binary patch literal 784 zcmaJ<&ubGw6n?Y6+}&8LwbDzCD81xhiER}rB8b+aXh6}+vM_8i&t${?ayL=pNudXC zdh6dH^*`}c5L)Ky$=gEPOD}b1HZk#_b9nQ;H{Z8!-Z%SwZq5a<&d!#5KM252nM{^B z21lC$>;eNuB8Z7c2xzbkOxppbBk3Cx!F1o#E9_|_qhbD%NrP}V4!e0U2-BqKOt}Dm z8ns1r7Z5zcz|$D%5>M9vjlR0%tOP`RrhhZ`w5s|amN{j0HP0GZjdR?2Hn~Yd<7OvH zhm2ouHk)fS%hPs*G0oC^KnEDavjuL*3a@3TNNaSM3B4Pq3?rHZF>*u2+E{c`5L%+0 zP1Px-+@(~ohY<>Vp3*nNAd(81G0ZSwm~=uca_Jwhy}&qqi;qH#793X7GFO*8K-^nj80vBJ3tHCIf#fe;p*-LL7(h1BSg;fMF8)&o^$3 zRh4%7IKFUVo#v{!@_^0^{CB-_OU}8PjdJ;rDp&#(TO#a0X@PU6)U`$H!_(3Q=jtc- zz^?Dx^~0qrhZpO|rtY|<{f~OhS+G7n$rmTzZ8dc6uzrwq(^b}1E>%r0Nrs|b7UCl-)v$JPa6eQ^)wSN7*uPCz6|{Tnvr&8`3d literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/__init__.cpython-312.pyc b/ErfanGeramizadehNaeini/Q45/cloud/cloud/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cabf1e1640b074223bbf1dacb003b7c2ef3b1794 GIT binary patch literal 196 zcmX@j%ge<81j$9h86f&Gh(HIQS%4zb87dhx8U0o=6fpsLpFwJVCA(O~c!q|=n3ZJ2 zB 255): + # return Response({"error": "no ip available"}, status=400) + # setattr(instance, "ip", f"{settings.HOST_PORTION}.{index}") + + all_ports = TeamProblem.objects.filter( + up=True).order_by("port").values_list('port', flat=True) + index = 2001 + for port in all_ports: + if port != index: + break + setattr(instance, "port", f"{index}") + + instance.save() + app.send_task('tasks.start', args=[instance.id]) + + return Response({"status": "started", "address": request.get_host().split(":")[0]+":"+str(index)}, status=200) + + def delete(self, request): + problem = request.data.get("problem") + if (not problem or not Problem.objects.filter(number=problem).exists()): + return Response({"error": "problem not found"}, status=400) + instance = TeamProblem.objects.filter( + problem=problem, team=request.user).first() + if not instance: + return Response({"error": "instance is not up for this team"}, status=400) + elif not instance.up: + return Response({"error": "instance is not up"}, status=400) + + setattr(instance, "up", False) + instance.save() + + app.send_task('tasks.stop', args=[instance.id]) + + return Response({"status": "stoped"}, status=200) + + +class GetIPView(views.APIView): + permission_classes = [IsAuthenticated] + + def get(self, request): + problem = request.data.get("problem") + if (not problem or not Problem.objects.filter(id=problem).exists()): + return Response({"error": "problem not found"}, status=400) + instance = TeamProblem.objects.filter( + problem=problem, team=request.user).first() + if not instance: + return Response({"error": "instance is not up for this team"}, status=400) + elif not instance.up: + return Response({"error": "instance is not up"}, status=400) + + return Response({"ip": instance.ip}, status=200) + + +class TeamRegisterView(views.APIView): + permission_classes = [AllowAny] + + def post(self, request): + + team_name = request.data.get('username') + team_password = request.data.get('password') + + if not team_name or not team_password: + return Response({'error': 'username and password is required'}, status=status.HTTP_400_BAD_REQUEST) + if (Team.objects.filter(username=team_name).exists()): + return Response({'error': 'Team with this name already exists'}, status=status.HTTP_400_BAD_REQUEST) + user_model = get_user_model() + team = user_model.objects.create_user( + username=team_name, password=team_password + ) + refresh = RefreshToken.for_user(team) + return Response({ + 'access': str(refresh.access_token), + 'refresh': str(refresh) + }, status=status.HTTP_201_CREATED) diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/wsgi.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/wsgi.py new file mode 100644 index 00000000..15827bbf --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for cloud project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cloud.settings') + +application = get_wsgi_application() diff --git a/ErfanGeramizadehNaeini/Q45/cloud/db.sqlite3 b/ErfanGeramizadehNaeini/Q45/cloud/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..5dba7916185d2f415ef99ffb5d21bf817f46a132 GIT binary patch literal 184320 zcmeI5Yit}@cHg_$k7763U3yWi=cw2eMfOk}^@IJAy!LRY9u0TM)`+4oBP=F`>h2;{ znto8-MUCX~253s_36dBFY{On7n;14WF#HOzMvx#e{3UVVJb)~`us_&d7}yUb&YEs$@>aXkR1G=nJLVGv z-|MpM^ZC-`cai`4$^TyS1fCxb0K!n`}|okJ~t=q-8Ix|L#s8~yLDx! z(!jq>tlS>9ZJW34PF9I}KwpJ?qit6C=^>n%gu);e{Eg?TvJGBRDXFi=uB?p>BTGzU@j=p2)?N&lIv?qpLs5jMZO&MVz zx%Y)LVti#qc>XzCFovc!mEEq^QFgRWQ}1?(@viB{zkoVcOasf3`g(#;2!+kI%YLTRP%?a9@b( zj@s>h*zSYu=`jL0Z@y&j@(D5i{({h3XPM1TXd9DiZE{^`8H(|AMr5E9DuU2lB-;)zAsj{DygnYX)q)j7rRY)XzcaMwlrwhWKbSO7#?Yc&T zS5j%Unl0p1Ww)h2a=8`cPMe7=AJTVk(}#|PjK(MqDaSk#c1UR-i?+5NszQNSKGEw^vbPW;J&ZVS>tRFn z6tjf*T}@|Fwdz*M+wbV1{2nrPkjwoF#M_6_@p#W)682_BvF=xJAxhQi*-WmQvbvk8 zXd&rN?%(T%bS)~D0ot~X(;PZBI@}L#C0Wz#RU%@%R1%&Sto}FTgm*)PJ$mC%)feiN zrj^6p3^LtAcS2|MqdU86@HyN$lD)S=V!WLddLOam@fa}_b!SIus8y|@G|3>{Pzw2K zJzLLKS;}}+2zcg;hvI0SpuR5}an^2n`%F^Ap6ko-lt*l!qZmkiR5BQ7XJN{}{m`&}WKR-e8?HdFB^*~;Rk zPx@Wyi_)4j7W?hkN3lZmZ=$~(RidXSe{b?9C(Dy3C%!fDuO{wJOhmpG`LW3B;lB?5 zdRPljjsMT_kH>F_e=2^J7{Ct*fB*=900_L~1S)dSx3Io!v_H^VO0}WZK4|D&Bb7>L z6t!WHMc($VL6&z~b-lH1D$(VqOe&LGOp$*@IbFJ*%3jYdy_QXvvYDmwC1US}hrP7Y zAgeuUNB>c+t2`j*Xm_4^nn@MY>3rptecVbZTly2lynWFWqpgr-Uvf*_-qN*3-P>Mv zshIlwMPjc!>{hDyNo-|`>3k_$zTh2Vs=yW^l}svKNRwYBlSwamxs=HjmNMD$`F+gf z-DcA1td|+WJC(~<&Uuqc<&=)rY(Lh9TkxTwd)g~x3&mpj>^^QSx!p?b<5oVEUdolv z>|-W7WF}Sc^d?(K6$)?1iJ4m-?UwNjOL?F@@ia!3Eegf!r-`vy4`XRXZ|R1vHazR5 zQ-yRsI~DX@oL%l}=JSpe=^>*krHZLiy7=CypfA3=%odqRjcmU~*fR^;BBrz4d{{(R zKE2#YIq`!-DS1j)LYC$ zvLa2E6+2HAwO(hdx9yg))lj#U+Jm-ECMBMxNS+s$mX8xtw+5y%baC4>#q*GMQ)<@J zM5>r6=2ORriP?dP5rng^l}hPSW+^4H8hyf}YZOwYeCDlK&^JXQCXZ}vqa1slWv!Ph zP4$V=(8!SYVAxx7?xjpVlYKo(ERldsOSHY%sx|@t#RD0!kWFU_`ISjxVZCo5 z#YbFooq?^A9^gj0kSmmKO%NmZxRF$e8({$r7WWT|honL}|7L_3y4yEYv>WO_ayYd<*r^ryqVq%a7Y}z}9cOaynrE)7lVxiyGWGJv%U=LUhLc5e9>Hb!L80jZ( zs(*>LEgu~sYl_))v5>mvCzeQ8W63*eEF%Qc#Z;#F)>zOtduy4mOf&8jdw=M1tXNYo zyxOBsN-d@G1%X(abz2(Qbqo1aA(x9v-|&f2aZLIx>3>N@>DQ&7lRDD6H1m?*!XbPR z009sH0T2KI5C8!X009sHftQcKe9ZsucuV_GAxqig+#jY7Y+EQ$JsgAa@LgKza|WQwm>EgbTZ6~ z`3gdO%%AOR+7}fft!{*CdG9A^nl`n)JGKM*26>&r61M`{iqDL<|BT00JNY z0w4eaAOHd&00JQJvJsdH#AgKd5g6MCe%m?d7Bf2PPjE@0aa!~#=swj{w;2mB`kQ`79w`Y6K~ z@&96&tta$9NJQuV^OOI~C;d5@{r?x~H>H0meMxFc?@G6%C23kZ7W;p(Z^iy=>}#=K zi2c*pZmb%+6-&k@qJJL!{pi1oemVMM(Ps1u(bZ@vIu|`L`Q6EHPyYVoZ%zIZF^C@! z009sH0T2KI5C8!X009u#pTOyWuqZ?x>*PtRZO%1+CLpAR2>I)IjlAB*CYUn?O zdx{|r@-y+mlV%}50WUnk7zU|bUUHmeNr0KNO@5EDWC(DRHi2XcxLKPZ#UqFK%j zTIFO7faK>GwQ3axPXxkq0<+wo!v{_U!V3a7+b{I9LTOKmY_l00ck)1V8`; zKmY_l00fRO0s8rWKK~bwaF_@U1V8`;KmY_l00ck)1V8`;KmY_@Y65uv|57(Uf(HQ* z009sH0T2KI5C8!X009tqNeHm_|4CCm>F=fgEBzID3&8)8z9s#!^as+{rT-@VXX&@4 ze=mJa`ZeiaOTR$A6X2(%pO8M5deTSIuGE%vsV2Qo-V}I8dRr=!HwKiXEO~3d9C>Tt zd14ShAOHd&00JNY0w4eaAOHd&00JQJStk(m3qoX`ZRgnb3fs=oZTK?V&aiEQZKvsW zTxQ!#Z2Jn^UZh*`0^6Qv+jDGtmTp65*f!3#r`dLjZiA=TmV5yq*+0Ry$LTh3jBO>h zjj?T%ZvB&NJHfUQwhhzm*f`sYY#Ud`0 z!2JIQqM6_%2!H?xfB*=900@8p2!H?xfB*=5PXsXk|DN!nG6;YG2!H?xfB*=900@8p z2!H?x{6G+(fB!!pUh_%clzvnCCsI|qE=|V%B=&D(KO5`BDzVpM{^&QNzZf;58_`#z zW0QX}`74vH$?U}6PyFu0KcBcWaW3)?k#9!+W8^E5AB}88UX6spe;oeR@Ka(CKOg`C zAOHd&00JQJ5)fFJ5Bh|~LgcZoeW)0k+T7{1s|~HWqPApOCet#R7hanq%IO=Cy4KJP z&8=>hIxAc;E7TsSt?i)-W~rk>a+XwB$VJq8-EE!}IaCvuiR$cPn0fB@njc@8Av(!) zm^*CK;?DN<5~d#a)27FLW|w1 zQaN{qX}n@;*oaXL?grI3cadmZoE`5YqGIX*mE|rFSz%dZXK(KsT|;fv_13o0{y=LD zJh2I6CMlgK)ozqU?v_nHsK{NkiFnm>W>xO5O+Ki~eYc6ss@b!oYVJow8i-9es7Hgc zm7A4vXIO+G7Gbra);?(HT|=u6YEgk~6L2@<%*_yw&?X;Ld^>o6F~}n9YTd5hwwjI~UpYy1lIb81$EL-j=g?@)m|YPB^4HO0qU?zn>uY*ePxoUPAC1$^X*Q1cW2-;J4#Ft z`Rt;fJ3G+eZkjp~Q-}LE(BYo3;|pP;b7{^`T^cA*XV}5~IFT-7$Cwv8TBoTy8`dhi zDiY0Wg)#1rC7^C|r>w%OAyb=sW(lY^ch4%k5+vHm^ceNgDy6E_QLE%~Am|IvrJ1vh z_BLtj&eH)kQXsREc|Xxw$Z<#QdfZJ*bBt+nC+(Wt#err*Aeyt+sDpMj>fS&H&;MV7 z8xw>G0w4eaAOHd&00JNY0w4eaAn?)?u)Y8PrDp*EAOHd&00JNY0w4eaAOHd&00JOz zR0&}Ie^gr*ae)8`fB*=900@8p2!H?xfB*=9fJFfFe~Sh7KmY_l00ck)1V8`;KmY_l z00cnbs1m^Z|ERVs;sOB>009sH0T2KI5C8!X009sH0gFI1aNT!o?CU=1a_k$iQ1r&c zws%cNCs#Jg%bR6+bNP+6vYc?p67qbawcD&}orHA;Ywy!OhpdxVZf=t|$X0G| z%9VR-Yw|lAtLw`f_vN?C_pi!{mfF-3@?*6_UZ~iaPp4AJfhLjGwQjAW?-=A&q6zX6 z-6w`!s5e#eZr%|Fl6zk`BgR)&gy)~L0i!PlR_IG-ZEuq7nut6_C%j;KYEra%Juxz5 zdHLSv?bQmgxn8bpk`S3CTC1vW6IO!&<&E;2<&AP>rF^&Ff>f2CBPrjc;tkfotCiKw z)#bId`@FDxli0Ohim7<|WH+zw8V_tV4tI{^UN$bquU!+KPr2!`H;3Apngz%AC27h( zQ~a1qheXG84@oV1IuyS(E%@|SU3=1f)X>QbsR{o!J63FYn6~!EN&mbapPm*zKI=kF zb)J2GN~FRcSGsWU}Kr*5cSgT5qHCw;oE z8k(UuH8wPmtkt_pcbB9t?VqGewA+nAhagf~>gw+~+khe8tE}F+S0;*EdWW22geuWt zZj4sZnyTKg0?Fi-9Dz`04Rvd4*ij-;Yli-q3~lZhXvE4x(%c$BWQEU1$7J@@sPteR z)y&MawSTO4{3OeOUXwMlC9(D|H(~#@}BMdh0B+*$Hi95`WXN zLSMT~dYO{hS}NqVrK(FW!rfl2+$_H*CtTA0E0l+$Hhv@9uFi{&Ydu zlMdx(tzFk>@JcGJRw11 zC4>dv<*wwB8kX`4<%b*d@FmfH`Kdo7Z`p4<8k3*(;LF?~W^1@{-9tEYHIvI(eK^^> zE{XB&lF(DF);GJC1)yuYGSW;fF4c0iQbuDGhm>O;2|J{;k40Ns4^^Q+ET8CgDcM_y zksd~zxAm~0dgd#=so&LfCRM9$mAw6q9?Eaiyv^7_F83=CZy!d-<2`>#*qa%}x?jPC zC{?RxGr4NY>TW}kPVV39hIB0|4yKCZG>49jbUlX|(*G(EFc^Hqcqg2)=-*c zkZvf2e6^mfXR9n_JSqe{^Tk7Pv}H3(JgU*i20kT7jxe`KM_3Jt@oZMuE3w@0sOeD@ za%P2x#tWr{<=?);r|Gq~IQh<4h+byyvq<>OY*%}yH>(K9rz$KiggY;EWGugW@ zut~+9YNylGw>v7G1$KGlR>7FVZemFOqFn5^eYQ&mX~z*46e1-^8@l(s9ew^k5nS;F zS7QGt`sJuFxjmsrel`4u;nMgog?=$u3w+W4JN}Qy{$lLB?_cx(*uzLZ2sAEYt2_r=%5`1-o=+`NN4NdF-D6=$Oyr2ax}^w7`~^qV3& z^Vy7bNw?+z?4-l12DOex?!fDcYIxj!llIe|?C2eh+`sQ5XDbJv_Iy3r+gN1$_u?$= z-N0;Lw!%aQ$!ACNcbj`5{x&1tu#&w~SH<|rNjr~cdihtycrq#M&DqB%ek!M~ zYZcBZq+az&e4stGMw=!3gx0xM*4HP<)ZxUo$LKM!?A4NN@$gxYIc_d4@GpOI985cN z$04I$^TosAtGv@$=P3DUE$m@MkAAHZz5O5NZ=X`V*j?7Me|$xZFD?onU$ZB-T5swt zx?saIcyOF>X3CJ5B#Wn`wnQ0P4sBN-YBhreXs-8?C1Wxw^Wu)SLzad53riW-Oph+P z5I9>6bvq$9e$t`_F7UPdrgx;>pzoF+0u4!$)lwC>{GF2=5p&A$Vb9+d0 zAKUI2hU!t&&KX>?_d}P&xJCkc|G}#Q8o^u%uHvOp$DiUnI9(q_>#2 zT{dUftiEe4e$>=zs+up_+ssrsyKhVFXJW`_Q<3Ht+oK~o8D1`U4=<)m-2t3BxfiUa zGW-!IYgg0WnS&hbCr;nO2*0d!SvfDpn*`X0?rh=F_Ko%#Oyb&}n>h#J;7GBAdSbCe_rC}RnhuyGWYt7(nj`O?JgRivxEcn!)zqUJM203{8 zO(IU>`~R%Z8DI|tKmY_l00ck)1V8`;KmY_l00fRI0nGo8YRe)n5C8!X009sH0T2KI z5C8!X009uN2w?tivA`Y(fB*=900@8p2!H?xfB*=900ZDzyCj~EsMB700ck)1V8`;KmY_l00ck)1VF$dfam`f z3+#aa2!H?xfB*=900@8p2!H?xfWT2Dfam{5wPg_(2!H?xfB*=900@8p2!H?xfB*Ra=y|p#@osHG?<&FFD+vWT6^1aR5 zs}*8>ye~dbiFKp=W_hDrSt;Ko zyc+G@x?*T*lea=rzDdO!to>FitDCFKYisv;VfiMp`Owf4@?*7Ad!TmaGr3%Hz+b*s zS-o?wOmse3b0+n-Lh&!YEBN$QU3=1f)X)u0QFo0tJ5~;rL`wQlYFB+e;k|f!UFbbx z#y#7m_s*(#kPhik{kBs$Wu=&{*7BK>>S@$gVV38{YUO76J)X)Va%0GTLcU!&xEgKH ze)}gCLb$uWAK`->R?-J)TvguuBqtb*PFmfxJahuL#@yapWih_KEI+bzYsNGbH%rKmYFoaFOar^;pL z=;0K4);Grsry|WQ+qn|S8w;WM?c{zVgtM}eb{^04@~?{VWK!6hW1Z6}bsn8`c08w$ zdetZKf%eq8&Mc*Dml@lA0lC)n^$9X{_=dn9qwS7>_sV3imK5W2bHcMAbKJZf?sVGZ z4y)-nn0C7DkWsH&yUnWB8GRE&oNcL1&5A0WvV}#Yb*)?L=sN~UgyBf^rn;>uqYdn| zJLJa4osP-gv3W6mdr|16?J1|$n|e!Ww6_Nrm|8Bsq*c{CZ5z9ZoV zRw$;y1*tbbC&m@x(j9M?YHe~i*fJF3>5fM3V3gWYwWbxds{7oR4sdNhJNvuns*ygHW>+HDz literal 0 HcmV?d00001 diff --git a/ErfanGeramizadehNaeini/Q45/cloud/manage.py b/ErfanGeramizadehNaeini/Q45/cloud/manage.py new file mode 100644 index 00000000..d46555e7 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cloud.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/ErfanGeramizadehNaeini/Q45/cloud/requirements.txt b/ErfanGeramizadehNaeini/Q45/cloud/requirements.txt new file mode 100644 index 00000000..9d09d477 --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/cloud/requirements.txt @@ -0,0 +1,27 @@ +asgiref==3.8.1 +certifi==2025.1.31 +charset-normalizer==3.4.1 +Django==5.1.7 +django-cors-headers==4.7.0 +django-ranged-response==0.2.0 +django-redis==5.4.0 +django-simple-captcha==0.6.2 +djangorestframework==3.15.2 +djangorestframework_simplejwt==5.5.0 +drf-yasg==1.21.10 +idna==3.10 +inflection==0.5.1 +packaging==24.2 +pillow==11.1.0 +PyJWT==2.9.0 +pytz==2025.2 +PyYAML==6.0.2 +redis==5.2.1 +requests==2.32.3 +sqlparse==0.5.3 +tzdata==2025.1 +uritemplate==4.1.1 +urllib3==2.3.0 +celery +dj-rest-auth +django-allauth \ No newline at end of file diff --git a/ErfanGeramizadehNaeini/Q45/docker-compose.yaml b/ErfanGeramizadehNaeini/Q45/docker-compose.yaml new file mode 100644 index 00000000..a121877d --- /dev/null +++ b/ErfanGeramizadehNaeini/Q45/docker-compose.yaml @@ -0,0 +1,48 @@ +version: '3.9' + +volumes: + postgres-db: + + +services: + + postgres: + image: postgres:13 + expose: + - 5432:5432 + env_file: + - .env.database + volumes: + - postgres-db:/var/lib/postgresql/data + + backend: + build: ./cloud + env_file: + - .env.backend + ports: + - "3003:8001" + restart: always + container_name: cloudbackend + depends_on: + - postgres + command: sh -c ' until pg_isready -h postgres -p 5432; do echo "Waiting for postgres..."; sleep 1; done; python manage.py makemigrations --noinput && python manage.py migrate --noinput && python manage.py collectstatic --noinput && gunicorn cloud.wsgi:application --bind 0.0.0.0:8001' + + redis: + image: redis:7.0 + container_name: cloudredis + expose: + - 6379 + ports: + - "6391:6379" + + celery: + image: celery:5.2 + container_name: cloudcelery + build: ./celery + volumes: + - /var/run/docker.sock:/var/run/docker.sock # Mount Docker socket to allow Celery to communicate with Docker + depends_on: + - redis + env_file: + - .env.celery + command: sh -c 'until pg_isready -h postgres -p 5432; do echo "Waiting for postgres..."; sleep 1; done; celery -A tasks worker --loglevel=info ' diff --git a/ErfanGeramizadehNaeini/README.md b/ErfanGeramizadehNaeini/README.md new file mode 100644 index 00000000..e69de29b From d5a9b54314db1cc4d113c196397ddd457e9fa432 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:18:18 +0330 Subject: [PATCH 03/17] Rename README.md to READMI.md --- ErfanGeramizadehNaeini/Q1/README.md | 0 ErfanGeramizadehNaeini/Q1/READMI.md | 1 + 2 files changed, 1 insertion(+) delete mode 100644 ErfanGeramizadehNaeini/Q1/README.md create mode 100644 ErfanGeramizadehNaeini/Q1/READMI.md diff --git a/ErfanGeramizadehNaeini/Q1/README.md b/ErfanGeramizadehNaeini/Q1/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/ErfanGeramizadehNaeini/Q1/READMI.md b/ErfanGeramizadehNaeini/Q1/READMI.md new file mode 100644 index 00000000..d3f5a12f --- /dev/null +++ b/ErfanGeramizadehNaeini/Q1/READMI.md @@ -0,0 +1 @@ + From 18324272d77a27b02e997a07834669ae666b6d1d Mon Sep 17 00:00:00 2001 From: ErfanGerami Date: Thu, 8 May 2025 23:19:32 +0330 Subject: [PATCH 04/17] writing readme --- ErfanGeramizadehNaeini/Q1/README.md | 7 +++++++ ErfanGeramizadehNaeini/Q2/README.md | 6 ++++++ ErfanGeramizadehNaeini/Q3/README.md | 8 ++++++++ ErfanGeramizadehNaeini/Q3/test.py | 6 +++--- ErfanGeramizadehNaeini/Q45/docker-compose.yaml | 2 -- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ErfanGeramizadehNaeini/Q1/README.md b/ErfanGeramizadehNaeini/Q1/README.md index e69de29b..5e35c59d 100644 --- a/ErfanGeramizadehNaeini/Q1/README.md +++ b/ErfanGeramizadehNaeini/Q1/README.md @@ -0,0 +1,7 @@ +``` docker run --rm -d --name pg -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=ERFAN1234 -e POSTGRES_DB=postgres -p 15432:5432 -v pgdata:/var/lib/postgresql/data postgres:14``` + +POSTGRES_PASSWORD and POSTGRES_USER for the credentials neede for authenticating +-p neede to bind the first port from the host to the docker container. +And -v needed to perssist data that resides in the path specified. +And at last the image is postgres:14 +I wrote a python client that I will explain in the recorded video diff --git a/ErfanGeramizadehNaeini/Q2/README.md b/ErfanGeramizadehNaeini/Q2/README.md index e69de29b..4e44d1bf 100644 --- a/ErfanGeramizadehNaeini/Q2/README.md +++ b/ErfanGeramizadehNaeini/Q2/README.md @@ -0,0 +1,6 @@ +``` docker run -d --name rds -p 6390:6379 redis:7.0``` + +The explaination is the same as before +Int the first client program I set 5 keys to a value and then publish hello followe by an integer to a channel then in the second programm I retrieve all the key and values and then listen to the channel for incoming messages +Using redis insight will be explained in the recorded video + diff --git a/ErfanGeramizadehNaeini/Q3/README.md b/ErfanGeramizadehNaeini/Q3/README.md index e69de29b..e4d9144d 100644 --- a/ErfanGeramizadehNaeini/Q3/README.md +++ b/ErfanGeramizadehNaeini/Q3/README.md @@ -0,0 +1,8 @@ +The docker compose will bring uo the redis as well as celery +I useed this bind mount so I can run docker containers outside of the existing container +- /var/run/docker.sock:/var/run/docker.sock + +Celery depends on redis. It means that runing celery container depends on running redis container. +I used CELERY_BROKER_URL and CELERY_RESULT_BACKEND for telling where to look for broker and backend(used in the tasks.py) +tasks.py defines some tasks that can be executed by calling send)task which is demonstrated in test.py + diff --git a/ErfanGeramizadehNaeini/Q3/test.py b/ErfanGeramizadehNaeini/Q3/test.py index 1366fff0..9ce56ec9 100644 --- a/ErfanGeramizadehNaeini/Q3/test.py +++ b/ErfanGeramizadehNaeini/Q3/test.py @@ -16,6 +16,6 @@ id = container_id.get(timeout=1000) print("Container ID:", id) # pulling may take time -result = app.send_task('tasks.stop', args=[id]) -print("Sent stop task, waiting for result...") -print(result.get(timeout=20)) +# result = app.send_task('tasks.stop', args=[id]) +# print("Sent stop task, waiting for result...") +# print(result.get(timeout=20)) diff --git a/ErfanGeramizadehNaeini/Q45/docker-compose.yaml b/ErfanGeramizadehNaeini/Q45/docker-compose.yaml index a121877d..142d9353 100644 --- a/ErfanGeramizadehNaeini/Q45/docker-compose.yaml +++ b/ErfanGeramizadehNaeini/Q45/docker-compose.yaml @@ -32,8 +32,6 @@ services: container_name: cloudredis expose: - 6379 - ports: - - "6391:6379" celery: image: celery:5.2 From ae5e681325f1ad3b86f3ecf6722589de7de0a635 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:21:14 +0330 Subject: [PATCH 05/17] Update README.md --- ErfanGeramizadehNaeini/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ErfanGeramizadehNaeini/README.md b/ErfanGeramizadehNaeini/README.md index e69de29b..16cc7b6b 100644 --- a/ErfanGeramizadehNaeini/README.md +++ b/ErfanGeramizadehNaeini/README.md @@ -0,0 +1,2 @@ +each folder contains its own readme whitch explaines the corresponding files. +see the recorded video here https://iutbox.iut.ac.ir/index.php/s/RdntjSHsNrweSmG From 0dc85c9059f48cbcc9a33e2b3c5c8489827dd707 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:21:50 +0330 Subject: [PATCH 06/17] Update README.md --- ErfanGeramizadehNaeini/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ErfanGeramizadehNaeini/README.md b/ErfanGeramizadehNaeini/README.md index 16cc7b6b..482ef3e1 100644 --- a/ErfanGeramizadehNaeini/README.md +++ b/ErfanGeramizadehNaeini/README.md @@ -1,2 +1,2 @@ -each folder contains its own readme whitch explaines the corresponding files. +each folder contains its own readme which explains the corresponding files. see the recorded video here https://iutbox.iut.ac.ir/index.php/s/RdntjSHsNrweSmG From 43143333063fa9ce901350a3a845d1f1fa3b1a65 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:27:06 +0330 Subject: [PATCH 07/17] Update README.md --- ErfanGeramizadehNaeini/Q1/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ErfanGeramizadehNaeini/Q1/README.md b/ErfanGeramizadehNaeini/Q1/README.md index 5e35c59d..293d5837 100644 --- a/ErfanGeramizadehNaeini/Q1/README.md +++ b/ErfanGeramizadehNaeini/Q1/README.md @@ -1,7 +1,7 @@ ``` docker run --rm -d --name pg -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=ERFAN1234 -e POSTGRES_DB=postgres -p 15432:5432 -v pgdata:/var/lib/postgresql/data postgres:14``` POSTGRES_PASSWORD and POSTGRES_USER for the credentials neede for authenticating --p neede to bind the first port from the host to the docker container. -And -v needed to perssist data that resides in the path specified. -And at last the image is postgres:14 +-p needed to bind the first port from the host to the docker container. +And -v needed to persist data that resides in the path specified. +at last the image is postgres:14 I wrote a python client that I will explain in the recorded video From d650e6b893698a6b5ea51d00c86106d49a2c69ea Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:28:15 +0330 Subject: [PATCH 08/17] Update README.md --- ErfanGeramizadehNaeini/Q2/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ErfanGeramizadehNaeini/Q2/README.md b/ErfanGeramizadehNaeini/Q2/README.md index 4e44d1bf..cd6f0c6c 100644 --- a/ErfanGeramizadehNaeini/Q2/README.md +++ b/ErfanGeramizadehNaeini/Q2/README.md @@ -1,6 +1,9 @@ +##redis ``` docker run -d --name rds -p 6390:6379 redis:7.0``` -The explaination is the same as before -Int the first client program I set 5 keys to a value and then publish hello followe by an integer to a channel then in the second programm I retrieve all the key and values and then listen to the channel for incoming messages -Using redis insight will be explained in the recorded video +The explaination is the same as Q1 + +Int the first client program I set 5 keys to a value and then published hello followed by an integer to a channel then in the second program I retrieved all the keys and values and then listened to the channel for incoming messages. + +Using redis insight will be explained in the recorded video. From 108b525090c43d54b4bc3c4a3e8147a012f67136 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:28:23 +0330 Subject: [PATCH 09/17] Update README.md --- ErfanGeramizadehNaeini/Q2/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ErfanGeramizadehNaeini/Q2/README.md b/ErfanGeramizadehNaeini/Q2/README.md index cd6f0c6c..06dea656 100644 --- a/ErfanGeramizadehNaeini/Q2/README.md +++ b/ErfanGeramizadehNaeini/Q2/README.md @@ -1,4 +1,5 @@ -##redis +## redis + ``` docker run -d --name rds -p 6390:6379 redis:7.0``` The explaination is the same as Q1 From 6fffd30ade20fee3f4fe2665125709d3d58596e6 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:28:43 +0330 Subject: [PATCH 10/17] Update README.md --- ErfanGeramizadehNaeini/Q1/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ErfanGeramizadehNaeini/Q1/README.md b/ErfanGeramizadehNaeini/Q1/README.md index 293d5837..0b3105ff 100644 --- a/ErfanGeramizadehNaeini/Q1/README.md +++ b/ErfanGeramizadehNaeini/Q1/README.md @@ -1,3 +1,4 @@ +## postgres ``` docker run --rm -d --name pg -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=ERFAN1234 -e POSTGRES_DB=postgres -p 15432:5432 -v pgdata:/var/lib/postgresql/data postgres:14``` POSTGRES_PASSWORD and POSTGRES_USER for the credentials neede for authenticating From 3876161731781ebc886152732f017bc55154ba06 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:29:16 +0330 Subject: [PATCH 11/17] Update README.md --- ErfanGeramizadehNaeini/Q3/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ErfanGeramizadehNaeini/Q3/README.md b/ErfanGeramizadehNaeini/Q3/README.md index e4d9144d..0d8a8b41 100644 --- a/ErfanGeramizadehNaeini/Q3/README.md +++ b/ErfanGeramizadehNaeini/Q3/README.md @@ -1,3 +1,4 @@ +## celery The docker compose will bring uo the redis as well as celery I useed this bind mount so I can run docker containers outside of the existing container - /var/run/docker.sock:/var/run/docker.sock From e14a314cfbfa71ed2d2503c611c6862907132329 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:29:38 +0330 Subject: [PATCH 12/17] Update README.md --- ErfanGeramizadehNaeini/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ErfanGeramizadehNaeini/README.md b/ErfanGeramizadehNaeini/README.md index 482ef3e1..faf24e6e 100644 --- a/ErfanGeramizadehNaeini/README.md +++ b/ErfanGeramizadehNaeini/README.md @@ -1,2 +1,3 @@ +### cloud assignment each folder contains its own readme which explains the corresponding files. see the recorded video here https://iutbox.iut.ac.ir/index.php/s/RdntjSHsNrweSmG From 8f7c473208c0f95d9152825d5eaa1cc3977b5c9f Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:30:31 +0330 Subject: [PATCH 13/17] Update README.md --- ErfanGeramizadehNaeini/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ErfanGeramizadehNaeini/README.md b/ErfanGeramizadehNaeini/README.md index faf24e6e..9574d9fe 100644 --- a/ErfanGeramizadehNaeini/README.md +++ b/ErfanGeramizadehNaeini/README.md @@ -1,3 +1,4 @@ ### cloud assignment each folder contains its own readme which explains the corresponding files. -see the recorded video here https://iutbox.iut.ac.ir/index.php/s/RdntjSHsNrweSmG + +recorded video [here](here https://iutbox.iut.ac.ir/index.php/s/RdntjSHsNrweSmG) From eebc033cf9cec28e03f46487d84c603a910b0e4c Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:45:35 +0330 Subject: [PATCH 14/17] Update README.md --- ErfanGeramizadehNaeini/Q45/README.md | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/ErfanGeramizadehNaeini/Q45/README.md b/ErfanGeramizadehNaeini/Q45/README.md index ac8242f5..d3d073a1 100644 --- a/ErfanGeramizadehNaeini/Q45/README.md +++ b/ErfanGeramizadehNaeini/Q45/README.md @@ -1,27 +1,9 @@ I wrote django application with 5 apis 3 of them is for authenticating and registering.(ignore get-ip and token/refresh ) swagger is not implemented instead I explain my apis here -Start-stop/: +instead of explaining APIs I implemented a swagger. -Delete: deletes the question for the loggined user(authorization header must have the token) -{“problem”:problem_number} -Response may have 400 or 200 status.if there was any errors it will return something like -{“errors”:”error description”} -Post: -Creates the question for the loggined user(authorization header must have the token) -Request body:{“problem”:problem_number} -Response may have 400 or 200 status . if there was any errors it will return something like -{“errors”:”error description”} -If everything goes as expected it will return something like -{“address”:some-ip(or domain):port} - - -Register/ and token/: -Request body for both: -{“username”:someusername,”password”:somepass} -They both return access and refresh token -{“access”:wededewdewdedewd,”refresh”:wdewdewdewdewdew} -In case of success register will return status code of 201 (CREATED) but token will return 200(OKAY) +run docker compose up --build and the visit localhost:3000/docs to see the swagger. Database schema: cloud_team is an AbstractUser means that it has everything that a normal user would have. From a030edefb6325e392f33ca5ad66d6fffc7ae9c72 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:45:52 +0330 Subject: [PATCH 15/17] Update README.md --- ErfanGeramizadehNaeini/Q45/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ErfanGeramizadehNaeini/Q45/README.md b/ErfanGeramizadehNaeini/Q45/README.md index d3d073a1..a0e35584 100644 --- a/ErfanGeramizadehNaeini/Q45/README.md +++ b/ErfanGeramizadehNaeini/Q45/README.md @@ -1,3 +1,4 @@ +## web app I wrote django application with 5 apis 3 of them is for authenticating and registering.(ignore get-ip and token/refresh ) swagger is not implemented instead I explain my apis here @@ -5,7 +6,7 @@ instead of explaining APIs I implemented a swagger. run docker compose up --build and the visit localhost:3000/docs to see the swagger. -Database schema: +# Database schema: cloud_team is an AbstractUser means that it has everything that a normal user would have. Like username and password and email. From 373bd29aace1c3e46aec3722be6b551238ef5de8 Mon Sep 17 00:00:00 2001 From: ErfanGerami <52499982+ErfanGerami@users.noreply.github.com> Date: Thu, 8 May 2025 23:46:06 +0330 Subject: [PATCH 16/17] Update README.md --- ErfanGeramizadehNaeini/Q45/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ErfanGeramizadehNaeini/Q45/README.md b/ErfanGeramizadehNaeini/Q45/README.md index a0e35584..80bc5d94 100644 --- a/ErfanGeramizadehNaeini/Q45/README.md +++ b/ErfanGeramizadehNaeini/Q45/README.md @@ -1,4 +1,4 @@ -## web app +# web app I wrote django application with 5 apis 3 of them is for authenticating and registering.(ignore get-ip and token/refresh ) swagger is not implemented instead I explain my apis here @@ -6,7 +6,7 @@ instead of explaining APIs I implemented a swagger. run docker compose up --build and the visit localhost:3000/docs to see the swagger. -# Database schema: +## Database schema: cloud_team is an AbstractUser means that it has everything that a normal user would have. Like username and password and email. @@ -22,7 +22,7 @@ Ip is useless because I distinguish containers by their ports. Port shows the port on host to access the container. Container_id is what the name implies. It is used to stop that container if needed. - +## setting up Setting up the application is rather easy .just look at .env files and configure them as you desire then just write docker compose up –build and hit enter. From 96dabef49fa09b1f206bb09c4edaa2f9038b5fb1 Mon Sep 17 00:00:00 2001 From: ErfanGerami Date: Thu, 8 May 2025 23:47:17 +0330 Subject: [PATCH 17/17] adding swagger --- .../Q45/cloud/cloud/settings.py | 8 +++ .../Q45/cloud/cloud/urls.py | 5 +- .../Q45/cloud/cloud/views.py | 65 +++++++++++++++---- .../Q45/cloud/requirements.txt | 3 +- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/settings.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/settings.py index 58125a94..e3269ca9 100644 --- a/ErfanGeramizadehNaeini/Q45/cloud/cloud/settings.py +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/settings.py @@ -55,6 +55,7 @@ 'rest_framework', 'rest_framework_simplejwt.token_blacklist', 'rest_framework_simplejwt', + 'drf_spectacular', 'cloud', 'drf_yasg', ] @@ -138,8 +139,15 @@ 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', } + +SPECTACULAR_SETTINGS = { + 'TITLE': 'Your API', + 'DESCRIPTION': 'API for starting/stopping instances and managing teams', + 'VERSION': '1.0.0', +} # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/urls.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/urls.py index c515ce00..92e39a83 100644 --- a/ErfanGeramizadehNaeini/Q45/cloud/cloud/urls.py +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/urls.py @@ -21,12 +21,15 @@ from .views import * from django.conf.urls.static import static from django.conf import settings +from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView urlpatterns = [ path('admin/', admin.site.urls), path('start-stop/', StartStopView.as_view()), - path('get-ip/', GetIPView.as_view()), path('register/', TeamRegisterView.as_view(), name='register'), path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), + path('schema/', SpectacularAPIView.as_view(), name='schema'), + path('docs/', SpectacularSwaggerView.as_view(url_name='schema'), + name='swagger-ui'), ]+static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/ErfanGeramizadehNaeini/Q45/cloud/cloud/views.py b/ErfanGeramizadehNaeini/Q45/cloud/cloud/views.py index 85cf3ea1..1432536d 100644 --- a/ErfanGeramizadehNaeini/Q45/cloud/cloud/views.py +++ b/ErfanGeramizadehNaeini/Q45/cloud/cloud/views.py @@ -7,6 +7,8 @@ from celery import Celery from .models import Problem, Team, TeamProblem from django.conf import settings +from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiResponse, inline_serializer +from rest_framework import serializers app = Celery( 'client', broker=settings.CELERY_BROKER_URL, @@ -17,6 +19,18 @@ class StartStopView(views.APIView): permission_classes = [IsAuthenticated] + @extend_schema( + request=inline_serializer( + name='StartRequest', + fields={ + 'problem': serializers.IntegerField() + } + ), + responses={ + 200: inline_serializer(name='StartSuccess', fields={'status': serializers.CharField(), 'address': serializers.CharField()}), + 400: inline_serializer(name='StartFailure', fields={'error': serializers.CharField()}) + } + ) def post(self, request): problem = request.data.get("problem") if (not problem or not Problem.objects.filter(number=problem).exists()): @@ -52,6 +66,18 @@ def post(self, request): return Response({"status": "started", "address": request.get_host().split(":")[0]+":"+str(index)}, status=200) + @extend_schema( + request=inline_serializer( + name='StopRequest', + fields={ + 'problem': serializers.IntegerField() + } + ), + responses={ + 200: inline_serializer(name='StopSuccess', fields={'status': serializers.CharField()}), + 400: inline_serializer(name='StopFailure', fields={'error': serializers.CharField()}) + } + ) def delete(self, request): problem = request.data.get("problem") if (not problem or not Problem.objects.filter(number=problem).exists()): @@ -71,26 +97,39 @@ def delete(self, request): return Response({"status": "stoped"}, status=200) -class GetIPView(views.APIView): - permission_classes = [IsAuthenticated] +# class GetIPView(views.APIView): +# permission_classes = [IsAuthenticated] - def get(self, request): - problem = request.data.get("problem") - if (not problem or not Problem.objects.filter(id=problem).exists()): - return Response({"error": "problem not found"}, status=400) - instance = TeamProblem.objects.filter( - problem=problem, team=request.user).first() - if not instance: - return Response({"error": "instance is not up for this team"}, status=400) - elif not instance.up: - return Response({"error": "instance is not up"}, status=400) +# def get(self, request): +# problem = request.data.get("problem") +# if (not problem or not Problem.objects.filter(id=problem).exists()): +# return Response({"error": "problem not found"}, status=400) +# instance = TeamProblem.objects.filter( +# problem=problem, team=request.user).first() +# if not instance: +# return Response({"error": "instance is not up for this team"}, status=400) +# elif not instance.up: +# return Response({"error": "instance is not up"}, status=400) - return Response({"ip": instance.ip}, status=200) +# return Response({"ip": instance.ip}, status=200) class TeamRegisterView(views.APIView): permission_classes = [AllowAny] + @extend_schema( + request=inline_serializer( + name='RegisterRequest', + fields={ + 'username': serializers.CharField(), + 'password': serializers.CharField() + } + ), + responses={ + 201: inline_serializer(name='RegisterSuccess', fields={'access': serializers.CharField(), 'refresh': serializers.CharField()}), + 400: OpenApiResponse(description='Error') + } + ) def post(self, request): team_name = request.data.get('username') diff --git a/ErfanGeramizadehNaeini/Q45/cloud/requirements.txt b/ErfanGeramizadehNaeini/Q45/cloud/requirements.txt index 9d09d477..d7476b7b 100644 --- a/ErfanGeramizadehNaeini/Q45/cloud/requirements.txt +++ b/ErfanGeramizadehNaeini/Q45/cloud/requirements.txt @@ -24,4 +24,5 @@ uritemplate==4.1.1 urllib3==2.3.0 celery dj-rest-auth -django-allauth \ No newline at end of file +django-allauth +drf-spectacular \ No newline at end of file