From 785a40ff9defd01be0b57fc797ec940627f00c46 Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Thu, 27 Jun 2024 09:56:21 -0500 Subject: [PATCH] feat(server, autogpt): Add Example files and update build option (#7271) --- .github/workflows/autogpt-server-ci.yml | 2 +- .gitignore | 2 + assets/gpt_dark_RGB.png | Bin 0 -> 50111 bytes autogpt/poetry.lock | 137 +++++++++------- autogpt/pyproject.toml | 2 +- autogpt/setup.py | 53 ++++++- rnd/autogpt_server/.gitignore | 5 +- rnd/autogpt_server/autogpt_server/app.py | 14 +- .../autogpt_server/server/server.py | 51 +++++- .../autogpt_server/util/data.py | 35 ++++ .../autogpt_server/util/process.py | 6 +- .../autogpt_server/util/settings.py | 108 +++++++++++++ rnd/autogpt_server/config.default.json | 3 + rnd/autogpt_server/poetry.lock | 149 +++++++++++------- rnd/autogpt_server/pyproject.toml | 5 +- rnd/autogpt_server/secrets/.gitkeep | 0 rnd/autogpt_server/setup.py | 85 ++++++++-- rnd/example_files/index.html | 19 +++ 18 files changed, 531 insertions(+), 145 deletions(-) create mode 100644 assets/gpt_dark_RGB.png create mode 100644 rnd/autogpt_server/autogpt_server/util/data.py create mode 100644 rnd/autogpt_server/autogpt_server/util/settings.py create mode 100644 rnd/autogpt_server/config.default.json create mode 100644 rnd/autogpt_server/secrets/.gitkeep create mode 100644 rnd/example_files/index.html diff --git a/.github/workflows/autogpt-server-ci.yml b/.github/workflows/autogpt-server-ci.yml index 6eabaa132..6fb1d9c23 100644 --- a/.github/workflows/autogpt-server-ci.yml +++ b/.github/workflows/autogpt-server-ci.yml @@ -265,4 +265,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: autogptserver-AppImage-${{ matrix.platform-os }} - path: /Users/runner/work/AutoGPT/AutoGPT/rnd/autogpt_server/build/*.AppImage + path: /Users/runner/work/AutoGPT/AutoGPT/rnd/autogpt_server/dist/*.AppImage diff --git a/.gitignore b/.gitignore index d23d09da8..d7a9964ec 100644 --- a/.gitignore +++ b/.gitignore @@ -170,3 +170,5 @@ pri* # ignore ig* .github_access_token +LICENSE.rtf +rnd/autogpt_server/settings.py diff --git a/assets/gpt_dark_RGB.png b/assets/gpt_dark_RGB.png new file mode 100644 index 0000000000000000000000000000000000000000..e99d5ec6c9f85f4c957056ea6dc786669d7590b8 GIT binary patch literal 50111 zcmeFZX;c$g7dBc|83_pi1qpKy2NZ`A5D-MdV9<5~wQZ#xf}%tl5j7$rLnT2FI}8r3 zh@!zbpiQ?Zw2e3=f{Kcm*rZ zAT~5PBye`Z-o;&7Z9t_fizMS&N<@W>WjxG9f=Gqunbn{JQpROLF+2L*qdoqi>lOsCVqyCJRC_BCB1 z3P)*N1)K6ABGo}YDk=*4PaBz)d|4|cUzkwy;h?Ab?Xe>}$NAir)%jU#J=~Kx%_EX{ zJmUI+69i66&Y|^BmI3L&8tI-q9`A=`A%<q!jXEGn8On1e;F zm97YIN8RnA_2w*=*VG4ozH4zqyRu+RD1?nRGC+B(!}^rMTOAN}kJ&NXNt9King`oA zYh6xcr0sF)j_zW%vM^uj_KzjWydIBiBC}X5V~tpr4HtQLk=e&PLsz+)ZK{=PilJw% z-1Qy=m&%D@SJVN7%Ji#e?s0cnX6c-U@}tv?;LqxCgMRA*zVcr}ZF}frT%koNn$f=n z&C;4z9OPF%T@Yi(!nXp{TJ%5cV#(jGb(2HOJH#ac1QW)k!m}ZKpb}*LlV85P4RDDX zW>K^jUHU?^=73J8=Ex5^P50;T(hh~@ebGAIg4v~ooBu5w=j(Tj&z7ou{!UeMgwD0QN=K zebLO+%fTl7D2Ek)*B8pKh$Zu*_1V?j3p#yH)k!h}&!6b_!Tuln7_Z6w zN~!qzFH~VN*Rgd!tfA&E9`&~Q=p!3effc*9F>2l1wlk!%&IAOgWTo4E%>uFxZiN3s zmO+}_PRf1ie7PL*CtF58iGlnGvQlKneebep5_;RE%G(`9N93JaC$LfJY=Z&BGYq?Q zOU;hX=r*8KDz<=l8J+8g9Ly8X@^|pXSDM>6ZBE9f+=!OP(xoA$oa>tpud*o^sdG1_ z#g7^$g0*(Ztr0}98Mg$L|X#6=#cuN&u7a%J2cXxBLPJ<-cOq0y!~BMG1%)Jq8lVIaFN?RU|eaw61?BB6)aaIfnb<;Ul&9!DGn| znjPKIP@^dpKhWHgerX=;`2p<4vV3DlEsf_viSHL)DVZjlvRNm_>>uHm%+PH6`~q6h z-W8oTiX?)6(rKfp`DjCA;J<4HbD#zOfBa|4H&LbSw!3GB>LD8*`-67L_JYa6PXtda zn{;Slh&)Gm@ID|)?AYNbeYm5gi(4oD_#d_q>vv`fKSWygMr1n%2v&0HqC>{b$T#*F2Ux( zF`pG4Bv}CtL0mZS2R-n~6_>Pw)erikc{)=>-3N}r;rLH<7_g<0-fCGh&#y;(^^ZG|KwoX)8dK(5IqNCrty;`tOdUKk2m-6mY&V1iRT7t z?Eyn7g+HTXaaq7tkmeIN2IRix3O-b(&VeeswtBc>v1a_2VHdlsWJk>K)EV;wr9nBz zsU16{WHL8BDe81!Y2h04b!6@*T3GBO%|f`PnW8#*_;Tmm**U%<3< zHREEJ_$2Nt*dqT4Yw_6gN+s6Pq?EN8iU#z$Z6jwqu2X0o5dkV$PwrrD zQnFe~kzknKFi%*>N(bu2PC;dYwxFQ88I+0!Jti}H?W{6C)zY6G};8m<&(Wa=$A+nfh7QdXr0WPsdOup|A|H? zp)5Zncti`2SJGl7?GN4TR~4%Dl>Ygbj@~u@;HqiDltL|{b-uFcvWGOQg!z2QfQ+Xg zt$YSHKB;ro)5&F1p78$2GTjv?+2@1%NEpF5O^G-cl&Kk7iF&)}>D6Xx?tv7xA3=P= zMUIB}5^&X)tBsN31_-ks@PmI{9j(gw=nzc@R< z*W}XuRxE_4^g5P-unq!ETZDm?q4Rrlw>AaMZ^=>J{~fncpGEZQ$rFRE(dfAw2`v^@ zo#;L*>>AF~UQLhs2Piq=_7jijr#EQQKOa#mcJWk;vsE`P;V!eR*JbqUu*50O${~^I zrqXQaujFy{A8GVq=p?(_!3g~h_d^)5?iCfow5i;5(-W%$xZc(|!1wcveSc~o(2#OS z(+BmQwD93;8fs|tWvC{alpe$~yE9MdOeMcAhCaaj$&Wkh%biHUJ{7ph9~vtLC43dB zmj>FgST^ljlexPF2Z^KR@FtD6ust|sW%}cjhYL^EEkjT5`Kc7CuOW}Ni#Qu6xTgd# zC8qVpQqQ)8DGIF_Sd5^uU@hh;TXD1l0gyhN7309NMU=0fTQ7bbx{HCwa#3$4?@=yh zBGTG*d!TjVWO3=^BabdO0gqwr@3M%e+1++3{4$Z#93Za`+n`kCFylI22ECX(pjh_r zp`8~<0H5e_^^_G)P1vWIwb49KZ@u*0GX~)F*!8m_=Rotmh5~>P4L0=|peGV!$6nd> z%W023u(1I{X_dJI{ifdG&6UUW7ny?JfV8;$I=lL7I~QKNpbuT zcFJn(b0d5$^xo46gJzfytbABlFDxwafS!z=e-c~LPQ3+E0NK{~O=$|EP%90OP*V3y zXxg#?@X27Q3unvesy~mEd$gH*if+o~anOYPo7HiJukAl>{ZeQ~b5IwM#99fRhI%FR zA3s>fQkqZi@pXV%J&UA8HE|6-f82(us9U%(SVOlyy<0IUrwL83gQ zTPtP!VJG!Y41$K~jCAa@T~32I_xi(bv8`72YCpxfdbM^b^qNJ){B8&1Z`QUISaAkW zUhiMcdTkC^E{D>K7J3U-!(}dU(0RxF$h=w_D(5cGs413*YNp+kmfuq*{IQ{|$vuse z{be*v=1#f--9K>_s7cd2Swj!IV}ZfS^ZD4)wOsE307N*mjMv_*z-3-r{$l&0txI0w zWm?$d)*PixJ|pXHo;L`VNcg0`+<`zjIFHb+cwobNUW!ydR&P(|`r+=TG&lC{Ns5q^ z>de5|uc_*vXB_Ahw9x5sp^!U4E-xu;`pl>B24OKb7nx`SOUV+Y4Z#(!$Q~vQ7Z7t_ zPn|y@y8U1w@B{u2x}}0;t1<%xKqIv@_MXzMLW>75Yh{`wEce;hDUk0hD8I1Osir^} z=>u59^vCb+$sBNxD*C~rs^!=^;-v6^+yb~Ep6J*OC=XOo^HEJj+}&_aw#j%`~Y4q2t5_VC;~hp~qct)EVRp;4n44d z7EHgiSwltXCu`;C9;^BeCr{J3?VS+bZJUkQq+CFNokwgmB_HrWr$&=|qUpF0{qq_<*W(CA~y@jx4*a=93=38OMD6gQ= zHW6c!_1+TRO9}KFqd=`x&UD7W)EjL8rrotqQpxF}hBLAPEF3KhT%nvH)Jl~8B>ogi z=(}QQ)Y{AuGuR$PeZWzFP}34L(>f_fP9k%ww_%ZEaZ>-<50SbA4ebK47q)SIyFeO_ zCUJg36J%rfhuNus=mjU?Nt>U6HxL&aIWs31&7{0s7CGGOPN=3>9)xH1eARThE9)|Q z@Y5qmS>-F{$7ewB*tI6RhN{gJ&CB(o#TnPj92d@?*-)kVOFE!`apq-d2cA2=C+WhR zI?1f_CDd%GKAW4HT_AJ@s8XErqf5S_d}2~NkRuxq@2H&eq7^=BS0)|?LE zYi`o8oy5VjA4R9gbsbR-3<^%rq_!D??Q)zsa+TTdPeL*m-0@s}V|Hy1(ji8H#F>an z9pDxDGp^S{@&7m}rifZ|9IZex0z2ngW-ondPFEIspdlYYc#X!FQLO=8a-2*VZa(sH}oL1EU$)nwR1v6 zD((w?7SnH&#&f@^O#^k;d&Q8fTADg6XUvvQZQ%LIN?5PodF(OBm?>y3pas>%(8o2ja4c?0Qb~B zj;{wVB(LUc0GzbO+{OV;cfMsK4Z1{&7_cL(Gk3Wz8fCmN46JEFmuQDdTUH+k4TW;X ziH~|T;%13T0+ZH z^5=GLzRD|e!6Q^n1m*Gk4yNx)s^HZp&J7wp1)31a_cX~7Sr`)rj(xoxvYRFw$Z7}a z7FO0JE`BCceT9KF=pbuQtLp=j7?oG^eVpn8qXb(-6j++MB< zN4t9KRQ*03(M?|h_{5d|imX+$?N2)eZ6u8f0-o~QZ+MM;fIaGCh9Z^QwmkTAoD*Gs zxhc@o4U4G-1sgfz!&jNzmQV%SCmM7TVgw-Jah%IWEV<5{6PTe#alAVQG`L()7X#W> zktZfbiN_6G~W)Lm$pDLN1sw3xM4T!+q#8}WZ4%A zSAq69SJ4YMoFz|2stCU8iS}Gwpi4%SM8On(SQVV~X9the{+fzPbW-$*aGewoX;yi+ zw>Kb$QHgo zL$K50F3G9^s|QuPS!+W?R`FE6ZB+58ud zw)dI~$1NAfsZF0pW2>6iE8kd2C+KqzN>lS*CS@~~gM%rQ`wN9I(xn`H2>115qnZhN zNv&pXJ2Y+wd@Y*PqX~o#HJgtp2-w^@P)^{F2WWo$&7ybbgv<7U<}J3+Xgi*elgl+| z9Cyc#!9kVn#KO#HGxE4MZ|M$9)uiyN0UUzs+qkg=kpDPS(v-LDVq0wdV+EGQ>`*d;(bu|pr$`B%*6Thhni zYEf!xfahfL;Ax;+Nf=?TV-%nOgm>PsvGpMGID0? z-b{ZqTXM^pRaT0W!Jp4BeZ<{mnk6bULVpVwx5Ce1-EkLgCCuTO@ADxZ+xyK7`64T+ z8SGLX+!p7$$@7n8z#6ZTuU{CZyo~#Hn2n)9w<2U!-N?phl6=?W9RW*i{huw?dD7aF z#RC%3p|XHiF6j%zg5wZFu2}BgreY{H} z%#=eSKvQ?FFH!6e<^@h=?tj^tYRZ}>knxm#3J3pbK)Ju6f4skN5i~)+xTe^*)k2Fy zB$rDOC#{Dln#i4TO6R9^Ds_eyj@akp6zl!2M&33qkh-f=nw@*`d9CUUKrwco%z;~| z(m^`?w%LJf$boZFN9;iQ%jG?rY8GZQpBj&R?pIg{RllKPkT&(QegPwHS2X&!PA%j#E?_=`KBzI_h z?g~KZEBdGeUnP=sc#UY4ZT8UXGjK>MyLMRGa!+$LP$!XsIcM672O#Q{)tsrPeTlGR zfK@_Htr;l0jRrHC$hMnTmN72@hRxYymFH6tiJ$X@qdVlsUhb8;czbVq{Iqb5$lOsL zP_a9~lJ46Z$~q|soX|{>*NX5<0iYd@ZNBz=@jZ{js-rLPs8-|>v^I+Cn;b7T`qRlP zQ0Vaf$LIb$KaAe*F6eB7g#a9Ze|koZnutSk{Q|@LMVGZ?SX4=(?F-6D zra$Y!Cz?4T^EfTzwLykWhDiAEn(i4`tnz>_E2b2g)Ew$f$0-{aJeupzI9phrdwJ+z z3|F~(N7S1IUsnp)(Ux>G!`C}ArPh+I7k=UKr%&_V>A%Dmr9K#=^AD1x@b-T`Lvt%q zAvb*Wj#t~rK@V*}sE#r+EJWjjx*aB8DVAS4`C_Wf>M9=5JRf12w&W|}spC*zOXz^) z-%qv$4!}iWLr`&MNJ|k?S-ur3?T;H*RKH)+?Z1*yyzg44@Zc8;RT${*#^GJwAb10S zBEe94(EFBN`A6kMuPNpP-CKK@B0Czdv*QDK{?WY@7R&h)Qx4s`l4(YgSF_*z{5~tu z0dx~+)%YoRA0s%MY9_d$ZGYUj4CJ>X*XmAZLGd(lt_LYeE1$R`!kxd2RC3o@He~{6 z2pRcgA)OpM2Vy8A=ct{3KBB~l7}$OrqMTWsQ&$lclS|leQ*{p@ey*Y7oK46{bFl6| z82k-N&6oo^7mj4!nc9@ZDYba7aCgJ5IpHcJfQ|HRBb7`IsKuc(jg+3td zOP0|(%2nbx=Js)JXvlQ?ZJ&xAbk7^rE6x=1{bK0v!9lYTW@u=ZPT`;n!I=>zW3cQ? z5wx2>E`UZR8yc#RO8$z!mAllVVmyBE8;%ZCG+b3a3#tRgdoa{23lB7*v1UoUQiK)j z7zIxH8-7KVdEyoOg1kAF%{(;^?&pWfuIq`Q4D$3tP0r3Q+8P@< z1_irZ8%hy!;pFd}0}L0YPHMdCP2-|@*E*d%H~FTPtg;_+Dan2XbLV-Ut%HLtFe|{M zLFPNO4t2wFk9;hav*!&=i}|}Ld&u9WcUV@Y_E&3abAY!u(#dpTznv%8S)pmdk0(sgk>#0ocESwvFS4c(c`i}z#)$Svr zq@d80V+lE*SJ7mu0Gh_AFJ6cgdCzp81RS?0b?#@;a>2Qt*Q?1S&vP3gru4sJXljZe zJ;72*>6IG?xIm^(g4~W-E04?7B-tjd{^e@;)sQ%RloExDMYS7A8anO4s|zNQ!<)i6 zYYjJ12=Py)tTDeq!@L+d4~OZK4v8rLY_gZ3ynl~krUbo(gZrEkcYFkEml+LL1u~?& zBo@h+J&z8hG6sSHrk>}k5N@6O_ST_P6-6@2&Vf|cCj;YxE6n7(B&thU1aCKVwcx)t zz1Zf=JD=7%O0V3g3W1w%(&QcQS{brkxmk#9A6lV*+*T70N=Gb5CJVrg4T$mpXtc9K z+eQ-KlpCED3a|X`FuGCEKvU_J%xlceUo_rsknc}|_QOrOB;d-nD1P&TxS-~rICPVp z6(G99pETN?&vx|irSXjdT0!TZ`h}Ofccg#fjvf<*LEV7K%&`c~x&0a-)sSn#v%fyMt6IVZn>M6!3K~EDUuYsYfzYW4&>E|H<(1Az zhQfs zf4zOB$*PiJpA8`a^u1mbL%!?_vN66F@%9gpc{VY4c|2q`Y0(|ei1iYr+1Q@cu)AEd zo%7)4Vgl&~&0bowS#KQ{X|9~OWBVp4ucU?+))c!(RV#OuPUvl6>7oFTjc&?H`@=W0 zDrXaA8%g@y%;PE27iwCdl{?qp8esl!@#IJUy!=zacef+WHu7Qxxov+QI(HeV+OEl_ z@tY5qk>*BI)cA{Y1O6ND>j%mZqgH(&fwSHe^efszSKpM+Cv)-HBwg@JL@;a@SxPA9 z)@ML$m8bV&--w5(foC`g8_Fcd+76r}`R#6Sb^Y3QeKe)SdJu=EXRAIL8h zFUP~c_%scs%qmv`SA4ncL?AK%z^yIlx3xxe<#$0jUD66I@k$2Zzs4~9 z6%c<>5oj&z-B>Y+*x&Wtd;EPZC2eQQB%`csNwfP*IO#A3GM|!G1giH*+{97fjeRJW zOTU=r=Ln-Z>0sqj9s$|IFFMiM+M7rJ{AI}E;pc+7EgcUwI zAyjvUN6~Na`~yTPSrO!6BKU3ki|n=RResdAgPWz%(x`wv-^qw}Rdm+~=-xaU?|< z@l7F;N4g7qjGdZB5&SFXM}Gt1(VQJBoJr@+6REy{5Zhq1MdV{}OT&6t!S<4-b%P!wiE|h=0+n!WVH z0XkfANNg&2e4qOn9L@r>CZo7F9W=yxT1%VT@r>nS`nfr#k6$u`UbOw!v(9+ioA={uId8B(;$eEL_)LmY=WN~G&A6P zTojUd*ZnAobFd2W0$Bl2jp0!+cxK~I(Ij$5!+Lty$E5ZHCwgLE#B1BtcyPTvo!`6< z^w$j%HBuoQ_Mqsd?VRg;=+s zC7fs_NO-A_m74QlbK?zy7RaeBQPGBjH>op&nb-Gu_)E{|CJ1p~D?(14TCCft3adz8}>jO_#5llOQ(kKSqr7LA)<{J@CvIe`!uwAhObivT#{Ed=Ta{4moSn>8Fo>q3XH|U~hdNcj zgwHo=T~~(B7#w$^#pb^ZRb7t-g6(2{dsYFwqHT52gO$O9SoqH$8yYWB7&s5@%`L9% zb@9C1n>17sJJ697V&wh#;;Ygdm6F^Wm4vZw95IMg;6r*Tho}RJr#f}5zi$p0EP#d8 z2C#r6Vuj(Z76EQ@T~z6OKaw;m_s#A=Z*XIzF=TvV|F^Dexcy$!xIUl&Lw!ULws|o@nJVnX zoHYQt%G~$W%o7HddB)>@)@E#Ik+wv%x%x>+2826}9*o;a?S5?0gbz)cw+H^mYu=e2 zPyl20F)+h?>G(eYoM?di|9*uFrx+>(Z0aPS328jR`<@bt{u}46`#!VMr#g*y8EQO& zupuHZ08|pz!{Xk3H>_E_r_kHtzmz#xig=OCug5?va2#dZSdX9FWi+QW%ce8C1YX1X5A3YHG$jI9;{$TS6Ep7dE-OK_uN? zyp3#$kQ#32LVZeDx1fE{H&=z#mFWA&xF5<5=b4ZQ5qz#Q_gX2!T&}MA?m6@p{?iI9 z!kYe4M+l6q4|Y*qH|Vcul4f>E_9zQ|M?$ofkp3Sy;#dGwY%G>YvG$=37Y>nZcDS8M>PoAQ2)Dcs@7COwG2&aByPN_x2K!k4;X} zQX10-)0Tm_0??vQ5Fzk`0%4)I8+*ojyHJJFup@*-z`{TeH%@_QyMOw*{gr}ZfGDO|O1%;!fdLGFN)4Rb^T))W>tkfv4nebc^WE)m>tkcgc7+{?gm zLP!DV#uG$E>$nYAsUKEDW7af!)sbZzK~{)2LIAkqbBHMG!?!JhhNiH|(`|eOV4FN6 z3Kan-uc>kHEJcc*OCFBt!9W)ay0Xy=q!T6MyG>i}1~MRso`!b)xo=DIsK2QFYM|rX zpygx;^S=$_J@J-%umuD`@R+Z&{%oqfBl0HK{}WCc?+4|~h8+hD1AnFOn7%?y_9%I+b#IxOoj z%<3X%ipJk93>@IM-}*+vB6))2Ae<}=!|9mV1kpN#)f@zUk}_V;v58)x#;t}(SZB1J zzw~AO<;PXT8L7De!3omV-yZeEvEGnm!=xgL1WEq;ZgUyjSJ~lcKO?7seQ(et1FCv> zu0Cf)867S(F^bj&d}Dkf3sWvd2BOEX!GSbj@IEWn$|~Kd15mNld_0RG4@X-JfC7x9 zaQ!U5y=^n;%x|X^U>4Wit!=e=d88$s``z_g8Vhj;0WIhYiMvCmPc8d}W9~|L@Z}_p z`W`CT8+~iA&36|NZ3Ttg_nn%PDdDr}jpq>Alzl%qbAt##0@?uXIp~Gp4DYz<6T__w z#p#fd;LOeUrC@@E}W5`13FJEMhD;zc9RY3Ge`*85UdnE$fA24lyk9x+_=C z{ro_eCyW5$n7A;h)&1{meDqKEhOLy3b#bZkdT+E{o~}CRM>8Ho6vE=Az<*8z=bKJd35Vvj~yFFqqI0fM)3_9 zp7dmT31ZK?XkK8I2abY3V0joKR5O8_&a7V6?|}|Y^_!r_qLI{EGtkxJ?xJQPM&#g_ z_~Lp=)cyz*9HFS2wK)r$Cg^wKV&8IP7~Sv13NjSx~S7rA@+$iK5j34+%DN?JJTDY`kBP!~QKt5^#Xq7mJUfSae!Fsmts zHV63L_?D<3GwHvbL(DFk!|T96%qlxa(jY?=0m)O_#`WA?iin?773TcR%nLQW{cV%3 zP~uNFdClhd44+XI51u>luY@UmHQ=Zj7-m5eH+|{xB%~N>aHiT5H&XGj6D;X_P~m-Q z#1>p#xjx+$aINxlMA-|EZxJgu`8a3wDy-F6dR1+00SV@2=#IYo3}55tBJIsb!Z~)z zp1^-r$JBM@Vaj{=$zKSFJrVB~=41WEum;4he z+rW&*_cWlJ5A-BVT(x@wiU$21bYy8L#^se^-w=}H2_9lJ(_L>hjS_7F9ZKE61jnj( zNBG%_Cn`;b`MI0v zC=1NeQe+;G@wqC#P`GBEDqI&nl``zkPClypjCJ75ClCf# zmqF*o9kbQ6ouTrTHqe5mhhbn8u)XE^w~)iJ81E~{A@C32A&n;(kU2C_vC7o%zD?$4 z&DbqxMlSqN1ua_s&v6iP8=JZvk?5vT2n3CqJVf`1{y4~_VvsiQ@3`oYa~BJ$YoRXM zCvY*#Zn)E!tcMOg%t)VDFhk}F_*%umZkw*?kTVw@N?oAy7tet~JbF+0st5Bv*Rosg z3UNUzrJb{!o-W-A4zuO56?(}Z^!Xdowg^iIa{L*5asce<|NWW&`#1k*+EJZgV5oVp z%4rw@{V9(vG3%ceeo|35schKsFEdWguZa7QFnQa-@rU+O;^5bB4y__P@sLkHRVAF` zF2|U9n~br7*z_u8orzh3Pav`_S2Whr(n3&Uo!fNk_Zk5YJRW2rgZt0rXk8bnq5Dgu zYvej>_I{{FAAn&dsJpF*+l?P3buBkPES)D#*J^J%v9gYb_k~V8BKkOe7**;4o3@S6 z77l^d(fW031GGHPhg^7KFH-c}K>ilI9GDm783R~B`HUlAXs&MG7l|aDBzx;cbL}$~ ziX-$l1_g*Ao4|=Cc!iY@1)WC=-zja8o@Sx&)!ug)Nd-QEV8dWYhjzCyMI~pbzK8hu zWt2(1f!*?845$;R2z}QI{T01tDc$qwHoOe?C`H zW4D3HLp+4^zpRq4n)LI)18tM47W}?D6Na!oDfY;p^V5B%xa)pqYpgPeV^{w**mbXE z=o@DiiTIrzw=@*u+aR3CuGO$S`K{Y5R(#n9*1PmH@I#EtY4d*v0Xp3GqeOaJt0|;l z-Uf5ulISQ;0c-wrTawtUHxcM&C%-|cC>#T-Cppp;wGh=Fd_SoRzc-`q)uet{|63)l z0BwqX>HJU(_VwfGW`W3V1_ZFL@2JTp!Q*4nE53xnBfoFS*e`i7a1WZY^h<_2m6dfr z9P2Y*YGidDrLxd@WI)AizNNbNV6x?YAkY#0V#()U{0Xl0gNI)uEP){2mwu}0RWaYI zM!akggSzs(a9BcwHE|3Cl_Y1v(b!+UdW-zldwP{3pMVnUJ$&@MZ^D{LZ@_a#09?{oeC58ut zIKF_ygWvXNaqMVp`V$XM=evXH4lXih_fO8?+@9e21+ef+N>pOm6P*2SfQG#}@E?8l zwKMEE^Pd8+#dEup@i$WPhV*16c5m>5;zO(D*MZNBFmi3p$dj^CzXX~OaVpIE-Bfw` z@+Ot)DiA&lc99hlW}e^lEV4V$e5!S1=T4!pNzSLFYG8gtL%{s5_gd|S%YkYM=-wN& zLPQo6>2<_j%BqV~IxUWjvuG&C#-iL%=TPur5@q%oLO;h98$LPDe4&D#l{zM3I!cUpjtS%{Ot^CQrh$T4CPtBh7(R9 z|9ce^sZ1;7hFnBrIOd35BtxRQe94uy0y_HM>|(de2qdyJ1@w0qWJd{@p)mM(3J!3Q z1a1NavWCWv8o;r$mU)oDbtaL;Ls(AYd8Ei3#4u9%mj_n%GPwv-eO=RTbYANWRBS<# zIY1(wi{KPb!CwEumE{ao5M3k72pn_Fm)xHl{Y7J%9vRJZ73WOycqm)P8fysr&L+CV z?SNr{Yt~eUAx?#*r2bsH0W$0%P5UcXsTb?D{6Bk1_O@G8pvrVQ^g3$_ ztMS+1-V2v{K5r^5zz|o*1+)++6#u}{Y*;y+Q^}|7i&eV_Dpyx(-UT${ug@i9%GO!i z7&4kb3fB)7BNFgQCU_pNtUv0?d7_yLKf`T5NO2L+v!Rl94%?{d9Y~TgGEKmJS}+Dw zAQFLJtzx}|$AFU{e&zCunxhNFWXUL}1E4!VP9Fj84d)uo{RP6(O|2r8sw&XbEXa=} z`^`NRreXWc%6Nhqaw*BFaKn1R&YTeZH0TzuESNLmyC*NUwXL-$Ra#-T{eaI>q@-3b zaNdT51-}{ZB5Oi4?th1)7hzWi9n;+RCMTXq9t+(#Sqo^$S!m@0e8RmSXT0DL;Cn_h zr!WC5$dEBIohh6vK@$Lj9D(m?8{B>pRSvn`wbgMzFcsUm>NRDZn(Nmtp32AWXVW!=GkCE6g8e)V6_mF_V@CT7w$762W$w{ROu10QH>$=BLLgo&J(h`&9P2 z1z_dT3I?zX-eNULABK4i@CJ9W(?_xj2FpQ@nVimm4z1p#n)Oed(UYDO<-*QRaMhuN zEKPsBNyYfJ(vC-3DwK)hfmn|*>Mx;3|_3@>7 zq``v8k2K__t>Bs*m}JQ@cLYC*RX+jn6zX@T54!1|g_S`9LCESTM41^(;m%mi%7+pk zyx9aK*-ZQlfXKJfo0e{;cA9qA#~^5sV+0Mi@~iA$Y7QT5C}N4AhRh3S;_q#n$tBM%^ zN9W5mhc@<+RQDjn-?SR42#EsywW!>H#Izil8YvoNoFm02jnEEoz88tGyU$Z zcz_~X;Iab=Xhj*|v~ag_X)w6V9Y~axZqPlAq+@w7?sJK0bMV?3+i zh8-zN)Tz5jUZvnSiVbUfaNVgaC@;V^QHIgw0S(S9ABgcub?7MFc`Bv@FFzS=B25wrS}s%MRzA(f%YC^wKOP9bQMHvz&{?;OBsWHwcpF)O{9h` z^Ya-W-d6uXx_)H=XM8*P z6-diuzYf$knBNoyrGw4kQ+7tth64PZ%~~Myr;&%LGr)&2 zcG-h)3*DS8QqZ2~#6J&Jupv|Msoj9YE0EXs2yc0C0#r3bg1jZ*pY)m2-d-S{HoXW{ zx+|iGQ-1&Z<2crHk2j*z%Ti*tfu2)O)r!nrvRDARzpNIX;3{m3Eu{HWl&u2yj@bde z@5j@~=Jxjf6RAvtn2tjm^1$dkeJVC;x!qgH_m*#i99%CXb?796gepOXVGEb1f55yg z=kPqAxhURk1|OIz^8h393|rkcUZH*R2vAy#vgeU{4|m%ElBb)+`?|&^62WsT^v{`$ z>ei;FwEt}zWMJJeXo2I7fLoQ|&}yC%of*msjc(^E%qcGC@s}YJvPUro8eZSy=w4I_ zNuF98?o73A}(?UW0u(7CRq?d{-Z%Y1p7MSM!9M)J^=HA?Q(a2mAKu?V#b=+s6` z-)6`Y#-qNr9<=oS>WtVlr;kvgQ?>4~>AW(P7p;io=#HX3AfSz=`q+@aFsl7978S{O>*X5Ew|$3L z24J`7U^@Yv>L|^c0dr+mp8kJBmt+o}*Azs4p4l%-v|@SQaP`25hhL$^{nwg}yR~fq zfq#B1_E?orNVfzWWO@f^XJiz%WQL<`HM=Ng(BWrjOryO$I_yn;)?PKpo;y3sNQ1`l9DgyZr{W*V@!3F;W)}E0~IX#J@ ziv*1s0gHz|F_9w@WHyvN%G>l25+9HA?x!190oK5MkuHZB_gwY5X{girFz>pXE^5k}$O4=ujHH z;+`-vPispN+HEE=c?o52XDs<1&;WPnYw;D$lhV8f4xoQTC>8c_-HG3wh_yDwyty~b zz<|Cv(G(EIu+i4o&PtMU`d3X19E%n$qon^Dtp+?xB9_~LW5_<31UmH{Vv#Bvn$u?C z`_louv`a5U-$83!1W%{NZO&>__OE8{`n_7p*b06WUt-=6HN5V-qoMq?*a^0`j{G921&yN0#qszbx4+7}Fl2+0Sh97wmsywbWd4%|OVcMN)y?aFGko*DSbpCzg7Cs&lzf5Ha~ za}6pw`Xbc#_BDAJ6&!qx@%}aF&BQn?w#5D=uPFO(@L@uZ?Ip6y%bCsx=ZQizG0!KF zNy>Y#fyTkLjEHF7K`(4V z(EHYs)BgE0p#mG5t5dq$3%z}G$DDkFAfgALGmp%PbP!scE`yv{O)`me2{$8TALf9GRIT_A^f_RH-uz}@Q*aC!_5m%$JvTXit{%{_dAFDPh_d%AHqr_^Q$N zqf%^oF2ZDiirNHlqa^g=Du=^F%BY!=V$B2%ej5}Lf{K0bO=mp14Va2p6=%z>k38FFXXVGm7FZg0Op?cbj(^{NZ{y&4F0L-%Wz3xkAq7jp3QZV1y??WSwKovO$ zR-5~5x`R3S-ty)HM!jzZ_|Kpe9qBw6B$B}j$!LVnEed99Md8Y;>-b{P zbf|&ju>4;$CNVeTd1K_c7;0inYuut{?}0m4g02MTm+!8PgNW{NriS?`oU1wgx-vPQ zS5ox|XfOpj6~ixIb;_Z2%2)3D8sMaLhT79TXx$bJAZP8+nDU!u^qu29faU`70`~e5 zm4{L&!2S3n?!{zRTyX~Xvgnb}f|KqQHCQ)f`Mffosi5XLuwOj?H3EDBp-YZ+Rwf<4 zEj_bzPd-nu{{eWl;YZQwD^cH*K5-n!#IJLgWTKLsjU4o-S^sA5|W1lg)dVJyU~YE9{KBa!!?F;@8FRLS2HtoekjWu zw1t!GiLFu+OOxFWntt}|RG+^CGg`mg^P%nyGDRyg!TlU$g~1IM@O;JdggB_X$>$>V zTs0r}gOR$S98B2cyJf=s_pR8QPT&>1xrPxEjwT+sC?#}Owg;VTYLMz)xnx-zw1La5 zY)Y7*EqRU4pwM64R|Bb~2IpGz1!x4zYyxV3*NJ(*|8{bMV0HT>wSr`uet%|wrsiRs zKanRu!H0v86^8FzfZL^m(-pVJf%TlR1zz5jRol$?32NTUxFUwqU$w|Jyn5V|`kajd z7u3COI-Xqwa=t9dk}X!9^%MMm{?&g29L8flLj#HfMQ0wPy3}iLszV zT68F0ww_L3i29b|6{Ra{o`F{_Kof1Rs!5e60^jn$9A7!!233=~D%9^5>?&V#&zIvQcbt6Y?C&|_m0Ha$iKnOeZfvu$z zS!f5gC8gv#r5BF3XF`CH0srrFhg&bP9a`-5Z{STge0(qji!6T;?E`A$=s5gYvOx)e zuPhC){afrLX}w@W0;6P;$AbU9jDMV?&)$BR#JCv+VT*3-s^%a5u6MHI|JQ>bpkLe? zc4*??pMZ41){=*Rj_FYF?ZN0Phw&XR7uztvC#}FYSJQu1#4d8c6t(`Ji^sUh5J30;yfQ%SbW;3}1FS;ta}B0|6O zhRXf^{FAA9pZ8hLbJou}C!={iWEVkrd5CKazL(dc4Ae)h5y>CsAbh#XK%D$sbQT^Q z6yJ1r1THLW3+7FLZ>M4w2PC#A_4TMueNuZP2FaF0{i_y%_z!T2Y86phiB-Tr2O-Db z!rSPlmdC7xYdo=RD_hbEdc;@r6X#akEs!#!eW7C75Fqfkxqsr7P8v;@#E4;O_$4fJ zkGGYMZ~8p~&X`d$lZ?F%Qm3wt8ywD_Tf z3wNLG#OhI0w8p>w1vXQmY2Fdc!Ycxx_W-F(YyL|H*gKA`QU!S8XI_!R3ajoq%99m z%~1#OyNqE%Qk)=au|l{{ElzE1xW<>Qy6DQD1V@1kJ_<~)Us$^#%ci+eA6Hiin}XcI z0HKalEq~~K5dxij1#7YQZAB)&s4Gz*VUDmW$R^5MyRhck=S`wDF$u;7{rI5 zRs8ajEdFjRe@rhGyW>lLI+RZ>6`Iw0W%&64Jh$Hi`;W5}9|Rv3*^|lOwa}|9_bv^* z?Yq1GOon!Cz!WMW>@CMt7~|&P!0S&htu({lZ%qA=>6v_^xj%*GKU3`jg7)jeQ34cF z$kW1-Q6z}--blA554=i_ru8aRf@F|7xW9igMq^m!w`(jm%CHbm<+?KvbIt_|7}6bD zi7w!O;n}rFl%vYAJpKmb&n|;|3)JeVsOBdrZ*o%km&a?-rqSn|z?91*1aPXD zpbVUHmt@<5zrI!F@1&tXFexK7X9#bAmFoAebS@ZV!(=(Xs*V(XwGx8Mmb4>vldQT^ zc;K2C$L0D1j9KzY*~-YnmqEGSl~xu%IU%rNSnRmpm`GWUamk5@ij(6b9R0EvMSVlKVK(3f@S3kBic<6yN!!NM2i={ z&pNT5LE1g=3dY4qUV>HcKW-JA;j$M(sI2WGEzVR_ix^#e^9Ui_ zs$+wX!t%jPcS(H-b*2Les^XCT_yK{+%m1j>!)aruq0}l}N@r4=tV{%iPGJQwjiH5k zVE|j?qWP;xY z4X|vQ+=*D)A3LJX!k)uRRZ#pAbx2-n9)T&^D}I_VI6?w~KL_Me`4rXmfPScOF+?bE z7OYe#3dmBNQ)ImdnXL7b=%P9yUWuz7Yju0C(8pb}vO{6KZ{QyCXcAoAAwK}))y;jAOkK@Q#h0?dYF>s6gS z<1-^_@1`6jl)XbAiDKrr!n%J>cL3Lv*X8vGqepVdGVYa+IZa2<=JB2zFj%t0N<*2D zVS04xSCBIh7VZ|k$uT7cEY0fI8HQ*Tu>3j_AV#yrigJ665cqmg%_Ixamt@EkD!W6gDHpfRdwqMt&;!3 zpu`%NhhzIxxH2+RTfyD1cdH3CSI;YU^c$sS1wy8KI{9L$D!ic_8uld|$!E@YyHkmy zq1@V61yj?8k$2umCj$O~P+~oCRu&T~2pgeydcPDjjYW2Pz`p5oBi|OMLP87(HD&rw z0WRtW*6X^)ZQ7ij9Z5i_`uauojb>Mt-fx@mxpK77NF-2 z!7!Q9cD3qr)>CBi+1<8YKg?xryx6V-<5_l)+jn*!22TPy7}Sidkq~|;{rC|(vVH+HA(1)L zjsD2-HT!~BNiO4exX__*1*E8((igN?m6#_XhkOhgr=XcVw&C-enGBd} zkxs2&KmQgrY5j$`k_}EetU=ie&srmF4;2!64k|rR-Udlm?-QzU34AY-dWXu#f;rH9cM)dFSp3sRT3p{Eeh1IuAP}fLQqG zoAl_RhV$t^ColC3LM|SJnt(qLsDZ4~H;JZRB1mW?4yrOi3-er#A}++D=XiG3fsj_H8W{ zi=H*?3euk}__LNEg_&kYJ`U7R1D4f4ax960#Uc3u;zx}iXoC2ms;P8EHj;m$pGo#F zPC)b4`!u~02wD1b-3T5MYH!TKqL1G;0T;?qX3w`E6681j*TN7YUbpyNvGB5QQz#+I z?utiH4;e)KKe9`T4@#3EiSM3$+XajWqdSDL>)`s4#Kwa**u~ft#tKAmUbRX6*M}eb z8)Qo4Zy>@^^4^Ze!&z}R{XSvCENRhw)N{;N9s z`{wd#k~%LuQK2C}`pFW+-foN&TmcBl_i};&!5a53Az&6@Qh*G8Qmim|QCCqIrp|Ab z7ht3X=UWL~jA%U&=S!)q*?Pa^_$!mxAx6NLbx4_a%m!kh+0&-OH0yN-}5^4<`=zvpF^z4tM~%OKU5BiXGR^W> zr$10I^6~rmZj@nrW{Fz(uoD|Fwu4cx9x^U#IQQA9g2||Q^UqX--D?e5CZBbiK^#ifr&sP0Ip@P~O@!J>+TVRrN*ONJJIoR|$3Z zfATuPk*4BEvhBY>LXCci%MQ0PWkL`bXVY6ix3%KpbOc~I1(~-QQ3VLpMZ!@+4EhG+a9Poh@L}BSUxq-z#Z%`Uz+u#e} zHBv08_$hE&`DQuFK#tF5l^q5&#eGp)9NvQZd)6K1HzWDK)7Dq9Npg9{JqXw5qw1#| zIXW6?7>l-zrC*HAPDJMDjj)+OVPJiAV9G-aJ7IE)YKkzAlPAqL;W*e&h22iK%m65y zV5DJebq`S$HN*dAo1B-9*O0p~Y^si`d@n1p(`o^7uONh#I1}+wXaxVGgQQw(XER2S z0%^Km)b&-moG};C_qY}GP_nZQS%(u)?CX?FgTZjB@>f0#>jb6$LBLoNI1c~ssaVrw z86iQV+#!~#LK=#-=**anKq3!zsJY+@hy|nKBK#=`$y??7u`b2ANYP>)OJ1eaP_YoP z9E})i%VF4W+3?YVA{lZtyoH62q;fqFIWG`bG72ru^i^o>1FSVdwP7XVZ~wi#fK)VOnpcPlRS(gzgSefZG&hLzTcTIK<+$GNuvd&vQFKwX?+PFD8Vu@ zQL*&#%_TFglM%R_-xXnu+yK!(yn}SG7I(~bC3?@pa(o6=we0{Uke041x9yYj4&nt@ zEuLyE)LaXzS+})^PO11Jo^&-(Mg@z)hVLG4|p&s6* zQ_!o&%O@KvLJ88tR<_e!rVI$7%|SEgXN|e=-;Qi3 z!D_B1q3-!aM^hzRy9x!ZGT*E$ZTwL-SV;u^*(!9W>$j@XSxfb89tM3AEs~c+F(FK^&}jf`2!2U=r{QQi_Ty}H)!y5Gh@yeXWSEx$P0~0lS0vb- zCHeQe*woMV{@`(h?=^p=*BJ5>|5bk6|K~A%Zet3(klY0i`4gqJ8#D2q$ctI03dkIj zZPqgYK*{@ltG>S|8{vMS2I+AtSHUSlO_g^q?G(CD^U0qNnTV>i{Yk_@ga38oDQ$$K zMO41Jyv*?CGz;%x5!Zz?mm&$zXT6_pij+qGsc2}nyz{Gk19RI*(s!_^3Rk?k9xVzl zZg1fdEK~a2Qs0@^!*-AvQkNzD2VzT-W+qGVp1dQ_Ll5=T6g}BXx`a_SaoTdDDObwS&M3X4}a*sO6#Worc`;Wnpq^!Bz=#MaQLUW*|A+x7}5&y#eZ z%`8s7E)D=?b~jc??2wOqAO`~B+bOkC4YXlgrYs|wAfTWY7p`{a)PJoRrkYXt>-^_P zY<1h4H))h!_j8!4lYqq`v7>=)(uMNs*Yw49U6cuH^Y+~Q`2Ez|s65=Uh4HeSWXi~6 zK7j#~yK~soZukvVrB{KYfBn*?N)yFF6bUN!M4&o6XDYV-VZ4%ZGg7@T^yo67fKCc{ z?(bX2!I|Y=#5t!D=%)1U&3ByLaL2^iw~&}VgP82x`Wt9J%?oOvw4v-k~ zi^A>j1}(zS!PNOUmz8PAdsoogg?LjrdFdr9hF$SkO@dD2!SGN|w5HpbGiM;1AiCSK( z;+3}@dbu;lGDvPpf&Z@6EQX|i?}J%Ol)_h7#D5@!cpt`D6j?JKu?_!hC9LI81SMF%7Y`g`6U+m9Mrs34S9y z+;a8mLs0Y#soa@$GIOa53**8z{j@VwF}#Bf;99fVN}`?tKJt>;ExV8x#;+LS zKZvR$#!pfR?67#}NQI{5D)`hYPdKrh_PqOkD;;4FUwuNyf*z@Sub5(p#MQiXCwXze zQ+es~zZ0Q9d8t@^JtvICNQEQq_?1%;N3Qr<1bxqbQ$mZ05}8Ni9`BEpj2&ENOK1MHFEEgsdxS$s3eS$u$D(z z=(k8)N~J=Sl-^}p@XvEQi(&Kk=ZIQ8bF=H9!z^D*5^izOmDlgeNmb)ll@y!td2Y;8 zmqhUIJCVjZ5f)Z7%g2yt`a!oxy{550O=@XuJTAW>k?7KyW99g7tN=UUKasLkpj~e6 z3L=~N?oESv{}9Drg)0248UCJc=`hK$iL4vB^q-1{17v6oQpZ zxP`*qOmNx{xp&S^geIFyV5v!Uxmi?ZJaTW1w_?JhKRUW^K{L>;X>Rn3qTQ<@6$e@Z zVxr~7gez!@8Qe$8UJ5-#h-lKv z;0>aaCtXKNx$lEW^5Hs%&>X&Mf8#eB9<=TRWLXe}svJJS4r=NRx?okc$hrB7RCPv$ ztzOldtt9llfm>4Y-~8C{&LD#P?lX|I2AF3e9aX;${>4Jlu(|+mY%w5d zvTKp7`Bs`L8BN+kD}pKERTm8@2~~LJrScFgcgPPS`yNlfO9U7(0R8vnj^1-ITa`}{X5H)B7zrA zM?yX7b9F_T{#O%9vfXEzE@lTD#Hg7^NvwuFSW!L!sxD{iq!Uz!TsMo|N;yni&|%UbNUgBZ(V9!{U_#|D zF&F28EOM;+#qd$b$18d2QT}4OG?O?Rlom|&#N?hOlCRnh>QT+&ca%NPheZNW?3&0Q z1g{iMjYNNUT!JImihaCZL)ys*jelKJM)N$+-AaMSF5o2_FX>dyki6^B|MCQ8RN|p`Wo5BT==uCE#C?_YT`1oE}7~#pgDQSy)x?-O~ z#L0>v-)RfnmX2{-5IsVO2(HJhgSBY9&XcIuPsK9bE9v<(bg)8K;S_8@^Lu6$rT0MB z!4Fd;3DVFfld-gM-gnkd9nQ-8JplIluHKw+A%4Ku)?|Dy)v;{90(Qog@m_dV~ zFcAhEJqu_es?wk|336;wgxD`y?{0qzsZ6vHiom+RrbtH7qZeUkIa#5Zrm>URpzWi; z)*>@^;9t_wmG-08o<&N=AWNDha4+=jR*(L1wXoq~@f8}wLOJ>yx&itwDxqMRb}(k# zeAAqzbCA$#LY}o9+WreN!8TRR;^{v`sedqW3}ezM-yY<|jmnxqL#c3CB)Zro5zB9q zxu~A!X6*0i?7X9zg&sy?BKPn7?$L#^xn#0Hc zeG`1Ki1w3rH-5G3=@Gopc<&IA<;gg(>h^=KkEB(djF+SH zc(}_8r4?5LrgA^%Q|;)-&Bv1D*5Hc))(#g)HK_g<{uasMc%Q|nAohU5PBy9~ZN?#z zRPt6KQs+1>L)9#dOMSa>LvSgDrA}5>mXUCM=lkR>;^LU-Wi)A_A}wtzG#!Hsjs6#6 zK?qFIi0yz5bAvwe!lVc^rp478jBC;eExW3*NeRV**z+n5sxHd`)fTLOs5;McJ_(&Q z2f-GFN1UvV7%W!Q^e05AhNHW5r=$DT9y%H-H{kEF6gmI@Tb|7Ycxtyyp{S{6G4{%N z2&Y^YR+0MQgGqLBW3!!=k#xr1+29%>e7iXzO%Q_^1Q8bUBA^pC-OCI5ix~?z7i8ha zDw6bmX8#dF?P(B8Ln1def5E$UXy9F}#Ph)T0(lNccI@u>+WcAV^-C8~9tVcSV2M)* zjtxi)c=G$Ys5%fuTG?(kg;!!dl{TOll+6JA_uvlNoOiN1xNjf4N#K*m;VP|=x3aFD z_Vy--)n8PAss_HDpbUH%R;7#t7v5k5=-@2Qowvvq-u->&=;o`8WXF(Jh+Ui57 zmU`T8l02|R;uxN0n_g9rOCc(-ibpdN5}seM0+B-fNp^m@qUPp<=LE zaH)YRHIcW3$9Uw8VJq#Ax6Duwxnyz;Vzw)I!wNK~n4P`uBel=;ZRp-h7Q~%d7haVH zWbsE+q`TJs6zaAqgSqe0gT}p(31yB>Z%pl=Xu2k7c_yr1KDs(Eqd0{9HZO>vVFXj` z)_3*HtKeAd@cy?s55%Wz5=QxCxaGEHr6p)CVFH@@M2^@nKF#-_B}5o-;$N>_4yMJh z_xiF zCBS1zy>A6H9r41>dn{JLcwtM!=SisHtQmaEC)URcvP@)g{gHSKK z6#`QeIWIO0WACd)%kS1{w>ydvYabzFzd})JJm8WG^SAVPc1+);X$Q5JJle<~XrJ+-K=v zrGzbn%RiN&ojx%pal`&m9bQ4k%~@>TaisTIu{`QqtZPW!d7FAu19iCl#IEJ*5a1BqLBIGoF4_McK|YiJ&TKJ;I`VOlTt{xtgdc%&&!%R+4XLttB|udBB#nc{E?Qniv@D9MGUTD3qd8erBxLXH8igwB(Snyu%iq*g{5E#7Aao)-J$1PB z*+0RY#j+L^rQxnvcVU81mj20U-2iv0Xf!qW=cYD~z9&~2O&p$i^5jg@ZFdjDkB3%& z?pcF`)MS+$^8Z?x=Z^QE)K2!nt^mf4n?wQ3gc9Z}8IfuB$?YH6<}2%ePiZXvJAXOn zy^_|AG2iWY05)j-x$A#fQRU z`})(ch+8th$lhyHx8Jq*zZ7G>q}g9!wo3Ws%cdt!7Xwp6;9p-~#RFLMbt5=$^C|M{ zvgTctua<9@{G;A+^5pbIR)6kXi%Z;~419sr+z^ntdr$8WgQTogoO!kv|5_{fbiliq zBev^DBf6Zu1ubd&tM9Xp*``652y~w~wD2)eHLIM=ICd7dhZ2%mFVnc;?v33o+^_)` z)z4SIPvN|1cTSEque2>+DYkTU)VrJsEuuePfy)XPRv5FfYRsicYvm{&OfKDvN(gMW z(!l-JK`XC!dGE-3py|~&GCJc+fAuVE{4=9NZ+!ekiyuG%Nn=*xyb7qyYsa3h6%?D- zf$1CGpx%1Y9_Jnq)gX0a$wDJrS;+9qv@3%;fi@QUa zn2)DG;8u86d11^$yrH%z3Mp z$HxM*%>k?IpnomuC(}6N&aO&t4tOVy(7FE$d-{B>ytWIMv(gs~s(}@=&xqSc&{sYT zqkhg2iDK&45_!m@nOtyERd2PmS_zGdWMJS$Ep?`*&Fi6sbsQ+*Az38d^X<@&u z5J=fF!w5?pwWJC?*!xAIPPFju`tHW z!gE^A{vEvCP^c|*+++ePv5fo_ljA*bf$JT-4|Z$&RW)vouqk4EL?68&n9lo zmQt|JRVR@2TkZB?bW_vk`rA;#ar}AN6VI_N&5JskgI^EG%8E%&tYM5Ji_(`RtO3(c? zvTu;S0}zsSz7kp;?8XP#=IPOri=#>|UP~x(LMRxb1Q)}(w$4$Y{rzxTX5H41#|EXf%zA^@zPJs=)wlRLAdM_9og+jr zSneUfBg}CHT<72$@pQY=#i+nTJ8x10l*~~d1M?2~&3-#rFUnk$7J-B~5*t*~^E=@D zzd181nlO&APd7D7UUx!{<5q9vmv7*e%#yp%(VVVUGS^?200%@3yxXzS?4#Qpby>ko zX};}?)Zg$t=X06(FvRvqj+gP_}a|esvI~Y9MY@adw)(%~hteXyI#%i+n?E zPGxxMeyfRP(?AdOW0iIB=BM^aKPBY0v4Y;ru?~6TuT|UY&CZ5=2Am;suT=7o>^Yeu z-gd+I-c!Fp3UhH{Ei?BbU-Ty1^v zfj8$tbe`g2=mJYv{C5YH-yfr$$A8c@Pf9tF9J@!$u;t_VOxiZ?PW^)1IaCw$Lt#cR zXB_=FvwsH`DrEvqmi_QT8!W(rnDD9+CqFm9%QC4o`dHfRk1=1sjymdHmE6_j<3}P~ zZinH5ZvSfKMy2o}!3iX-KNDEOZAAxB+E=`OxoQPtbj2}s35L^G^Ny?~bC5fx1DXR& zu*$hba5t|Uuvwzisi|61!?1!y__@M)*ky`D9ClH19#78Ov5g=3Qt zUqmW7`0`QqYG*#&Z|JRfn%A{o#MeHObl)fHgD$HujLfA@oYiJdqV|V7Ac>;8(q?+c zU!}L_z@&NKgi-2kDogKnFNynRxE0iQbF`pG+*r=J_^EPqWe0H`{=J~ zErqN;BfhPhrp&nMQ!J-p{?*qk>>85Fo-H+u{H`Wkm z&U9sFyO_;uBy+P&4voNknslrv)>zK6Iolgmhr2rqs<5OYFoF}59SkrQzOSyLRFps$ zVWlV(!ZLIPW~D)B9HKUvNV&bGzO4JG-wx-lYrqS^fxI+Fj+oKoU!?xvMSjgrtftK2 zP^lpZk@b=#QzLm@3Bltqjbt_4WR@pRS?&FIZkwuS^kd9UQfdvFe%Q0e*o2ug?q{u} zAJSs!{Z+d|x=voPeS5b&_jWLqYjzs$507+@p|%|FYMPbW?=D0t$A=CmN7xWDy#mJs zw|$;YR%lE@9GU0wj3V-oxInl;h6Ph#C!1@EUY=&!bk9n@tqi2dpFZqQwJRGqV8#ho ztqhk>cEp)8?$OS%%rnm|&q}q{qNkaflMFcTL-BpAiRV8Upt!%=9liy#r~}SBYzF&0 zy&6nqc;1pF<}>!DL(@560_({~aNuck!~b^w`Q1-Pf=;(Vu>t45GVv>TrH6C}SqnVA zkdaK4=i`>)swr6Z4ywal9`KtI5Em>`J>!+L_c&uSO#FKFt57bi*LO%i+&GLA0HB6! zN8883mvbOz3|@Hy3V;AKd|!qzloZZ$Vor$0nI$PB){Z#WiaN#h%5eulF9{ua_*MxX)K z0tYB%+`qSY++?>e(Ce>o1f7Su&R$%LV7@@{g89NN#(d~)yu6_Xxb|0 zAX%AnlCsaeFn{}%gU5@jNBJ95D}$rUa)(Q)kQ4gcP)|l%p6AeL+Mi1f;rzkue!o0Z z9(~4CKgssRS0q`)g=*4tYG?^u=Gw|G||`3y?gN(ow>q%KWaEryrCw4oO6RO zn#%us&Mx1FYYP;&ZgtArY#}no-w}TFvWXTw-dUW)%qXsd){_iAT1(67K<;u*p9lJjplk!x;7ZWnyCmsb#ual}ZUy?D|H0Z-0RGrFJ(tvnKeY0e}u$btKPZH95gt60m>=fF@uh&bKa*J$L zmfV!{Zmj!`dQP4?bQvu^iBA0*9#*|UK;LRQzuQoB>V<9fao7k0BzE6hR)zeA=UAc) zcZ$Djv^~u5d#+=cul5LTHP&n6y}v_ZkV0@WHxF?PpW~C{>CATYvkww#;^+~Pf6{7( zm8ze;W05rSxBk(0SvesAR;6xIvM)Dx-7G!HAM}(#j_!vgKc{m48AEN=&2#Z~3vw=7 zjQ+{1pKB=JWc`3w-)2IW)hYyMmb>AP(K>yLqY`3|8eHMIwe2-~DZVJiQ7^j?f80S( z4m{n0x_s5AES){FeS|X#wWiSv+bv4anBAeCWDGE{1jJ@F${(?ku;VOnhe|_(MpFfu z{452^Hw7BgBV4CN5y!`sp0ZAijo(L=85Yk0yCkMG?#PgBs94=gdrSniKg(Y@{gtw} zS2w`OZ6{{BSxO!-B2#|7sts+mM&jWo_&8*KLWqnUf+;8g(7NQrt1*D$BAog}-&_Uz zolcM)I$il^li5l!JC-Qbt30k(e#-h2tcZZg7O(&{)TVzI_ghC523@l&Su;cgUAn2g z-kGigtZnk`;}taqtebZbEqzssQm9)KjAYJTNLw~;<=0U~IaxO*9E=CgTro+0=J6A8 zD|D(09d`p5rsA92sz`MB`X!k}10~udEohT-=U1>|7eH1X3H}Bw=WKH-n|1jln zbE$NiOnvvA*m*`a?ntB)__O>$ZH(pbj`qCs`|ABGgsWDy3mf%)jleEh06yTT`e;wH zBR!U(Ax@sS6YAKox@WVyM_Mgg^_#^5o?En)L&Y2gt}Pc)~sve>NF99Xy~ZwaLKb^37DQqf}(42TPH z9`CHa5g&LU%IfY6%|(hF!JjypRgN@I_AKuZd3iM%sBNz?4 z@dwGy_vuC5hxi1c=ZhL#i{ZW2*j_dvc3n5D&zNU^VyfCYS}-6GZI)$zXm4Mks^LAh zGTn@4u74?9yY{_C!e`?G4=*pxh;Y<Wh zA^6EZmU6p}diJt(vfqxkeY}Z(HpY14)4x-Hho*$ zOPYnPXar%{oA&EEr5Ao#9($$(MO4l&gv+bYP60oiWOrdYCG^BFpJ|ViICXuQi`XvH zaPF_(QEn8qg2&sMwUA=vdxjuCtka4ujdL|yzi8Ckd&G3-0S|`FN4xY37aT2{9`1Yr zH(<9`UWBaExjF!N5*Pk$g1-gSouygPi|!t@8h`SUcX)|EN}SUasRg>OJ-w)tRzdK* z?%KruU5?_W`X^y3{@vPO6sfx}Nd`A#xf^xnc3dm@c=kW?4|+TRkQzy%_K8`A76Uq_ zP4B`|4-cmiO%L`IAdFLom87L61<%I8N3}3AvRbo3fr|O-3Js_xM@ny-PoTCU&VN+c z`A8qH=RkM@Q?6A>5A^2d>KLxw-f73dRmL4P(4gtsAg0ASf=$QBv|)PZrau-6qo>>1 zcn#PCHVJtK*6;$hpejYQ+xN9l1k zwE`iM#r)R+g(y6rT5$cNzvAc)6xR-*9KJUBnzqm6Nl!Nay~fxo&EQBA{lrrF<#{!E zsmqu90kF3vQ^8QJ?g7w*afnE4M;@36gp3dZye*V-Nj>9A_=qF3WyqC!1;Or;FfyP) zQ`2Wfk-5$4+#MG~|FENbu4lyb(lfTvRVNN?jMt>CUn&%~+}Nv*s1p+Bn|+%0#7&;#6}hb)8;lq%bZ{rDY)_ttCF8i2McGL9f6a{N0DhxHvV%I2)04 zU&7J%pM2>aIhpDD=S%khgmLb(tyKy|X>~=Ydl!=%ztuh0KMl$XZXT;CK zMTC-88od(#IuRM)mUiCNXHh6~BfGcq$5kzS08Iqx5?;^D?G=ioxhKz4&z&2k-)oA8 z|Kh2Y8>%T}i{|ECo-MOmzS(Bx4-bFZkJuPzfM!bL5!aF>??P6S1)<2Fy?E?h7m(kR<&j6DErr8@KtuZCGSp9WcY@@yBJ&?HvnqBGZ+EJ7LXzD)57`GBDSnzTZmx<%=2oXw_LNSczpv9<>=U-@#B#aetT@>0d|37ae1E%1{Ld?ZtC!?WOYjCY#ZR%+-s zg~T52>&=Ve#YLGfowO#mEw-xtY)EyXKAycP+qXQvCs9=}Oz-#K$$E`mkf(S%aJL~M z%7V{f@&73(It=$XaQEn6$=%Dmbrn~iH8*Tyjn|nx=>Q3oF6kGsVr&;te^vAp`pCme zq?w2H1JHAZ(_bC(yVvaO*$=WaQ2)4HV zeOg<63@n@jioP+vjNCS>@Q`SR#Y4_C`oaaKtXaEsl*Qhf{nq*E8UAHo{mE=YGi#^E zQfa5{F`KI9LC*tL;REl8*!j}V?YvE#sNpt$f!CQF>9sdsJ!S&@mtU&@aewlL@J*Y#`!#SuJC&e+ z@>s{!MT6qA|BZJ*p-wftzn5Dr%h^bInX*+<^>hjRFu(U@gow*|=EQP*o27DVOjxt# zv*!3SIa-9yqb0Mfes>rZp9zkmQp<^3bkSV_v}+6SutXhLo^L+-)$r`^dSv0@1%uZO zO92TaySiQp1r^6S%E^1C;@2hP%h2*k9kFtd_9(}6!+6y=qo>P&|4a%KQQ^bj~U&pN8 zj+ELH^G7(J#zmPb<3=)N?qQDW>ND{ECA{(U0w-Kei&b+E|A#B1f6G^c6Boht6pR`F&+;CJ^IEjM zw62$QL63tr8jr_wb-k!8P39(MzkzcIlU!zN?12GDVAN%(#ZcGG>;q zd=jCWro;!8QkTq!zmW64{?1Cx)Ex!=GapwBu%aoE7zn#R)=d6Y=fthivhc4KH>W)_ zA9?jl27Zi}hXP+tXF#zWW9xtkK=9z6i$;F?(ZzuCB! zRAGq|YNqj@m~gz1t2mvdn!(Z%v&s50x+NNY5B%}Rx&y{^Z6+J7T#?Q=oBI^H(2|NL zoj7`FMOt321mmaV`AB}Ud4A5X$T~rO?n$%1pW41f>3_2+Wx;+B>|0QRpKnzD+6yG=!Njjhiz$PcEsnNnQ+Ij}itx&x;vnLc2h+kD)Q6WD(7 zX6{NuXD*v^p!W+>@@}FI*}C+S_pn&W7o}m+8-<-kQjcxygf}uGB+Sxga;}~KT2ksP zy|Y&ufQxClGwY3h_NX(qZym1&dnR-SXlAXf7zmiyBt{?&R{ye)$Q$Cs91{Q~IY7mA z`aV#+qhjO1bvK&T+R#w!d*OFp3C_zC*GzVvX!~i$O)FJ`gVN4QiyKJ+L=wTsenPj+ zi6IKwvIvYyD4MbpBKC!SmQeT|Jb)WpU?_qr4h1(H)j1*X`aKN*RrUa3+U092;DW)`>;cVK#bUd8Z=ui^mzPwDOA?{9&i8nWyAu-1 zaIS~<$n-;XvRQ8XoOI}l?F1=JaIh^8&fw0Sw?g8p$2N+jP5gEkCu%=?vhu3 zaDWQA!kAN6@n7nhBtq%IM2H9686xs4*wBMwK>|yhpt;7C^Rm&u{u28h9%n4g%*=X( zQy85*p=V)pZjb)Cu8BHy6}L%=?gCZ6$w-l&YI-W{(R&#G^t%rNrrQ>Zjzf8Ay|}B_ zcfdJQ@%J=ArGe?g<7u@#X{s;�k9+0L}=7CFAK=VypB`=~EWlx(D$}M`Z*fIOoM@ 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.1", markers = "sys_platform == \"win32\""} -filelock = {version = ">=3.11.0", markers = "sys_platform == \"linux\""} +dmgbuild = {version = ">=1.6.1", markers = "sys_platform == \"darwin\""} +filelock = {version = ">=3.12.3", markers = "sys_platform == \"linux\""} lief = {version = ">=0.12.0,<0.15.0", markers = "sys_platform == \"win32\""} patchelf = {version = ">=0.14", markers = "sys_platform == \"linux\" and (platform_machine == \"aarch64\" or platform_machine == \"armv7l\" or platform_machine == \"i686\" or platform_machine == \"ppc64le\" or platform_machine == \"s390x\" or platform_machine == \"x86_64\")"} -setuptools = ">=62.6,<70" +setuptools = ">=65.6.3,<71" wheel = ">=0.42.0,<=0.43.0" [package.extras] -dev = ["bump-my-version (==0.20.1)", "cibuildwheel (==2.17.0)", "pre-commit (==3.7.0)"] -doc = ["furo (==2024.1.29)", "myst-parser (==2.0.0)", "sphinx (==7.3.7)", "sphinx-new-tab-link (==0.4.0)", "sphinx-tabs (==3.4.5)"] -test = ["coverage (==7.4.4)", "pluggy (==1.4.0)", "pytest (==8.1.1)", "pytest-cov (==5.0.0)", "pytest-datafiles (==3.0.0)", "pytest-mock (==3.14.0)", "pytest-timeout (==2.3.1)", "pytest-xdist[psutil] (==3.6.0)"] +dev = ["bump-my-version (==0.24.0)", "cibuildwheel (==2.19.1)", "pre-commit (==3.5.0)", "pre-commit (==3.7.1)"] +doc = ["furo (==2024.5.6)", "myst-parser (==3.0.1)", "sphinx (==7.3.7)", "sphinx-new-tab-link (==0.4.0)", "sphinx-tabs (==3.4.5)"] +test = ["coverage (==7.5.4)", "pluggy (==1.5.0)", "pytest (==8.2.2)", "pytest-cov (==5.0.0)", "pytest-datafiles (==3.0.0)", "pytest-mock (==3.14.0)", "pytest-timeout (==2.3.1)", "pytest-xdist[psutil] (==3.6.1)"] + +[package.source] +type = "git" +url = "https://github.com/ntindle/cx_Freeze.git" +reference = "main" +resolved_reference = "876fe77c97db749b7b0aed93c12142a7226ee7e4" [[package]] name = "cx-logging" @@ -1340,6 +1306,27 @@ files = [ {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, ] +[[package]] +name = "dmgbuild" +version = "1.6.1" +description = "macOS command line utility to build disk images" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dmgbuild-1.6.1-py3-none-any.whl", hash = "sha256:45dba6af4a64872c6a91eb335ebeaf5e1f4f4f39c89fd77cf40e841bd1226166"}, + {file = "dmgbuild-1.6.1.tar.gz", hash = "sha256:7ced2603d684e29c22b4cd507d1e15a1907e91b86259924b8cfe480d80553b43"}, +] + +[package.dependencies] +ds-store = ">=1.1.0" +mac-alias = ">=2.0.1" + +[package.extras] +badge-icons = ["pyobjc-framework-Quartz (>=3.0.4)"] +dev = ["pre-commit", "tox"] +docs = ["sphinx", "sphinx-autobuild", "sphinx-rtd-theme"] +test = ["pytest", "pytest-cov", "pytest-tldr"] + [[package]] name = "docker" version = "7.0.0" @@ -1361,6 +1348,25 @@ urllib3 = ">=1.26.0" ssh = ["paramiko (>=2.4.3)"] websockets = ["websocket-client (>=1.3.0)"] +[[package]] +name = "ds-store" +version = "1.3.1" +description = "Manipulate Finder .DS_Store files from Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ds_store-1.3.1-py3-none-any.whl", hash = "sha256:fbacbb0bd5193ab3e66e5a47fff63619f15e374ffbec8ae29744251a6c8f05b5"}, + {file = "ds_store-1.3.1.tar.gz", hash = "sha256:c27d413caf13c19acb85d75da4752673f1f38267f9eb6ba81b3b5aa99c2d207c"}, +] + +[package.dependencies] +mac-alias = ">=2.0.1" + +[package.extras] +dev = ["pre-commit", "tox"] +docs = ["sphinx", "sphinx-autobuild", "sphinx-rtd-theme"] +test = ["pytest", "pytest-cov", "pytest-tldr"] + [[package]] name = "duckduckgo-search" version = "6.1.7" @@ -3000,6 +3006,22 @@ html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] source = ["Cython (>=3.0.7)"] +[[package]] +name = "mac-alias" +version = "2.2.2" +description = "Generate/parse Mac OS Alias records from Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mac_alias-2.2.2-py3-none-any.whl", hash = "sha256:504ab8ac546f35bbd75ad014d6ad977c426660aa721f2cd3acf3dc2f664141bd"}, + {file = "mac_alias-2.2.2.tar.gz", hash = "sha256:c99c728eb512e955c11f1a6203a0ffa8883b26549e8afe68804031aa5da856b7"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +docs = ["sphinx", "sphinx-autobuild", "sphinx-rtd-theme"] +test = ["pytest", "pytest-cov", "pytest-tldr"] + [[package]] name = "markupsafe" version = "2.1.3" @@ -5429,19 +5451,18 @@ tornado = ["tornado (>=5)"] [[package]] name = "setuptools" -version = "69.0.3" +version = "70.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-70.1.1-py3-none-any.whl", hash = "sha256:a58a8fde0541dab0419750bcc521fbdf8585f6e5cb41909df3a472ef7b81ca95"}, + {file = "setuptools-70.1.1.tar.gz", hash = "sha256:937a48c7cdb7a21eb53cd7f9b59e525503aa8abaf3584c730dc5f7a5bec3a650"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shellingham" @@ -6978,4 +6999,4 @@ benchmark = ["agbenchmark"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "a378031626ad6640c66c53d2b58266d7d464462b69f0b5b5b95c317bd20c6b79" +content-hash = "0f198975b29b94700bd4b0179ebb285f4e12c2c5f408b0adb03916f06a064d15" diff --git a/autogpt/pyproject.toml b/autogpt/pyproject.toml index b5d08fb7b..b78ad9e69 100644 --- a/autogpt/pyproject.toml +++ b/autogpt/pyproject.toml @@ -57,7 +57,7 @@ agbenchmark = { path = "../benchmark", optional = true } # agbenchmark = {git = "https://github.com/Significant-Gravitas/AutoGPT.git", subdirectory = "benchmark", optional = true} psycopg2-binary = "^2.9.9" multidict = "6.0.5" -cx-freeze = "7.0.0" +cx-freeze = { git = "https://github.com/ntindle/cx_Freeze.git", rev = "main", develop = true } [tool.poetry.extras] benchmark = ["agbenchmark"] diff --git a/autogpt/setup.py b/autogpt/setup.py index 5fa328f35..d254a1f26 100644 --- a/autogpt/setup.py +++ b/autogpt/setup.py @@ -1,7 +1,9 @@ +import platform +from pathlib import Path from pkgutil import iter_modules -from shutil import which +from typing import Union -from cx_Freeze import Executable, setup +from cx_Freeze import Executable, setup # type: ignore packages = [ m.name @@ -11,11 +13,47 @@ packages = [ and ("poetry" in m.module_finder.path) # type: ignore ] -icon = ( - "../../assets/gpt_dark_RGB.icns" - if which("sips") - else "../../assets/gpt_dark_RGB.ico" -) +# set the icon based on the platform +icon = "../../assets/gpt_dark_RGB.ico" +if platform.system() == "Darwin": + icon = "../../assets/gpt_dark_RGB.icns" +elif platform.system() == "Linux": + icon = "../../assets/gpt_dark_RGB.png" + + +def txt_to_rtf(input_file: Union[str, Path], output_file: Union[str, Path]) -> None: + """ + Convert a text file to RTF format. + + Args: + input_file (Union[str, Path]): Path to the input text file. + output_file (Union[str, Path]): Path to the output RTF file. + + Returns: + None + """ + input_path = Path(input_file) + output_path = Path(output_file) + + with input_path.open("r", encoding="utf-8") as txt_file: + content = txt_file.read() + + # RTF header + rtf = r"{\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}}\f0\fs24 " + + # Replace newlines with RTF newline + rtf += content.replace("\n", "\\par ") + + # Close RTF document + rtf += "}" + + with output_path.open("w", encoding="utf-8") as rtf_file: + rtf_file.write(rtf) + + +# Convert LICENSE to LICENSE.rtf +license_file = "LICENSE.rtf" +txt_to_rtf("../LICENSE", license_file) setup( @@ -55,6 +93,7 @@ setup( "target_name": "AutoGPT", "add_to_path": True, "install_icon": "../assets/gpt_dark_RGB.ico", + "license_file": license_file, }, }, ) diff --git a/rnd/autogpt_server/.gitignore b/rnd/autogpt_server/.gitignore index 26452b1c1..7fd0341ba 100644 --- a/rnd/autogpt_server/.gitignore +++ b/rnd/autogpt_server/.gitignore @@ -1,3 +1,6 @@ database.db database.db-journal -build/ \ No newline at end of file +build/ +config.json +secrets/* +!secrets/.gitkeep \ No newline at end of file diff --git a/rnd/autogpt_server/autogpt_server/app.py b/rnd/autogpt_server/autogpt_server/app.py index 298852129..debc26448 100644 --- a/rnd/autogpt_server/autogpt_server/app.py +++ b/rnd/autogpt_server/autogpt_server/app.py @@ -1,9 +1,17 @@ +from multiprocessing import freeze_support, set_start_method from autogpt_server.executor import ExecutionManager, ExecutionScheduler from autogpt_server.server import AgentServer from autogpt_server.util.process import AppProcess from autogpt_server.util.service import PyroNameServer +def get_config_and_secrets(): + from autogpt_server.util.settings import Settings + + settings = Settings() + return settings + + def run_processes(processes: list[AppProcess], **kwargs): """ Execute all processes in the app. The last process is run in the foreground. @@ -19,10 +27,14 @@ def run_processes(processes: list[AppProcess], **kwargs): def main(**kwargs): + settings = get_config_and_secrets() + set_start_method("spawn", force=True) + freeze_support() + run_processes( [ PyroNameServer(), - ExecutionManager(pool_size=5), + ExecutionManager(pool_size=settings.config.num_workers), ExecutionScheduler(), AgentServer(), ], diff --git a/rnd/autogpt_server/autogpt_server/server/server.py b/rnd/autogpt_server/autogpt_server/server/server.py index 40a87c2e7..c41ffbc27 100644 --- a/rnd/autogpt_server/autogpt_server/server/server.py +++ b/rnd/autogpt_server/autogpt_server/server/server.py @@ -1,8 +1,11 @@ +from typing import Annotated, Any, Dict import uuid +from fastapi.responses import JSONResponse +from fastapi.staticfiles import StaticFiles import uvicorn from contextlib import asynccontextmanager -from fastapi import APIRouter, FastAPI, HTTPException +from fastapi import APIRouter, Body, FastAPI, HTTPException from autogpt_server.data import db, execution, block from autogpt_server.data.graph import ( @@ -13,8 +16,10 @@ from autogpt_server.data.graph import ( Link, ) from autogpt_server.executor import ExecutionManager, ExecutionScheduler +from autogpt_server.util.data import get_frontend_path from autogpt_server.util.process import AppProcess from autogpt_server.util.service import get_service_client +from autogpt_server.util.settings import Settings class AgentServer(AppProcess): @@ -84,6 +89,17 @@ class AgentServer(AppProcess): endpoint=self.update_schedule, methods=["PUT"], ) + router.add_api_route( + path="/settings", + endpoint=self.update_configuration, + methods=["POST"], + ) + + app.mount( + path="/frontend", + app=StaticFiles(directory=get_frontend_path(), html=True), + name="example_files", + ) app.include_router(router) uvicorn.run(app, host="0.0.0.0", port=8000) @@ -123,11 +139,12 @@ class AgentServer(AppProcess): try: return self.execution_manager_client.add_execution(graph_id, node_input) except Exception as e: - msg = e.__str__().encode().decode('unicode_escape') + msg = e.__str__().encode().decode("unicode_escape") raise HTTPException(status_code=400, detail=msg) async def get_executions( - self, graph_id: str, run_id: str) -> list[execution.ExecutionResult]: + self, graph_id: str, run_id: str + ) -> list[execution.ExecutionResult]: graph = await get_graph(graph_id) if not graph: raise HTTPException(status_code=404, detail=f"Agent #{graph_id} not found.") @@ -152,3 +169,31 @@ class AgentServer(AppProcess): def get_execution_schedules(self, graph_id: str) -> dict[str, str]: execution_scheduler = self.execution_scheduler_client return execution_scheduler.get_execution_schedules(graph_id) + + def update_configuration( + self, + updated_settings: Annotated[ + Dict[str, Any], Body(examples=[{"config": {"num_workers": 10}}]) + ], + ): + settings = Settings() + try: + updated_fields = {"config": [], "secrets": []} + for key, value in updated_settings.get("config", {}).items(): + if hasattr(settings.config, key): + setattr(settings.config, key, value) + updated_fields["config"].append(key) + for key, value in updated_settings.get("secrets", {}).items(): + if hasattr(settings.secrets, key): + setattr(settings.secrets, key, value) + updated_fields["secrets"].append(key) + settings.save() + return JSONResponse( + content={ + "message": "Settings updated successfully", + "updated_fields": updated_fields, + }, + status_code=200, + ) + except Exception as e: + raise HTTPException(status_code=400, detail=str(e)) diff --git a/rnd/autogpt_server/autogpt_server/util/data.py b/rnd/autogpt_server/autogpt_server/util/data.py new file mode 100644 index 000000000..d9659623f --- /dev/null +++ b/rnd/autogpt_server/autogpt_server/util/data.py @@ -0,0 +1,35 @@ +import os +import pathlib +import sys + + +def get_secrets_path() -> pathlib.Path: + return get_data_path() / "secrets" + + +def get_config_path() -> pathlib.Path: + return get_data_path() + + +def get_frontend_path() -> pathlib.Path: + if getattr(sys, "frozen", False): + # The application is frozen + datadir = pathlib.Path(os.path.dirname(sys.executable)) / "example_files" + else: + # The application is not frozen + # Change this bit to match where you store your data files: + filedir = os.path.dirname(__file__) + datadir = pathlib.Path(filedir).parent.parent.parent / "example_files" + return pathlib.Path(datadir) + + +def get_data_path() -> pathlib.Path: + if getattr(sys, "frozen", False): + # The application is frozen + datadir = os.path.dirname(sys.executable) + else: + # The application is not frozen + # Change this bit to match where you store your data files: + filedir = os.path.dirname(__file__) + datadir = pathlib.Path(filedir).parent.parent + return pathlib.Path(datadir) diff --git a/rnd/autogpt_server/autogpt_server/util/process.py b/rnd/autogpt_server/autogpt_server/util/process.py index 88ae38511..764d1f947 100644 --- a/rnd/autogpt_server/autogpt_server/util/process.py +++ b/rnd/autogpt_server/autogpt_server/util/process.py @@ -2,7 +2,6 @@ import os import sys from abc import ABC, abstractmethod from multiprocessing import Process, freeze_support, set_start_method -from multiprocessing.spawn import freeze_support as freeze_support_spawn from typing import Optional @@ -10,10 +9,9 @@ class AppProcess(ABC): """ A class to represent an object that can be executed in a background process. """ + process: Optional[Process] = None - set_start_method('spawn', force=True) - freeze_support() - freeze_support_spawn() + set_start_method("spawn", force=True) @abstractmethod def run(self): diff --git a/rnd/autogpt_server/autogpt_server/util/settings.py b/rnd/autogpt_server/autogpt_server/util/settings.py new file mode 100644 index 000000000..2a60d58ab --- /dev/null +++ b/rnd/autogpt_server/autogpt_server/util/settings.py @@ -0,0 +1,108 @@ +import json +import os +from typing import Any, Dict, Generic, Set, Tuple, Type, TypeVar +from pydantic import BaseModel, Field, PrivateAttr +from pydantic_settings import ( + BaseSettings, + JsonConfigSettingsSource, + PydanticBaseSettingsSource, + SettingsConfigDict, +) + +from autogpt_server.util.data import get_config_path, get_data_path, get_secrets_path + +T = TypeVar("T", bound=BaseSettings) + + +class UpdateTrackingModel(BaseModel, Generic[T]): + _updated_fields: Set[str] = PrivateAttr(default_factory=set) + + def __setattr__(self, name: str, value) -> None: + if name in self.model_fields: + self._updated_fields.add(name) + super().__setattr__(name, value) + + + def mark_updated(self, field_name: str) -> None: + if field_name in self.model_fields: + self._updated_fields.add(field_name) + + def clear_updates(self) -> None: + self._updated_fields.clear() + + def get_updates(self) -> Dict[str, Any]: + return {field: getattr(self, field) for field in self._updated_fields} + + +class Config(UpdateTrackingModel["Config"], BaseSettings): + """Config for the server.""" + + num_workers: int = Field( + default=9, ge=1, le=100, description="Number of workers to use for execution." + ) + # Add more configuration fields as needed + + model_config = SettingsConfigDict( + json_file=[ + get_config_path() / "config.default.json", + get_config_path() / "config.json", + ], + env_file=".env", + env_file_encoding="utf-8", + extra="allow", + ) + + @classmethod + def settings_customise_sources( + cls, + settings_cls: Type[BaseSettings], + init_settings: PydanticBaseSettingsSource, + env_settings: PydanticBaseSettingsSource, + dotenv_settings: PydanticBaseSettingsSource, + file_secret_settings: PydanticBaseSettingsSource, + ) -> Tuple[PydanticBaseSettingsSource, ...]: + return (JsonConfigSettingsSource(settings_cls),) + + +class Secrets(UpdateTrackingModel["Secrets"], BaseSettings): + """Secrets for the server.""" + + database_password: str = "" + # Add more secret fields as needed + + model_config = SettingsConfigDict( + secrets_dir=get_secrets_path(), + env_file=".env", + env_file_encoding="utf-8", + extra="allow", + ) + + +class Settings(BaseModel): + config: Config = Config() + secrets: Secrets = Secrets() + + def save(self) -> None: + # Save updated config to JSON file + if self.config._updated_fields: + config_to_save = self.config.get_updates() + config_path = os.path.join(get_data_path(), "config.json") + if os.path.exists(config_path): + with open(config_path, "r+") as f: + existing_config: Dict[str, Any] = json.load(f) + existing_config.update(config_to_save) + f.seek(0) + json.dump(existing_config, f, indent=2) + f.truncate() + else: + with open(config_path, "w") as f: + json.dump(config_to_save, f, indent=2) + self.config.clear_updates() + + # Save updated secrets to individual files + secrets_dir = get_secrets_path() + for key in self.secrets._updated_fields: + secret_file = os.path.join(secrets_dir, key) + with open(secret_file, "w") as f: + f.write(str(getattr(self.secrets, key))) + self.secrets.clear_updates() diff --git a/rnd/autogpt_server/config.default.json b/rnd/autogpt_server/config.default.json new file mode 100644 index 000000000..cbc8006a2 --- /dev/null +++ b/rnd/autogpt_server/config.default.json @@ -0,0 +1,3 @@ +{ + "num_workers": 5 +} \ No newline at end of file diff --git a/rnd/autogpt_server/poetry.lock b/rnd/autogpt_server/poetry.lock index 50cf787bc..931d89b56 100644 --- a/rnd/autogpt_server/poetry.lock +++ b/rnd/autogpt_server/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -132,67 +132,33 @@ python-dateutil = "*" pytz = ">2021.1" [[package]] -name = "cx-freeze" -version = "7.0.0" +name = "cx_Freeze" +version = "7.1.1" description = "Create standalone executables from Python scripts" optional = false python-versions = ">=3.8" -files = [ - {file = "cx_Freeze-7.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:421920dbee2b4aab53a81f6c99d18b00baf622a328eae8e489f162154a46192a"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fa1ca4cf20c6ce45ce2e26bf8b2086525aaaa774e2ee1b16da4e0f9f18c7272"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a520bc6772325c0e38924da1d827fe370702f8df397f483691b94d36179beef6"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b89ed99a2f99fd2f3e28a91c85bdd75b4bfaf11b04729ba3282bfebdadadf880"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5174821c82826e5a57e43960877087f5af6073e3877b0b38a0be244111fe1a76"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfd18cc00f3240b03d5bdf9515d59ace0881b5b5b6f2e7655d857d1fb71f351d"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bac44e65bdfce0839b9a6d15373ea084fda3cdbd902351cde530991b450c2b2d"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:51a374f273d575827efe4f7ed9a88b6cab78abffacb858c829d7cbe4dc4ff56e"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-win32.whl", hash = "sha256:6603e6c47a15bd84bfbb20d92dc01d5e586b54928eb618461d2f14305471d570"}, - {file = "cx_Freeze-7.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:d7ec847af5afbe3c638a096aae4ff5982a17d95e2fb7975e525ecf9505a185ea"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04b7a2e5c53f5d537f3d958ebf2b0a0a7cbe8daf980cb0087559a3e698abc582"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:50e7e78001d4f78e70a403ecb5507685854ce1e6c3ff37bec1920eb6f2256534"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d37ed560e86ca7958684701a6ae7f3300226d0d7c861ca5b90c78bf4c619ad2"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42145dc5c2c7a98c620b30b7e25661954817a13355c50c4219a4a4954b39db39"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f9034d6f9c10d84d7edc0e4f4020e878de367e83c5877c039aa3c8b733bc318"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:adc6bdba9ff8705745831620efb6ee5eff9ec6d31d9b8c56d2a61d6555299157"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37a3234c0e54b4afd561b47be4f22a6496f9436275fb7b59d90d7a3269fb4d6f"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:83549f9f817cafa59ea2f6e2045c8fe119628458ff14bb732649b01b0a637f6d"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-win32.whl", hash = "sha256:c508cd354728367311a7deb5bb616eee441bf79c900e3129a49fd54a372dc223"}, - {file = "cx_Freeze-7.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:8fb71d23dba27dc40393a8b460bbf64759899246cd595860f66493cee64f27a5"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:648fd0acb439efe22dced2430cbaeca87e5ca9ab315d148933104376cca9553d"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3125a8408da3ff4b0cf767689d678909f840dfe08633f5f2d3cfe333111dc334"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07e56b06c7ca0bd2fc37e3783908767dbe1926e1e2609edcaefcc749ab584329"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25531d5c61bb5e974d8a5d042f29a37a786e91c1d6f66e018fc50342a416f4e1"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f97154b4b60f6e1953ebce05803a5e11a35047d097fad60d7c181303b7c6ef6e"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2333db5cfa6db700c79fd45d614d38e9d698f1df2a3c7e21ccbcc63cc8a7a9b7"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d45a58e0a9b010e0823c30fb8eb2077560d2bb0f78e4481a55bdb6ad0729f390"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0422dbd426fd9f4f4ec0cadc7e3192d38227464daa3eb215b03eb577cd9a49d4"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-win32.whl", hash = "sha256:2018e9cbf8172da09b311cfc3906503ee6ae88665ec77c543013173b2532b731"}, - {file = "cx_Freeze-7.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae5facd782b220bca6828eb6fb1834540cf431b1a615cc63652641bd070b11e6"}, - {file = "cx_Freeze-7.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f06368dd41568572818c4abfcf9b45449dced3fa9f1b5f29e3523ba4ff7fcfbb"}, - {file = "cx_Freeze-7.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e203d90d8fa1cc4489b15edac7dfdd983518a02999f275897160fc0ecfa98e4c"}, - {file = "cx_Freeze-7.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f800b0bc2df14c66fcf2f220ecf273c5942d0b982268d8e5ccc9ef2fa56e576f"}, - {file = "cx_Freeze-7.0.0-cp38-cp38-win32.whl", hash = "sha256:c52641ce2484222f4d60f0acbc79b2dfbfb984493101a4806c5af0ad379ebc82"}, - {file = "cx_Freeze-7.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:92a15613be3fcc7a310e825c92ae3e83a7e689ade00ce2ea981403e4317c7234"}, - {file = "cx_Freeze-7.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:60a0f674b6a55fdf46d0cc59122551a79221ceecd038fed8533dcbceb9714435"}, - {file = "cx_Freeze-7.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb15314e8395e9658a8a5e4e19558d0e096a68b76c744ba81ebc249061b7dd9e"}, - {file = "cx_Freeze-7.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3290127acc67e830265265a911d9018640ffffb7fddb86eacb1e3d83ed4136c4"}, - {file = "cx_Freeze-7.0.0-cp39-cp39-win32.whl", hash = "sha256:aa885f2fb29b9f7d9a7d8af223d38d98905484cc2356c474bb1d6fd1704323ad"}, - {file = "cx_Freeze-7.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:fe4dbbfd52454c8ddb550f112713ee2ac36cc024303557763b605e35cdb6b9a8"}, - {file = "cx_freeze-7.0.0.tar.gz", hash = "sha256:b03f2854a15dd1e8962660d18882a71fefba0e1b6f68337193d4a072d1fc36e6"}, -] +files = [] +develop = true [package.dependencies] -cx-Logging = {version = ">=3.1", markers = "sys_platform == \"win32\""} -filelock = {version = ">=3.11.0", markers = "sys_platform == \"linux\""} +cx_Logging = {version = ">=3.1", markers = "sys_platform == \"win32\""} +dmgbuild = {version = ">=1.6.1", markers = "sys_platform == \"darwin\""} +filelock = {version = ">=3.12.3", markers = "sys_platform == \"linux\""} lief = {version = ">=0.12.0,<0.15.0", markers = "sys_platform == \"win32\""} -patchelf = {version = ">=0.14", markers = "sys_platform == \"linux\" and (platform_machine == \"aarch64\" or platform_machine == \"armv7l\" or platform_machine == \"i686\" or platform_machine == \"ppc64le\" or platform_machine == \"s390x\" or platform_machine == \"x86_64\")"} -setuptools = ">=62.6,<70" +patchelf = {version = ">=0.14", markers = "sys_platform == \"linux\" and (platform_machine == \"x86_64\" or platform_machine == \"i686\" or platform_machine == \"aarch64\" or platform_machine == \"armv7l\" or platform_machine == \"ppc64le\" or platform_machine == \"s390x\")"} +setuptools = ">=65.6.3,<71" wheel = ">=0.42.0,<=0.43.0" [package.extras] -dev = ["bump-my-version (==0.20.1)", "cibuildwheel (==2.17.0)", "pre-commit (==3.7.0)"] -doc = ["furo (==2024.1.29)", "myst-parser (==2.0.0)", "sphinx (==7.3.7)", "sphinx-new-tab-link (==0.4.0)", "sphinx-tabs (==3.4.5)"] -test = ["coverage (==7.4.4)", "pluggy (==1.4.0)", "pytest (==8.1.1)", "pytest-cov (==5.0.0)", "pytest-datafiles (==3.0.0)", "pytest-mock (==3.14.0)", "pytest-timeout (==2.3.1)", "pytest-xdist[psutil] (==3.6.0)"] +dev = ["bump-my-version (==0.24.0)", "cibuildwheel (==2.19.1)", "pre-commit (==3.5.0)", "pre-commit (==3.7.1)"] +doc = ["furo (==2024.5.6)", "myst-parser (==3.0.1)", "sphinx (==7.3.7)", "sphinx-new-tab-link (==0.4.0)", "sphinx-tabs (==3.4.5)"] +test = ["coverage (==7.5.4)", "pluggy (==1.5.0)", "pytest (==8.2.2)", "pytest-cov (==5.0.0)", "pytest-datafiles (==3.0.0)", "pytest-mock (==3.14.0)", "pytest-timeout (==2.3.1)", "pytest-xdist[psutil] (==3.6.1)"] + +[package.source] +type = "git" +url = "https://github.com/ntindle/cx_Freeze.git" +reference = "main" +resolved_reference = "876fe77c97db749b7b0aed93c12142a7226ee7e4" [[package]] name = "cx-logging" @@ -224,6 +190,46 @@ files = [ {file = "cx_Logging-3.2.0.tar.gz", hash = "sha256:bdbad6d2e6a0cc5bef962a34d7aa1232e88ea9f3541d6e2881675b5e7eab5502"}, ] +[[package]] +name = "dmgbuild" +version = "1.6.1" +description = "macOS command line utility to build disk images" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dmgbuild-1.6.1-py3-none-any.whl", hash = "sha256:45dba6af4a64872c6a91eb335ebeaf5e1f4f4f39c89fd77cf40e841bd1226166"}, + {file = "dmgbuild-1.6.1.tar.gz", hash = "sha256:7ced2603d684e29c22b4cd507d1e15a1907e91b86259924b8cfe480d80553b43"}, +] + +[package.dependencies] +ds-store = ">=1.1.0" +mac-alias = ">=2.0.1" + +[package.extras] +badge-icons = ["pyobjc-framework-Quartz (>=3.0.4)"] +dev = ["pre-commit", "tox"] +docs = ["sphinx", "sphinx-autobuild", "sphinx-rtd-theme"] +test = ["pytest", "pytest-cov", "pytest-tldr"] + +[[package]] +name = "ds-store" +version = "1.3.1" +description = "Manipulate Finder .DS_Store files from Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ds_store-1.3.1-py3-none-any.whl", hash = "sha256:fbacbb0bd5193ab3e66e5a47fff63619f15e374ffbec8ae29744251a6c8f05b5"}, + {file = "ds_store-1.3.1.tar.gz", hash = "sha256:c27d413caf13c19acb85d75da4752673f1f38267f9eb6ba81b3b5aa99c2d207c"}, +] + +[package.dependencies] +mac-alias = ">=2.0.1" + +[package.extras] +dev = ["pre-commit", "tox"] +docs = ["sphinx", "sphinx-autobuild", "sphinx-rtd-theme"] +test = ["pytest", "pytest-cov", "pytest-tldr"] + [[package]] name = "exceptiongroup" version = "1.2.1" @@ -506,6 +512,22 @@ files = [ {file = "lief-0.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:2db3eb282a35daf51f89c6509226668a08fb6a6d1f507dd549dd9f077585db11"}, ] +[[package]] +name = "mac-alias" +version = "2.2.2" +description = "Generate/parse Mac OS Alias records from Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mac_alias-2.2.2-py3-none-any.whl", hash = "sha256:504ab8ac546f35bbd75ad014d6ad977c426660aa721f2cd3acf3dc2f664141bd"}, + {file = "mac_alias-2.2.2.tar.gz", hash = "sha256:c99c728eb512e955c11f1a6203a0ffa8883b26549e8afe68804031aa5da856b7"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +docs = ["sphinx", "sphinx-autobuild", "sphinx-rtd-theme"] +test = ["pytest", "pytest-cov", "pytest-tldr"] + [[package]] name = "markupsafe" version = "2.1.5" @@ -846,6 +868,25 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pydantic-settings" +version = "2.3.4" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, +] + +[package.dependencies] +pydantic = ">=2.7.0" +python-dotenv = ">=0.21.0" + +[package.extras] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] + [[package]] name = "pyflakes" version = "3.2.0" @@ -1631,4 +1672,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "17f25b61da5f54bb4bb13cecfedda56d23c097aacb95bb213f13ce63ee08c761" +content-hash = "a243c28b48b60e14513fc18629096a7f9d1c60ae7b05a6c50125c1d4c045033e" diff --git a/rnd/autogpt_server/pyproject.toml b/rnd/autogpt_server/pyproject.toml index 2de400fa7..028a52c45 100644 --- a/rnd/autogpt_server/pyproject.toml +++ b/rnd/autogpt_server/pyproject.toml @@ -25,10 +25,11 @@ tenacity = "^8.3.0" apscheduler = "^3.10.4" croniter = "^2.0.5" pytest-asyncio = "^0.23.7" +pydantic-settings = "^2.3.4" [tool.poetry.group.dev.dependencies] -cx-freeze = "7.0.0" +cx-freeze = { git = "https://github.com/ntindle/cx_Freeze.git", rev = "main", develop = true } poethepoet = "^0.26.1" httpx = "^0.27.0" pytest-watcher = "^0.4.2" @@ -85,4 +86,4 @@ patterns = ["*.py"] ignore_patterns = [] [tool.pytest.ini_options] -asyncio_mode = "auto" \ No newline at end of file +asyncio_mode = "auto" diff --git a/rnd/autogpt_server/secrets/.gitkeep b/rnd/autogpt_server/secrets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/rnd/autogpt_server/setup.py b/rnd/autogpt_server/setup.py index c83cf2f22..690905023 100644 --- a/rnd/autogpt_server/setup.py +++ b/rnd/autogpt_server/setup.py @@ -1,7 +1,9 @@ +import platform +from pathlib import Path from pkgutil import iter_modules -from shutil import which +from typing import Union -from cx_Freeze import Executable, setup +from cx_Freeze import Executable, setup # type: ignore packages = [ m.name @@ -9,13 +11,52 @@ packages = [ if m.ispkg and m.module_finder and "poetry" in m.module_finder.path # type: ignore ] packages.append("collections") +packages.append("autogpt_server.util.service") +packages.append("autogpt_server.executor.manager") +packages.append("autogpt_server.util.service") + +# set the icon based on the platform +icon = "../../assets/gpt_dark_RGB.ico" +if platform.system() == "Darwin": + icon = "../../assets/gpt_dark_RGB.icns" +elif platform.system() == "Linux": + icon = "../../assets/gpt_dark_RGB.png" + + +def txt_to_rtf(input_file: Union[str, Path], output_file: Union[str, Path]) -> None: + """ + Convert a text file to RTF format. + + Args: + input_file (Union[str, Path]): Path to the input text file. + output_file (Union[str, Path]): Path to the output RTF file. + + Returns: + None + """ + input_path = Path(input_file) + output_path = Path(output_file) + + with input_path.open("r", encoding="utf-8") as txt_file: + content = txt_file.read() + + # RTF header + rtf = r"{\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}}\f0\fs24 " + + # Replace newlines with RTF newline + rtf += content.replace("\n", "\\par ") + + # Close RTF document + rtf += "}" + + with output_path.open("w", encoding="utf-8") as rtf_file: + rtf_file.write(rtf) + + +# Convert LICENSE to LICENSE.rtf +license_file = "LICENSE.rtf" +txt_to_rtf("../../LICENSE", license_file) -# if mac use the icns file, otherwise use the ico file -icon = ( - "../../assets/gpt_dark_RGB.icns" - if which("sips") - else "../../assets/gpt_dark_RGB.ico" -) setup( name="AutoGPT Server", @@ -41,30 +82,48 @@ setup( "packages": packages, "includes": [ "autogpt_server", - "uvicorn.loops.auto", - "uvicorn.protocols.http.auto", - "uvicorn.protocols.websockets.auto", - "uvicorn.lifespan.on", + "prisma", ], # Exclude the two module from readability.compat as it causes issues "excludes": ["readability.compat.two"], + "include_files": [ + # source, destination in the bundle + # (../frontend, example_files) would also work but you'd need to load the frontend differently in the data.py to correctly get the path when frozen + ("../example_files", "example_files"), + ], }, # Mac .app specific options "bdist_mac": { "bundle_name": "AutoGPT", "iconfile": "../../assets/gpt_dark_RGB.icns", - # "include_resources": ["IMG_3775.jpeg"], }, # Mac .dmg specific options "bdist_dmg": { "applications_shortcut": True, "volume_label": "AutoGPTServer", + "background": "builtin-arrow", + + "license": { + "default-language": "en_US", + "licenses": {"en_US": license_file}, + "buttons": { + "en_US": [ + "English", + "Agree", + "Disagree", + "Print", + "Save", + "If you agree, click Agree to continue the installation. If you do not agree, click Disagree to cancel the installation.", + ] + }, + }, }, # Windows .msi specific options "bdist_msi": { "target_name": "AutoGPTServer", "add_to_path": True, "install_icon": "../../assets/gpt_dark_RGB.ico", + "license_file": license_file, }, # Linux .appimage specific options "bdist_appimage": {}, diff --git a/rnd/example_files/index.html b/rnd/example_files/index.html new file mode 100644 index 000000000..0c3c960b1 --- /dev/null +++ b/rnd/example_files/index.html @@ -0,0 +1,19 @@ + + + + + Example Files + + + + + +

Example Files

+ + + + \ No newline at end of file