From 7f11d4b3aff963d33c61ba19f785674c3b700eb4 Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Wed, 5 Mar 2025 10:11:25 +0100 Subject: [PATCH] Prepare for full rewrite --- .idea/.gitignore | 3 - .idea/BiogasControllerApp.iml | 12 - .../inspectionProfiles/profiles_settings.xml | 6 - .idea/misc.xml | 4 - .idea/modules.xml | 8 - .idea/vcs.xml | 6 - BiogasControllerApp-V2.3/.idea/.gitignore | 3 - BiogasControllerApp-V2.3/.idea/.name | 1 - BiogasControllerApp-V2.3/.idea/ENATECH.iml | 10 - .../inspectionProfiles/profiles_settings.xml | 6 - BiogasControllerApp-V2.3/.idea/misc.xml | 4 - BiogasControllerApp-V2.3/.idea/modules.xml | 8 - .../BiogasControllerApp-V2.3-stable.spec | 54 -- .../BiogasControllerAppLogo-V2.3.ico | Bin 120363 -> 0 bytes .../BiogasControllerAppLogo.png | Bin 36750 -> 0 bytes BiogasControllerApp-V2.3/bin/gui/gui.kv | 694 -------------- .../bin/lib/communication.py | 96 -- .../bin/lib/comport_search.py | 22 - .../bin/lib/csv_parsers.py | 122 --- BiogasControllerApp-V2.3/bin/lib/lib.py | 73 -- .../biogascontrollerapp.py | 893 ------------------ BiogasControllerApp-V2.3/config/config.csv | 1 - BiogasControllerApp-V2.3/config/settings.ini | 19 - BiogasControllerApp-V2.3/log/logging.md | 5 - biogascontrollerapp/biogascontrollerapp.py | 0 25 files changed, 2050 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/BiogasControllerApp.iml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 BiogasControllerApp-V2.3/.idea/.gitignore delete mode 100644 BiogasControllerApp-V2.3/.idea/.name delete mode 100644 BiogasControllerApp-V2.3/.idea/ENATECH.iml delete mode 100644 BiogasControllerApp-V2.3/.idea/inspectionProfiles/profiles_settings.xml delete mode 100644 BiogasControllerApp-V2.3/.idea/misc.xml delete mode 100644 BiogasControllerApp-V2.3/.idea/modules.xml delete mode 100644 BiogasControllerApp-V2.3/BiogasControllerApp-V2.3-stable.spec delete mode 100644 BiogasControllerApp-V2.3/BiogasControllerAppLogo-V2.3.ico delete mode 100644 BiogasControllerApp-V2.3/BiogasControllerAppLogo.png delete mode 100644 BiogasControllerApp-V2.3/bin/gui/gui.kv delete mode 100644 BiogasControllerApp-V2.3/bin/lib/communication.py delete mode 100644 BiogasControllerApp-V2.3/bin/lib/comport_search.py delete mode 100644 BiogasControllerApp-V2.3/bin/lib/csv_parsers.py delete mode 100644 BiogasControllerApp-V2.3/bin/lib/lib.py delete mode 100644 BiogasControllerApp-V2.3/biogascontrollerapp.py delete mode 100644 BiogasControllerApp-V2.3/config/config.csv delete mode 100644 BiogasControllerApp-V2.3/config/settings.ini delete mode 100644 BiogasControllerApp-V2.3/log/logging.md create mode 100644 biogascontrollerapp/biogascontrollerapp.py diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/BiogasControllerApp.iml b/.idea/BiogasControllerApp.iml deleted file mode 100644 index 8b8c395..0000000 --- a/.idea/BiogasControllerApp.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index dc9ea49..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index f7486eb..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/BiogasControllerApp-V2.3/.idea/.gitignore b/BiogasControllerApp-V2.3/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/BiogasControllerApp-V2.3/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/BiogasControllerApp-V2.3/.idea/.name b/BiogasControllerApp-V2.3/.idea/.name deleted file mode 100644 index 06ffd37..0000000 --- a/BiogasControllerApp-V2.3/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -biogascontrollerapp.py \ No newline at end of file diff --git a/BiogasControllerApp-V2.3/.idea/ENATECH.iml b/BiogasControllerApp-V2.3/.idea/ENATECH.iml deleted file mode 100644 index 0e4e9fa..0000000 --- a/BiogasControllerApp-V2.3/.idea/ENATECH.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/BiogasControllerApp-V2.3/.idea/inspectionProfiles/profiles_settings.xml b/BiogasControllerApp-V2.3/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/BiogasControllerApp-V2.3/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/BiogasControllerApp-V2.3/.idea/misc.xml b/BiogasControllerApp-V2.3/.idea/misc.xml deleted file mode 100644 index d1e22ec..0000000 --- a/BiogasControllerApp-V2.3/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/BiogasControllerApp-V2.3/.idea/modules.xml b/BiogasControllerApp-V2.3/.idea/modules.xml deleted file mode 100644 index 6610bd3..0000000 --- a/BiogasControllerApp-V2.3/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/BiogasControllerApp-V2.3/BiogasControllerApp-V2.3-stable.spec b/BiogasControllerApp-V2.3/BiogasControllerApp-V2.3-stable.spec deleted file mode 100644 index 7ab73cd..0000000 --- a/BiogasControllerApp-V2.3/BiogasControllerApp-V2.3-stable.spec +++ /dev/null @@ -1,54 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- -from kivy_deps import sdl2, glew - -block_cipher = None - - -a = Analysis( - ['biogascontrollerapp.py'], - pathex=[], - binaries=[], - datas=[], - hiddenimports=[], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False, -) -pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) - -exe = EXE( - pyz, - a.scripts, - a.binaries, - a.zipfiles, - a.datas, - [], - name='BiogasControllerApp-V2.3-stable', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - upx_exclude=[], - runtime_tmpdir=None, - console=True, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, - icon='BiogasControllerAppLogo-V2.3.ico', -) - -coll = COLLECT(exe, Tree('C:\\BiogasControllerApp-V2.3\\'), - a.binaries, - a.zipfiles, - a.datas, - *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)], - strip=False, - upx=True, - name='touchtracer') diff --git a/BiogasControllerApp-V2.3/BiogasControllerAppLogo-V2.3.ico b/BiogasControllerApp-V2.3/BiogasControllerAppLogo-V2.3.ico deleted file mode 100644 index f42f7297e06358aebe1fa151a987d1dd427192e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120363 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

