From a6d4b1192c9bc2b8c1506b6972c9cfb8c29d6f01 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 5 Jan 2021 13:53:01 +0000 Subject: [PATCH] Added data processor code --- data_processor/data_processor.py | 147 ++++++++++++++++++ .../watering_model.model/saved_model.pb | Bin 0 -> 227928 bytes .../variables/variables.data-00000-of-00001 | Bin 0 -> 8311 bytes .../variables/variables.index | Bin 0 -> 1779 bytes lora_nodes/master/irrigator/irrigator.py | 2 +- 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 data_processor/watering_model.model/saved_model.pb create mode 100644 data_processor/watering_model.model/variables/variables.data-00000-of-00001 create mode 100644 data_processor/watering_model.model/variables/variables.index diff --git a/data_processor/data_processor.py b/data_processor/data_processor.py index e69de29..3b9a345 100644 --- a/data_processor/data_processor.py +++ b/data_processor/data_processor.py @@ -0,0 +1,147 @@ +#!/usr/local/bin/python +import logging +import time + +import firebase_admin +import numpy as np +import pandas as pd +import tensorflow as tf +from firebase_admin import credentials, firestore +from Flask import Flask +from tensorflow import keras + + +class Firebase: + def __init__(self): + self.creds = credentials.Certificate( + 'secrets/icl-iot-weather-firebase-adminsdk.json') + firebase_admin.initialize_app(self.creds) + self.db = firestore.client() + logging.debug('Initialized firebase instance') + + def pull_from_db(self, last_n=24, orderby=u'timestamp'): + doc_ref = self.db.collection('weather_data') + query = doc_ref.order_by( + orderby, direction=firestore.Query.DESCENDING).limit(last_n) + doc = query.stream() + logging.debug('Got doc file from firestore') + return doc + + def convert_to_df(self, data): + doc_elements = [] + for element in data: + doc_elements.append(element) + dict_dataset = [] + for element in doc_elements: + dict_dataset.append(element.to_dict()) + df = pd.DataFrame(dict_dataset) + logging.debug(f'Acquired dataframe, length: {len(df)}') + return df + + def get_day_df(self): + doc = self.pull_from_db() + df = self.convert_to_df(doc) + return df + + +class DataProcessor: + def __init__(self): + self.dataset_mean = [82.02044198895028, 10.402061304914362, + 8.634944751381251, 67.74198895027624, + 3.7384419889503326, 0.1401436464088398] + self.dataset_std = [9.125022051705823, 2.9134906109549754, + 4.024228079173571, 32.40531138722004, + 1.9577510487361403, 0.7008829473121821] + self.arranged_columns = [ + 'humidity', 'local_soil_temperature', + 'temp', 'cloud', 'wind', 'rain_1h'] + + def drop_useless(self, df): + clean_df = df.drop(columns=['datetime', 'is_test', + 'local_soil_humidity', 'timestamp']) + return clean_df + + def normalize(self, df): + df = df[self.arranged_columns] + normalized_df = (df - self.dataset_mean)/self.dataset_std + return normalized_df + + def correct(self, df, orig_df): + df['rain_1h'] = orig_df['rain_1h'] + df['cloud'] = orig_df['cloud']/100 - 0.5 + return df + + def calculate_avg(self, df): + total_daily_rain = df['rain_1h'].sum() + df = df.drop(columns=['rain_1h']) + day_avg = df.mean() + day_avg['rain_24h'] = total_daily_rain + day_avg_dict = day_avg.to_dict() + columns = day_avg_dict.keys() + rows = [day_avg_dict.values()] + day_avg_df = pd.DataFrame(data=rows, columns=columns) + return day_avg_df + + def prepare_for_prediction(self, data): + clean_df = self.drop_useless(data) + normalized_df = self.normalize(clean_df) + corrected_df = self.correct(normalized_df, clean_df) + daily_avg_df = self.calculate_avg(corrected_df) + return daily_avg_df + + +class WaterPredictor: + __PLANT_AREA_M2 = 1 + __WATER_ML_PER_M2 = 500 + + def __init__(self): + self.firebase = Firebase() + self.data_processor = DataProcessor() + self.model = keras.models.load_model('watering_model.model') + logging.debug('Loaded ML model') + + def bias_to_pct(self, bias): + offset_pct = bias[0][0]*100 + if offset_pct > 100: + offset_pct = 100 + if offset_pct < -100: + offset_pct = -100 + return offset_pct + + def calculate_predicted_volume(self, offset_pct): + baseline_volume = self.__PLANT_AREA_M2*self.__WATER_ML_PER_M2 + total_water_ml_day = baseline_volume + offset_pct*(baseline_volume/100) + return total_water_ml_day + + def predict_water_ml(self): + df = self.firebase.get_day_df() + feature_df = self.data_processor.prepare_for_prediction(df) + features = {name: np.array(value) + for name, value in feature_df.items()} + day_pred_bias = self.model.predict(features) + offset_pct = self.bias_to_pct(day_pred_bias) + predicted_watering_vol = self.calculate_predicted_volume(offset_pct) + logging.debug(f'Predicted watering volume: {predicted_watering_vol}') + return predicted_watering_vol + + +if __name__ == "__main__": + logging.root.setLevel(logging.DEBUG) + predictor = WaterPredictor() + + server = Flask(__name__) + + @server.route("/") + def root(): + return "

IoT-ICL DE Watering Predictor running...

" + + @server.route("/water") + def get_water_vol(): + try: + vol = predictor.predict_water_ml() + return {'success': True, 'value': vol} + except Exception as e: + logging.error(f'Encountered error: {e}') + return {'success': False, 'error': e} + + server.run(host='0.0.0.0', port='3535', use_reloader=False) diff --git a/data_processor/watering_model.model/saved_model.pb b/data_processor/watering_model.model/saved_model.pb new file mode 100644 index 0000000000000000000000000000000000000000..fa63d8e8e21a0684067f7b84fb98398c3d550871 GIT binary patch literal 227928 zcmeFa3y>Vibr?9+^XZ z6FuF-?w$caiV`JL6mKa}5>K)uTB5AAB~!E{Q?h)LWu45^Ib>O+BF+k#_DOLU3Wa3F zUHBBV!f_$TT^#RaRb^FXRc2OJcMTRxHW=KguF8Dx<;%?XUcP+!GGmy3^j{~?zuIm7 z_-=Fw?Yh`**X}l6ue55F+x6-P&TGe)QtF>00nKmcU@OGuXRh=7N?>yS9&P^ca z!5kt#KW!N3yHWa5tpN9oO0bA4;gX6Al0)@fB5 z?agMpTCSKwx0}s6PMsN;<38NxK6vaON65-d?tu;%&6uc)%&XPb-RkSs<$Kk&`)q1s4EjR1y<@H*t z?IAbFXaQcn+Pt=juA-sqm9_i99^*N}_L0H%(UjA#cK_kj%mBKK#;(^ZYt?&zwb}}I z5I=0^rqOWwUS+dtI)Cs`DK%rD_oB(wYGqwE7jX1kcn%G%R_j~l1j^j0RytcSkw~ZQ zLSvP+PHo%f6?rpv$Qy5^-Dt|1aAv{i5k zo?HI-nZw8}AsEF?Gz!2w%@%Yu48{?sQ=vYRQxl!4$J9!%IvhkEFjrDT7URxt? z@otoM%C)T#TPU<)&bUt|s@K|`GekC=g^6W%c^!@1sBCwM&5Vof8NdbuaIFKKFuK-k ztk=i@ok3&Im*_zlnqz|9+E zM6&XfXsg@RyS2vL@Ri1T^&zl%u-aIszjmQC(Ip_a+&8i@Ft-=E031c-DgbzmZ1Clc zO8dSie1N$bz!G>l1DvSWYn$y_JN%_leNZNfDe&bWnQx%%?h8JmR}muZZrptdL^BNT z5u0H!AwkhGOiR!4Qgc5VZC5udtqODrWg>=dM1RjfV<75Ygt<-hJ{f7g-UkIjCQqkQ zYgD;va|h5E8JyL1TS~AH14?fWIs;02LU!&rnu2lKd;nF~tJ_4FnB%sza1{JmoI(RI zM&^dw)z)@3J8WH8xRAH@Zrgv)=g;3QE?aBM>(>0@+U;e-{E5F9L!UFy!FKf{TST>1 z>gC1Ui?wyovxVG!7&29u6HEiM`_N?B8Chg{Z36lslqwBm$EZn@${X1|lxS4Sn5oPN z{C_I@6yN52DBWI#V+Ak2;3 zYxbHZu|boDL1Sdk@w4fWslbW;I|E&ilcdEN1$f1XacJd6%%=@BBcdgl0b^v(@{GZz z6dU?p13e`pMT;p?(2CJw@T27p8ojt)*~rzvc!@1#M+q!PcM=7K`KFJVK4?@%hdn%6 zZS(8uD8y0pVKinVxLt)Mc_DUFY_|AKIm9<*!eoJ?H8jiM(rOM{U#CF^-ymxz8)Wef zvf?(#(reH?glw*@SJx_!dTq}^zJtb11~#goBR(dr)-bj88uJjDHi~++(rSRQTL#0m z+H0eZ^NpG|1vtRxaw?2jtC0d|dX2q>hC9tpr5ihy6A=6O_N7e+EP6jWV8hpHg;PhH z@U`Yvqtk20gbBC762k2VJ;LpxdW7Ew-v!}#?~-hW=lQ5f0fYDEpo>F`d|FSt0d{kD zq5&>o(g62SuK{jhy$1XP1I^j(yMn7es#b^?>c%y+% zVP-k2PtMHxNdp~~(?*P~u9z2E)fITg&6$x{(T^HvA&N9DrbVJsm|;`A8KxR-bY;{P z!vdqtSwiWLHXpZgwE4xf7$+TVJ{-kp6D$K&qs?7@bu(21qb;4)A8iz?aC+5$_&FBs@pcm{Cm#3Tlrv--058G77|MvZ>LK*dM`wYV0IOfk{~%SZ4=I<`Nj z7F^aPCDx2=o@d%IGYTpCVFS%eS>_O?#jq$uicuC=TB>9k^?c^G-$o6(t(0j#iCTP< z$}}I2Vx)DaLAzmIK&DN_kZA?mtCrhV$~0O?i)m7sMxiK1TQ?fC8-^vNLDi$p(|p@n zjFXNwAC6+Qb*DkQVP0Ugb)iAkqs`TQdQ6j!HVQ>C+Pcu7-S8_g*t*rA+gch_k86<{ zbXzgfy3(NCFfK6A;%m@t4GpTtum}yhtr%qi4GLjFBnSlph)5{P=bv)pdQ2z0XKo_r z>`#_1Uw^HX*ICx4v;Y1a4FUSwF%~WK!m| z{iFP#*11=HP_5m)*J;C-G5F#Z18X=lNPk#RXGmCw6dR(&=AqcIuo&2h@WlnafF@v1 zbF{hHscqCgT5X|yK&e^2y;Xx~9eYFB*&9U%G8uDkt9o~<4v}FWb%K2A&33!m1_-0( z=(Za$)<*j?$lL=_NDvAH0c2(W!$bx=)vys;X_qUTH8hz4XCjF;bK+vqLo}V4Fn5*R zK$-Gdv%a;_XhXS46P4*!bQ>s{l2fvarvw7X#FUsUCEzg4>@i22Jz|u}OhbqgESv$; zUOA?HJf{6JOfxK|Re*Uw4iob*56WO3Vqp^M4>Qys@u;7bV>-%XIwr$37sPa&!F0mI zbW)D#6p!h&4AU7F(=Qp&4QI_EvReYp%bFw3b^|=0bDu3Vnt93`ww>H)cjmk~!MTWW z8oJcjn0Y@uOp}KXz{6qk@E!1Qggm?f568*F2jSradH6f<0JXMfJ_HX?YkTGvJV34O znKC>;t?ilbga@d#JyU@PsI@(F8x6q!vS^sp&BGt4S%5!K&w@WtYaaeUodx&%je$i%mrvT5hmr0Dnx^nE<vlL|AU9*ZNU%$9|<>IAR zo-4n8@s-z}Q-*fnMUm)scYt#jF5bMkdganSt6`OJwhC=Dkr=Ukp;MJF4iCLO80t)vcn#bw`zBh6_iPyB<^^aYhx$HX`XjwiWDA z#{RbZ=MvjLx{3%Qx0(KVR@FZejWwHr8LN_2yED%R`{$0i9-54bFbHAySQ?Z5w)veQ zJkrPlVeeRuV<573K-ZAo0bS$t4*T2gofp{N(N*3k^CHtbS5&0cAG#nXUC5Wn zS)`<-%UL95i^eQc64TWz5|5V1S)?T7A=*ohqmW3%_3E9KD_H^jz z0i10u?Ka0U-=zNxJG`5X<;fnRLB67*=wl?Fn#X)^Yoi9|*&xW1IqbM2$RV=)R1kZ; zxdwrA?PjfB?o>B6!LdsYIPN?x0!9#TbJ<$BxAVv!py?nVNaNoY#1CqX$1v{xdPsi8 zP*JEM7gx?aTDUVZOg(FUNphj5Fb+xG62~rn8cE58-a~GPl z#tr-5wEZtT;U3f+MuV1NWDleLWVeJIa;e##G8l}(Tz<-*GHqJ?19(uVWFtuj66%13FM9*w&U9mZY7&dRZQBWXhv_#($f z*J;99-31TgZUX4!E%QunVc3AYWv+QFt|jd?kB{Pd(q5yMdUt#jBa7gpxRMjpkUirl zmt$zwI-GX2%c%2*|8JVtHt8sBBNNX@mCA+ashCRTG*K#Zt4GlhR;iG!%{4etPBci_ z$}cP}qCZW`#lNL5{zbZ<4n3jncgB~{)}Vt(Sg#kG0W+>~&bQ6{urTXc7I}tUN2lX% z#h%YFO+9@&uD581m=p@-4mhf$P^ehK8g89PXN!~)+P}GNIVDt#U?~)@JqjpPJVdu= z+tsDg!02tT`0VT+Fg2`0X~$+1{`X0p+F3HSPp%$E$3#;bLV-xO8kpV1#U=Bn{tTfX z9z}m*po?r_CsMrZ_*`L~TDNo7w5qT~ZGf@trh$R=s}sZoz~<){N%|W%i-uv&p(BuP zYGbQz+r%`Csk!MH#*hu`IGQE9@Rjv-c_ETW19FVm$)09N0-U#ueV3pTB*?OLfuHr^ zEn}~frX>?B+eI+rGCj!0S! zT?dH;DH~iAKWHEc-$Go7>J;tBKx;;Z6T_i$FV7i$z`Gn;OKwW8QXU@>cXbaO8TIhu zABQk0FOQh_gm<|(OHDf?0Z_63mY58@@0PH`y67la9#T@~4*MhC+)dwl)MPK92{yK{ zZ5~Dk!_KiZ$-zbbZ{=m3U`hsrbwM(6P4P4;UCRuZFC)!CnMOy^ba@NhK;`ykb**-% zMw8!UOm`ljPmIA??`K(owBBlNLVuJO^<`3FrMS4l%A}Ae!E0#31)RG~Qqj2~t2!~N zMi#Of*%Q+ozl2~WuQ|WW3GOHM znrVXxHFHo`pz(((tW$c_;4S14@B(;fAS&{?k8D-yxko+r_aA=kYflpyM_IxH$BuQqI`Q|Qaf!S8=zE9I3#<%g zP3AaacsW1MieZwi&oL9rg&BkSWpTgexnB$1uOj@~jVA6n>B+$HxwNzZ_GIAIBKxXH zN-gKZuPk^4xf&g1ZxBQ`uL{@(Gjq|As;Huz?lnXN}LM3pgIP7z3e?%-qXDI zwBS7zv%B5AiYQ}^IDQm7 zzdVSdMxoqAb6O4D(TF6G{&l^S}0iH42+Nn_-|9_fU7|uy<%YEn4y_;CIX(J3)VpebMY6wsUj7}@~JW>?KH0o=(KPZ4gb@6JhLSI_-9Em z&MaBXFZi=W+70*@LFuUVqP(ZvDI*2$_ZO$~G5c%j@${ClGrjc^nN-iMUhd7KS6Eq` z&l3%#?g;!f1Bpxw&-EK=VuajJytYyJ+``!itY>;827@D%-{_?h*o}G(H^&@tEHC_A zPnKHPr4^Bv7W_IfDaHR(mM>P&IL;rUa1yWyf(BuC%k_y&Uozp)ElFvcn#&BpKLh@6 zqrDSr>wHFj} zE}RELBIoppk;yp)1f`r))C;Ug3fP+Z`97-DCaH0UwS0~YL!PPFT zi<89dkkh;c61oF%Krf-^S&>@4XK$?(%g)LS!gIWhhH~2$sj(tP-FW>JA`Dko!futr8#}0ohGy3d_{eu-HxWBqeXC6R5+eS;hYf8eS4ws?P#?B znmCe8bmT_HI6II+XjcnsMA*eLr%Mbocz@6ehAlojo=t4C=~LOG&4j-6-y7)XN0JGR zSXnHP-~%@t!afQMp$&V`l>3GrQH7Vs&|&wb_~a;8j~?rTms4oWtw&B;axchXK6sHu zryO-(fWvPQA-m_$Xf^+387QkuAVj?-L!x0l6$fiPBCWTDNQ=0u=At=ia(A5K;c~o6Z7R4{>kU&G6-=^*!K_JV(deZ#%%XvkVc6lk8hFUwg}Bc-f=v5HYB7tUpkYH(YzK~_#Mvb;Hl7h}|7^+Bw9iK~Runykb>W}smF zs5j#|sgvtnF`U&#h5wTwZvaP@s~#?B^^)JKd0BZ5c+S`FF_naZ{~QMV6}aIif)-y@ z1f?#PHk(7@HQSfc+8bUF3>!fn{>NdVEneF4Dnz{u_DNOg;;`ISVJ6I83A9F1ULX<@ zvWy3;clAI7{?`V2SJzEQP!T=d6B#`=BRM72Q!_05dxI#rSkM_z0RVqE+iAtjRo%9FKXvX46)}VN+V&5WzBzdXjk^ zObrV9)u&CRb;HXzTHk>#TE=-LxDmDE%QzKU(b`B=K0)mn?oc)2*rX<>A!Cv%T*iqT z7tn&iWt>+jp!b5>(kmwzS>B`zE#p+RSlt#}#wqJ1uFb;B2r+)qGR`Z>iJ=5ER(KgF zLnT_qiOWisab97rZ~a~kF5|rNfi`r?Qb!ysD51!?iMOHk^DmT|$Vj%$`{ zL`=V5co`SOfjjg#x`gmpxC^vY0TxKj44 zh2f^p0n^V+@BK)!fH0wDxF;AVXaN&saDj+K^nDTUfN|xZ6JCd$2Sd8 zOqP!Z|I{Gb8_+sy_GdE#M-73R*DV~}#pS|G{6P?m?F#NY`Xz&laJBc#uNTA+T=V!P zgOM?;5hX9h_K#mGXel}Tv3toYMAxAszSh;$`y(VFsjvs|&l^Y`#~3<4p&2l$I3FQM z-T>}FWi%x@G&;$bFllp=3>_PFZlh1P_`xF(bl8L+sRzsZ|8Y z1X3eH;toodIC2#KoPnkSMNBUf>kR$kgq1QGSx?a~VzA-k-P)Yo9ij(sqH&6DwOZdY zhsb}iN1RK7*UPcz#1zRm$YQ_`(0)JF56$%l0xFr@pa-PT$sF7p#(b3~Prxjdr3$&K z#J)wo4Y@0hhU?iB_rez9XAbaUjxU{M} zyfKN-hAXmYddp}^GUtVcFAE<34CKQO7h%$zGAX~@ayb@2G6_%p}IdsKV)J6T%n{lJg58P3Ia8Q3pa4hJzp*if1@T zs35CjS4-0pp5bsX%qzQXHX~iDfmTY&YDoK50|m`k4YIQ$Azr#xL*#)Oh1FnR^|ao3 zv{@y24?J-E0xl5DSxFt$sk}u&8{{38Yn6ZD7uaO)JVd=qx#($Z3 zGQJ&I==HPoDURUDvR4VKa4QpqP2JDZ=j?k+yj=Y(eH(P4`OePLClP=#4u=P?1lkdU zRV)DYsqClkt5;gJk3!b_$0z`W-DBhLr|)wwCJ?d+M9WU5DV5{=cFY9wOM`x*Ip*3D zYMcf=rjTlnIu<1+?-8$nFvEZcz*|=Z>|0C$&{bjhJ8#4WzaOT_0LA!)DNBU5k}zdS zKNa9^b1dWU;@Q~@1g~VN03ijRdH|Ub->vsV?E0AMO(Bv5Q0=pz6v#%XPl05JQVJxW zNqyxIHr1c4cdHlfrgB*?Ng=2|1BB^t^s7to3#GDf1`6@(S1-K=m(RUV_wqRdosy(5 zoHX4uBsqK6x%2@@WO!2_>{$ue-KHC~o1?qbr8}9Fd0QXyk_7Us=^i%8iFdW31%t`9 zfbN2qZf1te>-sG?DQUrk=?1;!$gVj+9ZnW1*=0xH7)PH@p{Ll~hg_mV=89924sm6v zxNMH1VS5ljZX~#?igq0Q!f2nE*-lByAo!I*L!?p86Cnhi#!z~zalg@g(0~i3CeWz+ zqf9QPVty9*pX7cj=IcEF6Ry1yq%GPn%f0(ogGlyGex-)P4D2xiOPGK&lmXaoJRTwq z$F$MdZ?OMZ@EaYB#r9 zYgOmU%{E+Qmcb(<>C7k^i+kD7b#gJs%d1zCNgcMdFmJ)ujI5_2Ym0Yl9b*U{m6Z3q z;dthjq)2Q(`L|fsV@t|x>C`E`3d-pveMvbhk(6oEnS-VGfmXVz4{uHa51HO%E|ozY zeNZ1{UIKE)lt=}jc`zZGsdy<}1qF0PpXMVHnnz4qP64>#guvM<=f5qWpHJxOM403| zesy9Ye05?We08D~zBVx#;X&L`CGdZktWV>r*Hg<>+2h@{p%HLcgt|w zcc*C{HV>jS8oYe{wOw#EI2wEb9tNz`O9RWs_Zb7(q_0<8Sg@YR>lF(N^y0VzF-8mh z>lLeQU_?>xdc_|ZgkwZr+>d0^OSLubU$^)OZe?Gq)azxq%^OVL&Q_~YUTZeiYn@uN zQK^?n+IXi!7FR5C04j>v_{+UqyO@oH@7t~JwQ=@!N>-lEBIjrS`bE3bp496Xts;B< zqP5h&ei208lW_fFVL=gsB#7V_?`!JYQ?h+c1q9`_WQux$ZH92%`jJpFReHmL-EhgZ zWD1P^z>aDixb9sf;@()^zkU%irLZnZ)g|xtUaD+gQ#kg%MFKk{*UaiKwL;N@yuF~1 zbAo_lv7FNeL{;KPj!7FG6U*HkvYN_nFvqwLS1}($bnT`3W>`~>$dqndCYOvRHFQ_<4~{r%?=oGZS< zF`3Kl#|}+3r(x6F24HZ$qh z1XEu@MjHj12r`mOZ>1!|!kz#uQCVa-u4V7z_Vo3hfiq8xUCgy;1?0b<+DF=wWZf;?t^PtmIM` zOk8+Dt_?9|cpJ@lU$|+QK*BsMhmF4kIY`8aT|qYMedRdr^ZJ-qAV9ZQB&IlHnZ$v_ zKW?C1L2SNI3yTu$6VCzSD2plD%rFV~Ga!1zh8-{LqRc=&(FgKJh0MM*Q&NEI!i1Ak z!_A)hSn)3y=qdf;35v`M@$kkaG&yk^k5CK$=M*}j!_k1KJt?UZ5WMq}VuBIn%`RNj zufz)FIMost(Wmsdh(8DCcqGl^WK9C{`;0Co{O52_st!@EY(Fn4%XO;Xosv^Nu)Wu2 zFJbj6#FYDT&T|OxAA)@)A>1wK>x3wYi)Ad}P;xDbsV~4PQWHyTW4hqy)rGIn=yyE@ z0k$!%-~hC3WA7E$y9p}+&`l~lwmGUQkf5Lk#;Y+!6O)`Uk0Qpgjm7i^1onQfR6s_Aid{2@5kA8!{aD`yivW>|=sL?2rnJnuz3tmx>4rew zs|Ed!$7MxWK_xGgxR9C_wG}tev`r^BBNGr#`^0eZ=M9$(4xuZQ4u)CgNgI4vM5p&T zrZA$+;HbdgZ=i7&i!X%uS&tn;xyl?RF%2z9qs*cuf`{ym@FtZ{0{Nybczi%a@Yuh0 zSn$Yj*mGX?FA?Yk)fQxYrmx_N2dfD8by>jOR~0ldfbRwaIBntPB6U|k>fiUjsC)ARgD zyjG<*ASXb=t)LU6^g1L5Sk-UEX-O-lOwV3%^3%KySppJLmIth^t_uW5_Yf zGNhx)m#zGKaS>8TJkOpGDc`HD!%Z%Q^8IS7QLV#4P47@mx&4u?N~>xoFxiG2iIv;+ zYID=eVj|2I^E3-vb^1gYX^X!ij)uq4SmSw?)+*VgW zuRzG}qq)NB*vg zq-Y7`QdDqep&u#QX@Rw|UT)WGYgNY`%nGZ1r06>-QWR2;Dk4Q08S=P7M7PyJn_=l@ z=}EVKFz8li(?3=Tp5T&gi}AM&?W31Q2duStF_wjXFetDZZhP$qgMxlwv_(G{bYrvH zvJXQ(?qJa0j1dg#i+$@!i2DQ+mu?vFK?**d^Lk34AMoj#xE?>b=}C>be!wRyv?y0R zhgw8rXyPFaY%C+!U;ThjYR052mPuTc2PP)2H{RV({!*QhA&)E4bCnIy3>&lyda|q^ z<{4ar_QO0KtFs^GX@`^0Xe&G9hLfAVB!3KHo)7@d#aoI*&%#c}c!J2WLyYYBzOcwC zYKt5nNE$TfgWTI7%QPe$LPCxq_aaBQT?6jkD7TxndYKrQu2&C=`1RA0V>v+}UkE^k!Y_f2x(Po6oF7ufxroz$Vro1NWfVv%#6*8=^Vop~cGUu37Oeh6nj zgfr-zVRmupMgnhvy0Hia-GYe+EwIsvyr}Kx>|||YulsnZNNnTaCqJmc%Z^i~Wgb@~ zXFq3WFV?CmU8WOR6%O5VXL6#c^W<3iIXkQUoSkfBRX=B^+&0r%qYhY*ELavSsE(#A zB;@2YED$_068a&XwnT@si^rubO58f?hjg0M(UY<$Gk6P#2p+pb+}FPK<7K`plkfeg z&VE!UGWt0?ze)cYB;gS1=j?P6tO~<=4WyHKl&-DbaXC9q+^x3Cwe_}1Zm~X%Cd*B35iFi!*)z%uu_2ou9vMkzM$uT@ zi?Ndp2VKt3TL+|Jz~n5gmv+$fp77Bdol2*AXR9u|EE~_ zqAl>0-c3kUeO!mCr$NDNK>6CRI&s>UmrmqL#Nmr)z=&eRj)h((FNxg z>Lg(`q^n*inh1^58gPiOtv-XmC%^o(VZ3GRm&|DVUs6&5VoEEyREWa-vy*7>X02hS z(XcgWOiyPg(9lf~y5=w%Oj1OjP>N_snu=3KDz12b2^n|H=Tkv#_IiHK-;dIHXSePyr`p&N6UYl_a7Is`yEvPQ2^GsVgH-9|Lv4c*fF#HEYS-mR_D-Bb`ZK_ zZ@s+HT!+gd3M=zV3*Sm&|69`@e-#wXOS+22K(i7>lQx~nmEieeDy~Xpu)sg4Phws| z;*2So?m%-=r;VxHC|w1c`-(ozM}{aKj0Kv#so(*hc?+3LWESZ>LpRgTVY& zwcTmL#V%I9xVS{l{@$t8tL4pB^-k^KOxnz&rz<ZkS77*!u+nSH{dt3u_e0!aBEW zl{VC{(1j2VOH`xiUQ8pwGB2*NzF#c>oJ3RPGv zSJo>V+#Q0m;*?phu2mjEkt{kDDpJTh zW$M*Rt5Iv*g(#Fx70Mn)2f}3we~fM zXfX_-=+G)0I_?cc8-RToErjd3To=|QomD0^g;?F*5Y(i@&#o)P>h_Ybu7`C66~pwp zeaF@0hNF#i3C)M9T5gw$s(Ls@Ewu{K{N0xD*Rm9KZLFlG5bM0OrpI3?)&)gf537j3 zmS`;T{3S?*{1pu)w<^VnNzMeiRI!$4(zerK*F{@$zV2R^b#3!4!wkME7v3`VgkR=` zZ^dOTVcB`%+XdmZD?XvLgim1UtaxGzlEn$N#F$7_QEn$N#VS_DbaJYW} zZ1^QW4Zj4S;g>>~z{7A!U}5;>3jW*_+6VjSL`T1FfhVrfZnnye$_Cs(IDEO;Xm{o& za_iM?I6+XleEqdjUJ;Odh&}b2&VFH%CeZ$|$xA;vnMvD+T@PJabld|EYMp!K2i4l$ zd!6?Ae9pat=)%RDH&?G*dhO*aO&FZpkRwTBw&CO12qxR8iD@WA7iVf%dqK+L9r?90eob@5wmVv6Q<(K6w z1XY~{7#W~XE1R|4MimaUthICboNYM7u4UU3F>4jN!d1vc;#w6BXF3h8UB7wd>XkR1 zTP@#s<=V}h&$kT~{nv#sok80jL=lz#^yvC$^Wtvqn4tN)Ss zQ8}gfH&bZT`)vA;m~{i-S+59ZfOx)feB3V(WQJELXs3MA2!$iG&?enPd0c<9Sv0cV zc|ipsVo3_RnX5qWSosT^pCrXa3)-L6PE%!DnWi{R8-#4L46@V=vVursGRVUJOvE5dz@V5OIEF=j zgmsYGE?H!8ESgudXg-KECX439V`yH$qVNP$I2;)U%}YgKmkgTc7_^{f&_a(4S|HcV zhR5-OfI;#6s|<%0lIG9?$DyK{L&Y9BRK#BvaR~Bs24_Ex<4$JyQ%ssaMUFpn~PJFXEpQ@n=!MAEo!4VaQ_l3>hVd7J?m9UgQ|Eq-MyHgdv6|LzeJA6fp!M zd4qJ}h|L0qB}?72#1OJ%iDSvKnkCCUvSeAzl4UKHaC;*ROO}&n$uh^16*Ws%dSuB8 zeoHh;Rs<|jZv`R zZmeLACzgaKB0E^X6L+7JvCLKkZ?t0?FzW!?P#-H>B+bia%F+%3TxhqxYCV%%W6wB+xRTQda`zf3@h>sW9?lL!(;}p%D&?mwupaQ$S{$~+g0oW%dQ@5VZ#!#YmsLc zYYmIo)r~pKv1>^(zC;GGV0`HWY_JUL$x;?FY>8(WYb%Qw){U{uF>F~fzC`A-V0=YK zsj%$o$%+=TYnf*kYe$RN)r}#|v1?S1;xM-@46PO ztjGtQHwBLAytr&ZR8|7l5|y>YaOXv3=f!0gL}eGmWs9P+MRD0hQQ1Xt*(FigC2`qh zQQ2j2*%eXQ6=4rsf*uxg7d#2!9)?^4qR{~BXhB(V55p2tP*y^NsD~|a4_l%hw!}RQ zcC&y6aSvOf9<~;R+?^M2cV1X>K~Qo*Sh6T6SrnFpYxaURU0F=$lAz?05azO=XH%#b_bIGXi}N>ebfb?K2}sJk2a2{YZK4D721c6J6n+YSB~gJ>#{*~$#Q zzya!Um~tFNHB*ODjCpFApM=uvZYLcAgtl5EPGs%QBtjU;9#tmCAz`fN(KuwTxl_9f zC!L#}rg_*rh|*{fPEhSK$ioZpFkq$VHMXlH0m9YQm(dlyfuhc;QdlYG3)b#XKjFGC zq(ni)n`GacDG@=o;k!!*C4f3m)xJ@eZ)d**)}LEnW=vs3iN+B%5yLRg4H zu7e%OCiXY)$ZTR$*&WFy_A(Kg&#yjO=&>RP=5LwQFCM$OlJ5ZNsMA%t+wt$I*ZHqs%!T*o3%!#jepoc(5VbEjp5K7q-e}byWqs| zz$H|+FN(5pje02XXACrQqe}9Fo9iplkTxz{HL3$%MXyEn`hXmX~ zh}?kMxcd?e0h4*=dKXVQ#Z?$zg&RXtvVJG2K7Blpu@p77Hp*~LxdnOAooy$!GnLnKvMw< z%-{>W$LEH}RD2{*%^}?XzQ=E-_mb~>X?uvPBLE%$;1t?(11!USPMe4fIy4P~JnxPu zgN~nSL0(UkL5HSOkk{(xw2>!35@o`P%rhg%pVQB2Lvp`!38*wOoW#z&L#LKBvx^d9 zml;l!FuTfdqJ$`-vY*pN+T+S>F(O|2g0?%DUG=zf2rw6@UHlaT(rY{F7z~!p z>XVwyhFtd|CKLa!<6v0Y-@vxD|6&}lI!a{ck62}JW#Azf4x3TWGi>0J7%>*VM3;Uo z+?7uYE3kPBe1U68g-!0u!rl3?a5p|ItmVJLn!YPRIicSQ>-ns3Jbx9A^i_E!q<$)_ z;iK}(DEw2nH{TTQ#V-|!+Z(b%hfpMLl|KsiR_@N?Ot@c4hwp!(Xip1@4TX>(kRT94!6x}2{mxEK|mPLGrBi+Cy=Me|$Raj$y|Q*+ zsd>`39H>Ep!E-|V7zW+ePb*Tn8W1O=Ns*m>B}}|2a>C`pE<*=O}ce z3XV}a1P)xtJQY1fPr4sF)~B^=T&tb{|`bx;Y1 zjNU`?-b8;sk3KboUSOjLxNTD>J+gi2UsO=YBHVntL)TqFj3wQ_g}dw)m*HXn{?$^R zeN`kk-YqSJUoFBb*bsB~KuMvM;G1Q*?}HEEv~LcWb>o(Dl4}d!GTahHd5I&}?28oT z1)gSEpQ9L^9qSxy!fn;z;sTPp{KiMNDy=HKs;skj8Hnl^X)g81`uOJt(Gfn>HWvtV z49BhZcA-~40@c5wkwl<^_EdKO{^dawH5BEyWS&+7_l-z?wqf??QvUH=sQFF^fjbu2 z7x-^e=zw?4WAt=7LnpmN%y?at9d}~4-Ahb&;4C|R5iNSvYXN}@D2R1Wo^9w&0uU^1hD{WWmTd?mzy%t7P z!>xQ=O7TB6Aiz_zuk0`)8hs;Qo~Ky;4`vV32%PClCM?^DFC;aW8GwHV{NKvO#E<{l zK<9KRzOl7o4#I!1rCr1BxY8roZCcc=!-re>y(RGnSm$FkfTTCn?xKyYdhQ|ZA_;!B zdkhG$bEDnHFCp;G3}lB$*Tm@-8z=rojBbG%=HS(>x;~3-9KM`h(Cr%Nd#_fa9Rmc( zjGPmKCNf$g=Y-{Ld9ZVGPL5M1=VUeHa!ytw_t2AA5DE}h&BA&~ z$T=ZkBIo`rCEV#btu_PwRvf(*v1Y}zgw#aGv$xdP@Oy3vc;!W)MZ30y^@S`Ey4HN< zqIs^@u$XQLwqsR?DdW;TKVfWbh zWe!wf4W$EBTtn?Z71l|{fhq*8aG(my@2~?^j#K79mDP|tP-Qiu9H_#2NjOl2fOmeQ zs8CeMx&B6xz%8s;==L{?s&zpisdPhJ$jW5ooDj4^&I!x!u$+_Ql*u_+4Y{0?)rgXF z!g@)_IU!&o=RP_34%jG~yA`=E>u)A~)36UF?Ka0U-=zPNe+38UXvReLufGu_b!O0w zAZY;~hIFrp!jKk7U^D4?4KITk?e&pt3JDDk;r66(Q%JwM1iw%a=;PO~-rtmJeH(5{ zeeatF`uUM0jviV0d=c(mL*w>A&32jQf8T?q+&4`2_haa=`%;?w-LFUUs6+14DYy`% zvANZ0+j-o$7f#l9lB4sUn`CmM(gBTWCpPpGsKU>7bE~yhh25xg=rk=$@+el;gV|Qu z!XDsaSs$=-KwJ$NGKDtnBT3P4fd;o|B)x*uQ%7is$R%j(#r5?-h}c`kVOjt(3|@sO zM?OOMEyD#+%tZhw<|F_Py8$M$`iI=_lIm~shFk~Xz|kFhjOQSm%4XFZw*O#m`1=tn zicnq)&b`Xv;x8EJjPP?Cas)y~y>h!=TZ4Rh9XMZ4qqXGN4Avhv2$}YnJd94@uu(Dw z;KmVcocJvRWpxSk(mATm@avFhSWm^l8jnaTAwI?<(jq}%bJ3hM$4Q<-==mF@u2Slmtyw%1NNVzh7jFsvhLs_@6r;Q-atbm3)v(6I4Ikqh9IH5&mP|04+Vm*MC7 zI$@y?XC`8x#b1Oo6EVssDEi?%ODx2(Nli`x#3a?ia8<@ht;Pk^z$sa!fF@Xwl@p9C zZ;s)`7`0e^5UXC|D&e#yEAfvRD0nK{oAI2~NkB22)kcN?lOb;aN0zG|E@<_V->Z39 zc@B8@N3%-JvJjbCDl_iEc|j6sQim%vJhu|+8sHn#aPO>JT6qmY0 zjK7f5Z7N5yt1#cK*IG^v`s3z3dbK&k-78b=KIQP?zYSaIl9}b!^A)XHH(^cYapZW+ z^EI2c5)PZv>V^oGanzH{>tJe7(62siDySNI;4)5GFL7-a zUPg%ViAquU&#tH?)ikR&`vnTqACR%Q%MLFT9Kk;=mt)TvpsY*E##bD0}wNEgp6YQcqWq z3|TU$_@~3p2OB5X+X?H4@aUDH#Q(rRXGO#d$V*T+oQr`p7KzE}gcu}R_)k(0r6L#t z92Wz+Ah<8!k3?@0;NaYsb)#RyiX_7sYpnd&u9LXzCr5~)*oJ@5K*3!wn-83HND; zdsT2)Ns>UGlQh2(EejlEKIr)`*gqV*AH06*R~k{@A_b6{73V5ntirRN)vK@v@Xs4a9mg0t(5e|QsyG2AIOz)RL1i>0NyRqFmoP`1xJMjJKko3(V;ern z*9*jHhEtkqGIh$@6(or`F(bl8L+sRzsa3=mO|c<>2Fb%gTP%(oC3pEu1&Wwyw=ABa zUmW(9He1d0t+fuMA3a6Ch{5*2Nx0fK02^g&LcBJpD<<#Dpl4xwQaa*9BwFQ6XI%*9=O6NjE$L(lCa>=0CMMJ zRGhV9J_=4`dh=021u;6^`AAE6^YLJ~Szb5M$w(_DH5t?XWTc>($tVlK4)M~RjFEBZ zipiLkOhy?E%w+V6geD_xQ+P6Zb&}(xHyJ(H{$wlyn&4#gig~>pdorf|$>?Ap5y;B$ z_E6X9oeEIQ0{d`}JV#vr+A0Y@a zQS-cnV)%0r^9G6DbXzOd8Te;Fj_@V?!M~ql6f^cu@->oUA!u|SH2%xPGso|U{nSq> zuQ)m=J3%k30xObshpvniUM*Hq^i#@r;FKA?ZO}e=&`&83hw0=e=!HWMYDAr&7uHMS z1icV25F`_T`X^<>O6Hz@;xJi*RV)DYsqE*Pr}wlyMgb`79viXB2tXm|ehLxiia-qkDC6JGbPN%Iza&l}LXFd)BLecmQ#XOcujKL`^mh*On_`^}z)0rFxm9>2x% z)zFY5!aHg7SUn@y6;!q$Pfs_K-cb@{u5Tz7IK9l;&A#AEYTklpc+)d@O zUXofwe+InMQ=7b&88F|6G##06r#+f3Z?&tfa(lD7R=ZP!L-vizM%A1&-P8R!do!o> z0l3WRrasuS60o~XHx@2OH-AcZ;Ck-c`jD3-kY`OdhC3(TEP@scCffqKxm3Cd7lU8d zZ^21P3nolAI>U~`1E|BvLM5A5=r8x8zn?;v*z1>FaS`*DMH8VBCqD_KCYeJ=Hli|+ z97nUaqcV>OGI{J1E8@3|y+Q@pb1M2DGLRT@XekuYWQDg<;IoH4K4E)s8@XF$o_o?| zJ3cI|(Dg=6+R9K=Bq~9|_YfDNI#uCr40zk&#(QyJ)3Rh``0d@ ziLz}wQLj5hf|WwaF{fw}OSqp>q8Uxed+UP4oG`^!hGf+w97;mJfpFENU%hkz6C_ zx*2?d1JvU%%IiSv?xBVt1 zh`CXVp=eu#VErB4U7!qUgs=~wTEDStzE%0ps6$&}w^dV}6| zRlEVNir4i4pOXOIV|ug4cUIg3XT`cc>=g;@W2QF^W$ubMz+I7WE9iVKy$%kGRsB|+ zmb7BZ^aO+BvUnX_774>m%xPie=L<`Hr$wSm!@kqP>N_nuwMxCbn4_Bx_p7aj@Xm+8 zPEp@!krP_dVQb0Lpk zLSQWoWQPXep9QHubg#Fu9SYx$my-0I7Ja8h{fk^IndEclO>|2XeI zE@byRz7PmSx5gb`$h7@$XFMWC_Keaa0xlUmGLp`WqOojD&&YLT+%aEXy^_Rr88A@u z^VR`rZ<0*q-a#$q$ktKG$nYE`c;=R*$hUhOk|kxfbn5gk#rbx;6z2;g=r%gbY8>wX zU_jk~hkSX3b)dwN<&YC7zASfr`TYyV$pzz2w)mWi?jphiur;$jxu!f2ljm? z5u(4!g}`qs@OwV+dm-?<7}_*iMPq_{dp!KUmQ?lel zo>>Rvg@7hF=)Bi?opkaX@N)|RlMAa{N;s5mf}BGFB7NKSh!CXroy^S`i7P#paD?s0t(~mmo=q8dEee$w{XuVl4cVDYQ>aZ$L)v_eurC)JgAypohJoichPG zvBFASFmZVWn?z#D@HU$9zHsv|fs|iZ4jX?70(`}YUD-A3edRdr^ZJ-qAV9ZQB&Gyo znZ$u4?txuFY`z?0WC-@D<{)q+#S~^{7&r9VA+c9UCfzJO=>{T31=qgWPf~#ErGzss z!u5mtSn)3y=qdf;2};Ea@$kkaG&zYGk5CK$=M*}j!_j~=Jt?UZkgfBQVuBIn%_CgY zuf)pTIMouD!f;KY4%PT`a4JetkdrD2i0CuAnDC#&WsW*Tx#Ii0q%7B|es@ZOkYLN+ z-b17}MS2xtigr2YIRyAO!Gw|!?iLh@eGAK4%R%RekEsN}#!=HnOkBF5AX5VKdP)FH zTpp5b;(D*R9!yx!gZ@$Bv8_r~fdqv)a9oWknwaDSb`&v=i7TczAe8rer2=C3r1wG4 z!`|4%r&YyRQL8SPxNrsQO-vavalJ3xgiJtwf{81GZJW5_kJQBVzH%J*d40?)5TM&D z5>pPcOyWS=CT5c*Gc#;=NTr@$h&M-x|fu`-Z+&oM`B<&N!#h-@+rD24wC^{G>(33IvaJX9c$+9Uk zxMq_H4%x594Qfw$O(TAiX6K{P~?QGg+z|52q$u+g?2*Zgpm=EW54BQ zP%)y)|1EygR?~r`&uM&iufQ~q<2dPL=FoOS7B?@&vj1| zM@r5e^GPF>DfP*gsSg)_E`>&%-%Qf{ecT?2&-(*GSEv8!w0aTh7d#NO=loB5S((ec zX8Gd3o@Sciy`@%fH@WN~$AkkCuL)zmrkt-Fu2_rpkvNeEPs&-i_rY1XtNI7B<|GHQ zkm+semEH$&-HC%tB@c2id5}ZNgB(s6B>Fdl5O?(~7gf?~Zo-+_@?xxjlBETcNyLL8 zoTTRFz9-=%;Fb~vR?@&K*kX<~x40-DTtkRv*9TL^!-IFzx7|In%OyZWGUwt--6jx7p%-xQroOmK)@1)7f3i>h< z!d8pR+_Zbrla=Y`D#VW?S()I%pSSSUS36%fo3=NvD7jyGevCSWQ(f@@$Gb(ajb{ol89(K%g) zDUWVIC>*VeIfKQV^ZdfxN`hwhR(4*_f~PqW`7fTK?^ps#ABF4D z5gK~7-Enq`;rT{ujXWcLLLlsh0=H3p)E~t#sA2PXkc{mqS_Xa)ym%LVK`IgJr3)S~ zW8FptAwS+uHM?g`QQ3v;R(qa3-9c?1!2Y8QFjVSP)6NgDn%K2zdY1j zL>5OZ#C4E6b|V`Zmdl$m172YyLpk=qoi9t)QjtdsP zX0t6PBl;{yv|Ct6Glo%rnk&s;2H<24=Od4u;qQwal}0_Q4V|2ED@IeYlkv(+T@rwQ z+dxZQk)B|r^Geqw^gw=cG16U=Z{c4VM7fyU4@6hzqpS0V9DYx94Z%qDY!>|9uIjTv z+g(CPJfgc0oB8;Q1}a3iKj~ob`7V&+&!%*m$C2uWkuOKLkQ*WX*eFHUK>(3`o zr3@imgsN+K9Aq`6WS3W*8%7DA8Z32B1O8nDDTlJE0SPL`clSa?Z;eP!J@(QF3x8#h zH@kDP(ajB|fRf~vCsGIjJ$X@Uz;kGWN0=^m3xd^_-2+KnVJ>vj7x-5Uewioj08V}; zaE5BJJG}VwDb03r1iQ-fUGe+eQx*7Wt;!tQ?p3I6Z*u7HpFt|1I8^$I)KfWFk4GF{ zk4L_~(pIOCn9r(UIPBUG0PKM8hxUe#JjWq}-{9#=V~ z2J7P;%fS4-9mv3zl&zA_0p5 zju`b$1^%N{R~+FQ<609}x*&%W<^GU-xeHJnN!?o--Hi|qIY~IGT#`v9x(md&LL`bA zcf)CpLXXqFj@PzOBGyRiwncgX==M#(13+K<^vX4T%8Kv+P+$&@NDqKloExl<*8`xU zA#(Aos+^#05iu~-RP@$}iR=1^HKVviksbiA8YfT_(B}~z02$s$4}iF$jt9W2$qgHSz$iTcUgZFvyy`@h z$4D@*+nXG^NDn}eN?-T-_j4&d06_q~=ZJ~$00a?|TOdxU%q2VD3b)?3qayS)DI|#1 zgN^@(2+x^K1~-rr)}RsdM~0txQ23zafY(-5F+t6_+${y&6Q7*M?3Q>7e{nEyf;5uz z0ZpmgkM_sCCvwz2OIb(z)t`x+3xWa8YRB#XB(52QCwC+HPI8qickgZ9aiTW?jcCQk ziQi0Vj46&#R}(5DOTt6L9~3K*gMvfX{mN9Q*Em%8e=*P*UFv+z=iEmb%?}Qj#}8kx zXs;-<`cy`0J3EaSukFYypDNY5F+$tXgeAHNQEJ*`1rJ)oPzF& ze{9-LN_@1o3s;S!?d;ltHKEcz52Fk22rHG9th% z4@8MOxD@xRDdR3#TUoOTJ1G1rN{ifKeXjDb*7j;pmrFN^Q%~shH2zvJz|YA=SjY*( z;zPNZIM=7<*^KNFG+A~JDzxuaHmhwoFoH@M*wGiHR0wVjDCxs+81*1GzWL(jh|?_0 zpGXKSr<|VfIsx-@fQJ~Flu6U5p0eQ5P6g%otA^xcvG}kg!E8qe**5h z6&6^n*0;bk4KhR-e69OzuGE1g%0PZTQ~>1u$RSpV}wn{9tA_H}rBm ztmJwpXb3PB9o6D9%nh(S|f8c~>M zNU(60C)zD6q&c==Gvb`w|5>U9K-?0 z%Cgq$fpdMT5pVKm6;(w`ufkO$FX>-3GAp@iByBop9TU7~gu0SSVhg=%?z1W^l3gKp?So#cmDv~a6;gS>k9qwD1x&d7ulpA&LGjxqhDBA zoXp5?y9^vQ2hr1hW+k&gmTw&BvZoOx)xSfQiphM2gmm!0 z#9J;3%BXG=QAWSXsu!KqPv&{FFGvU3eo<5-`bt!dyq8on-;FX&XGK~t^GG&CB(*Wz z*4t<|TX*Ws2N2L^GcC8-s;<|-6aDZ0n}PoHX*33xsio_cN7dH(JemRXWZM2weo*V& zD?g~#?%wOP;ma6&af=n;#~}S-L7gFC9a3zF7Mq7+!@^<~6dR_+7SIIjtc*4{JGG74 zN2@KgFOxRS^6jl!eVtvIpaYqVxwlolyH$sbS|7E2yybec-LAF)!l*e)6K%E8{tPnr zbV#R?#9L+m!$fAx9KBy{RodmsW(`ed#!b|&-ECAlTP*;S&8(TH*2vt1G=Y$<3*I)$ z(ZNjB+)w9_JtfN?+`0dw1m;oaPT4{1uWikti~$qr z4@w`KTdP;v?J|)VbETtmH>w}msx~^cN`3CBqjU7FU$MMM-g^y%DxKC=6<$>zZdTVi z?Xvxe%<4+(uK#tt^JvqC4`ZX!nYRd#+m+7RJ(kT-ys=fU!>5g{c88=a>oi-{@|_lB zQ3N*JsS$v8D)lzO=e_utluCPKwV}=jgROiP#%c9=NOVYePiPT9mtr^)147m#rdd8<3l_QYWLoe5c_S{W!n~qSGLm3fXrS)naM>&T0cyBJV7! ziT-+LQA||l+eYz+U}A52hFnWAS8ee|=oE-G*LOs|3Z%G5LO=rB4v{T|BGmCWIpNJ* z3${uKq^)+fd>dTY@Xl2Spl}+H0h3sTpi78&fp0;X@Y?W!&3m?K%c*m_p$Q;T$yS!q}F)^>dG|_Z1C<^ z7d3!|5Lz$_I&PC_gF+ufqW4*6!!y7js++y->KI+xf@Oi-x&jc=Xx5~{n#Ph#^DhI9`d0kv!G@?FTWeXrc8b{;fa_kjeuB6QZc-~wxdqYK{8Sr-;A zZFPJ!0zuQ>ZI4dRgR#ih|-aXQ->ACr5i`YTR} zq14T);~lo*Bpy$1Cyf!oWYdu>V>YUlM!5}lbiwXwx!P(qZMVuswFA3K_C8Q(%j+uC zaPGWbe~y-C0MiwX7;wmB`1r>^M2rJx!g}uY2d?!U$?8BO1WVFTwbyN zEiD#`%Y_AtII8Tgj>8we5l{tdd1+xWKR*v&tDEgw-Ck1`s^{~zmvW;G%TThSv{#=W zhkxiZyU=uI!rWC3YyiSu@1%*m8<^U#n>;1oP2R=tChwN*CY$VTayD}(#_sW5fA@Iq z>yv28-ypWvukPOPZ%+ohCbVlx2aVQNX`&m%Z8xxmb^vrzcYDTKq=$w-pbK;|5E7bl z8e69QU0y00L_8L+O1j#cmZ%cw$o`sJ5Sx)8=lg4J7-agRTe9W`7_s&OZrYJpH^?b+ zqD{T{5Y62Ho$8V)6}HZFfJy8#ovN}u0iC*@8>Bwuw(#HLPBqQen5fGM`zE=}1qKa-#_ro7V0S-y;dJON0OtPMs5~qO-avS>`-ZF>Di0wlkl;Q~77UAE+`~(;_~kc@ z)FNl`L$FHt%R!I;2jmg}^Ag~oOadI@CBTPcNPzo{1o(PNCINms734h=heBmQlq*mo z1>7JZ+G%roQK5+mfhej)ba`t{y^tC7_lW#I%*g*Ep8TJc_x@47_m9bXe~$0{dW_!R zV0!<*Nag>3(3StPI3G#RKN<30MzpBosr>H;Ckf))z752Gp_r8XFBFLa_`lL17>+Z7 z;e;m`PRa$tDPAy~mI;P4ykKa=5DZO5F#Nt$F#JliU{HpPJ)v?zNwZ2U^uyfPV8!_H zu1}!Bx0KX`Un2AUU%|=A%vo~?mf$Uz`B`(saYe)PIrrH@qnW47VcTJic4y9;6P$}1 zr(q#!Y|OkL9;V5|2jJl_dH4=^I6@xYfQRGc;e+sSf;{{kcz{~lGarHnsI@(F3m%}> z_DmTbpw{-xcfteI+McPv1Jv4{xjnZV`RAb=PcS+a{y_0eXg1GcARmaxiIfjSHZig$@$&Y7SY`)=u73|@R+s@%QVj@+BXBnJ zuBZX=?(l$MJb*AD^nHh?plt60B8f>D4a4r0r`cZ7^|_$TdzfB%M%614=ge&8y-~e# zG2APRR|a}T-=A{|%J$wX{xr3-I!dN#F+5Gvl4)AZdD9e30=;PpMgTDhzzB#oA;`3j zQ{EmBm)HTJ>xMy@%glgyRy80b{+ij$b5R50`S5^X95pZ?^j$osplt60;;B;BmD_f@ z7U*SRPCQp^pDLYj#kK(@XV|!Sng`Av4$%{r^edQuWE_C`r#BAbl()yh3+y=1U3H_( zi_AEv9+e`YZZVP`3ARu&1;eG8_z?8MH=8{7ueY#_TQa zf$ko1106GAqJf_#E`Rw z7=|@Oq_U45kI^N_h<(K&kzh)8E8Gst1W%U8QOImk(p@uYac~#?S3>=&PyG!_{bc4QL=oO;lBdhs+zgWU`$ZL8ev81FyU#wKZq! zPtN9|8A2WNEVqFibIx8@TSw*PiIE1SeGK+$K#qYf2sjLBIRwfh?urAdoGYD$Dx?X9H7hM1YJq)qhP(yT^N`z)#iQ*mc*J6e=FxV19&N|r(Kh-& z2d%#vL@%(pEZIR6C!^)cVj&4YRz6>xPXZ9+*etFj1ZZW+{EC5o!}ztqe`cVu=OH1< z#nxRCf&%H>hKMLO&whUJ6dL*PP`g^cgEAi;u_IX82z@w1WBAF}jY|8zIf2rU6U?ra zLIdU)8it?uADHCFew1+&H?_^N&ktr$YI6XQ54#b%|Df5ZKeFo$etvMk+>0iiS6+?5 zFTraQja3>AP<-|^6efAM%g6!@^#7%-|0ji>(&=o_G0+h!OL0ms6}3wjR+fs(F-k8N zmcJD`z?p4F*$!}bMQE1A!pi*8g893H=rb_ZejqT`#@w-H_x^5w6v4ova0YnN4#!vQFQ*RBzs`*Q)FAe@e3Z0=D8fV{39iq?Sgp4x=x_~k?--J2$W@?uC zDJ=hzGzVk;%@m|R6vvyILRf&ChIYERy`RGJr`#-y|9^W|6C%YCg}190m1m4t>xN~Q z*~DFU-Svmv>Diti!HdL$ClRlL_gprRTq3#UAZZXi>_Jxu?2sVnA+Y3!4dfuAIY`7n zj)4eX{6#^~gGBwhy1J%&rn{$lQmc;iX=jJ3=~wT2^?ts7-8Js9G5IlVod5C-9*h$o z6URMa&Lc*LqhQCMG|+dh&b(80P5o5at#X{YasvkTN1K5ik_L8Q+1{_58C;lbZ~cNs zKKlr-w8ISg0&X>l$9Rxw0-5Dl@Idq%)Jj@Gr}`i316{EH^Nc zYOO!kbe%a@8GRaElj?KK1!ApX;#cYm{3nYp!xS#InZm3zg&oWGc&8~uv!+b57>dNW zjm!3+F-LNiIj0%Tc2#6x9`%Oy&_>^?B-K5*c`U0^?vt&Q>Kmf9kTF2=6fnWuC~STeh#byDDtMf;q3xq{ zO?xj*HSG!d#A79r~pQKBBGB^teZm}v>h){j~(O~ zfG7}d1JO9@13JlsLj8uFn+ZHuY-ovX=#t;?hE5KzfRyJ&v*Pjs&9}T!)6x9iGQmgI z8vOWZrHMRXwu!s7*|mtDYHJ1#Rgahv6SQewF||CM67y?qy0YHjM|#s(GL{g5>t7vY zY2K?#MWkPSe>QzG#;u{zEy&GDa2FzT+~~1EJ^;y6=7uZ==9W_DUNzKZfu08byj2xk zLn3*F(Hj2zT-=}C^cDEP`7FpX(du)&B~)Vi+bu>~s0 zAIVeIK@wHH#UxSRCf0QOB&<^&o1o3|y6L$+hKuSgHaw%A>tWZL!CN$@6?lg^qGDmz z8*kD7mTP}suyeGQp%IPWF9K?COCoVY_Y_c*Gccd{%!Q8M_*bA~JW!^ib4`Emz#-OL zzElLjHV$OH9bzPHHH9P6(E`UXvV~mMdgB-gZ0R_DXY1XCe%1HSzD8b`|15cV92N*OFEC|+EL9sV1 zLD5gc)u)0rYMLTMBN7l1jT#br%eQxkf^aAC`{0kAx9`o&Z|65NZ|>px|IiDfV`=l{ zdSLB7fvO&@ruppcwAELG!B|N#eSX^tTAGmyPEQ-la}cittBiUa7d$aI{xB_ve(IM4 z{DB6<9X&JsJ9<_aG=g(*EclZ%p3Wf*j-NFNq@mqU0N-gkNZV>b z=QSEC52S^H1!1u2rwuhU3jM}AVVMg)dqV@8yhXf|r z^nijeVD+Dq^c**1ddct%-omy5pACsc!J`0Ly{=Z4e8)$uBU(Hh?F{MjJLW2kETZX-JD!CpH5#3-Z@UN9 z?+n!V>i;Pe4D5HzAjKoZo)|^IpH9i~JkG6JKBO zL(6X3%r6M!OD%Y-o4*31T~+{OG#kwRu7tjM>oGmcF%CTQiBT=8IYw9e8;uwjlt7yu zO{Vm0ZNZ(5#>ZWkI`NhS%XsxodwD$%o6+A4w+B1d^`rmRuL04B#qo)Ig*=zqXLuq0 z7$DC|nOGlD&1xwGS3oXMO{t-6(pG|_&iWwk(M7uIRj(0e|9q{iXDjK#2{qtw&OBQ2 zf~H-Ueoc8m74-A|*MVdCX_d03KkecjK%Wg2t1@H`ysaA_P{xldRdlaUTc zl#$nuYE`1CZO3TuZ$PPxp@}0*Du`4#s_?6IOSj#ky)bw&D zerVkhqG?PnHV+?*C-~_Rli0!XyU}~)7k?j*FSzC*i}F*-t&Ktn6|^P8Werg}@|26Y?-8ub$~ z=lp58{`djpWVbhX1{yA(BQ_sq3MB7SY)pEIhDgoU>SK^)gS@2l0;=+E z!XNHfF1yCb839<^h&_`F@ygOwL`l(c^1ef% zEN>ek8+5V+pEde2Zg0Pw_F zF(cNR3Ow+djQAs45$>xP^IuFPqKiz(%xis>2SaP*aUq4uX<0ew)d%Ov(67E!G%bHXj9LAo ztnfZ6cc}^@0=ecMRhMjJRt_!k5)*DtOLu3aVs08{Wyt4 zLzx24;Wx``#rqWb)|;gzjh6W4JbOh`e>*D1ZmZ&ci8X0`0w_=2o^~LDEx9!gZ8<6B9;(kn4wdx93?N@TsIm`c$_Cu5!FQ2{zP?!R(*mqV z#1hQb)ezq_uo4Zf_zn#;-o=%Tcf@8Q_NZfA85(YM3Om1S88ttCEQPNd@4f8KW`vsi zii(pfsDqD{yqvYKse<)o=pR4yrt13Sd#}2BoLY?)dYhH)=Kfr+kC8V<;Fbq^WBA>x z+?$qvBc72_*tJpFSiPbUvv)AS3nRZr`)!e;HS7}Zwp33nG1LX^@w^ayF*^jEYL$!K z9nyk~i#0|Bxj!NcpIt%CUOJ(#a=ftD`&-a4%lDvBv$i0ia|xtCkBb)Wtwkm*az!g< zJV0MeoPZyVHN;l*Dn^Dlo1z28fS+po6^*Rkhi>1Qf}EVQ7?bQ= zjP5W07X3x>HTrkjBy@zKAIks5kh|dSAtd3P6$(QAxmDR!lm-0*6>!NN3%V{MGdB2B z#N7qd1WP?)PA@kiF(jXec3F=L@j7g5!;t4d!s(*_PV1_3|nJGAZwFx zXhS6Cay<{P-E;+ibnOLF6vd{39(+wz-`z`2mRu(6;%<;W^`j`!R3ZL19)J$1+mBiQ zm5Z6Z%t7i{wWv8+f+5Y$=%}a8)ct4QP+=TPYS+;or2Stn$)y&vsV@eUprKI{d02W$&u@Owug_5{eRLNYa@d z6K3b_F*dU>Xj^a?9m6hl)W;0lj(Ic3jJiC=VU8KK9rIzCLOtM~sk0=aWKp(I%<2aj z!!Un(hA1hHFG`t}A>pUb5X=&?Y#<2kD;6eXBniZ#Y=K0Sn!-;?O-~o5GZuQnJu{it zg6T=j(h6e1780>Ql%ihq-*1>gCUDP0p;(a47t9i|dPBWnR=Ox5MIgx#GkUXGmXImj zhaWH0yx_;CCS@e2q%-Gw!z?~?A~i!C%bc@;%(Nrv(-DceHY9L+Br{kn$O7)cKuZxO zu^`A2Hk>XJs6F-7?x|l#PgdGIS-1BT#@MvcZqv4-O*?Hi`?t5LMn9k(di!_i9khFL z?C5ErHcw6;dU9^($>p7=LE1eH?&xWVHczhYJ$*tpHTIu>pJ40aR9`~6<` zOP2-tv_s9+g<4CEJ3xqT)aDTSVdxTIA*=T!zpy~Rk-=m5ll+1wj)Cpcg=rbW6p2WX z#78^>L~(J#6t-t;udqeBYTa))Jw5y)BEkYkPK+26?%B~OD;5@Xa%9t`BXuLP_36@$ zdP|oRJyvff;o9fqhieT#SbKiD+wfQr-i{wa7e87$qXR^Kj34Slep>TNgPPYKb$44T z3!>Yh9-#}hmfq_C`F;$w--oEXn^jz0S=E+ux(M%XR&hPGW))krrOQccRx!Oz-RYR# z#@1w6`?ZFjk?r~E?nT6cMz!N-v@U+M+*l3}Q?a^wl{qx_Lw@4nxK71r+o2dkG9=6- zq>CO-H;R5b9Mj2o}KPq-Yh7f9Xo-#*wJ#! zJ3v7nW9Rb^*$IHhc8Xe0zc@j%r+PTBb$d6uYSy|kHy94;WXVKhsdc!pb$@TG_09ia zjnl~*N0+rAIG__YmIj+#>}f#L{og zug_ZN9D~+5$FOzIF;dSt>PD@;Y=T=4j#D3O8w$Gr^kGK4@vxC3RU$}Y#1PmhHZ>zf z!u;Tv(0-^ig+klUj-#2QVehrV+q8N^5zOz1_!NF(mOz}Ko|7hav@)r^l@NGbry#Z> zvGsZP8^-hP(BtXlsR5}ga$OqKd{5T~HCwt2s^dGpHNGM0_?mqfmo7bOaCYU9{r~<1 zw&zDbp*2auT0bJZ?ISwSvQ!_=*YCuHlO~-z^v;fxnP;+XSeHXn>)__;5i%hna9rTj zF=71h;E)K<_oa}mE9Q&!;f0;iIBG|unbDGMCv=IWb%6UcB>yrlZL@`zxV)b(J`K&k zj7#eP!eHqtE^Q;ory*IQ4=?V_(7?_Nb-2^DgysFM{%K(H^x*}a!8m9Iqa$0|uKrI0 z@-MUHT{>ibY87Sv|Enmo%WUy_I}&M)i%ul}GA{3`sOz}A3!C=tq7%)hRZ-V*`DhjC cMDmGM)OA?8QAIkzd{Py49hHw(kuD(r1v(yR`v3p{ literal 0 HcmV?d00001 diff --git a/data_processor/watering_model.model/variables/variables.index b/data_processor/watering_model.model/variables/variables.index new file mode 100644 index 0000000000000000000000000000000000000000..b97083469fb97e55a8b7c313ec9408435e832bcd GIT binary patch literal 1779 zcmZQzVB=tvV&Y(Akl~Ma_HcFf4)FK%3vqPvagFzP@^Wr!5R7eA%f*iN*1W1)2J}sU=03$;J8x`pNmFc_sRKjv*mIo=%}5uEF|YjzOMa z!@?YWLR~o+fu<~A*I+T-QpP_=M1ij)za%k-kcK%R4Rc>Fe<-BHXGokKD@e6t3Cs=# z6QP{M%G9Fx^30Nq`0~`u^o){XT?753%*0~+4rLKy;^0?!!K7hhy74*J8);J^|9}ur zU(YDlp!i@P{}BEBf|AVK%&OEP{aj*9n!*J%X_4H-6DBf3WyENhAqdp4XD)ZWsGvb9qV06VQ8}}eBlL}H04l#HgTcNuJA(ysA2cPlM_T0#fc4V zeqd;`D=cBwSi)?2JMC{WLy$O@#Ac`uGmnzkfY^0`3uM>T^};E{#Rf#z6+w`${twJs zfU#jjWNa`hG=MTu^<2A!6vhUl!WurHNsqp*oJ?G7Fe+>i1!}PKoH|=nQ4AJ(_=+J= z%3}v&MujJ!B%~Rj%PMOsMoD->Oq;+5G%aY#nRGK5F(MK_MAH;epr%jRW?LDw`4ELf zQff(JydnOK&!Er)3iH3OkKgB);WHwncmhcA?zg{gaw+hoq$Vd;64EdQq+waLpcR)q zUuFrgv{P>Lij=W?}l!bQuo^c D*1px^ literal 0 HcmV?d00001 diff --git a/lora_nodes/master/irrigator/irrigator.py b/lora_nodes/master/irrigator/irrigator.py index 6403018..4e04f42 100644 --- a/lora_nodes/master/irrigator/irrigator.py +++ b/lora_nodes/master/irrigator/irrigator.py @@ -64,7 +64,7 @@ class LoRa: class Irrigator: - __DATA_ENDPOINT = "http://todo.maxhunt/design/water" + __DATA_ENDPOINT = "http://api.maxhunt.design/water" def __init__(self): self.com = LoRa()