861vr8EUKp_(4Z<0q(Vq~EIgoU5>rG${O zFTJ51-2d)dR~?*plC(aAjae>-PJ9j^aBNqZ^Lf7dDg=y9cca~U=W{01|9;dENf-@%J;%m3zy8V7tBFAvXnAg zH_MKeGX*jrLSEPK^z?L*qh#|mDH31TA>#`OrCgxcUw|!w|7AYZeczF_7)xbk+Vk%O z(CqBx5&DkBWmmqk{bGb{G((=sp=IZ@D=*Pt90^G+Nq%159e}2>OLm%bpEJfk+l>ak zM@|JG<*RS4*R{>e%*>fr#}goi)K1D9eD1&Rj%RT1-!3gJtpGw0jz8OY>s=aQW zqCYT}#t#21$jzOy?AS%Le{FpSaEOLs0x}r|Ea^kbeQAe>jg_sf>Fwz%2sqSo(Nj}a zR@NzdVQT7ku2|Ry#%KGaB#p0U0+}SSy)ih(vs5GC*tJf1i16V2{k|~LGxLusYAz0bs9}Oy=X!OEiHHf zKurW{;ZSux77Tde*sG7?F{&CvU#L2PXlLgBn*o&wWxQ!wkxhP$8-UX5p#)J_h% zeh&*13mBGcEi1F&K7_?r#=n35h?Alt45wRodwVO_L`6k~aWcq4`T(sOu%>8dZH-s! zBQHNTm6g8$kK&=ApnyOoYOw+*t)M`(a4AFr44hNjD(FoD1H(bz%|#a(i0(@}{3r;> zRbf(e{?4wl(L&rw(gAmkNG& zy(Fl*{vsmX)#hw$Y~fK+`DJBMfB*g^8~yzGGpeqkg#}ejO^quUjHYW?j4+Hq3M_W; zaCvxs`N=*NvgOJfK%dI3rEhRzG)Rh#mIUyIu$!n*YP5*Noo3GapS3DIj{o zY<+!wQ2XtgcegL77Z4n@fa0Gh)hH94iJi^Q*)*Uc@9;Cd{*Dv@0t^Z(KpsCq?T@Ez zV)*=jW`w?ltU73M!a;=|c=#6k`z3j@{a<-4Co+e@otIgxP@J&d?zi+Y7zEJ4!0&#? z`2EjUY0F|ZK*Rn%oBhgpo#pPUsRqP10VAjWKLR~4I2i8Dsi>?Q(8{Pf-4E}4KcCHcN!;DtjgNurIe!9Z;mGjS z>n!FL&@?XVzPEt<=GkXuN{Nag;J%15eEPy;CTM8j|9ri{;<+=D)XTJULk;{`)vt8= z@&TDbP+vZ{y;(CzYzpk`wf6x&&l3<6C1qt|MYHE;y=d?iw?Tju^t{^)TLKis*Xt}^ zw@83?5<^2j03@>hw95@x{m!3$s&dlr0s$5G=5RhqYzn<>3%xPNKWd>(K!_5RX;oQV z{2T7;>jNyJL(`jOYqVPu)z-#SEOHUf*HBf(oD_QH=U(?=cW=w`e{AyK2Grlq#V9kH zL+Dbg8~vN&-T7|JmErktP&CL;zW8*1IXpSJ2PAX*`2fLNGr*GHW41_XF9=PL2kLvi z>G6VxhxY`G@m{j7LvCkh_JW~*R@dt@)aSa)kWxs9B&t7f9Xhz_q^zda`?tZ?8Zh+T zf$!g16noEY03HKkj`nW1b0=9>(#)SFO@76x7sUr~x_3T;fRuRecOGT<@!Jg$ylpi9 zJ259URX~|Lu}=YmF5%|J2?EAj(;VUXrm1TjP@9u;T8865?c%ObXzJ>Y0taF1-5SBmJ@_zGLTaHI!a2)t){N$3cwKU{lP(i>jO$AFhl>t zBOu753|}r%f*v3_9YoD#Wwt|?Ku6-!{rx>G`e+I>iBnK$9*xQNK#a*iG#>dH>eI9o zNy*`)a+W_$(>waeFE`M2lB-LSQ!E@D>THj#2$#R^H|`s`TrejqE$q#JrOT7ZYislF zyR|Sk{{^^rSag8&dk$PbbRBi!7(L#cYylvIGVld=zs{%|*7<6GTExHX)gZw4@g^b% z81^r8bT(5D$xQlmBcr2IK8iR!#lh=yN7vn)TlUM1=Rl3A>gq-TJ|E!bx+VGV-`M~v z__wp;445Q#@TndoApxEPf24M-VZlHS051QB*__2%^Z&2C?|`f7SpL^k6VvnZViFT$ zk{9z*EYZY{y&G$6(b!93FR_bYMN}-guoCMsR3q6ku?gY+gHq!*q4e)s;*^>!|D zZSQx6&*7f4XY0)F?Ck8!o~CS?@6fU1hb>yP=&&lmfF2Az_UnSs^S+KhUSiTo(CqeI zPAnX630=)Xw`^zy{>zSZaM=0HpdY7r9xuy{9zAw!|JAEIvs`>S_8m4X_>=tqwr-ut z22qzrAAUP@M5Nj2E(U{4$1}RO024(*+4RVIFq7w*W@1U?m~j``0*|e|LzWn^CfiKDdX&k0jLmJ`+2l{w z**;%+w=r05@VwuDndbY-`l3xOUNNHEw{O4fHvY4>Ui-qJb_rWm`ZaCi;ms6H=k4uV zeb3~CjW1!5;lk48+YGU~i6vr%%{ z8a9#pWdCy}JbRmo$(W2IRo6ZoUSvj9W{ucNwjEnQor?CH>KwnMQ**X%U`mAF*RI)m zwA~xt_TkyALuGY;w_x`-gZd5_Fr{>u-V~>j=-jev*RNZZXLucM`>Dw{|M}0BAG0-Ed8ebJk4o*X!e!(A18&`1$CNkY<&7*(KPFo1=pH=Hl#Qw@?UMnpQ^6BwdwWP z;_BSWycOU6x%3T-OV|1|={4`q&*PKU?He8M96olO(S<7?jqd%@8=rhK^l+C0|6zS{ z!oF`?PBHxW^wmrIy0_53ws&_A3v;J`yWifLIRD#Ue=@mTyDl?feb;_X|2?(2`Oto! zX2B7CTkP~{)n(D6uP$qqSg>%H&6FNrHSXlLzPqRAh|%VZ1^U1I?Z38cV$(yES8dbo zmR|=A{-Dd*_vh$$-*xoUoD~H#L+05p3Fz_g>v8K!jx`JRo8?@bKIma}Wm-hVtM|G+ z`0NX#mnY8n+UY?}XP4P;FDvlacWixSpEF*YPj39U{n17{+g~4Y&_VA%ug)3Lbb#K& z!;wkV|Ni$!QPb^j_@xZjYwT@$^j3ORNl2yVeecGTDav`V)0NZhkKCN%YWm+F#_kzE ze%o2sBOk^)ExEVIz_0Kh$8yUa`M;fEy0EW5eIur8*VR?-N#^ULTYqz6m(A*u!)%~^ z^YO0=zkz!2p)JH(fB{OzQTTYin+gZ*y#@q1?;iCvj=JHJO&z$aaQ z%$l^mbIC%l6G=&HekkAi+6u4oPn$0CI??>V$aNk1w^;De)Z^`%y%pqH+`m!nuvSJL z=Z{!^ckl2X*P}oFb57K69ZwV||1xgO$jFbIcUY9o>?Ms1nk}}R8nE%zNhJ}Z2RiOd zS~w^A*dpt9QZma{eV4mq+MHcG(y9yf7kTGL#%|d%>3;sAue1NDbaU@~ab+PpG)Hm} z$D3Ipty;Hv*YIqi*Y2xr5+6*h)Yp4weQmo&Q8qumS>t4T(jqgoM)zc_CfAOjFJLf>J>u&$Hv3~55*ZNpSzh2>%+xu|WQE9$m^BYYwvA6ln^WI;P{k_wVH(!6J;@6IEUGj)toZckSGkb8dZ$moAxL5^ytV3U=6-+c*9EC3T0Cg7HmTb~$HMi8BAN~z@Sn|7 zE0P}i+Z~$RB`s;6<**F9DG#R-R95c}=bm65F#aBOQ zGJ+YrHR*MK|9^+(HT~J@-z{G;IdH(EHho`h*=I?o&U!Qtn3`;A@Nmx9yUWK7EPwUd z>{)v|&w1x>bMt0tX^rolKc8I2UcR%g{K(v|&-%xlGHK+y?fkvJEGFsy@=Mp1sW~~R zMb%|L<~H5*_6UQVe=X2YvDtC(r?2O}GGU2ZTwG;s#-Z4UMm?q$2KM~y(6PXrR%SC3 ze~I3Ft?O{pZ(6TSZakLlR&76%oRgOx6MSNRWk#F7?|PYyYoY(I;$ul|a~%Wy-7ox7 zjdOqYd}Ew_VQg`1h{3Lqg<0MMT3jqGkKg2%`SQG|_ljzInI2y5_qKInOk*#zO=kN3 zaakwN7JE1D`=ue9jwWHb%btDOhU zxEuD$mqBfh-VSmp=+ekzMOUNhZV!*no%>h8#Fb`Cv(2;SKj{A1oZ;^-q8kPd8RNWs zvzE47l0B-RCfuwtZn(kV;Qjyo`0|5~PhC8-G40r|OQy&F>ftx@^@HCS2l@7H^wPqP z<$7K(n-mXV=eC@i8Suf6fB)U2Uy64tvs2%_Srcv3tI39Q;q7v(bB!)r{IK2E!mDUkFTpgsX-`n8NVcCOeryfR^dbFnX5keo|3Y5iKM>Yz27n(GHBWz z$61X!gIX+%tqTbp4(E(My;yKxLfp~@ZEcD7Pn;B zeZ??3<4}S@+q%0nTekFP z-@-YCM}O%v?B!3t|Ngrv&hHq$(SG)xPW_!;H%SQ_+t_!%?}SU+LITfTax~qv$fL30 z{I+d#kIviL{9%p91^4`O5as^%r_Iif#I_>CZu#Ukq5;v7GHruKDz{)fo?K z#!zM{Q)Zt`did+%Gx4!e{l_E)_Z>bwS>s7l*DX{cg;rbuQ87PuL%c_EX%dcs|`1M zZ~IF$7Q$Z6_DRukILkE-Q0s#iI3o6Pb##L-S5ObN7CI`HRj=XSW>WYkK(R znb%vSJHGx!vyl-qOu_~XdFuoJ%Bz#hJ!)DHHY+4n*{^3G{(Mz=@UUGrf9^0iZ0@>Y z;PFm-&zKL{TfMbtL1bj}!ee^lKlt#-n(H6E-2cInihe&^$6VRrzx_?O+?=+pzBS#y zuMg|W`zJ5|$SO8APS3Dy-wz?)^`H3alRX@zzK5?o>~SIX$Lu|4n@nKG5;hvtZ&+Wu z-cvVz$Lq7!WZaVnD=zhyf7;A_hbZJjWP#`0yd!xsyie>G?{v%*-sHu&`8>S4>P6 zk6%$y&EMzd-j}9-@ZbRj1tpM$g&*152T)?-J?T5~=J~=vSXdH${P7|hIB+|mFUZ2~ z-Bb$&*%8RMF(ghv@6Cm($?EJE?EqZS>`r%V_IXdmdjl zfARj=V_^My8~W*|we-m+izp#MGNy%ExwwQ<%a;F8NJs)DCuhrD85wyzT2WCMojvPE zQBi69`Q%A2`tG|`tY4(F{zSY_d3uJ^7hfzTclR(MYw`CvzyQYT&p+#vsi_O~>0?B@ zc3qLHRasdj>FI5zwQH@YrlwZzow^5%{UuAzD!u;gHxpXE+)^oA40v`J@bZeF&pum1 zNlDqXd$$wy=&^-rYahr}C^|ZgI(ObcW5=3OXlRns93dB(J!EDUQek1KVlWLIYC`|~ zBhp_9G0!ky-n>(UaS4cx&0urDVkQeFE7d43?>?-j1^oKymIAsoxDR`UShcJF<@hJlgVVu7{7kB?%TQZGIi=?NL5ue z(gGFN1QivPOjg)NbLW~##KVK@% zSMH_w@YFE?-rb_bGCF_WU#@KQi*DUE)9Tgdc{tX5&6_VFPtORsc*~Yq@O3@b|B8V5 zq)nT(tZzKxA&H4uJfG{=qZOlz&(8n@hYq>(IXN${SgCYlV@F26b%eFwg9i_3(xgMw zwd+RK2f`^XE`tsnaN}!+vuAyk(jp)uBcHzgb_K0iVL{+0At8x0YSdop(7}Mof)y&$ zh=ETJ0~oXY`){Y|(~qhw6!Jgj0MHvyP*6e(7oK5#Vhw%s%|Fz=`(`?Q+DD@-=kFiG z=Z#jameUVEtmN}dbacAP^2ETWivh@XE-rVNt}k0jELWm6ld8{eX6Q zAoMfvkn-|MjeSLBCB#4x19f14on*uMXq=p!p(+VGjEKk6w%@ACLkxTVFyQIwNz5OM z$r~9OE9d6s#^dGW#B;13Mwux=D&(M6#?_$QTOlPXY*#+Gnq4W zS$=hOHE%E4qH3KewE1y=W$BOnOG-+ZtWmC%o$UD66i+Fk4gx^u%a<>+wQ^skTmOWb zHf_q*!OfZc-JjSw%W|?5JD-r+wrxx7>@s3U#L?){quGAzBV9b|K5En`V#nRc)eQLU z-n~0HI51;njmg|DO#c-?US3|bVZ#Qdd;Nmh#U%1#K)Y97d4(1&T14z9F5YKAH+I?? z+e<6taX|kce)xgoR<>@y_xta^&-C~wrNIjqF66k_xN##H8yhoQoFM)Vw3;|^qBNdx zqfPl}PrG*Q*dFe3AsKDozMbvsd`TGV0Cvh1@9Ut$p+kqr-`}6N$IQ%(X3d(#-y9wUl@W@V_q-D#NDV3{={@RwW4gE2$Uw!pe!kE+qs_2jSpwBz+yhH3% zFQw${m@|6$<(CO~1qk%l*VmVe%Z~D-*Is*#Qc_ZQxIll51z7-In>1-cX=xI>71?(U zy$7y(_wLQ?V7`;`Jau`ZA2e>v^Y`C>=i%DYUtK(8qKf|7mah%{r%s*9 zd4y6!6av)I|K7cOe9pjl=++y!2Uxl`aZ0{tT*C>{oI=N>DfpVH|+qSLF{J`rl{?DB|rxX`55@bGrKv&3h zvLLiWNH4^L45kR6zmT8sPTTUep+Dpt_Js^CqkvYcR;}Xl0_J{<$>88%UM%SU?z`_Y zePXFl4e775voq(*>_BK~7-)@oB|7@i{*gfcsHiAuJltTN4_V62&W?u*^oOoU7C{d2z14qfO`SJ*MJ+yjQ}B@ zI{Jf$VjU`gw&iO>e@jbCF4rmQTAZAmI6q_uQ}SX#fAHR`SFZ}ykp4o3Y}v9U$MP!#k%vInX3d%r)-K`U;mlU+4%=rL%JyqMrJ|xDjvsb1 zD1U}L2{{*+Fh^qigFk~$vtvzpS(yK|DPJ4`A@7p#rYpX&m|hujK0K_-O^4EaZvw}JkB`t%_qBO`*$3pye$ z+VAS>%8S5Q2JXQRkOz1%E@5prdGci5CrwODcppJL4-fV!CN0X>hW@Ao#yHBs91I%c z7warpUXL*fo`>=O4k@FX{dBTJV zd@KlYkq6>=dwX-;0pv2o!#Y@&4+`;h_3P*7$LAO5TR;~@0Dr=ml?C(_$ffA>z_%vA zypOnw{Y&5zs`$Tbei*A5bKq41XewV@`U`oXe(b<{zQz^8RQ_Uy^^ zCgA%sXUIw}{oBq&yLiYh&$=Z_Xsy$*p^~V5YPC>7R)Zp78At6tsAJ@NjVhRxh zA_hbZh!_wtAYwqofQSJR10n`Q42T#IF(6`~AsBe@@Bvj+S5SUwKBX6>Q&K?^r52^q zz5Dm5xT2V&lu+3d;jYjKdPDlC`SuPT=$2?1XjVLw78PLN*LU>0hovaG*c{?fY7K5m^FN`FOK473?Y z7a}hZ#%eeWj6MDB`nSgVq3*Fcu_|#2xlvU=pXD-(Y9A=uq zLm=k2+0L_-+S>YDYmQ$HNp<#075&lXYpD|3&AJN0{Dn2ZOy`*@aRqv<^KSaadNE5LNB(wd8AR$12ABI-hlqz5W7E znCmuI3D=tFkBXiMIiZvW{l+}pTx~nFePJ7Is}f&_f(~h$MT6t%ivFkwcreyzz>ng! z(QhL?WPj=abIT})QA+8M4`{z9U=LN*)NQw_E`Nld3_Yooe_ixfH%6ykncAQ^0P+Ra z5{h_&E+Zi?K~pny`c9YhN5!yaQ8i~`U07MIeoc7p&N-FofFDC&L$1$jXu}_e{_5mF z$c@m0od`SeSl8j;!zy_{;M=#Mh|Q~e1tnPQuC{fu#A8)aMHW;H0juIZ1y`{$)Um2ic&1!YKlz7;F% zcGpei*l%~PolfQ8$ECj}eV{J;0M^&_St}{x@o}DYO@Hvqe>|1fZ+uOWqP(U+{H0fy zD)krORoA+<$E82;dNSms%08+~`mga`^VIEDbxwaK??UAMO`eBiy#>90m_ z1|1#r1d4Dg?UqU%FXTn=U0p&$=np=%(sQK}-TGhX&vj1P))P7^=$#e$2IL=YbsE~1 zrA<6t(;vP*Q!Yie-s4%r6>ntZ3-Qvwh)*W zsB#|Jb8C;bS?DyLuIUf`uqyfgcZc5zxYQ1tWhWrSw?y$K=SL1)^sIq^X2AV2W6>Ej5PE(ce@zc4VDDs}< zTn?o~S_EJXig`ux+TgoEsjRy6KZ?a+uO9tVmVZNT*JiH{{b#VvV7au&2f8HKD?JO) zCH;Z-VfMq6+Skdl6SvP&Y#;P_&~?k=68F#*zy{}W0X74$1%k{WdnwWlW!0Dd&!!7 zvLgchF)u6DMb&eC>5o0CRbH!<@?Pw*Sfw3-Eb(^U+^LkV%lR&pbzlBmYuPkU`o1Cb z2QDz*!zOB&o$|N`zOjZctx`Ty2kk1UD4~v)9hGoWUzu7FM^BReDC=hGO(i)Hc899u zTcK|1_7azQE~~TO2zfk-Usd!6-HiQ>IbEIOoyjA?gS?Zy$tT%|+!Nf%F3OHfZ<%u1 z_OR-qL_eg5oQ!dTeK&PbTwbh_{sU|VG-&Pjr0I`&e6+)8rFLtw3yHWFp|s8gk3wCa zC8(pnDqg8g82CMGGaO?b>y&9==c8);_p|OtrIo6AhBmlL%ul5K!TV`n@V+{)Lm`JK zw=`FqY~|vd3R7OU&TyWgcJBuEhKl%uy%KQnEI}9a2hG9%!0VBpwzR|i-`z@iuL$yV zVVPzd-Din2lnt9B*aFJZ^cVAARPJ#>&c!~KY+T&$xUu6|H$$cVPqChLJ)_-60*`34 zr&ZNZ;05+!iupr!*M)tJsxoyI27RC^IS~3RMZnr#(T)|*QQ7k61S+O`8qey+KV+~8 zmnP5@rzteuc{r*S)~zSezJu4DA9^vELIqE5aqvO+Cd+tPUe>_8}}QpZB)Vy@`F9d^A3>d73DziuIQXcXM%#p<1dX@ zYU9~E%HN}Y7VT9>e{JnQp$~!0ifkW1|5@#|S}Pky$jq{7g?spJX|fl47PwMXCj8)p zIt#zDy8QUOc4N^q+akh3iH7jAg8zUfz<#JI-4S?* z>)pC_s+#hC8t*VSg4fCRU&wYr=|NOetJ=2<`jqDdbVdL4!gQ6k+cr@)bvAYTjqP&y z6L5)nMb(~Rof$sm2-s&*lmoY3-%8L!U@t>x4}M|$@vPVUvgpwj{bAeN&9a+ZThZS2 zzU%9p1E3pgXRbU4U>wzFZ(X)sPxBt@SVh})=r9ii9#Fyu`o;4Ex}rbiT&xRa`#SCy zx-C?>_aln~jB!@a4lC zSr=fw#9o|YdOX8-8OADAAfv?qr4Z}r!X-@z6HKCg;6 z!!ypheE@t! z)jR?`VosfMWeT4|p_kMaz;m(Y5`1~jhCLbG8{|Onc!B1!zjIyZKGS`Eb+}STfA_oY z+^!jI!a5fG85eK~{V)2meY8DIaGapD_7U2>`Pyc!=6>0_fsew6P@OD*yzy?K`$A6B z+>%^gKiNERk2+&chONTHOB3bBCG4-YvDZ_~Q=4b>EycAU<}ar>CvB2H^*E~N4;*9c z!d4OcbJ)8acWE5gW5d69z=Z*v28!(z=#F3b>DQ(EQP)_=iB&& z$1!~Vfz9})Yn%A_5n~<4a@zuRb%b8-NdRoQx}BF_2V>3uyzXbKqrW1q>+{^-rawhw zM>Gh%-~+I?M_%P1_g88Ca(q_!;oMjHMn+ z3G(WUD>G=K<3zs4jrn}AtwbJxe;4Awo*Cl^vLI;mqyhFKI70w?=ioD#SFv{pIY4oq z$1`m0VXF`M5Bh_o{G=x~<`vrx`vverl=~t9<}cv_e^hrN&a(uR51k|S*Zoucxx9ET z{2ZMOJ4sfNR^%4%Mj@FY+$Q^J^i4%vV2u=;7yCqH48^jq7!WZaVnD=z zhyf7;A_hbZh!_wtAYwqofQSJR1J5%C{9|rWd}gAwiqO|N1$$6hUIry*r;ux?Cpoj{ z*o=6lkCfLt#-zuwz5YkK=W4d^AH(7)LPb>t-G~h&$3PeIi@HIDrBD9b8j5ugpH*Yv zxW`%Yj(Bv|qi^I5+Hr9|x8X4Jv>>bN4&-#(ownNTrYr1M0O)`Zxtg(laaRbUnDlr$ z;BrFF?xdumly*8Ep#9Fr$tC0}oxEyJ23E$rZ%Gr1H_r?Mp#Rl7zP$YWl0sT z**)5Xd&y*Iy`7ySF4IpP`_;p)B4msl8V~+-=%>=$JT?YE|LqR@Xy?TPoG%xZ$)6dN zTbxgJH!ss#%dJwnqOcQ;k7G_h=we29vl1yRDT0o%ynG`4>9~i)e;mAj<++VamXP8JT~I~M-qbmo_GA{sQVeR@RL9P9%Ekryb+zhW=B~Ck9OsbKfpU6OWrHY;r*zzqKutIQ^vE*P{cttS;D*K~9fMm7I-R%j|!uYb58Sp7XuH*N8&R_gp?q2b>?t z{aEJ-yaci(-j}mAAOL;B+W#Vt51S$po-GDs=?@xX9=OEl2LNBd*v4EB83DWizQzbk zWa|L|Jns0ASHz?5OF*Bn;ld8SRzROQ<88&{z}3kkY$V!s( z5h1q z7!WZaVnD=zhyf7;A_krZ3^Wo!#DIta5d$IyL=1=+_&hpB^v@i47{@=idwe?LJFkm~y#Yub)H*IpDfPi=^EG(ts;xekKsinlk zZ1VDoq~piEd84;)zd}JlkIq1NkufoI=5Y!OOQG%CFY{)Ul~t0y{slrmsIGowvtLzJ z!*Kz8Y}s;=Zr^_K+nh0)PKl_Rd_1v|G1cB*cC2;Kd&R2M>C% zel78-MV}50P3E-C&6W7{PMLB*JF1 zNTQhqA7 zmq!N<9H7mcH5}9-VJHLrro6mdEEy|iQok{zsSD8dzJ2?WzrR1Fq_DH)&z@!SNeK-dI+V@FL1brV zM++B9zF|3f^k|-4RaF&@A3vVo4<0<2e0_cC{{8zjYSbucaf<2jLP$Sm%osM-YiaG; zwY&|fsj1}c?akYbcY;sqz<~o9FOm4WqR)>UIg-f@iS*z9{+A*nBRLNC?c2xO|NZyh zQ&dzG?b)-3(^6WII&Ki(++2Q6DlILgv17+dQ=*NaiBNx`{jy<*EVN%$db}6X3+>m_ z)8qIC&T*lQvh4?rd-Ui*lO|1~&Ye5cxpU`u`#}!?`X%T9`Y&F*n1>;cKmPcG-)r*^ zW696YPcABOK4{P&9)>c83>m`P-@A8j9tK)ZojO$xCwS4bXHUlCYBO`krU-=m#q8|Xi7+&CVVmX^lmm07&~6DCaHVd%qi z=FH*u+WgzUe?Of%bxJ8J`UTqf`|rQ=I)c`H`t)IQ*gw1-7cX8UXJ=>n;)^dheLw@W zVd>JPOqM^*`=M-l6rk9CjJb&uC-U)(u>im`c-hXKJNfgpY15c28Ab~hEa1<{$;lkg zixw^7bh&fq4#!EaUcE>Ni-^$v+e1Y~MbxifKi-z`@NhnMF#Z9cy)gcG0Q-k=EAT_b z{*O4abCF_t#r7jU@&jFE0r_GK0l-s#_~8e(eh83_LY0-3N_A5eCYMOf1Nt+@AI96w zn>W?OQXL!8{a|z(^;lolMCm%!k3FFDu)|QVo<+oyphyf7;F9HVOe_vWv zN<|e#R9;=q{qdi-dhZF^Lw`8^p>+M}^e4^tm`^)z?W7y&H?%%84(E(qO}a`;yp~Y! z3+!7(>>Ky^E>Q>b4%E-4A1%1LfXpM!>0XKa8DteT6*R+j2Cv6Nr-_tRqTM%ClZ%q2 zb)V-xPwRRLbU;0YZ)Iuv9pyNR!m{Ph(-HCzev=B5Xu_2VTIJW)ye+NsTSxij`9gA9 z?Yml<_DsYXX}G4F<6+08X*S*1q$#S(ce3qY;j@Bv2koZAA&1E%(1aFwE}|~yyGZkI zZ_%Fo)BIKD6P*`L-K^xl0XfuuC~ffHK&a!fuw%5wZ;etMqnk$3{DQNBrDXw+580n4 z!21c8CHO`ktBXFW@{(z$5ytK{^aSn3TK^ugz1N>l2YJ%W0(6GB=2Z2QsZOQV%8gbQ(IyUj+j#{zBJ zfBEiZX?f_E0?4MfkFytoHU8Gs{*bH?>9_rM+}fcsubqKArS(DG9v5WmuZsT(`EK;z zC@s$=QKIw0nhiW&==&*!>iHGEp$&e8%Pql8nwR4EM|t3bm~WA9ADcc@^Wf3`iST}~ z-C+J6^AlvO#|3TLA9gQ{I#_hzVGJ_P0 zs@Jn@`-M6w{_0uj5ypIOS*~2(=+i%2{LJfu@2mnJ>HzX>KxTl_rD?8Q>$jHY4Y^AA zo+`%12!|0oe2Co;l`@99I;aYlZGU&G?p%%;U^{?t5Bx$7ft;#J9!FjJT`AC+Pi`0Mzizo};UVH-?veB4JWB4=ht_!HE{V2oqwkaBse=ciuZZzlX zc!#+Nd`p*rwT1Bg=RLRf&`;-n;&ri$wbMy4+O+>@*imWwT@oa7zfd@2fSIl{rSHKj z5T;8&p1?2qJbr(*{FShd(goDje#Q1-jj9OX3&OYB!87;Y-mh^j2Hv7-tSROzJcAF) z&Yf64>I!7rpHPs%=M(T9$TpDGF#iMRxS+og&Zt!^-!{fpIt~yQx*W(YvhguLdZ&1E z9m(*E!MtNm<+GNS&fDdBaLtm*&z#Q+B>O*dcZsZu}NY>HTbS~-~ zS;ttDSF#sn-p{NzKZ6Vbxehdg?g)C+Iqq|~e$VWV8DX3~4xEoZPpQSqI;zLXOH3nT zK*WHEfrerL-><o|7a-n?0Qkm268m0T z;N1|4X5VECOOE8{wc{DzXcNBcbJphqZ|^;J{yM(hg!BFJeGgsB%1;|-X#ZIsYqDkE zA^~8%h;I)74>;o--=x8}N$`yte51}i%$xG=OZL3*jk^N&?W-3V(0-rD>->8xXb0#m ze0SyYZ8!G)mV30%=@|cx3%pew#l z1Hkvm0Jb+T@wQ)J{U34gEa+Q!gctB%89QqqYaHl4aTY)Bvx{>1b8)$3jVk?i8+(SW zR0TWFKc_hNg&+GbAi2aUix?0wAYwqo!2cl(2gl z{@aXPUBf9PB$@eZCs9O18uRD4%KT?S>EgxPPZ_gy7nh!%PiAJm%$M;Bj|?C4-MgKc zzoNt+89ukAr4`K2FOavf?i`^8Ni#$!dn zcq}S@u zhq?)QA#eEB0dSA^t5>h)KF&TqKHOjQ=+UFxw-s3K;QOqvug{Yk z8yj=HuU{{*LlnXl-G&3$0uLkpi$_}jwga_-!@j(d4)F0&`zP-IY$N!ZpS7^`1@v9i8$Qqgqz?`brlh1K?n66s=1lGri*VEl^p%Y-TYuzr>((u4UTFV~ z8#lOrCHj@%YmYqQxKtO>phnHC{ioNfV&X+LWg$ z5AogegMqT@GRiB@le=JJhkYh(0JcN0U4`wfPnr+i$+^RA^w6JW0XF0)2X-c!0Qm{^ z(WVXuLJn}dDA>me7yLDPTKA+CzAFg!GV0)Z`gQKx*5+IrIlCd)BEd%vHY$QWrbD~~ z&mZ+n4_F`G?kBTSxP*&Lcf*Jsu9<7q=ug zrKD!zW>Om<*v`*#pT&K_misIx_(uu$Kxc9j&go@o++ME+pneGOO@=tkrwShJ>VlJz}A~vd6+u;JlOpW zvKz$XxF)&^$u$0|t3MKf&Y(By0r~@A8#cs#2oD2})Y*y&cD1tgkIj$ec80%L{z8kr z7Sm#H`3w2M4zas+cfz>T1~k_}gV|OI}TQ@Rp@Vdi4Qj=}Gs`?|pNlue^df4I) zvL7UOVcY;$8*gkxRINZ${jqmB{))se&L-A|=Li2ulu?&`vby?TjK9d!EB0^r4`9pz z|DoBTTGbtqG}S+$FoD}E0@vyHCGyB3uSL9kb$&;V@s1pSe>(rk8fu-phC$!OP?F<2dhw4;XATPllhACYkCgvBwwslk~;^ zzX88NJ%mfK{)o0UKr)VDZzsTp8yk2U*h1F_g!&8R3BRBt%D$Z?uRoaSCb6Yf=i883 zl1b6|(b6mJewtEsFpgnk2^yh~f(L--%F4iAz>W}vVt})jNfH__8$#PB7ZjKSs%Kn1i zbhYYA@cHO#)0g`;DEd9i##eW*sr~}5Q5;j?&lo4L!&cS5Q5O1$q70{42LbQM3v$cj zfKY$^>-wB;p-jxX@PWp7!Z^NtPksy+R~AcsW_sK7CeU4w$&eo76Z5Nkvb)AA3F8>` z56slO?opSKP=D|P*q?)@!aNAxX?)9AB_4Cia%hUn6ix?}4>=FA3-}1yjIdd5vowxJ zv=wIDc`}W=JdWcPb3FJsWCcxq0DKSW|MK{Y%SmWAWYNL)gK7J% z?SwYg1xT;hKkG{KB;I4Kalh(5_jRp(DADm~Qx5R+xVYCQe=*MUg#p->@xH=r(O_qb z3n2L6RMkk<%?O9>?(+t5nF(~4*#>(>T%(NqEbVM+uIm&1DkGS`XzR7JoVf*PE?7`b}li5C&vNnMR!HIXCX7%bU z3w4gqN~D`{LEKgqHoLI#gl!}2StHY8C@L+M;ohIqD3{rMK2K21`Zw0uWtHXJ{u=d$ zeL4U(ns|q?fG~^|5kw4#7!WZ43^4N`5uPCiV5jvZyLz%qYNz#{Xs7j}kIt;DLT(4) z?;lU+&)+22{=kj~wh>paO7=6KWE<`6gV_FSAh%(FO;2207PnnUN@BiPHuC2=Jc)W( zTLU7ebq117cy}&&~i>K2Jc`b*QYA?1ST1cD*cnFIy(|cmc4L(6rZ!J!1z4 z2WAfy!S~j&$BuKs;p2k+TAYb2oS%-pbm2YDp2pe9*4Ebi7iok&ZtT6|d~et;VDI0+ zz<`$_TR-9c*fGhT0rvT^*N%O5oRn4T$-8I+N@Mq^lXQ{pp@lYoAuK*|q^}+ry z_E>~#na?sB;W$FJN^O^kUKFphXR0UHtwYZUJ)|N)rz(^WU0pAmUR*cX<3bO@ zCF}>EjCi!aqnL-P@}Z9fuCY&M7jMV!1zICL_#Qup({Giue1w|@n{xUHd=a`o>_KFg zskcoL%E#HS1?2_2%n42tXqxLZu6H{Wc8KF1_!a>63xW<+Xg}WJ3`gi`!*V427yGa1 zH<~~wA7^9WLcZ9$6KoTXg&*U2%AQSz{+?dK&f;U2q7D@0VgC#IYUoPQXEcFOKI|rd zH{cw5DmOE4@?=8)h24cVa5d#Br#;GrzFM~4s?tl#ml^ZGJ!~rg7<*l;x^UYCRp}MO z&<~-r$2lv8HzYQCig9G0h4MjDv>!VA&Q_giSI{nLG`l!EPM2-Bwn=#t`pTKeGjj8> zkYHbk<}SH?XOTi>^X2w6zC8BBJcwtA$S;c|LD)K8Ne_0lLa0j#KUh!Nd^tO zI80^TWaHr;{Uot4k#PQRcy2glm#QBt!Wnp%6E4&BjO$ch^T^IrG2j1{b53g5xQ9Fh zJrw+a!3P9hfG~mAD7If$&p49-I#irH0G;0Tm|Ju!K9~~kC38JrcuJJ6ic*;m%D)jC z$aRRgzmpQl>jB+uOnN*;uyYWeBmnod>;gZ8-VeA3|AQ{DQq=!FNz^~FyqS97nF90_ zOfA866;eILD^E{Pk(LI#+9>+L-rPt|iB3Ei_A@K| zR?zBetI0gtoX={@+Rjcv-uHck}mt>3%fk@)&-<_WD{XsV*VdLhYgKR!M$BH>wE!3=GWaEPz{se{RN3;f+9wZvoy zC&wZwRjv{tgV&z_du@)Rq%7&p5t0Vx)|HGLBc9Ukosg}stI z`{#KVmr03K37o%y<_Gg3A$Q8x(IBHyeOQpTIft=tO1$mkv+=pgPETy z-$HY7eF{cM=(xPOoP6wj)0{isLh0sk7zE=5rvT0c+TiC85wMScKRF#m@xUE8J8^YK zFfc~)f4|^v1>aqOn=noi(xNbjP^hR3pQ_}WRDfH!PNHf~!nW4d#x_o1!VbpzPR2$g zuI5f=BtImi3+%JEGfw^R3Vya zI8xx^F9Qo);GKYf{gTW13|ugdf!naT0@VL5P~86p{desD9P|q!^WSX$9s55A{jUlC z=b-;J;s1Tr|4#V72K~<`{O_avuT}p$_J0ogfB7~3KcDb_?u!CD0U^XKeH$ldxbO2} zSE4nj1KTJ3F?dosS$_BDb2`d9dahEA73iw-dg$2f*yGqR`7@dnh?=>LEz<7mFC#|i zB>i0FlN?3d?Z)|DYv=ryLQF`mg@Pl}c8w zY8iGo>&9zh-omJ#c4|JdW?pt0KC<69)`^E^Z_#T9tX3M|B13v=Q9fwCVB9?q1o`%F zc|UOC2fv6NCKuhf>b@bp??iNo(x(53kNan1M6zK_JF3a=H3lFQnRgt#2A7SYPsxza zSGuo7;nQp7S%VLj8z4<&)%j~|^7kQH9^GMmUgp}zw_)#{PIXrQl5lInhYb{ODUR%( zEuX*HENs5sKdXk^wi(~&LVUyI*u<%+NzZbqT!lEQbreB2QAaZhOO2OT2zh?4Oz)84 zLbG}Gti>P_d5t&CpwNBOnZb^c%2 zn(;Z`p2nd}NF{eypXPEshxccvEs@fzc9;+oy{nXpKTA&(FF7zjNr`ux5_> z`8VzrH!KNPu?HCA7$K-ru);|_i?Ot@LBlDm7%IGQy?0H$6TjY^eL!w#QUksj^Fy<$ zWTVt|`#e{b(`&q=MgCKKgz=gb9)i!uL3XdXv+}Etsv?sP_bY9{82EZddz2OnOoL>d z%?i5<%5OYYg_nMB_H)vVZ_l%ZABCQqvCcw1(B2gw&WC3aTAdlKO-)}gNtu=%LqjFn{A+~wu zLG07>y%Shzl%oZ#wy~tEM2*&<-?PmCwA?#f7(MnnYc2Rm{9!tcy0tTfJTFy+=1 zp5#WS!$l^;G_+jSr1cZ4%t84@wO&dGoqJ#fIBpLp80UaOtD$r5z{!D zMM)&k`I~R260t>xKA_TgC!!xb?iU$O4r`?=n|*fr&)d!Sw4$YsTLlXCGNKa4EWJYa&Qpex4Do zV@%8z9=XbAi(P(dX(8VmtQNWrCX+7(+H$F~3N0Xc4Kr<1R641IGY`TZ$iBmKETfob-qwor>M%7*+ zcoC7a_SIgR8cKgwD{N<7x!>IvCT88~P<`}vwf0?k63qqM5@v*_km%ij;htYmPuJs6 zTYP&fI1m`HtAm_?jLz^fVQsh%WcWeX7?StX3F7lVWB4n5fr#Vvu^-*dmzS@hF2`}N zYz4X=Y`YHWsJ$qYED_W7e(^p=yRsIKtG~R8$P3+hxy3!x;dMhM`srTQ_v>micnUY1 zF%c;l((nB+5dZys*Wut7=L3qADd>;IVyeL+@y)D+)IUQw<80_^|B#+v=8IOAF*W3r z!uu(D@zmvY>$|s`c}J53Uwdx*1o>3Cw?ad9bKTm7ul7i;{cO{!)V2wiybvjDJv8cL z>*izE=Q&g7Kl;T$(~^f{{kv^(?NNtTe0RBO6z5l2Y8K#-jH-ZW&@s9C>$CS1pNqPr zOc-%SIe`wPBm_Uc2l2flh`s^7x-CabWN?)n&5&~gGp z0hYe%d*b=Akh`oy`X+eDK+Dd%=-e3Qnv_Q!eO0o&Y3cH#-Wm8mlQ?I=f3WbayrRbl zr%v}TFQ`QN&U@2#_UJK%HTP_Ht^Eq}eRplP1O5C{S3>Q9oGBLV;`;K7(Qva3vx`~+ zJ@{}meU0Z-RV9=apTW%Dg_rFWoFq}Y2cMx!?bw#c&CK>eiN9rXAWAZ6$*QB~Z>mtZ zj0pgYMsyl=6nVhBSZ|?3EYELlRGag#k{X0evS;7!6-uGXK9X&6~eyX`u^Jw*qgXvau<7g?1%>-@o{PvqgSI z5kIpE|R=Y&5(vwv1pAC6R(NR(Dwti8C|zGrOInr+jp;97+YiqLu=q7*z3!a8a7>Y977>p z^n>AVF_M32#Ohlzr32^vYtv za3)**mCcusSl8Wl?%4DZSn2Xkw$uExDx(Y8_C=?;B; zuk*GA5&M*+s>uc8tOE#jw#SnEpupIRa+R0<;bPC3x2Hs9cy^z?eUzKknWh}21lRRe zK377=2-e$<6*VkEB<<%D%@61<=TqI@oXYbWJ}yt(_{|&X#Ha1)8Y`9vJ+^CW={B#C z*}#e)iyhG$8cWbnpbgql|7MgLqx!r?WH9(7;lQ$!SWv+d4qcxQJ#TNz>X?!Ud&|VO!#A0SkjC)a~FSBVdQRjT3Jop&?Cx8AIth5Hq1 zPR~QcqUZP$f7S)(^+@w|c68S58f*``y+957Cy}ENax7}iDR5v|aq#+U#&gp8+6FdE z(ODcXj(R@iBixRge{WIyCR#D1^Mji0KjG@{=FL{Hps5x$frWi*8?TpU1}`UpygdcDf;!Y z(RZAN#LPYTf(dDqv0C~^P9)xX%Dl;k;{#pKv`4=CqmD=r0ON|4@dzyVRchWA`y&|$ zi(*rGFw2^q7w<4s=}huUFDeiz}|4yc0I@qG)C;{^4~1KJ26HwU3w|ic<0=G`p;v3uC19I zybP~73DZKv4w)Kz*K+)sD7+`-F;+;ddt~94HdhX+s~p^vUcATTns>0;$abeks>Z2^ ze&Aea!ha^jX+X$UJIpxe||poq`5w*z!Hmus&KyeKXFlChsXT{unP7d zzc5#$eMo~FZScL}?-m&o^k;`=2Z;2+w27znLkxny_$aDYOEe9|uIx6g8JC9-o;6RL zgkI-{L(GVqygDmAc2+mYlPKOTC#icP^4(QcK7MFh72(<5SI@Toigr$U|AAqBsYqDu z9@Sn}t)JkCwLuHP{!Y&KWbe1hA25ttEq+E+FVnYyV?UqQWIv!=6khUZ-;hFcPo_y{3{I9!U)U~Q(f0BBX+XwAVJ7Mr?L%W@7TM{~%+ zjR;|HyYk3`5QuZLIVf-j$JU~$ zKbzWJO<((hXmCPvIldY2oukVpl`$XYD5_HsAS6J#vC0Zi-mcjD-mmNXdNtPQ%l6Eu zamJl9=hYOq+TY8U@XJ8m+J}}aykz_MaPxOLdYA8Gk?g#sW`R`lDt2fLKV=gfqEknh$g zi|3l`H_C76E^cS=_iEb<&=&6<57)*UI+x3xV5z)?z020w^OEh`x6_OV&DEhp5LNMs z&AI2U19Ahg_F9vMY6tz0Y|+fl52kk_pVxKSZMH>Toiagb;`ihAu7S0pEq{%I-1yiS zB)NDV(sVc-z)Oiir0?&qzF*efcNTQFqc>k!Y1E+ZH6V4q-EvP7a7DCq(|hf>Ka=V7 ze;pgfP|)k{E@tWZQ^UFh(Jk3IbqhWi*6R9i0q=J+t z5FRevG@LaVivFkZ7%k-iOcaoZ{{N-s{7>=a|B)zFYijQV3+vu^4G|qD2f=i^4druD zMgosYiIztpgbF1d_X(iAs=@l*U(ZKX%e{DOKObO~=HyOAjW*lv>WIQ&niGm8FK&`6k_wI`amVj=xN*>X~lr5SUteWjBRxhE%T@WiyJgr5M`HSk^I<>Z7avdipM3&sGU;ww-j2%A~ zpCUU&E-y*KbQp{FbvP9F&o7Kx1(&g@4!q0u{w?2w7E;@ph>>%Odwsrpcs{mrXvPKv z?L|hXWu9q0YrnDM0I?GAv09~k&u~UE#TN|dz`*9Xb_JIi7_h<=xLhT(i{41N9Mv~r zmaIraHfDI=S-=Q|&25OjqL-V_FoevpZ!VYser( zj6#G=f+zPhsQmnTHZJ!Cs5HpVxg)@(3PJZ6q2A57ONkb3%YxA822sC=q0)Rp#p-P{ z@kLMo*C*9#l+_CE6Sw%((4(=u;L_Y+&@&&!6~G=db^D**EwqT?^|?-DO~PDsw1v+gQzux~6ORhHQ}n(rCiq=@EIEc95HbChUK#uYDWZV(yyxS#r!ziiYR}_>-hXS!D(fkG=DvBzdS0tjz|y7c>{Sh`nm)B1_%`*8p!C}> zF->v;F&HOW!b}pLH$2R`6j+HwHOzbCok&gO~R5g?yi&J+I z-!0y&rU}dj>Da5bMc&}*xi$0`G)untz)(6$XrXBR5EAEo?Nu7rW9AAKehAT4ocKsSxc22y9=hj zLXOq(auz>!1pjNrldV0A6B^S(`>*6RU7Zu&qDA?!84kKz(NBtkT56qs2`L_K(mJEN zUiZA6$$yC~7#il!W&CAaW-U+-jHuwYexdM1@Nuo#VTGKb^jW*ieInIFbdX1n9j9bL z%jl+N&DP`M|1H4cSD)fjco}QEU_m`S@=8Ir2`gqm?pAjoO<>Lok-iBHRhDySm)>8? z@;hjdNS&vvD~Z2>w_$N47N7#!sOOz=C^K#t2rW>*fBm@jn!Dpt^Nq2Pki|J{Q9z!{ zHP_1M3bov^Oc|BtbM9DhC0p(j!by%#M#~H}VB-x}UDFk9Ysu#Fd|4T$iMpphJq ze(NNGYesAJhs=V+I0l3m&JjuV-$z4eh|o1Dn!lJX`%01&iyP)=_tDZRB*|Xoze9Tm zHn+Rs3XhOJOY(CwN4xuf%ODJ{+7{*_9<)qdva8-9*(j>0b>c_T?G0HwSxdJO-0j)Z zc*Wb4>I~yh#gA0U5uk39*806S_MCiu*seCowC6Nu?$pwjqilY%&HG0s>x&UH9?n3H zFX~a?kv+9*2=X|VNDvLb+B?{Y0{V>?!4JHsoSsF2i7RDv$zWzIT+jWEy9a(I6T`Y= z8Rz^>64M;)R2WNsbz+#Y-#Y_50QpX3FYar-j|c%F?eKWl|*#~9dmMJpw!%*CN-r;S z0%B?JUr&Ko-(3_bS9sa;#nM}lq#voO=@&%z`IC>5k66&smuG`MybOqbhEcNdq@6SZ zn#;;Xt`DCx;prE4wWNWOq0*H8O zRKZn+oxL!Q#CjAwLel4J+c|F}z&-<0H*+CT1*H5OC+&u5R9e*YK!qHG)ehq$lvSa#xYYUX(yXUhzrAxS{oiNBG(uDLS&eK45S3TMzf@_0E!o}ULNy}(uHqP>u2Xx?vzB6Vl~Wpcy{2U1do|ej*d=& z5kwX)gyv2fZNvhnI~fwT-XGN@kl~aq(pHw~(Ku%14Dl!S8uqgAYE|S;_XCVaanKAirLWw=NtKb29ZV(7O-8kDo_PNaF}HQ0m=eBG>e_JhzLpgsw)15 za#+90=7Qkkz;yOwkM4#M+>Io0MG)ja-3dw^6}b+)t%4DEC-*STaBKx1t!4WbE{OmV zd}j(uwyaN-uh#RBHjn)8SoU4N9k4W{2|J5S=F&*!V#MjP`)S&SX&QF9TFGj9O&1+t zJ-Dqb&pa?e3^{bk;Y5dFOvmA*+R&ptSYx5(j8-lTYMt24EA9`}mo7vaV`hOc~AbFkN2{y*^v~rF&gk`Ji2c$tGCO!0!mw znLjz*p6A|~{0rpd>%)%P#8h;}6zM6l7})L{mg!P=jN`WK;Dv3Y zK8gFKC*g^briT_vabVxXjXsC|A-|@6<-+|QCP3xaGEP9{@Oe!oa7t1gu_(m8&lA$6 zgOD-)EVZoX6FRt7N{3%p+IyMy%-7w+b+d)WJo&9qD#gzl6&1xS3*Guo05MZ3NL3st z`3J&JE6iNjs@NA8DU+CqGlyc2(cBbu#!V0HACc98hJpX~0x-GCChhh63r9D?fcQW= z%nBD;Hf7}OHqf>PmCV$ZE4f0jp7hfNi{YYXio%ydV35&2L+T*^R~Ax%Lvurfb* zO_!1}sHqMenBD!{M1ZRXsZ-(!)o`c*A4E$703_|K0WTLKs1g#(mCihrCE=wTp&h8> z1rP3JAO*1!mzGUDY9wMsK8nq2SlYLra9u)O?YzFaYlUhF#Gs762X_#o5Y4@qBQhZO z7(3-IDuCvRH6`Lurv~ly4s&NTCN)Cv9Fd~fiThq}d7<9|pG{8i=`pZSv3H}LksY?T<=yS--)ZPQ5IR=M zNHoWH7k3#%B+*{Rl4?^X#(S~vdj7D_1TbJ6@7sS_PDD{D5DWvK0Mj5~z)>UU{x18@ z8vIpQxkBHhfS&)sH=N&fOOg0Ej)GKkc(->Rs{Q*1|6#Zz&-LJbj&TE*4R@4knoiIA z>Ra`RHQ>Q*jZj7xuZlFeif7a3W`ie(bIpex!Ax(u23$Ptvn!6D*hRt?Np%(B#-!;v$n7WhQ9*=L$N zRl54=AIt?D+4>bY+S6JK0L3WECSf==sc}p7zMKf@LgV*zj z;08F*7BWceMZr21A#=z5JF9)ogw2st-r0K|hkwb(ij|jkmFB)^z!po+zOWUNDFQyG zd?uBSir(Drgge#13zP1j)KMTnt%>Xszxaz$7F#I;-lKqs7>2*{G^Q-<_>;%y4q59Q z>=&|2hK)XI$Lwv7+rN#`1ZGMcyP3hR|4tH~J`$*ZiI};kdA0wpC5G)}K}hHZ zNaV^EGLguxFgVPpBH+Y~-k~JK<)e-pp_|QcK$x!I}* z?f`;UlVTv#9OhU4JRu(U%Zw`gr(^Q9{q>$TE@5@4@I@7=T&&xKRq-3Y_59iJ7 z8@sJt@;9}jxpfIU;d}yj#+lu&?PxQWO*cYZOnJDH__In$)4~kMzSb0=!KQb*#e_HG zwT6F=q~2!nJcfvb$Q;H!?P%x-HBzC<#~nvhIdCUifh9W`R#fgA#rTS&iPyI^@k*HV za$xPb$!|@(S?mjGx;B}&snTUyI67bAbX;}yBeMXRC?CeA3SafJs{OPRYKSFD9}r|i zd=o##3$DX%E+-uU;85}}ybsUI+P_E6;h07c@R!-o+f_QQIvZ-a|F)jlteLoDq@#KMBqy`!_&mVZ#=$LqV~C4j7_onyfVPUv&)gIdSpm*(m@V;D z!h8yP`84$R=Bm!Th6Skv`fm;Lg~>7sR203h+$|SVo|FzyKhS?n?^@+z=cZjzbAR%@ z6RzJ>h-Pgt%`w?0-s6!^5uo`TKmy948 zt!QI|l!&Pvnajzj^FAjpJbw{C9YlC1g-E>EzU^*5cQ9_T_Z<3PkT;hzEiD`MzHg8D(HgUvXsacNfhzICZp0OCNpT5y zthZI4_LX}onWoHOd11oN;YV~zw6RoUsX;1NBkceX!yhc>E?yLQ^phZCU- z3r^u4w(*3D+X&5=%|V_ko;<|IFZNRXR57Ck#YsRY-|uHeoR?&$mqg%7Euz?_BoeJ@ zK1*9?4MGHHS<1+yQiscX-hpU_1#b|RDMHY<6*S7+PrmEXsq^EF_n0fc2hPb%l1+OM zcsm3zjzweu;f>t%S3s<5Gb+6euZsLQQ=XlhEWi& zal@SgIDjwc53yY*_$Q7ISuk)QnEvB7E0!l7GANkjA72yODkK;ZW%cQ~f@AN+l~olK znc-iHPktO%U4#H~L;UY^Sc$lp(IPwR6Fi854c7NH)q8z5j&L^)nWxz=(_ydF{;x&; z5aFfk>09CA+yQr+cgot38bil+gAUL`_|bjFPBSB-E>fKdAxwvTY8FyS>Zp7fFgBAN z2M%u6*9TrH5#zbT*e5}G0@StI1Hyo6DiE{Zp>U{%Oe@o1>EUb&k4rCteQkU{R=PN8 znZVAqRiq+tiILF<2>;lv-Q>8~jcr-|T*Owh`v?bdSxft-dsT5CI_fYFp}L#{eH zgCOcJV}#%&AtW;_=-2LFDQ^Z~EZ2!GTq$T43<4qfQk}@|UJYhF!tUI^!fc-jR^;<2 z$kM`g)3-Ur!$%kr3k;OF4!DAj@UwnoSI8#4A>8R}A?b>erRQv30*5lm=@TbAsw2Ea zci(2RgC>YkjicLt)H7AKTG#PoE6|bQNDt6LRC!k9N3_uEX4J>`O&Z$+a)KB1vMq^$ z00;Cr#2bqsq7d~Mpw^86c>C*pfPBv9Zx%-{3Pk4o44%^`i5@9zZH8otfC`YhETwEZ z;^1gQP){tPYfU_#ktV}fo1d3T1E5MWYU>J#bV!(@*)S^2&lyzITF}^0c+sP^(Qu^x zYd@O+apMFkAIRhY4+qxSrhKuiph|>O>A)OkR72e$elj$2|5G|;-|YrQjVB{ewK!*G zXEe06^mBwV10{RQ;bQ#{^G?DZ2E7J?T5yoI?GP!5RNdkP5cwivBSKB`=GQWTEOav% zeY8s>aXWduSZpN{*$Hh?;4#!!F^pYK%`QWMj`X)UG8%f>^Fa)THvTeJ;*__r2_NZT zEGpKaff79uh%6mK-{2&O&WwTA>tK?q!vz2f%oPJH#hNcGmd6u=CTwc>F6}Me&Pc~A z`&P=?rd{6OxwSLfb{`>D)&M!6-JXeYkjaK`98>0A{V$+hE(YrX46bZ49Q+Kd{(SLA z&Goju^9yaj2nl-|pm%_lMT=rj)P>*tA%@5c`3?^ zUxXb4k;xn8M2ZANkCWH>a=!KKI^GZyP1gC*%!?BSNiy`7PwiirAiN$5J9rPcgRpoQ zI)z-aNdANE<*dY$ZY}27&0HH*%SCfk&t|MFgA?mU8?Ov!Sm+0_PelI+P|K3Vh3nCO zr8*O#Bj7@8hMBgq-Ms0N#SjJj6LlP_?2&+gt6oEMhoj}>7a5O*^X6m8F$OfNW|yyx z;_|eSRlwYFdCHAkiCnKub^h2g6uD)B@duMAQxE=~LLCnv2WSDYPj@|JDtSNMEC@2h zaM1AB&Z)b!>GFAtCKSRX$#i?{rBs0*2AN4iM9CJ+hIXR-BlU#`a z(gNk|F6!1xl+Er|pD~|jXeS*ZT!Yh7V57f?Mi`=rMioG+~ z#PhDw%!d(<5=bg6x+ztwjsy-w0dw1bK8K%k>FnFPo-ke(UXCj0bW{>uL_H#Hjo}qQ zXHLqbaJ{H}&XAEZBy9zQ`;Qo>2pEMJ1o^YaiRH?u601eKjV~dH7o<0%?jm}@3xKyT zO-cI+pD4>wCNJ`M?v($u& ze34JQ1#nh~bO>-HOM^$~wT2Cj{zCwmKuCpBA3fu|&tF*lJFO{!*ax_J{?H<1^ep+< z9rQDp$>%yX8HTz4FeQBviC^C@hmz}bcYAN4Rz@2fUE1ZJp#NHe^yhJ02ew8Lc(Ha7 z#IG0NocPLy{2alkBEw|pYxf)q2y7TOdW8hD1g@B!a|SkVhutx`ph9#^nJg9>YTp<( ze`Ck*NSqP?;xmy7D++brv(v7k7w)S9qrB44@5dhgS^1*$fq;9po#Q zSeqe3JT6*S>0K;!=tN1&M!HaH@)Qjtpl>getucSA@D%WMy1K!rPJyPSR^?=$!W&+azOKO^kQn5@?7@Y3>x7JSD=0-l1)!Gy zq2qDOYDZl9A4l8sI%9J{b5n07s_xB3M3x+@8Nwb3O3jy2jz zaZcMI6s@7ipac(uZ$}Y{eg_ZS6`2z+JcJsk_0jdX0w|d= z3sow~S-us|ww_r(BE@Jcf1=L@|919Y9b|U)S`JvdSx5#@*!Ix@DNqjw8eRn)8WATL ze5{(z|Knmhdf_6POafg*LhFS(9F+pRy*m)w9VlZ%=nBwg3sDgE2pNF8lDXP_^J%f* zYu(7e2OP()@__((p4d;PVr!x5r$3V(6^~*f?yeO)zC}HoE6<91t`V#-sk@4@BCEyy zv4@;xrFY&FXCJd&`nnk#JH%H8s}yv_X7siI*V(IXV+VO4I(s-D{2{QR-xT1*4w1M1 zrBV`yO15o$E7(oSbl>#q( zQ{j%9tVKR*9!XTFPjTR0nD3HVtKaemzC4vMOi=32sBg1)$W@hxR8dR?h?|o}hFyO; zrFXW&A-wNZ%u%hOqQSi0ob{Xza@xj0Cg}4YkkqTw>-l=V`UKX!$th&l0fnMc#En5( zIX_Dpko=s8*V>;?f+ZINKOCA`x)6i16r3Dl>^Ze$c`9#P5hByjkcyHiM%`+qEg;@0Id|}E{3>?K zIc;Y9CpQmBcXhzAZ#r}Z%|#Z?9GV46+j^c}Vgh0fdXUJ%=#ry{+QXuD4KMvlI$-&S z29C`bT@*jvWhTQ6D-D?~ert9n8ZBr7D9bNuW@Ishl2(L;FjFkO4v8otL6RJf z46xFQmQ?=NZ*FWvY%6I-o>!XnSOiW) z{RRD$*Kxf5KJ4z8RTMgct|jSC$<2=vSC!?Uc*y=G1a(Doc(Ovtf@(uHD6FArf7wavJfD) z!Zf%-`5mz`!67-NgG70H7;-hGi6|ikcsoisKoe zgSo^!0HKx@5J}c=2@dD(YT1oBE%0lqOo+KuIwO=aB}4EOkF5L0tjSH4>F-LJ%{A=+z^64sySQmlxN25-1idDSf=aDKmmT{1Dn{Az|}x%`qIeh~k;z#lj*bb zpf7rH)@n>BM4JiN0Oqad(kvzh7F3s&lp-EXaVAlQqm1FgL9?;CmxkzAz{!)b> zP`7o9t;WECS(T8eP+=zQaDVS`KAr zZ)nUSp|(20MO-?PJ;}lMcH;b8dA4t9|Jg#7su*9Qzuy=|nRXhcE!}copz66bfhg_r z+UMvzvQpY1uVypFFdE1B=Vo)+^Z8(x$+(PAWzA>9=T&FuYUkiGIXg^17JxNa&B4D& zwh{(2lVs*K&&u%W>Hj&wsq=$e(LyZ)O@o|Tx11R)Q+>y^(*4 zdj}Z6c79DXK*ZNy?9b6j1WR}EgMx%|b5LTmKl~rhz5X2hbf>3Gvis(u-dLjZ4|g9z zb0IEhcl_4JF-z2NT5FprwMnd4Pe|#t^1ym;CKk;Vr{-OlJ}^{V&M{O?lI{5DGit~m zIejYoS!#1%SF81x14FcYo=Y`Z@qp6DT4EtUO+bP+mj+WlAzb+k_K_JVLeHGj#MMbi z4HRC>O!1hxHV7BZUWgw{#FT0Xt5(Bna3orl0XlJ8PaDvIv@+_o`N(S_#lAMHRiTFo z@Sq&hX}_A+6srTqeCzX{kaJATCO=n~L(uN=wFT-)z=zJzcAYUQWOZK*Tdlm-)Sd79}anSo-v>O+#h zyxx|5sW`#vFCkZ*m9J0TkDzzo4n2(ud&#&@f*7MhS^sbjiq5_~AXX&b0{95Fs83Cj zNuQQKNHa`RjfTNWS6V1^_pEvyOq?E>I zr3}eN2UTI82LnCUhF$<}Ri+37pTd|Po)*{Y1dU!TFJ$2vQY{(n%_Kty25+QS`se_; z?vtcBvubv$wX+^(DP_o}Rq4OK)|paZ4JdfYG%eH9lgmeR|yiE-(D6GxyN!c@luG_=@`@jWagMO&azfad{Vqcj@Z?Rl49 zODE|{NDDZCWoNewR)aOh`ktJb#ZWQB{PKxQT$Vt(9y+cSCv=(kco{tSd(*au?mz4m zY_2Qm)2hdPod@2>NKXb7Ujx!>(o<-plrCO|ZVk7wxQf5APr76TDce?fII;(xE>4R| zl#kNd{Nkla3e)G{pj&Id0Mk=eo3XLodW6fx3HI;X7Rby+2I`dM6jO1ffNxlqSi(|3 z{!3X!i!))u{_p38IM8B|XnYNPX0Af1g3mAM#+ zYr&!Pl$c_{#sQlGJbZdk`fOk$W0%Kko8MBx>iAY~@IamR`)1BE!Cbk>X!&-84Sfiz?pb#=^*NK^;o zy~wXVw%@a7aZKA=!ko#4aqM{yWvX_p#C^Z;u;YsI&iG!vhcZ)IDN}s6%@Uj0-S)I8 zN`h8wQB=F2@4wI+!Mh<$txPFNhV?ljMRt;$anP7mT4^WYFzhcqt40L#A9+pjy_D zOOXgj3QoH*r%sx!b0CPkavT)&7cjulU_eIg5Hc5&Gs zvV?#3)7M{6XPM^mYf9f51k%Jxb|6f2&p3(Avn@#stkMI-K(3QgK~mNZE6}NMpDS1z zfbH&FjBpa!khI3nh+iW6=w5{kv9CL? zZrf-~qW#<*H*$2aly}P1e~KA5O~k)ya=sq;8kMD!^>q@YVM_j&bFrs1x1xwp!P{dX zBRa*2;+bMwk<0=c)laPwmO_Co;OwJ#D@?6N=#JN-B}qTm$zT4jUH|~lE(&!lDnuws z7hSjSy_E6}iReS*@5q1JT_`DVghy6MY@m%O7WpYpfiR-Y5{v5I7#bI9#25xNBpt## z)+Vl%+K47sAb3RjsFtG-f8kn2av@+N{1qPS+SnSq4-3d+B%z+3m9T)?Q8=*>yyrYL zQv|$T_!2l4n1U#)au8W$l*n9C%DTx%|0|ZZuy`bMm{E7!kd`-S;5DzDj=J$!bNb?R zQ@QLD9=jNU3vqDp!Z7}E3mTBHVn(kno@k`$g-46IFk9EP-N=gSwr(< z^MSTDROCS6#WcvGZ9OI2TmfhPZlDnw(DMp}TBsLAf%iNug7A_54(D--@dff*@D!3Qqa*KC{(21! zeK~xWg@Gcm692Vxv4~2j9wWKMf~+FeIUKmCoS`{k;Kfc_s4@YdEB1)@Xgl+6lwWvN z%>r?6$DY87m&Vds19*}@m75rKxcq@49N<8!pvukpR>dq0`*GO?B-3rJ4hailAdv8Z zzP=Qu$*U9GXN4CGpiFj+{Z^~9e2?QfZDG5i+;G>R(JC3;7uAR%|nS|OFiT5LzOrYtgt@)gsaG+T_xtyvbFur z40W;id~?|hNO%?bh7%zu`Irve4|5El3B&jX{x+}OkpM`Ga<&y)iA}+5l1Luf9n}o0 zMo3OXyk6?Whe=0zi)pzkmmPNz+yk*lTTVc9dmHpQ#(AMGfISSn9&F!+dar z{zQ)u2F(U7PDaz8Yaq90+!VwPYqk`#WUkjhRi;%|S*N(@xqBN)X|yO%*1$P=a_}UW zKr*azoR-gNxs&O-Gn~dPzt|M`F2X5)aWXFYC!*46Ce$yxWjiWq8o1-cS{b?!&D_3% zLD?wW0oU)IWo6jZ%hYUtkv1>7(;@lK8O1Szk5cUnA$=mtpt#z(GH%9UAR)Fe_&#s{ zPDE%TbvShK%O>D!d_TI*%N2y$m2v~P1qH5%wLS!JRX?X z-OCSBk`YN#fmRHIMW}%`^l9_Y5_Z#R;q{M6lcW;+%8IR&1YvPz@x=HP+sR6@5=17_g1oW{wJ7CIK!5p&t%Rk~ zZrW}JpP+2-4^uuP-J0w!GtuS_zopSU>R=N*Sf3aYkheq z8#ok8X?|PZUZ3$ZktPDq`7_{rdFW*1&Rb)M<-FLZUuSC?$ zh_d+3Mv_1wJ|h-SLt(J}izFEu89N91{&zRSi`C-QNKLcDCVY?LASGC#wO$H#$1)}F z_3#mk&8r~Hm|mHQB2i||OSO-TX78)3@iJ)$JZL3)*pQA`1mYV=`{);|bX63f%AG~RulmTg<2uyx_eo&Ot4B0tt-WqIX-!$Fs%(z|#l-X4qVQA|vd0B1_h zGgAG6uT?KOqL-N}NHcvkO(sMmw5PRAVK%nyoGZH;1}hIWZ0JB*7>y-OLCFt=kwiu1 zn+FMxRu=tU)f~M6zri^x(87@#5eX(rbpZP5@(ybp;RV8gEClWGdOVYawwSX&9FqJC z2leF4eiT=K-q2K^{5+}$QEy#=HP-m=93lrexkb4N8^`Sq+ykrbh#KUmFH+)kXc0^D zj?id1^_AdFF#LuWBIdkd^Fp=kT;4W+J83h4En)SX`G%Z%31v7+FkzW}cEFfyotl^# z@E7&$iNpASun=pXip4{39w~tE(iV#=RfZlZfSSKNGwS_Je1hUPeS@x1M{0k<{SH5U z+Jn))q$9sWW| z5?UvSQ3SpOs>@m<`?hMo$GK7oRptzEZ)~N34?*3IcAZUzcCeMWW_GHONs608ZeX9c z%_=*4vfH%U@);y#h2h35hxAlLnp~uoaP-Th6(W6I{%X?MO$p=1;UsFA$|>a5-*d>_ zG}~$Q{s+z1%lC|<8aB-D3p+3jc34&%6%)rd&wX+l_o~ZWabd35r*|AADspjrVuZ^{ zO+a*mMQ-3OMt0~QS>)~&XJ@^whlYgUa8FAuPaC!+CY~dee(wv@PMi6UZ6UT~VlJm= zzU$6+?DtvSg0AYa#>oCq4qZ-i;)X?A6)%&M&mH~`39&z!uZ`MK06lBnLya%)L!shHjl3 zHA2lS4z~rp0b4iJ-qFio(O&2(TSRbt$znl1EDPiiL`i|N@8>?+pNE2zc#9TS4_4*< zP|(=pa1TFrmU|6;5~uaI-RtgW({I8P;i=myBxy0C6LG#qG`BRj&3<@q1anh=BvD+N z9I=A%CI@6S8-FgxL$bv6L!dPLXhlTv^fEM71#@)aC1l0k_-k*+a@i$U6uwjvF*mWZ zC^b(}EWk~;^4k22z^Pyt9)*iEWJI>744T)TH%`JJvV> z5j02a$GLytDTJ~}zFd9FSzIFimhfFols2GQ$RX8^#*LrfJ1v(Hb1;!iK1iQp*S_N4 zvuaT9pd?e2-W&FW7)pLTIHl{%?v;r4z5T;n*mtA8yC4Irql*o$ap(LfL&Rwf2W}z) z9Be`HxNTWP3-PPWha%@2wQs?_Kg`&f0|@dYRofh-PiHp+(_e6BGG|P@yU9W?y@X1R zfA&qR-rg-a{!yrNx{1`o#-@#2a#$geRuRiU1+Rn8cyn{~KBbxQ z$RQ3)M1T$v4$+Yyd~!-Q_D?Kvn2j&a`I8cGZ!*;)!|C7V;*@$X$A>zv1?|6Sm~)g4 z?Fc5A28vRC0;d z!n|y9?KyGy0ikTA!w{Hy*P@fa8%a3|^vX|>l7jpY22@z&y4Z2@A6VYE*OMSC1^A9J z|HQGgo)3}nrovIuhySYo9+@#CG;A(Z=>x3|5|@>$>jSKCxM;ArBKZ#OXr$&(Vje~e zM6zGiqh|j)E`6`On$oQfA_ya6Bb~nPGnn^%6r)K3L$vN|YQx!JqV>SSiyv^pzAwpN zP&S$St;}0bJ>t5TPQzI057JisPHshG+%0w+iY|)yR8FvNQU7pVn#v&7^snwFPs0h- zU>v=-x44~oGQ;wzk>P1?(F>ypv>*(~HF63oVOkYi`9@j?ra~iDV7GK#l8C-4KxBr| zw!csKU{LHd>=WB)PbHt6R528x{jNn(g$aYw5Hq1!)^!3@M#9@eZtWeo?82+$;F~4m z9}E2G3b3YokbBsw_$%nF8O1`|gD)TJO___R6vQ%UP&lgX^k?j)++Z*AFZfXRex>0u zDsm|xrw1wBj{o*vBH^*&x2ao|G}KcWc!>#MN0Azf=_eEM(s)lo_}=uEn6i<7&cd%|!uzO%*n#)5xF$t5J0*5g zf3%$kz2Hx?y-2SOuB%#)uAZ;hOx<-=7c`?CXm69tKNrZRV)NK8#UGVyG4z&gBvFp7 z3p&DWiYAvL*!MS7@sfZDSliV$HXqqD5?NjE&se$m{by?YW2ztcfuUhKKNdz3H0K9P zQ_W!}L#+gXlrGy}9V`A`jaLR=GFd`rtP68UXofvFZyHYCH>N)Xkub)+chEm6Q6xd0 zHS|#hTg3)!3ac@$@9(QpQ$!&$-|%vpdsRJ?H8k2u$Azv^Gt!pQlGCzSDnu+kAV5P( z(&wwB>PMBC{v@bBCTN2_I#>?BRqBX@x`yj^ssE8{AQmx}J-NFlk>7z1lCL)YiP1ee zYr+8Za+s=b8z4zT(M5vlOlK`ckE zLS~R0|D^=WaL$nwF-avXBaCQRJ}XkedS~x?r|qL1mtCKwMz)F82umH|;(&&)YZI{* zd!6X%bWcy%bJ@o@Zc2b~wzpxVFfA~X%7((#iil>4#X{m}#6z*{!BR$mt@ZF3zYkkR zEK9VfC_(sV)V3bc2^d5;mUX^&c4TK2igjg<)s1Rv5~M4LW+!wINs;^6JzY@R#IgTJ zb@j$!%E7K=IjBNIPj%jqk7Z^2qr0~1if%mfjNZ7h{_{4*bnFI`0D z*@Y;G`Pli)IOeEQqry%1u=s~(M|Uh#OQdWmmE1G(f|SHl`W(dO_c{DD?yx(KA8`z_ zSPUDBaek=c8AW|^#tfxMy_KJ&F>zSXXZobeVRJk6@b&8J+VX+;>@9S5(r ztSUQ4fLR9g;x`ZfRGyFSd-7%@3v0Gt0`FA+%iz__E2~ChB7Ox8AMW;JR?>=%(gAi$ zoNw1#Yw?Hbib1@vw2=&IE7+^FnYg$a(Pbm5qle#7dI!7c(|F$T3-JxpIE$!*9gCZs zfyzuIU_4R^us{E_A&yv#lr(51*o;+=EJvU!1qS7}OFNtG#HD5l5}zlXMF^{)%V1IAt|9hdv+<-&Y}nw>9Jj7ZHP;idYP5w7wXzN1=|WvO2lS+UHdH zMBMC1It%sj*<_`{p6&UR{P`uMvK9UViEf9ciOv14+sxHXt5a31J}eWl1IR6!Epcis zF(!;iNn@ZJDJ5WnIi?<={ySL(1J*JDC@B7%br;@#*|NgFvLG8l168V8Y9{RcE|tz4 z5vw03Z&r8c&gX6<{v(l%NZ5N!Trv6&05NpAtHF#88=rD`=C-vH!ReyrENREXN(112 zNyo*;UbCg6&F@UFmZui-V2l=>lq36V>@pB#lbzB7&m&g$4Tl#p8!ytH{ptJgTuAQ` z@6=>LxI2V9uw=uMRt9F#NwA0QjKdJG95%yF=+m-dtEvNobX-Nm?eA}9xuwMj(ya*> zpBr^cq-yx_*$+~ynvT0IScQ1Faa%NrcOjPlXoE`r!2ZhA_#hYgT{jNmo=M3IiT4L( z%pa{~s>^zDfMLiz$Vor-ekYUt6{o{vYI-CoDMK03aRQhYhZ(1{!Hs)WcFkpn>56EJ zpuyh3p?G}-f%^`>dDf_;raBIdl(OUx7Hr*cZY!T7rAExxJm8_8*H%VU99yhn%7QQ? zit+|066Te03+?dnxUhVtOdhzd-L*3}#i!Y$A(O*^IjahBNhpJ}AhwW+QOXYzUV(=W z$-zT$_10%w9AVRq+pBTQU0#akb|nPb4p{5c^jcMC1YL~X)VH_DCS+;aQQCa%8Cph{s@QOeYuBGa6e3?mw? zG)mIJoaINw%$}2{)A!B^v)E1-Yk8U2<`rM3G^QFx zBZ7hG9nscP^?>oZiD1de52>{3*hVv2#qKWF#@R26plbio-6094yLtO@xEF z%?LNR&dJ$-0QL{XU5Tvsy&*@<2%$pZZJ|0sxMVQAGxQe5U0QOfHf*U3;wKqMp!tB$ z>#JkKEq!mFy0T1CIYo>|S7NR>44Z@;c!iX}XlQ3@rV@X|JA%FX>pSjXFa5O;@$1c> zoF9Z~q7ltWuFmgwum=@~!_}FPfBO@W;wLokyN>Bga`Af^VR%Y*wYMYw8xwckpLA15 z$cRT$gf+!tA0HfRi!`9u5NCMq^q|AaunrUtK0E4sSj7?50iP2$i3B%;g!Z1u zf3Nx`r)M%4$MvmJn$o(=YLc_(k}p210ypN5D-F8(Zx>GDIA%pYG#fMLiSk=yOzu=z zl$WMS`z#gsGXBiQqJ&T94uJB!*EL^iZTq!S9 ztsqRiJV=2qRFaPGL5OEFV(5_H72~>P9Oyp484P~1{B6JC6oT>^J*2)$q5P{~&;c*c z`7MvF9ZfCiUBRs@@Vb~9oUVQ6jk29emEH2U3pL!lgyWMlkZw;#zF1<=^)hkgQA||t zsl=EyBxv|ubLU^CRzp3#^_{#809vT>Dc`HU&6!z<_VE=OCb^uy*)q10^u~%1_dtDG)Xc*>~+HcIwxGn21$~O|D9)+bBer1BW*~ z_MGmF${TCutP6Ix@SRE?DwkyOT0r8{Fw$%mZ!B+Bqv?Lwi2z~?&%95{RLVe{yT$U$N>2fTjh8^PLN_ z+BCgPa=|%=smrhr5_3NepvP7e@36*Yz2uV%)(^JI*d4nC%?B(amtx10Zjd(KIj5$x z<1&;YI$t~gYk9D>K{6|m(Fn^fc!aL~U}*+mlVR2mV1QOU4Vwk)RIKvtf1o)O5|u@x zxh?dGr1cGqi)}uzYj9#K`UI??t5}vuq*up5@*^0TMmZ|FqVHh7+%ap z*QJsO5r2nAZr8ELYrmqh$KZH}AC#4CPsBqs5SxXcipRrFHR=q+g(~0eaMf__FAea3 zAc&WZ$1m0wedVA=RC|ktkN%0y8|%jNXuxD>-T6Ug&T0a&KD9LMQ(85r>KDzht5mm@ z?0Ih8I64Q`hzYYT>K8m&q#|mCe9JLuCzH%_r3eMG&28&gHCy@v-$N5;?VKdImnAZw zUCRJy4NyaBHXG^X)Gj3_H>O&W+fpa5IK^i&MwYkyg(&n%^ig(ElBK0s1}7|tM}l=- zZr=Pf(n|e#2r+Eb-iSc(I~7_GmL}CjV&*mF?_N}^te(^^IGiNM9I}!|4OL*02;qka zKM-G8X&tw-mP+nGxRbprKa2z78My=?4)4E*=(Ol)f3Dv;5@;D%M0*egrjYkVRh!qD z9LRBh)!Jbm_;2G5^p3l~;+d9&G4#rqvI*F5;}kM?Zx#Gj8JYodRlbYZ{Nh{;CNb?O z%UN%|m$P6EWi5JPY~H2~6|TgAHr5`Z*W10XJ96so8st3ep1-aofP}Etet|uhgKf>u z=z{aDfVJyO0ezI3lxn44P|nXphD7}IPw5&wW&p7c9~qY@wOXecNt$dd=9j)ghFyA9uYnpzGh@#536E~b)Y2bG?GAV;4{pOK=F z!VYz_=Xbo*`pc*?^8qG#Bn%)*l`-d>ASJ&78MP|9kLb~#V-m4lKl18OYpIfvLV`R7 z7S5$vb0*~}c4ge~{he(?UcL2G{>m8}^P4`JUOS@+59Sk$OsqnfX72kiD%0sjK|Y^Knr_&<&uM)w6zw! z3Jy1Xx=GyJwpJov-au>)OO}S>eU!5R>|M#fzVCB;KN25v|!1 zHb?6#L}x*#h0*lDP;gLS+_B#!HpqIX9j|QJiKlfS0a)(xNzm$5yG-Crn^Y)xUqDVy z0rBaNWPwx>g+WR@@K|8t$YqyUf8FJX^RQHb$D%ji>nogO#Og{ggVjxRwcp~>f4lN0 zq0FPt%V-o)7@{YrD>BeXDvG+ObG$?Uo^w#>q1U21r#CRfVE#0zu|F6)TCm9?%Fv8h zx}Yu@lW*d>z)Py?+!F_68-gojONSTe{S6VU@t!XVWD@1PII0_TC4DwPj>=8mPb`v^ z_|A>|JLz}SOmD=Dyn0BcC|M8~pVHqSl9CfcQOw{N1Q=9jH6nI8KK}P|C&!>JTln-& zKGlpUFKfZP0@ZQ3IvGuBN=^n$OgBs*p1>C>;D3=AG3<|tID!3g`|Z-}0-I9D{i9?E zPBKC);EZ(~1j#eW6Z2D;*42dn_gaA8LshU6)k+CFZgI6mv;#}(D*wYkT>ZaIr7|b;9 zmBax%P^+VtnWhpa&W+HfivUBSLWZ<(W9d1sT2a|=xM{f3z^=zdh*^h;MxI+}*qoC{ z&&C*lBNt0u)zWOlnlrQ<4w%1F_%R|VCFZojzkLW|!Gh04V@#xw4OS;ZZoZHY11CdJ zqLD`j=~G354}eo@<&p(V7)doUB^EZ|Lsuwgwe`JLLL8KdK#CX7JsXDU3WVfC$ZDX+ zLdeDV@fuO;_TDk2HoXD0I_3zR>Fep-@?xao;bP;GV3>Y>0rnLdTSzIIAcIx`-v?QW;ip{enUO+mYpe16^K zmmN>fz6T_^&(hUx!Pv3tEu2m6nnD#0K+nqGb6qy50+en@cmNmz$Q2Z%fJg;i%&^Di znKM5f>+?Yf@DnT7r_};})Xnn|%Tx%XVHf|v^*`F@8(s?PN|Hr1n6f{pdKt{nD`KV0 zC8+>%qM|?mw2X@4cM0=jw-)L$xc|1tx$BDYn>0ySAg7k~IBOIlLA4H{r6oCn#>*d^7tCf(Rs*VyH| zu^XO=vyQPxx`|7gu^XYuO{&SY?%37E3+C1sF-c0ymI^#}V$4<)+IvyT8BxY5aqvy8 zAqJ=vy(-{TWMGs*cbc_Pz;_y;7TSM?2uH!O65|N?JVM@p5)~gRIIgUF{Mz>D+IH^R zcJDfN?%BNl)#C+TeFw@>NIh>LA6ExQ`5MjdUl`G4LA7@b_VD>7C5q~*9K6-_zcVhn zX0Lt$F9d_|QCuaP20X*`*b2I+u ztc?Ht0@U08pYKKYe>VTW?)85*|G#>U_H~T*`g-`IY8uLuJbv(sEFnV6-EcdQ|~9t zrv0LHrxC6>9l0Ycl^a{MYSWq9&nUjO@dh5>im5P_C+KMmAXsU9I) z1~$8Bv;9IsLck8j8Lc+Q)9L||9{a{+sftjv?wI9PPt<#X%C-x{3?*6(9E9wk6OYzv zk7L~>w<$%aXG0GU?&tG_K;ws-P?sEdz#lEGt*ReBgc1vQtbNro z?0USrEQLW6m-;%i-ECXh&b@bvjf=Yp`mJtaJ{aPomI3+_!`cxQNgD9?^mNHd3Ld4#lmAQq*`bG?EKe6Xh@b~Woez(h>|E98^p=;+Am_yLI z%W7&kj{a7g$#k|_Ptgp2=Zay73kyJfN>&!eXG;ydnYZ+MdAhB(n#h9)ZC)+Iuf}U` zZf-j5cu>*Pi_tRj|Edc(x>h=mFH_XnI9U{9Ps2BhsVc#q|aw?*;g86 zn(LqCSxlakoSoS8R_5k*8!fXwe-5eaxJQJ6foZc7U}SvzI^v4alwnSzMow8G zfx@3Ze?DtneHz^bi*x*O4J%U^62d-;zT7N2oq3yeIM-7Q~)Tz3=-3JU&}hgRD!a&K*I#rg<& zwHr>)%;eV9VOdyM@CH2c9vmK;G%hA3Cx@nSTAJQp?Z0+X?ZbysJ29sjJoS#d9YWYQ zhsw6LjF^bv@zVxKe1}h0*H3p#i?d9Bl$AlPJWu3H>s&fII0&EK>gwvIT4s5F9NgAx zu*0u)Tovx$JVz>HiO@q0eG)wT1qJbPyuH0WEP*QYZm+@PcmW&ZLBDdYb|>&`txI*J zhcsoV?`X9%yLmHSAi_XeS@@3XgN6nd!vOT$@rHh7=W~m)Fg-ne?7SVg8Sq?-?A4*+ zVe|X@dtN>fG$iTK~|7soChqqNqjijo%H-}`h5Wk`32l|Je+I_!8yggiATL3w$3IV%v%%*?~x;cxj+^@qMOn}NX3CqyUwZw+en&+UG3c7%ecqm7NJ zq2GC*iQ~}fCxO2=-c>MeAoI7qJU?X2p}yIPAapQRpuwbl?MQd_Oqtfhmh<*kt@~r< zfakm2@viTF9xg6tj)m!$S`hgA53eH>=jn1#r#2HrMs@F4JN}uDYv#<`eROC$ zm+C~O<>XAh1ChNiL(u#4#Nl=9)V?_p3f$E4@(7WDN32e(2Xnq=*;7Cu2rscCA2+vh zyiVJ1wSB`0c^u3S4i510CkC7JS^D?gINICW6=Y=*E|*-#?wHecD{h(_vCAQz;&@ih zWLwYs3Ddy6LrP0aO?-TP$4&^_4aY#(Vl(nPhp7#Gc~1Ph+l4a@_xvBo{Uh{%!> zGhbs7v)W7|@^~hpQvWtk_~~j2UGc)=aE29x#kGk)xzq1oo}S*)9#zNn9xb<~&@(Za zkC;6_-o;K>A;r9!Rm91OL#IGxULFM zR_(OjZ8G*x5X2%|Ll8`RzL&h4g%F~qrp~d4ITS|y7Ifmoo0{&>@`)?kvE%NeWKYJ| zuU{2Dex$J#AUW7l=veF%#idR$3TPg?Iq7_P7VB)a93z>nApy2=8}xkAdWyn023)Nu zC+FAcnFsHeILLdp>Dk%)+pEdLuF!-S;ul~KGSM~$)>1xH86!IanAfBEv|-|{C)fAw(X#H#yI0udjEQ*+?`RCfHo z)?^yR?%^~}|4Bv$260pLLTpA&Q97*nR)1k#keswvsXXQkJjJLmoNHcKuE2CS7vAPjHTr<6tFQd3jW17E)BIhZI0 z?q+%dw)6KJvo^G%s3(7BK&TAc0`LRd`_I(!kfRR^wv`r&tBsCEqIbfNXFX8~38da; z=!niU8d`S+S{fQK{t`xQUhFi=S%N1wcUGovIkfbhVJzjpDP{1YgTx`ckBp3Lw!i|m zZk~}1f4oc#xe~>l*kwUpJPkz^UZaK|$rcgGIi;ndS_2^GR`wM#LIoh(vAs?k3;=Pq zEt+M>Epo2BMCGSStPBhrTU%WI_inv?ebqNok26y$V3=svYCv+mE2wX5g!7l^-1%-x zh7&WeEKI6M$ZcobuCkuziSov!Im11yw4uRccp+Q_si*4aVu#&)jY&Oju1eHbMy>mT z&f67VfWJ5EhIy9VFefJ`Ax8&R>5N@nUA4af`SWcc9QGpiiT2^afhqGG2=lyre3Fuq z#&;Ln!uuc&K^Vvu6&J(lb2sF6tKhkyULpJEwv0*3J36u+5@O7=yn*VPl{h^ zi;EM}vVK;o0xp|jZ#G-56VNC$Y2q3#-X+WW>Dc(pOEBZQ_g`XaDlg0Joz?!{p0Q#l zfciOVrEfAs5a(V_U8n9HTQhwhMn2Xe`GCgU7BIhkM*i!IAonJBs2D zbIs{*VvY|D4LM)!O`sc4Reg$!+omE77Z1L>+%*FvVz==2>MG1)K16mLsaaY|>i(&` zvXZrgVZ_M$uTQ0Zw$-B$GMWq<2`c0=&+Bl<{5B`3wTDv^(Ld=77>Fm9u(mE$z8?#? zsYT!AvtM{OJCOrmE`wEkl52H)U|U%kBhwIA+S(_Yyb8EN=#NQ#mbui-r6(a|QCOV4 z<2MVtP{8yyYYeJP-qxh0rKPf)Nr~Er+DF`6j){!T7pSKx^y?5;DW2I`TO$mCFl>pA zjU5iS%peBYxrv)2Af8MY;{^LJ<%K&Ka4{Xc#%JX*e&TM2k2Q8}fN z)!IC3AepXhO-Qjw>j3oNKlwO+vh{H4Ir^RnkEj3Qrte!k8Wm~y_wegI@6>+QuK{Fv?z*NOPutd{D~SwaqE zp0-&75&p@B9vs*x{n6W`FMbU6iMR^T0NZAaG!CY-cnh?zTOnoxGMxEfbn*OXB8=$L#|M5 z$$id1c;EN-WP58?)Y_W%$ zk*KvNodBi;U)n3CafDwJ-2q$)^W}7aG%&WPs3>UYwfU-|TA>$Wlvm*Krb6?umO`yl z!jR1>`VbmA$z@7R8g14swdAAxb5dt&gC#q&N~|H%|qBa*X<{8xv*f?(2XKzfba zhn766ew+-9jNZ!~J?p;!E$3J}9nKO;=X&z&d@vBLbY%iei*rn{=N^Btbx4Jw4ws|Oa1O9yb-?W8WXNGPvh{NlBuk6T{c&YyWWoXvB;>7Is68 z%7rclDFaw1n=?f56dvOU3|&XK+Uz-5SrgpJe+E8ZW<$hz%*@QJgBb{$J0!mGRL4J|D#sdGkwPj)K+4&CLfmj3*C zqu0>+bnFO72g$|Fv4_CrxCH9mNM&iM^`JMgkk1#cgq@w8phN4;{=#oT-nK4}V&UM_>?{Lxet36o^m31T=z&Va%a+%|d%N3yyF#d`LqI@~`Wlkj486C% z1|_T-)9KN{AG``FX+Yj^_?6k}cjxjEU|xXc300ppG&F`=+z($_+2sYXoTw$(%G>CW zxmqK1^Vdwl(sDP)yRNQ|4W!G;Rlk*hhvOUs8-3`j3cbdf9aVMpUO#|`6`5y+<4>5ENfFLI@Jp~{qZMyNlPWJ1MKyR;2HJ&D4jUS5ZEI^5 zPb|>y2L@o+bxdgBH9l>z&q6!_&CPPe6DV5wE)G|?<*+R!S6aBc@hUej`ab)G!@w=O zUmr{=KgqduId;azf}fv16@)GJGObDyCsL3$)017b*Z}b6j}*F25WctSg)pWPkwD&i zYOer^)zvTpKw1}>_I8!GdtiMsKuPfP|MmXwf4v7mpy$Dv{~JVmS=o?dGw8YW_R>GV zc&i;=hFCj^JPd$h$qvZ8pyk8IS290$xV^Q6jRc5)w@T9(E5;|MDMg<3f9IP4TAw#3 zfqR~TA0yx0CMSax%F?9kVAOZYkzQfetNB#vnEexc{<0OvYy zrKbPJj+^juM$71YQov{96KyKsr06Ll#%xGFV}W!cteuY+i6^MxE~uF%ct9;-17Vf2 z7GS}|!(6yUVbp#SpU%-yr5zwtZC`1(Uycf-3Hjczd9?Z~#3LjO^yvE@*Oz;r%-33~ zOS6K;TxMOqq@*O2u-I|yiQ3=iCkPWv+>!kql9D(Pgu4OyC1--rjkYLl#A~|011J|C z__xkH&~~KNe}cLET>9e&qSr$%#`u^Jy@t9v8we;|m)&n!*}$_3xB^Y|Av29Y0YXUo z#+wc9Dxki;{?$E4m8=L)#-gzqQ#5e~+6H8uh+Ee=?XS#O@OTj>;{IQ{?6~twOA){gtnBP0 z4Gf4uaGh9Ki0bZsQ>>{7x@2KX|S#P zCh&T^w$T4~$$-i$suXeXwc_#Yv1o6#+%~^k3wLuQw$S^j&7rft8hvamZ8JIRrZ#&$ zSj(u8SQ6;@N`oq3f7dWj?z5|*uP`5O&Pm1@dSj@vvrGILuzP2^n_^@-R#w?6G2_H-_XupQ;%RD5>C| z8ou<9ssLe4c>fl7WDSk-jz#+M$jCoilU!w=(Tc{6pSxLvY9w%t_C2@&LR3NCh1b%? zH*B#)bzBtGQ0x94kd$4c|F`w!c{AaBJsKMV#`O&wk#KAZE^Ge{2zA#!mBQW_top8s zqFqF91Yx0sTeflhF2(}853kiiX|{;Krm0v)zNun~67}xIIZwm;=Q*Q+ny-xB_@9N( zfc~~WKUIu+zg$7cZG7o}i|mIs&`TCDN+d}`(>=Wsf3soQ)Y|&={H*1>n44EQ`{qI5a~O25LUw$~mN~CIw_7GZOn&xT@;7t=H#$~%`OY)UjVk&7 z4POEl12*DmJ1*Sw{oLhbX0dYq&o-iF&W}zl?eSB^6AczI%J+4?C&Bz2F27E*epU_? z`JP(52)MX7?YG~WE+G-w1kYp# z#t#KNyY|x1WZ@1&h*Er|5Tb?aY_Ey>2 z`d2`z+lbQeHev(HJ&`)~Q=P7YX_|fDO8Bqy&61~oX4zN0)bdUPwPPsWAN>{zWd8-8 zw)GH9w|X9TlasKR-h-Xqq$>f7v<6v8!K=@k9I;ujZ{8qt$x4c;lSawQ5vU0}%gQ!w zCj?4D59NnnXZuHdd$Ws!26~W)Mx7+X<~YN!YUpf4`a?Nm%}yY*qQVO3|Jhgbo-3c= z3tuN{sWE};=^Jf!m|yCcnXNnjfh?hnTDTwNc|@DcpM`-@`@1e89=#C6~E@p6)^N zx4^>+l@fKzKgwiiImYuG*;haR$k~9?HAQJRzlzfJhNL@^XpZ^twk$5{(1wlx91Z9H z?q@}AaJ^+Z!P-R~eOg-iK2B&b=o&NYt*rd_cl0@e^-L1i?bOuo*yGW_;w{1SBg>mx z@^9BGk!6!(@5KOh3k_&YF7(W*@^b!Vn>MuNGW*G*D2v4Kpz&dvel>__t)>E_bedMN zU_w-MB<;10$7orZU%l9jev``Wmnc4P+Nlv&>-8CIs zaI&12U`Kl($-(TgN6#M)te>Bv5$TLLhpfaWLtyHVn8IcWR^OKv9dG08{7pP@_9gOb$XW9$Ve(=wE_No*}Ir|SoT9pyI z&ktj#%eM6pFBSJU93%wAR9i%=n2L7w z@O$%oEpV>#R#poa%NP+@9VnVZ{tL_~+c;Y{*_~Nj9^nrY@$5sK-By&A*ZY8p^7M4t zkq_&+f`8_3-{IcaxEYw`1vy~k-M3qtEqpbe+PRsTXe=giV!o8lYk_EPZ7n<&aQd)? z$<%UhlU+Xvx8d02e}Q*H@i6?c?Y0-QJe#@cq$TGsoM8eSNh6_BF{Wk=%*Rj&dt~I2 zzn!GCMuC~v0`f*a2(GX?nAu>4!(u7b(vVzFo1g?pe2?0$;z~D|he~O0&2IKU;hd3j zT*_<18IJee;eWe62h=oq4MHrBPlf)tUAdIa_S}r?IoNhB%rAr?6?}Sk=yOn0_fFsQ zcG*nrrzn=tJsr!-HY+;u+T~GL7-dVO5`0kIC(K+%h6~wM0CUf31Y1Xn7RH=>SITwr z?;E`YNsd-)V8)C*@NL=Pf)-c2px6-*ay`2-5WV&0U;Q8~tS6WZ!$f#UpbsG z9!iVHk9XMx#rqivz!9DzMZ;;KaZLNPH>ad-;XKJ*zwTq*ChF(n<>m$S^s4VNJ)N$$ zQ=XpVnV69q+n@Peij+}*_-I+bYdX5yCC7;&|17gsH*d_9KH;|!wu&CH2>`(dLY|EV zo>fUDv|%VRD!f-DT0#KNx7jCfdWAp{ok1kn?9SMW@oDvxc)tGaDYMZ@^7HP6i&7T( zZSk00e>`hv@2tr4gr#%Fr4*t=8+xPQ&EKk33E|lzO-3bRfrtvn_P%=u?_9M{tM)6g zSL95k@-j{NjsZP-Y_~q`yfwDCvyWHB|4goJ zI=l40XT)y5JoB7*?-wS%-FZW%MaSm9BKX*Oeds)YIrcCsVMHnnY7ah(1mrodO`~=P z&{PpGwi99&E0{bD+r6t1W;AGWqi40Sv$g5QwVlhm4@HH2Y?q%c@1mYFBE5P$fD|st z&{t#hgy<0ib<0v)qJ6Y@;o`if_f|g3gDld=iy7Og`_UV^xWtT}~Z9wr( zFGBXaVD)Ibc-k!QcEh9PHvBPGZ8l>zR=+c`$J_$wxu3e&I9-o+nTXKZK10ljg@t#1 z4V#+@rRNxkd+IP@`ecwDuqjNR(>2YSP5~4r|N~Ajp22 z3%nyX95ZOfKs{QHN!O~B(pOW{J|X-n724dmdXj8-{`_!;bbc-_-i?jijOh}56apD# zX1dm~##JQU=qUX>oVHtdout|kEg zO4OtKNJXQRzEca2c9~6WHj|Vz9fWWVR`FO4Qc|e&avTMiKlx}gf4iLgp|di^9REq| zTlT|oPvPm_FOk!xP_9&Y42-jwz!yT)j&oR-BE`2qj89y6{Q{Z}#2#AXjM)jmvmfMQ zijVSaZp2jYhP-q9Fa7?iYjzzgB3`ZT*==<_X~VpTiV7MsZk#^@wW>R3Qu|zos_oBKk8?@{Gq1>EOW|p zfg|a&EY#XAFXsYvRXij-ffd3f;7s!p`8!)UfnEo8M@;9R=MvN5sMyUrb!x_+N8Izj z#M}JRP;tCx{C@hx>CY!WGn5E8`svKS0*g0gGQU98p`>;=TaBVCsI78nii5&|nrUBe zuD)L{Ukz-8d~foMnDz4VM6<%A1GjAt8gc5CKRx9bFCgsmXwqcC(u=NkFYoXFsb-V+ zz2md(hr|3ErcC|0#Q&S|ET>|b92qh`*(`_{cr7w&TsWl;mW86p8UZ6 z?{EJ6FPbvGTcq`X{uXBE-&8kk+SJw+HzM|nJBzQ6YSq{Ok#~7|{G)c)?hPeJyAr1_ zUAKtofA#mfb}wHwF+Djq!?Aa2fWvYvg(Lfcnx5P*lYYHAu(l~LFz~?b*Dv3+OileX z<8q$+(fW6Hi*+rPnWffFvt3YaQ}H|9KKbvPZ~6N^N?%}nuxS1tmf4ptJ;=zi(*L`g zU9REw(?h_iKAx9iOot6LZtj(qzgNiqTC4IpFc8lcfNT9`?LDtnIWkwhIV!GfX>0o+ zw{)J}*;)TgPdk~%?EKv>|A+01gGPu}%-`qs$-q@qz})`zVS8Z-aDi9d^SLL0?U#!m zKMHW2-_M-!;+>mwsOYx+|LtDSVPZJ3^K00dh#eE8G{NimV$OYeDWEmg?)#bZrthck zf0FX8@;K|>n*rweFN3bwe_-g_^JCHZ^k25sA3n}AKK1HD}wzAEVwo|8W zxO#!R1|pXXS&UAwknjs3)ko~7Dh3AdV9Z|u$#{$}@k&Hd{KHUZE0cyQ_J>cA~2CmV!6 za!8(M0S=Lc@U~32m|{4yVAndnUSQf@x1wR=UfE^S#3H1m1ZK|dJ#i%@Ls-}_@l%S= ziF0m`S~w^CtkmQN-o6Z4qbOwd0_X_fkO7HH2C=V51Z5SV4Dy0U6wcsT{rKen_VD9O z3_#HQXRZ3i%_>X_nHike86ac}9|MOhgMby3Ea22z)UNG1<1MfQ#lYa{>gTe~DWM4f DR*=M! diff --git a/BiogasControllerApp-V2.3/bin/gui/gui.kv b/BiogasControllerApp-V2.3/bin/gui/gui.kv deleted file mode 100644 index c567359..0000000 --- a/BiogasControllerApp-V2.3/bin/gui/gui.kv +++ /dev/null @@ -1,694 +0,0 @@ -RootScreen: - HomeScreen: - ReadoutScreen: - ReadData: - ProgramTemp: - Program: - Credits: - Modify: - -: - title: "NOTICE" - size_hint: 0.7, 0.5 - auto_dismiss: True - GridLayout: - cols:1 - Label: - text: "THIS SOFTWARE IS FREE SOFTWARE LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE V3 (GPL V3) AND AS SUCH COMES WITH ABSOLUTELY NO WARRANTY! \n\nmore info under Settings > Credits" - text_size: self.width, None - GridLayout: - cols: 2 - Button: - text: "Don't show anymore" - on_release: - root.notshowanymore() - Button: - text: "ok" - on_release: - root.dismiss() -: - title: "BiogasControllerApp" - font_size: 50 - size_hint: 0.5, 0.4 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Are you sure you want to leave?" - font_size: 20 - GridLayout: - cols:2 - Button: - text: "Yes" - font_size: 15 - on_release: - root.quitapp() - app.stop() - Button: - text: "No" - font_size: 15 - on_press: - root.dismiss() - -: - title: "WARNING!" - font_size: 50 - size_hint: 0.5, 0.4 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Unable to open Serial Port" - font_size: 20 - GridLayout: - cols:2 - Button: - text: "Details" - on_release: - root.details() - Button: - text:"Ok" - on_release: - root.dismiss() - -: - title: "WARNING!" - font_size: 50 - size_hint: 0.7, 0.6 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Unable to communicate" - font_size: 20 - Label: - text: "Possible ways to resolve this problem:\n- Try again\n- Restart the PIC16F877 or reset the program\n- Check the cable / connect one" - font_size: 14 - Button: - text:"Ok" - on_release: - root.dismiss() - -: - on_open: self.update_details = root.infos() - title: "DETAILS" - font_size: 50 - size_hint: 1, 0.7 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Unable to open Serial Port" - font_size: 20 - Label: - id: errormessage - text: root.infos() - font_size: 13 - Label: - text: root.error_tips() - font_size: 13 - Button: - text:"Ok" - on_release: - root.dismiss() - -: - title: "NOTICE!" - font_size: 50 - size_hint: 0.5, 0.4 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Mode Switched!" - font_size: 30 - Button: - text:"Ok" - on_release: - root.dismiss() - -: - title: "NOTICE!" - font_size: 50 - size_hint: 0.5, 0.4 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "SAVED!" - font_size: 30 - Button: - text:"Ok" - on_release: - root.dismiss() - -: - title: "NOTICE!" - font_size: 50 - size_hint: 0.5, 0.4 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Establishing connection with PIC16F877" - font_size: 18 - Label: - text: "This Process may take a while..." - font_size: 15 - Button: - text:"Ok" - on_release: - root.dismiss() - -: - title: "WARNING!" - font_size: 50 - size_hint: 0.5, 0.4 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Missing Information!" - font_size: 18 - Label: - text: "Check your entry" - font_size: 15 - Button: - text:"Ok" - on_release: - root.dismiss() - -: - title: "NOTICE!" - font_size: 50 - size_hint: 0.5, 0.4 - auto_dismiss: False - GridLayout: - cols:1 - Label: - text: "Connection with PIC16F877 terminated" - font_size: 18 - Label: - text: "The connection to the Microcontroller\nhas been terminated successfully" - font_size: 15 - Button: - text:"Ok" - on_release: - root.dismiss() - -###################################### -# SCREENS -###################################### -: - name: "HomeS" - canvas.before: - Color: - rgba: (50,50,50,0.2) - Rectangle: - size: self.size - pos: self.pos - GridLayout: - cols:1 - Label: - text: "BiogasanlageControllerApp" - font_size: 50 - color: (0, 113, 0, 1) - bold:True - italic:True - FloatLayout: - GridLayout: - cols: 2 - size_hint: 0.8, 0.8 - pos_hint: {"x": 0.1, "y": 0.1} - Button: - text: "Start" - background_color: (255, 0, 0, 0.6) - font_size: 30 - on_release: - root.tryconnection() - Button: - text: "Quit" - background_color: (255, 0, 0, 0.6) - font_size: 30 - on_release: - root.exitapp() - Label: - text: root.reset() - id: app_version - font_size: 13 - pos_hint: {"y": -0.45, "x":0.05} - Button: - text: "Settings" - font_size: 13 - size_hint: 0.07, 0.06 - pos_hint: {"x":0.01, "y":0.01} - background_color: (50, 0, 0, 0.2) - on_release: - app.root.current = "Settings" - root.manager.transition.direction = "down" - -: - on_pre_enter: self.reset_screen = root.resscreen() - name: "Readout" - canvas.before: - Color: - rgba: (50,50,50,0.2) - Rectangle: - size: self.size - pos: self.pos - GridLayout: - FloatLayout: - Label: - pos_hint: {"y":0.4} - text: "READOUT" - font_size: 40 - color: (0, 113, 0, 1) - bold: True - GridLayout: - cols:4 - size_hint: 0.8, 0.3 - pos_hint: {"x":0.1, "y":0.4} - Label: - text: "SENSOR 1: " - font_size: 20 - Label: - id: sonde1 - text: "" - Label: - text: "SENSOR 2: " - font_size: 20 - Label: - id: sonde2 - text: "" - Label: - text: "SENSOR 3: " - font_size: 20 - Label: - id: sonde3 - text: "" - Label: - text: "SENSOR 4: " - font_size: 20 - Label: - id: sonde4 - text: "" - Button: - text: "Start communication" - size_hint: 0.2, 0.1 - pos_hint: {"x": 0.5, "y": 0.05} - background_color: (255, 0, 0, 0.6) - on_release: - root.start_com() - Button: - text: "End communication" - size_hint: 0.2, 0.1 - pos_hint: {"x": 0.7, "y": 0.05} - background_color: (255, 0, 0, 0.6) - on_release: - root.end_com() - Button: - text: "Back" - size_hint: 0.3, 0.1 - pos_hint: {"x":0.05, "y":0.05} - background_color: (255, 0, 0, 0.6) - on_release: - root.leave_screen() - app.root.current = "HomeS" - root.manager.transition.direction = "left" - ToggleButton: - id: mode_sel - size_hint: 0.15, 0.1 - pos_hint: {"x":0.1, "y":0.2} - text: "Normal Mode" if self.state == "normal" else "Fast Mode" - on_text: root.switch_mode(mode_sel.text) - background_color: (255,0,0,0.6) if self.state == "normal" else (0,0,255,0.6) - Button: - text: "Read Data" - size_hint: 0.15, 0.1 - pos_hint: {"x":0.3, "y":0.2} - background_color: (255, 0, 0, 0.6) - on_release: - root.leave_screen() - app.root.current = "RD" - root.manager.transition.direction = "down" - Button: - text: "Temperature" - size_hint: 0.15, 0.1 - pos_hint: {"x":0.5, "y":0.2} - background_color: (255, 0, 0, 0.6) - on_release: - root.leave_screen() - app.root.current = "PT" - root.manager.transition.direction = "down" - Button: - text: "Change all Data" - size_hint: 0.15, 0.1 - pos_hint: {"x":0.7, "y":0.2} - background_color: (255, 0, 0, 0.6) - on_release: - root.leave_screen() - app.root.current = "PR" - root.manager.transition.direction = "down" - Label: - id: frequency - text: "Frequency will appear here" - font_size: 10 - pos_hint: {"x":0.4, "y": 0.3} - -: - name: "RD" - canvas.before: - Color: - rgba: (50,50,50,0.2) - Rectangle: - size: self.size - pos: self.pos - GridLayout: - FloatLayout: - Label: - text: "Read Data" - font_size: 40 - color: (0, 113, 0, 1) - bold: True - pos_hint: {"y":0.4} - Button: - text: "Start Readout" - size_hint: 0.2, 0.1 - pos_hint: {"x":0.4, "y":0.1} - on_release: - root.read_data() - Button: - text: "Back" - size_hint: 0.2, 0.1 - pos_hint: {"x":0.1, "y":0.1} - background_color: (255, 0, 0, 0.6) - on_release: - app.root.current = "Readout" - root.manager.transition.direction = "up" - GridLayout: - cols:4 - size_hint: 0.8, 0.4 - pos_hint: {"x":0.1, "y":0.3} - Label: - text: "Sonde 1" - font_size: 20 - Label: - id: inf_sonde1 - text: "" - Label: - text: "Sonde 2" - font_size: 20 - Label: - id: inf_sonde2 - text: "" - Label: - text: "Sonde 3" - font_size: 20 - Label: - id: inf_sonde3 - text: "" - Label: - text: "Sonde 4" - font_size: 20 - Label: - id: inf_sonde4 - text: "" - -: - on_pre_enter: self.check_config = root.read_config() - name: "PT" - canvas.before: - Color: - rgba: (50,50,50,0.2) - Rectangle: - size: self.size - pos: self.pos - FloatLayout: - Label: - text: "Change Temperature" - pos_hint: {"y":0.4} - font_size: 40 - color: (0, 113, 0, 1) - bold: True - GridLayout: - size_hint: 0.8, 0.4 - pos_hint: {"x": 0.1, "y":0.3} - cols:2 - Label: - text: "Temperature Sensor 1: " - TextInput: - id: temp_s1 - multiline: False - input_filter: "float" - Label: - text: "Temperature Sensor 2: " - TextInput: - id: temp_s2 - multiline: False - input_filter: "float" - Label: - text: "Temperature Sensor 3: " - TextInput: - id: temp_s3 - multiline: False - input_filter: "float" - Label: - text: "Temperature Sensor 4: " - TextInput: - id: temp_s4 - multiline: False - input_filter: "float" - Button: - text: "Back" - size_hint: 0.1, 0.1 - pos_hint: {"x":0.1, "y":0.1} - background_color: (255, 0, 0, 0.6) - on_release: - app.root.current = "Readout" - root.manager.transition.direction = "up" - ToggleButton: - id: prsel - size_hint: 0.2, 0.1 - pos_hint: {"x":0.35, "y": 0.1} - text: "Full\nreprogramming" if self.state == "normal" else "Partial\nreprogramming" - on_release: root.change_mode() - background_color: (255,0,0,0.6) if self.state == "normal" else (0,0,255,0.6) - Button: - text: "Save" - size_hint: 0.2, 0.1 - pos_hint: {"x":0.6, "y":0.1} - background_color: (255, 0, 0, 0.6) - on_release: - root.send_data() - -: - name: "PR" - on_pre_enter: self.check_config = root.read_config() - canvas.before: - Color: - rgba: (50,50,50,0.2) - Rectangle: - size: self.size - pos: self.pos - FloatLayout: - Label: - text: "Change all Data" - font_size: 40 - color: (0, 113, 0, 1) - bold: True - pos_hint: {"y":0.4} - GridLayout: - size_hint: 0.8, 0.5 - pos_hint: {"x":0.1, "y":0.2} - cols: 4 - Label: - text: "Sensor 1, a:" - TextInput: - id: s1_a - multiline: False - input_filter: "float" - Label: - text: "Sensor 1, b:" - TextInput: - id: s1_b - multiline: False - input_filter: "float" - Label: - text: "Sensor 1, c:" - TextInput: - id: s1_c - multiline: False - input_filter: "float" - Label: - text: "Sensor 1, Temp:" - TextInput: - id: s1_t - multiline: False - input_filter: "float" - Label: - text: "Sensor 2, a:" - TextInput: - id: s2_a - multiline: False - input_filter: "float" - Label: - text: "Sensor 2, b:" - TextInput: - id: s2_b - multiline: False - input_filter: "float" - Label: - text: "Sensor 2, c:" - TextInput: - id: s2_c - multiline: False - input_filter: "float" - Label: - text: "Sensor 2, Temp:" - TextInput: - id: s2_t - multiline: False - input_filter: "float" - Label: - text: "Sensor 3, a:" - TextInput: - id: s3_a - multiline: False - input_filter: "float" - Label: - text: "Sensor 3, b:" - TextInput: - id: s3_b - multiline: False - input_filter: "float" - Label: - text: "Sensor 3, c:" - TextInput: - id: s3_c - multiline: False - input_filter: "float" - Label: - text: "Sensor 3, Temp:" - TextInput: - id: s3_t - multiline: False - input_filter: "float" - Label: - text: "Sensor 4, a:" - TextInput: - id: s4_a - multiline: False - input_filter: "float" - Label: - text: "Sensor 4, b:" - TextInput: - id: s4_b - multiline: False - input_filter: "float" - Label: - text: "Sensor 4, c:" - TextInput: - id: s4_c - multiline: False - input_filter: "float" - Label: - text: "Sensor 4, Temp:" - TextInput: - id: s4_t - multiline: False - input_filter: "float" - Button: - text: "Back" - size_hint: 0.1, 0.1 - pos_hint: {"x":0.1, "y":0.1} - background_color: (255, 0, 0, 0.6) - on_release: - app.root.current = "Readout" - root.manager.transition.direction = "up" - ToggleButton: - id: prsel - size_hint: 0.2, 0.1 - pos_hint: {"x":0.35, "y": 0.1} - text: "Full\nreprogramming" if self.state == "normal" else "Partial\nreprogramming" - on_release: root.change_mode() - background_color: (255,0,0,0.6) if self.state == "normal" else (0,0,255,0.6) - Button: - text: "Save" - size_hint: 0.2, 0.1 - pos_hint: {"x":0.6, "y":0.1} - background_color: (255, 0, 0, 0.6) - on_release: - root.send_data() - - -: - name: "Credits" - canvas.before: - Color: - rgba: (50,50,50,0.2) - Rectangle: - size: self.size - pos: self.pos - FloatLayout: - Button: - text: "back" - size_hint: 0.4, 0.2 - pos_hint: {"x":0.3, "y":0.1} - on_release: - app.root.current = "Settings" - root.manager.transition.direction = "right" - GridLayout: - cols:1 - pos_hint:{"x":0.05, "y":0.35} - size_hint: 0.9, 0.5 - Label: - text: "This is a rework of the BiogasControllerApp V1, that was originally programmed by S. Reichmuth." - Label: - text: "Written by: Janis Hutz\nDesigned by: Janis Hutz\nDesign language: Kivy" - Label: - text: "This software is free Software licensed under the GPL V3 (GNU General Public License) and as such comes with absolutely no warranty. In return, you can use, modify, distribute or use any of the code of this software in your own project, if you reuse the same license. For more infos, you can find a copy of this license in the project folder." - text_size: self.width, None - -: - on_pre_enter: self.config = root.read_config() - name: "Settings" - canvas.before: - Color: - rgba: (50,50,50,0.2) - Rectangle: - size: self.size - pos: self.pos - GridLayout: - cols: 1 - Label: - text: "Settings" - font_size: 40 - color: (0, 113, 0, 1) - bold: True - FloatLayout: - GridLayout: - pos_hint: {"x":0.05, "y":0.05} - size_hint: 0.9, 0.9 - cols: 4 - Button: - text: "Back" - background_color: (255,0,0,0.6) - on_release: - app.root.current = "HomeS" - root.manager.transition.direction = "up" - Button: - text: "Report a\nBug" - background_color: (255,0,0,0.6) - on_release: - root.issue_reporting() - ToggleButton: - id: prsel - text: "Full\nreprogramming" if self.state == "normal" else "Partial\nreprogramming" - on_release: root.change_programming() - background_color: (255,0,0,0.6) if self.state == "normal" else (0,0,255,0.6) - Button: - text: "Credits" - background_color: (255,0,0,0.6) - on_release: - app.root.current = "Credits" - root.manager.transition.direction = "left" diff --git a/BiogasControllerApp-V2.3/bin/lib/communication.py b/BiogasControllerApp-V2.3/bin/lib/communication.py deleted file mode 100644 index 6bfce41..0000000 --- a/BiogasControllerApp-V2.3/bin/lib/communication.py +++ /dev/null @@ -1,96 +0,0 @@ -import bin.lib.lib -com = bin.lib.lib.Com() - - -class Communication: - def __init__(self): - self.__x = 0 - self.__data_recieve = 0 - self.__output = "" - - def change_temp(self, data, special_port): - com.connect(19200, special_port) - com.send("PT") - self.go = 0 - while True: - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "P": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "T": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.go = 1 - break - else: - pass - else: - pass - else: - pass - else: - pass - if self.go == 1: - self.data = data - while len(self.data) > 0: - self.__data_recieve = com.receive(3) - if self.__data_recieve != "": - com.send_float(float(self.data.pop(0))) - else: - print("error") - break - else: - print("Error") - com.quitcom() - - def change_all(self, data, special_port): - com.connect(19200, special_port) - com.send("PR") - self.go = 0 - while True: - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "P": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "R": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.go = 1 - break - else: - pass - else: - pass - else: - pass - else: - pass - if self.go == 1: - self.data = data - while len(self.data) > 0: - self.__data_recieve = com.receive(3) - if self.__data_recieve != "": - com.send_float(float(self.data.pop(0))) - else: - print("error") - break - else: - print("Error") - com.quitcom() - - -class SwitchMode: - def __init__(self): - pass - - def enable_fastmode(self, special_port): - com.connect(19200, special_port) - com.send("FM") - com.quitcom() - - def disable_fastmode(self, special_port): - com.connect(19200, special_port) - com.send("NM") - com.quitcom() diff --git a/BiogasControllerApp-V2.3/bin/lib/comport_search.py b/BiogasControllerApp-V2.3/bin/lib/comport_search.py deleted file mode 100644 index cadd619..0000000 --- a/BiogasControllerApp-V2.3/bin/lib/comport_search.py +++ /dev/null @@ -1,22 +0,0 @@ -import serial.tools.list_ports - - -class ComportService: - def __init__(self): - self.__comport = [] - self.__import = [] - self.__working = [] - - def get_comport(self, special_port): - self.__comport = [comport.device for comport in serial.tools.list_ports.comports()] - self.__pos = 0 - if special_port != "": - self.__working = special_port - else: - while self.__working == []: - self.__com_name = serial.tools.list_ports.comports()[self.__pos] - if "USB-Serial Controller" or "Prolific USB-Serial Controller" in self.__com_name: - self.__working = self.__comport.pop(self.__pos) - else: - self.__pos += 1 - return self.__working diff --git a/BiogasControllerApp-V2.3/bin/lib/csv_parsers.py b/BiogasControllerApp-V2.3/bin/lib/csv_parsers.py deleted file mode 100644 index d1f593c..0000000 --- a/BiogasControllerApp-V2.3/bin/lib/csv_parsers.py +++ /dev/null @@ -1,122 +0,0 @@ -"""@package docstring -This is a simplification of the csv module""" - -import csv - - -class CsvRead: - """This is a class that reads csv files and depending on the module selected does do different things with it""" - def __init__(self): - self.__imp = "" - self.__raw = "" - self.__raw_list = "" - - def importing(self, path): - """Returns a list of the imported csv-file, requires path, either direct system path or relative path""" - self.__imp = open(path) - self.__raw = csv.reader(self.__imp, delimiter=',') - self.__raw_list = list(self.__raw) - self.__imp.close() - return self.__raw_list - - -class CsvWrite: - """This is a class that modifies csv files""" - def __init__(self): - self.__impl = [] - self.__strpop = [] - self.__removed = [] - self.__removing = 0 - self.__change = 0 - self.__appending = 0 - self.__imp = [] - self.__raw = [] - - def rem_str(self, path, row): - """Opens the csv-file in write mode which is specified as an argument either as direct or relative path""" - self.__imp = open(path) - self.__raw = csv.reader(self.__imp, delimiter=',') - self.__impl = list(self.__raw) - self.__removed = self.__impl.pop(row + 1) - with open(path, "w") as removedata: - self.__removing = csv.writer(removedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__removing.writerow(self.__impl.pop(0)) - while len(self.__impl) > 0: - with open(path, "a") as removedata: - self.__removing = csv.writer(removedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__removing.writerow(self.__impl.pop(0)) - self.__imp.close() - removedata.close() - - - def chg_str(self, path, row, pos, new_value): - """Opens the csv-file in write mode to change a value, e.g. if a recipes is changed.""" - self.__imp = open(path) - self.__raw = csv.reader(self.__imp, delimiter=',') - self.__impl = list(self.__raw) - self.__strpop = self.__impl.pop(row) - self.__strpop.pop(pos) - self.__strpop.insert(pos, new_value) - self.__impl.insert(row, self.__strpop) - with open(path, "w") as changedata: - self.__change = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__change.writerow(self.__impl.pop(0)) - while len(self.__impl) > 0: - with open(path, "a") as changedata: - self.__removing = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__removing.writerow(self.__impl.pop(0)) - self.__imp.close() - changedata.close() - - def chg_str_rem(self, path, row, pos): - """Opens the csv-file in write mode to change a value, e.g. if a recipes is changed.""" - self.__imp = open(path) - self.__raw = csv.reader(self.__imp, delimiter=',') - self.__impl = list(self.__raw) - self.__strpop = self.__impl.pop(row) - self.__strpop.pop(pos) - self.__strpop.pop(pos) - self.__impl.insert(row, self.__strpop) - with open(path, "w") as changedata: - self.__change = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__change.writerow(self.__impl.pop(0)) - while len(self.__impl) > 0: - with open(path, "a") as changedata: - self.__removing = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__removing.writerow(self.__impl.pop(0)) - self.__imp.close() - changedata.close() - - def chg_str_add(self, path, row, new_value1, new_value2): - """Opens the csv-file in write mode to change a value, e.g. if a recipes is changed.""" - self.__imp = open(path) - self.__raw = csv.reader(self.__imp, delimiter=',') - self.__impl = list(self.__raw) - self.__strpop = self.__impl.pop(row) - self.__strpop.append(new_value1) - self.__strpop.append(new_value2) - self.__impl.insert(row, self.__strpop) - with open(path, "w") as changedata: - self.__change = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__change.writerow(self.__impl.pop(0)) - while len(self.__impl) > 0: - with open(path, "a") as changedata: - self.__removing = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__removing.writerow(self.__impl.pop(0)) - self.__imp.close() - changedata.close() - - def app_str(self, path, value): - """Opens the csv-file in append mode and writes given input. CsvWrite.app_str(path, value). - Path can be specified both as direct or relative. value is a list. Will return an error if type of value is - not a list.""" - with open(path, "a") as appenddata: - self.__appending = csv.writer(appenddata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__appending.writerow(value) - appenddata.close() - - def write_str(self, path, value): - with open(path, "w") as writedata: - self.__change = csv.writer(writedata, delimiter=',', quoting=csv.QUOTE_MINIMAL) - self.__change.writerow(value) - writedata.close() diff --git a/BiogasControllerApp-V2.3/bin/lib/lib.py b/BiogasControllerApp-V2.3/bin/lib/lib.py deleted file mode 100644 index 52aa379..0000000 --- a/BiogasControllerApp-V2.3/bin/lib/lib.py +++ /dev/null @@ -1,73 +0,0 @@ -import serial -import struct -import bin.lib.comport_search -"""@package docstring -This package can communicate with a microcontroller""" - -coms = bin.lib.comport_search.ComportService() - - -class Com: - def __init__(self): - self.xr = "" - self.output = "" - self.str_input = "" - self.str_get_input = "" - self.xs = "" - self.__comport = '/dev/ttyUSB0' - - def connect(self, baudrate, special_port): - try: - self.__comport = coms.get_comport(special_port) - except: - pass - self.ser = serial.Serial(self.__comport, baudrate=baudrate, timeout=5) - - def quitcom(self): - try: - self.ser.close() - except: - pass - - def receive(self, amount_bytes): - self.xr = self.ser.read(amount_bytes) - return self.xr - - def decode_ascii(self, value): - try: - self.output = value.decode() - except: - self.output = "Error" - return self.output - - def check_value(self, value_check, checked_value): - if value_check == checked_value: - return 1 - else: - return 0 - - def decode_int(self, value): - self.i = int(value, base=16) - return self.i - - def decode_float(self, value): - self.fs = str(value, 'ascii') + '00' - self.f = struct.unpack('>f', bytes.fromhex(self.fs)) - return str(self.f[0]) - - def decode_float_2(self, value): - self.fs = str(value, 'ascii') + '0000' - self.f = struct.unpack('>f', bytes.fromhex(self.fs)) - return str(self.f[0]) - - def get_input(self): - self.str_get_input = input("please enter a character to send: ") - return self.str_get_input - - def send(self, str_input): - self.xs = str_input.encode() - self.ser.write(self.xs) - - def send_float(self, float_input): - ba = bytearray(struct.pack('>f', float_input)) - self.ser.write(ba[0:3]) diff --git a/BiogasControllerApp-V2.3/biogascontrollerapp.py b/BiogasControllerApp-V2.3/biogascontrollerapp.py deleted file mode 100644 index 57b2ccf..0000000 --- a/BiogasControllerApp-V2.3/biogascontrollerapp.py +++ /dev/null @@ -1,893 +0,0 @@ -import os -import configparser -import serial - -config = configparser.ConfigParser() -config.read('./config/settings.ini') -co = config['Dev Settings']['verbose'] -if co == "True": - pass -else: - os.environ["KIVY_NO_CONSOLELOG"] = "1" - -import threading -import platform -import webbrowser -from kivy.uix.screenmanager import Screen, ScreenManager -from kivy.core.window import Window -from kivy.uix.popup import Popup -from kivy.app import App -from kivy.lang import Builder -from kivy.clock import mainthread, Clock -import bin.lib.lib -import bin.lib.communication -import bin.lib.comport_search -import bin.lib.csv_parsers -import logging -import datetime -import time - -version_app = f"{config['Info']['version']}{config['Info']['subVersion']}" - -################################################################ -# LOGGER SETUP -################## -logging.basicConfig(level=logging.DEBUG, filename="./log/main_log.log", filemode="w") -logs = f"./log/{datetime.datetime.now()}-log-main.log" -logger = logging.getLogger(__name__) -handler = logging.FileHandler(logs) -formatter = logging.Formatter("%(levelname)s - %(asctime)s - %(name)s: %(message)s -- %(lineno)d") -handler.setFormatter(formatter) -logger.addHandler(handler) - -logger.setLevel(config['Dev Settings']['log_level']) -logger.info(f"Logger initialized, app is running Version: {version_app}") -################################################################# - -if config['Port Settings']['specificPort'] == "None" or "\"\"": - special_port = "" -else: - special_port = config['Port Settings']['specificPort'] -cvr = bin.lib.csv_parsers.CsvRead() -cvw = bin.lib.csv_parsers.CsvWrite() -com = bin.lib.lib.Com() - - -################################################################# -# Settings Handler -######################### -class SettingsHandler: - def __init__(self): - self.ports = None - self.window_sizeh = 600 - self.window_sizew = 800 - - def settingshandler(self): - self.ports = config['Port Settings']['specificPort'] - self.window_sizeh = config['UI Config']['sizeH'] - self.window_sizew = config['UI Config']['sizeW'] - Window.size = (int(self.window_sizew), int(self.window_sizeh)) - - -################################################################# - - -logger.info("Started modules") - - -################################################################## -# Popups -################################################################## - - -class QuitPU(Popup): - def quitapp(self): - com.quitcom() - logger.debug("App stopped") - - -class NoConnection(Popup): - def details(self): - self.detailsinfo = DetailInfo() - self.detailsinfo.open() - - -class DetailInfo(Popup): - update_details = "" - def infos(self): - self.err = "" - try: - com.connect(19200, special_port) - com.quitcom() - except Exception as err: - self.err += "Errormessage:\n" - self.err += str(err) - self.err += "\n-------------------------------------------------------------------------------------------------------------------------------------------------------------\n" - return str(self.err) - - def error_tips(self): - self.err_tip = "" - try: - com.connect(19200, special_port) - com.quitcom() - except Exception as err: - self.err_tip += "Possible way to resolve the issue: \n\n" - if str(err)[0:10] == "[Errno 13]": - if platform.system() == "Linux": - self.err_tip += f"Open a terminal and type in: sudo chmod 777 {bin.lib.comport_search.ComportService().get_comport(special_port)}" - elif platform.system() == "Macintosh": - self.err_tip += "Give permission to access the cable" - elif platform.system() == "Windows": - self.err_tip += "Try a different cable or install another driver" - else: - self.err_tip += "Unknown OS" - elif str(err)[0:10] == "[Errno 2] ": - if platform.system() == "Linux": - self.err_tip += "Connect a cable, open a terminal and type in: sudo chmod 777 /dev/ttyUSB0" - elif platform.system() == "Macintosh": - self.err_tip += "Give permission to access the cable" - elif platform.system() == "Windows": - self.err_tip += "Try a different cable or install another driver" - else: - self.err_tip += "Unknown OS" - elif str(err)[0:34] == "could not open port '/dev/ttyUSB0'": - self.err_tip += "Please connect the PC with the microcontroller!" - elif str(err)[0:26] == f"could not open port '{bin.lib.comport_search.ComportService().get_comport(special_port)}'": - self.err_tip += "Try using a different cable or close all monitoring software (like MSI Afterburner)" - else: - self.err_tip += "Special Error, consult the manual of Serial" - return str(self.err_tip) - - -class Modeswitch(Popup): - pass - - -class Connecting_PU(Popup): - pass - - -class Disconnecting_PU(Popup): - pass - - -class MissingFieldsError(Popup): - pass - - -class ConnectionFail(Popup): - pass - - -class SaveConf(Popup): - pass - - -class InfoPU(Popup): - def notshowanymore(self): - config.set("License", "show", "0") - with open("./config/settings.ini", "w") as configfile: - config.write(configfile) - self.dismiss() - - -#################################################################### -# SCREENS -#################################################################### -class HomeScreen(Screen): - def reset(self): - logger.info("HomeScreen initialised") - SettingsHandler().settingshandler() - self.connected = 1 - self.info = f"You are currently running Version {version_app} - If you encounter a bug, please report it!" - try: - com.connect(19200, special_port) - com.quitcom() - except Exception as e: - self.connected = 0 - logger.error(e) - return self.info - - def openlicensepu(self): - self.licensepu = InfoPU() - self.licensepu.open() - - def tryconnection(self): - if config["License"]["show"] == "1": - self.openlicensepu() - logger.info("Showing License info") - else: - pass - try: - com.connect(19200, special_port) - com.quitcom() - self.connected = 1 - self.manager.current = "Readout" - self.manager.transition.direction = "right" - except Exception as ex: - if config['Dev Settings']['disableConnectionCheck'] == "True": - self.connected = 1 - self.manager.current = "Readout" - self.manager.transition.direction = "right" - else: - self.connected = 0 - logger.error(f"COM_error: {ex}") - self.open_popup() - - def open_popup(self): - self.popups = NoConnection() - self.popups.open() - - def exitapp(self): - self.pup = QuitPU() - self.pup.open() - - -class ReadoutScreen(Screen): - go = 1 - - def start_com(self): - self.comstart(1) - logger.info("Trying to start COM") - - def comstart(self, pu_on): - try: - com.connect(19200, special_port) - self.go = 1 - except Exception as e: - self.go = 0 - logger.error(f"COM_error: {e}") - - if self.go == 1: - logger.debug("COM start success") - self.parent.current = "Readout" - if pu_on == 1: - self.openstartpu() - else: - pass - self.communication = threading.Thread(name="communication", target=self.start_coms) - self.communication.start() - else: - self.openconnectionfailpu() - - def end_com(self): - self.stopcom(1) - - def stopcom(self, pu_on): - self.go = 0 - try: - self.communication.join() - except Exception as e: - logger.warning(f"COM_Close_Error: {e}") - if pu_on == 1: - self.openendpu() - else: - pass - - def start_coms(self): - self.check = 1 - self.__level = 0 - self.__distance = 0 - self.__x = "" - self.__begin = time.time() - self.go = 1 - logger.info("Starting COM_Hook") - while self.__x != "\n": - if time.time() - self.__begin > 5: - self.go = 0 - break - else: - self.__x = com.decode_ascii(com.receive(1)) - - if self.go == 1: - logger.info("COM_Hook 1 success") - while self.__level < 3: - self.__x = com.decode_ascii(com.receive(1)) - if self.__x == " ": - if self.__distance == 4: - self.__level += 1 - else: - pass - self.__distance = 0 - else: - if self.__distance > 4: - self.__level = 0 - self.__distance = 0 - else: - self.__distance += 1 - self.check = 1 - logger.info("COM_Hook successful") - com.receive(5) - else: - self.check = 0 - - while self.go == 1: - self.__starttime = time.time() - self.__output = "" - self.__data_recieve = com.receive(68) - self.__output += "Tadc: " - self.__output += str(com.decode_int(self.__data_recieve[0:4])) - self.__output += "\nTemperatur: " - self.__output += com.decode_float(self.__data_recieve[5:11]) - self.__output += f"\nDuty-Cycle: {(float(com.decode_float_2(self.__data_recieve[48:52])) / 65535) * 100}%" - self.change_screen(1, self.__output) - self.__output = "Tadc: " - self.__output += str(com.decode_int(self.__data_recieve[12:16])) - self.__output += "\nTemperatur: " - self.__output += com.decode_float(self.__data_recieve[17:23]) - self.__output += f"\nDuty-Cycle: {(float(com.decode_float_2(self.__data_recieve[53:57])) / 65535) * 100}%" - self.change_screen(2, self.__output) - self.__output = "Tadc: " - self.__output += str(com.decode_int(self.__data_recieve[24:28])) - self.__output += "\nTemperatur: " - self.__output += com.decode_float(self.__data_recieve[29:35]) - self.__output += f"\nDuty-Cycle: {(float(com.decode_float_2(self.__data_recieve[58:62])) / 65535) * 100}%" - self.change_screen(3, self.__output) - self.__output = "Tadc: " - self.__output += str(com.decode_int(self.__data_recieve[36:40])) - self.__output += "\nTemperatur: " - self.__output += com.decode_float(self.__data_recieve[41:47]) - self.__output += "\nDuty-Cycle: " - self.__output += f"\nDuty-Cycle: {(float(com.decode_float_2(self.__data_recieve[63:67])) / 65535) * 100}%" - self.change_screen(4, self.__output) - self.change_screen(5, f"F={1 / (time.time() - self.__starttime)}") - self.change_screen(6, "") - com.quitcom() - - def switch_mode(self, text): - self.go = 0 - try: - self.communication.join() - com.quitcom() - self.com_ok = 1 - logger.info("Mode_Switch successful") - except Exception as e: - if e == serial.SerialException: - logger.info("No running process found, continuing") - else: - logger.fatal(f"FATAL ERROR OCCURED, APP WILL LEAVE NOW: {e}") - self.com_ok = 0 - - if self.com_ok == 1: - if text == "Normal Mode": - bin.lib.communication.SwitchMode().disable_fastmode(special_port) - else: - bin.lib.communication.SwitchMode().enable_fastmode(special_port) - logger.info("Switched mode, restarting COM") - self.openpupups() - self.comstart(0) - logger.info("COM restarted successfully") - else: - self.check = 1 - self.ids.mode_sel.state = "normal" - self.openconnectionfailpu() - - @mainthread - def change_screen(self, pos, value): - if pos == 1: - self.ids.sonde1.text = value - elif pos == 2: - self.ids.sonde2.text = value - elif pos == 3: - self.ids.sonde3.text = value - elif pos == 4: - self.ids.sonde4.text = value - elif pos == 6: - logger.error("COM_fail") - self.openconnectionfailpu() - else: - self.ids.frequency.text = value - - def openpupups(self): - self.popup = Modeswitch() - self.popup.open() - - def openendpu(self): - self.pu = Disconnecting_PU() - self.pu.open() - - def openstartpu(self): - self.pup = Connecting_PU() - self.pup.open() - - def openconnectionfailpu(self): - if self.check == 0: - self.cfpu = ConnectionFail() - self.cfpu.open() - else: - pass - - def leave_screen(self): - logger.info("Stopping COM") - self.stopcom(0) - - def resscreen(self): - logger.info("Screen reset") - self.ids.sonde1.text = "" - self.ids.sonde2.text = "" - self.ids.sonde3.text = "" - self.ids.sonde4.text = "" - self.ids.frequency.text = "" - - -class Program(Screen): - def read_config(self): - logger.debug("Reading config") - self.config_imp = [] - self.__export = [] - self.config_imp = cvr.importing("./config/config.csv") - self.__export = self.config_imp.pop(0) - self.__extracted = self.__export.pop(0) - logger.debug(f"config {self.__extracted}") - if self.__extracted == "1": - self.ids.prsel.state = "normal" - self.ids.s1_a.text = "" - self.ids.s1_b.text = "" - self.ids.s1_c.text = "" - self.ids.s1_t.text = "" - self.ids.s2_a.text = "" - self.ids.s2_b.text = "" - self.ids.s2_c.text = "" - self.ids.s2_t.text = "" - self.ids.s3_a.text = "" - self.ids.s3_b.text = "" - self.ids.s3_c.text = "" - self.ids.s3_t.text = "" - self.ids.s4_a.text = "" - self.ids.s4_b.text = "" - self.ids.s4_c.text = "" - self.ids.s4_t.text = "" - self.__mode = 1 - else: - self.ids.prsel.state = "down" - Clock.schedule_once(self.read_data, 1) - self.__mode = 2 - - def change_mode(self): - logger.info("Changing mode") - logger.debug(f"mode was: {self.__mode}") - if self.__mode == 1: - logger.debug("Sending instruction to read info") - Clock.schedule_once(self.read_data, 1) - self.__mode = 2 - else: - self.ids.s1_a.text = "" - self.ids.s1_b.text = "" - self.ids.s1_c.text = "" - self.ids.s1_t.text = "" - self.ids.s2_a.text = "" - self.ids.s2_b.text = "" - self.ids.s2_c.text = "" - self.ids.s2_t.text = "" - self.ids.s3_a.text = "" - self.ids.s3_b.text = "" - self.ids.s3_c.text = "" - self.ids.s3_t.text = "" - self.ids.s4_a.text = "" - self.ids.s4_b.text = "" - self.ids.s4_c.text = "" - self.ids.s4_t.text = "" - self.__mode = 1 - - def read_data(self, dt): - logger.debug("Starting to read data from the microcontroller") - try: - com.connect(19200, special_port) - self.go = 1 - except Exception as e: - self.go = 0 - logger.error(f"COM_error: {e}") - - if self.go == 1: - logger.info("Sending instructions") - com.send("RD") - self.__pos = 1 - self.__beginning = time.time() - logger.info("Awaiting confirmation from the microcontroller for hook") - while True: - if time.time() - self.__beginning < 5: - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "R": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "D": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.go = 1 - logger.info("Hook successful") - break - else: - pass - else: - pass - else: - pass - else: - pass - else: - self.go = 0 - logger.error("Microcontroller not available, stopping connection") - break - if self.go == 1: - for i in range(4): - self.__x = com.receive(28) - self.__a = str(com.decode_float(self.__x[0:6])) - self.__b = str(com.decode_float(self.__x[7:13])) - self.__c = str(com.decode_float(self.__x[14:20])) - self.__temp = str(com.decode_float(self.__x[21:27])) - if self.__pos == 1: - self.ids.s1_a.text = self.__a - self.ids.s1_b.text = self.__b - self.ids.s1_c.text = self.__c - self.ids.s1_t.text = self.__temp - elif self.__pos == 2: - self.ids.s2_a.text = self.__a - self.ids.s2_b.text = self.__b - self.ids.s2_c.text = self.__c - self.ids.s2_t.text = self.__temp - elif self.__pos == 3: - self.ids.s3_a.text = self.__a - self.ids.s3_b.text = self.__b - self.ids.s3_c.text = self.__c - self.ids.s3_t.text = self.__temp - elif self.__pos == 4: - self.ids.s4_a.text = self.__a - self.ids.s4_b.text = self.__b - self.ids.s4_c.text = self.__c - self.ids.s4_t.text = self.__temp - self.__pos += 1 - logger.info("Recieved info from microcontroller") - else: - self.open_confail_pu() - com.quitcom() - else: - self.open_confail_pu() - - def create_com(self): - self.coms = bin.lib.communication.Communication() - - def send_data(self): - try: - self.create_com() - self.go = 1 - except Exception as e: - self.go = 0 - logger.critical(f"TRANSMISSION_Error: {e}") - - if self.go == 1: - logger.info("Preparing data to be sent") - self.__transmit = [] - if self.ids.s1_a.text != "" and self.ids.s1_b.text != "" and self.ids.s1_c.text != "" and self.ids.s1_t.text != "" and self.ids.s2_a.text != "" and self.ids.s2_b.text != "" and self.ids.s2_c.text != "" and self.ids.s2_t.text != "" and self.ids.s3_a.text != "" and self.ids.s3_b.text != "" and self.ids.s3_c.text != "" and self.ids.s3_t.text != "" and self.ids.s4_a.text != "" and self.ids.s4_b.text != "" and self.ids.s4_c.text != "" and self.ids.s4_t.text != "": - self.__transmit.append(self.ids.s1_a.text) - self.__transmit.append(self.ids.s1_b.text) - self.__transmit.append(self.ids.s1_c.text) - self.__transmit.append(self.ids.s1_t.text) - self.__transmit.append(self.ids.s2_a.text) - self.__transmit.append(self.ids.s2_b.text) - self.__transmit.append(self.ids.s2_c.text) - self.__transmit.append(self.ids.s2_t.text) - self.__transmit.append(self.ids.s3_a.text) - self.__transmit.append(self.ids.s3_b.text) - self.__transmit.append(self.ids.s3_c.text) - self.__transmit.append(self.ids.s3_t.text) - self.__transmit.append(self.ids.s4_a.text) - self.__transmit.append(self.ids.s4_b.text) - self.__transmit.append(self.ids.s4_c.text) - self.__transmit.append(self.ids.s4_t.text) - logger.debug("trying to send...") - try: - self.coms.change_all(self.__transmit, special_port) - logger.info("Transmission successful") - logger.debug("purging fields...") - self.ids.s1_a.text = "" - self.ids.s1_b.text = "" - self.ids.s1_c.text = "" - self.ids.s1_t.text = "" - self.ids.s2_a.text = "" - self.ids.s2_b.text = "" - self.ids.s2_c.text = "" - self.ids.s2_t.text = "" - self.ids.s3_a.text = "" - self.ids.s3_b.text = "" - self.ids.s3_c.text = "" - self.ids.s3_t.text = "" - self.ids.s4_a.text = "" - self.ids.s4_b.text = "" - self.ids.s4_c.text = "" - self.ids.s4_t.text = "" - self.openconfpu() - except Exception as e: - self.open_confail_pu() - logger.critical(f"TRANSMITION_Error: {e}") - else: - self.openerrorpu() - else: - self.open_confail_pu() - - def openerrorpu(self): - self.pu = MissingFieldsError() - self.pu.open() - - def open_confail_pu(self): - self.cfpu = ConnectionFail() - self.cfpu.open() - - def openconfpu(self): - self.confpus = SaveConf() - self.confpus.open() - - -class ProgramTemp(Screen): - def read_config(self): - logger.debug("Reading config") - self.config_imp = [] - self.__export = [] - self.config_imp = cvr.importing("./config/config.csv") - self.__export = self.config_imp.pop(0) - self.__extracted = self.__export.pop(0) - logger.debug(f"Mode set is: {self.__extracted}") - if self.__extracted == "1": - self.ids.prsel.state = "normal" - self.ids.temp_s1.text = "" - self.ids.temp_s2.text = "" - self.ids.temp_s3.text = "" - self.ids.temp_s4.text = "" - self.__mode = 1 - else: - self.ids.prsel.state = "down" - Clock.schedule_once(self.read_data, 1) - self.__mode = 2 - - def change_mode(self): - logger.info("Changing mode") - logger.debug(f"Mode was: {self.__mode}") - if self.__mode == 1: - logger.info("starting sub-thread") - Clock.schedule_once(self.read_data, 1) - self.__mode = 2 - else: - logger.info("clearing screen") - self.ids.temp_s1.text = "" - self.ids.temp_s2.text = "" - self.ids.temp_s3.text = "" - self.ids.temp_s4.text = "" - self.__mode = 1 - - def read_data(self, dt): - logger.info("Trying to establish connection...") - try: - com.connect(19200, special_port) - self.go = 1 - except Exception as e: - self.go = 0 - logger.error(f"COM_Error: {e}") - - if self.go == 1: - logger.info("Sending instructions to microcontroller...") - com.send("RD") - self.__pos = 1 - self.__beginning = time.time() - self.go = 1 - logger.info("Awaiting confirmation from the microcontroller for hook") - while True: - if time.time() - self.__beginning < 5: - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "R": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "D": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.go = 1 - logger.info("Hook successful") - break - else: - pass - else: - pass - else: - pass - else: - pass - else: - self.go = 0 - logger.error("Microcontroller not available, stopping connection") - break - if self.go == 1: - logger.info("Receiving data...") - for i in range(4): - self.__x = com.receive(28) - self.__output = str(com.decode_float(self.__x[21:27])) - if self.__pos == 1: - self.ids.temp_s1.text = self.__output - elif self.__pos == 2: - self.ids.temp_s2.text = self.__output - elif self.__pos == 3: - self.ids.temp_s3.text = self.__output - elif self.__pos == 4: - self.ids.temp_s4.text = self.__output - self.__pos += 1 - logger.info("Recieved data") - com.quitcom() - else: - self.open_confail_pu() - - def create_com(self): - self.coms = bin.lib.communication.Communication() - - def send_data(self): - try: - self.create_com() - self.go = 1 - except Exception as e: - self.go = 0 - logger.critical(f"COM_Error: Microcontroller unavailable: {e}") - - if self.go == 1: - logger.info("Preparing transmission...") - self.__transmit = [] - if self.ids.temp_s1.text != "" and self.ids.temp_s2.text != "" and self.ids.temp_s3.text != "" and self.ids.temp_s4.text != "": - self.__transmit.append(self.ids.temp_s1.text) - self.__transmit.append(self.ids.temp_s2.text) - self.__transmit.append(self.ids.temp_s3.text) - self.__transmit.append(self.ids.temp_s4.text) - logger.debug("Transmitting...") - self.coms.change_temp(self.__transmit, special_port) - self.ids.temp_s1.text = "" - self.ids.temp_s2.text = "" - self.ids.temp_s3.text = "" - self.ids.temp_s4.text = "" - self.openconfpu() - else: - self.openerrorpu() - logger.debug("Missing fields") - else: - self.open_confail_pu() - - def openerrorpu(self): - self.pu = MissingFieldsError() - self.pu.open() - - def openconfpu(self): - self.confpu = SaveConf() - self.confpu.open() - - def open_confail_pu(self): - self.cfpu = ConnectionFail() - self.cfpu.open() - - -class ReadData(Screen): - def read_data(self): - logger.info("Trying to connect to the microcontroller") - try: - com.connect(19200, special_port) - self.go = 1 - except Exception as e: - self.go = 0 - logger.error(f"COM_Error: {e}") - - if self.go == 1: - logger.info("Sending instructions to the microcontroller...") - com.send("RD") - self.__pos = 1 - self.__beginning = time.time() - self.go = 1 - logger.info("Awaiting confirmation from the microcontroller for hook") - while True: - if time.time() - self.__beginning < 5: - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "R": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "D": - self.__data_recieve = com.decode_ascii(com.receive(1)) - if self.__data_recieve == "\n": - self.go = 1 - logger.info("Hook successful") - break - else: - pass - else: - pass - else: - pass - else: - pass - else: - self.go = 0 - logger.error("Microcontroller not available, stopping connection") - break - if self.go == 1: - logger.info("Receiving data") - for i in range(4): - self.__x = com.receive(28) - self.__output = "a: " - self.__output += str(com.decode_float(self.__x[0:6])) - self.__output += f"\nb: {str(com.decode_float(self.__x[7:13]))}" - self.__output += f"\nc: {str(com.decode_float(self.__x[14:20]))}" - self.__output += f"\nTemp: {str(com.decode_float(self.__x[21:27]))}" - if self.__pos == 1: - self.ids.inf_sonde1.text = self.__output - elif self.__pos == 2: - self.ids.inf_sonde2.text = self.__output - elif self.__pos == 3: - self.ids.inf_sonde3.text = self.__output - elif self.__pos == 4: - self.ids.inf_sonde4.text = self.__output - self.__pos += 1 - logger.info("Received data") - else: - self.open_confail_pu() - com.quitcom() - else: - self.open_confail_pu() - - def open_confail_pu(self): - self.cfpu = ConnectionFail() - self.cfpu.open() - - -class Credits(Screen): - pass - - -class Modify(Screen): - def read_config(self): - logger.debug("Reading config") - self.config_imp = [] - self.__export = [] - self.config_imp = cvr.importing("./config/config.csv") - self.__export = self.config_imp.pop(0) - self.__extracted = self.__export.pop(0) - logger.debug(f"Mode at: {self.__extracted}") - if self.__extracted == "1": - self.ids.prsel.state = "normal" - else: - self.ids.prsel.state = "down" - - def issue_reporting(self): - logger.info("Clicked error reporting button") - webbrowser.open("https://github.com/simplePCBuilding/BiogasControllerApp/issues", new=2) - - def change_programming(self): - logger.info("Switching programming mode") - self.csv_import = [] - self.csv_import = cvr.importing("./config/config.csv") - self.csv_import.pop(0) - if self.ids.prsel.text == "Full\nreprogramming": - self.csv_import.insert(0, 1) - else: - self.csv_import.insert(0, 2) - logger.debug(f"Mode now: {self.csv_import}") - cvw.write_str("./config/config.csv", self.csv_import) - - -######################################################## -# Screenmanager -######################################################## - - -class RootScreen(ScreenManager): - pass - - -class BiogasControllerApp(App): - def build(self): - self.icon = "./BiogasControllerAppLogo.png" - self.title = "BiogasControllerApp" - return Builder.load_file("./bin/gui/gui.kv") - - -logger.info("Init finished, starting UI") - -try: - if __name__ == "__main__": - bga = BiogasControllerApp() - bga.run() - -except Exception as e: - logger.critical(e, exc_info=True) diff --git a/BiogasControllerApp-V2.3/config/config.csv b/BiogasControllerApp-V2.3/config/config.csv deleted file mode 100644 index 0cfbf08..0000000 --- a/BiogasControllerApp-V2.3/config/config.csv +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/BiogasControllerApp-V2.3/config/settings.ini b/BiogasControllerApp-V2.3/config/settings.ini deleted file mode 100644 index 89889cd..0000000 --- a/BiogasControllerApp-V2.3/config/settings.ini +++ /dev/null @@ -1,19 +0,0 @@ -[Port Settings] -specificport = None - -[UI Config] -sizeh = 600 -sizew = 800 - -[Dev Settings] -verbose = False -log_level = DEBUG -disableconnectioncheck = False - -[License] -show = 1 - -[Info] -version = V2.3.0 -subversion = - diff --git a/BiogasControllerApp-V2.3/log/logging.md b/BiogasControllerApp-V2.3/log/logging.md deleted file mode 100644 index ee2d608..0000000 --- a/BiogasControllerApp-V2.3/log/logging.md +++ /dev/null @@ -1,5 +0,0 @@ -What is getting logged? -Generally this app logs how and when you interact with the app and sometimes, which values you enter. -No logs are being sent to anybody automatically, you can choose to attach the log file to the bug report. -This helps the devs a lot, as they can better understand the state of the app as it crashed. The logs are -all found in this folder here. \ No newline at end of file diff --git a/biogascontrollerapp/biogascontrollerapp.py b/biogascontrollerapp/biogascontrollerapp.py new file mode 100644 index 0000000..e69de29