From ecdbe505fd8d4f633530ef5d09fce279f2d7aa7e Mon Sep 17 00:00:00 2001 From: Sean Montgomery Date: Sat, 18 Mar 2023 07:21:40 -0700 Subject: [PATCH 01/15] digital input logging written --- .../input_digitalPinLogging/README.md | 0 .../input_digitalPinLogging.ino | 122 ++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 examples/EmotiBit_examples/input_digitalPinLogging/README.md create mode 100644 examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/README.md b/examples/EmotiBit_examples/input_digitalPinLogging/README.md new file mode 100644 index 00000000..e69de29b diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino new file mode 100644 index 00000000..f2aa4e6d --- /dev/null +++ b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino @@ -0,0 +1,122 @@ +#include "EmotiBit.h" + +#if defined ARDUINO_FEATHER_ESP32 +const int digitalInputPin = 33; // Pin on which to read digital input +#endif +#ifdef ADAFRUIT_FEATHER_M0 +const int digitalInputPin = 10; // Pin on which to read digital input +#endif + +struct InputEvent +{ + // ToDo: This should be put in a templated ring buffer + unsigned long long timestamp; + float data; + unsigned int eventCounter; // hack to capture number of events without a buffer +}; +volatile struct InputEvent inputEvent; + +#define SerialUSB SERIAL_PORT_USBVIRTUAL // Required to work in Visual Micro / Visual Studio IDE +const uint32_t SERIAL_BAUD = 2000000; //115200 + +EmotiBit emotibit; +const size_t dataSize = EmotiBit::MAX_DATA_BUFFER_SIZE; +float data[dataSize]; + +void onShortButtonPress() +{ + // toggle wifi on/off + if (emotibit.getPowerMode() == EmotiBit::PowerMode::NORMAL_POWER) + { + emotibit.setPowerMode(EmotiBit::PowerMode::WIRELESS_OFF); + Serial.println("PowerMode::WIRELESS_OFF"); + } + else + { + emotibit.setPowerMode(EmotiBit::PowerMode::NORMAL_POWER); + Serial.println("PowerMode::NORMAL_POWER"); + } +} + +void onLongButtonPress() +{ + emotibit.sleep(); +} + +void digitalInputChange() +{ + // ToDo: consider debouncing + inputEvent.timestamp = millis(); + inputEvent.data = digitalRead(digitalInputPin); + inputEvent.eventCounter++; +} + +void setup() +{ + Serial.begin(SERIAL_BAUD); + Serial.println("Serial started"); + delay(2000); // short delay to allow user to connect to serial, if desired + + // Capture the calling ino into firmware_variant information + String inoFilename = __FILE__; + inoFilename = (inoFilename.substring((inoFilename.indexOf(".")), (inoFilename.lastIndexOf("\\")) + 1)); + + emotibit.setup(inoFilename); + + // Attach callback functions + emotibit.attachShortButtonPress(&onShortButtonPress); + emotibit.attachLongButtonPress(&onLongButtonPress); + + // Attach interrupts to the rising and falling edges of a digital input on a free pin + // IMPORTANT NOTE: digital input pins must never exceed the range GND-0.6v to VDD+0.6V (i.e. best to keep it within 0V-3.3V) + // See Feather M0 pinouts: https://learn.adafruit.com/adafruit-feather-m0-wifi-atwinc1500/pinouts + // See Huzzah32 pinouts: https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/pinouts + // See EmotiBit pinouts: https://github.com/EmotiBit/EmotiBit_Docs/tree/master/hardware_files + // See https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ + // ToDo: consider the best way to toggle attaching sync pulse interrupts + // Options: + // - dedicate specified pin in main-line code + // - comment in/out + // - boolean / ifdef at top of ino + // - separate ino/bin (present method) + // - reading field from SD card + // - control message from EmotiBit Oscilloscope + Serial.print("Attaching interrupt to digital pin "); + Serial.println(digitalInputPin); + pinMode(digitalInputPin, INPUT_PULLDOWN); + attachInterrupt(digitalPinToInterrupt(digitalInputPin), digitalInputChange, CHANGE); +} + +void loop() +{ + //Serial.println("emotibit.update()"); + emotibit.update(); + + while(syncPulse.eventCounter > 0) + { + float data = syncPulse.data; + // ToDo: consider adding EmotiBitPacket::TypeTag::DIGITAL_INPUT_0 + emotibit.addPacket(syncPulse.timestamp, "D0", &data, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// + syncPulse.eventCounter--; + + Serial.print("D0: "); + Serial.println((int) data); + } + + size_t dataAvailable = emotibit.readData(EmotiBit::DataType::PPG_GREEN, &data[0], dataSize); + if (dataAvailable > 0) + { + // Hey cool, I got some data! Maybe I can light up my shoes whenever I get excited! + + // print the data to view in the serial plotter + bool printData = false; + if (printData) + { + for (size_t i = 0; i < dataAvailable && i < dataSize; i++) + { + // Note that dataAvailable can be larger than dataSize + Serial.println(data[i]); + } + } + } +} \ No newline at end of file From e0c79959e9f3bafd055da706eccff67c65393c2a Mon Sep 17 00:00:00 2001 From: "Sean M. Montgomery" Date: Sat, 18 Mar 2023 07:35:55 -0700 Subject: [PATCH 02/15] Update README.md --- examples/EmotiBit_examples/input_digitalPinLogging/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/README.md b/examples/EmotiBit_examples/input_digitalPinLogging/README.md index e69de29b..0af68ab5 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/README.md +++ b/examples/EmotiBit_examples/input_digitalPinLogging/README.md @@ -0,0 +1,4 @@ +# Digit Input Pin Logging + +# Instructions for use +- Wire up an input to the shown pin From dd8855683560c32a50b8e51eaa1fb1e292c36f44 Mon Sep 17 00:00:00 2001 From: Sean Montgomery Date: Sat, 18 Mar 2023 07:37:32 -0700 Subject: [PATCH 03/15] Added wiring image --- .../assets/digital_input_pin.png | Bin 0 -> 57235 bytes .../input_digitalPinLogging.ino | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 examples/EmotiBit_examples/input_digitalPinLogging/assets/digital_input_pin.png diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/assets/digital_input_pin.png b/examples/EmotiBit_examples/input_digitalPinLogging/assets/digital_input_pin.png new file mode 100644 index 0000000000000000000000000000000000000000..58df1d28e47a4483b671ad9fbbaf6374b7d6a06b GIT binary patch literal 57235 zcmYJ41yGyK7w(Z_#VPJVOL2F1cP|p$U5Z=q;_mM5?zFgDafjlC;Cl1@@141s$>dFD zGI@8iyXTze`JG4=C27>pgrA|HpipIHB-Egwpcx=fCPaA1Cmb!z{*aeXmZFNHP*4qV z$ge;+$a^Fw8C_Q>D73-bH|31j&Ha25^$V5PkCSgQiY6mx+?@csD zUo;|LJ)H)4JIq{U+7O(KO}pd7b}Hw%UM2|35YESkaTH?}V`}|(r4hn0 zC?^iNvWb_{v6c}hR70Idq(_BZRf-Y@tdgLd4B9%%{R|=v2OqOyRSx4 z!ANHV{BaXaS-p`@H1ll_(w&pWSKw{g-#*GRE#ul$(yi=rPDs$8rDEVIO?8~`yN=CL zC3V2#5ZS9*?RQ??dgGw)9WIjZ;JlAf$G*4HkN5YNtD9rt4_z*YjjyPL9P#UpeS$ll zvUD*-+^Ic2596^U{0BFO6LebB*}Rm|xQvMv>Sg0(ACJ;Aebfy%AMe{ANfeS%qmvoz zhkL)GZ_eua;5U-`UJscY?bo@imnt>;1-)LcM-C6uj8Z?I^8TcG5*CI_U}`169N&Qh z-oah|ZAeuvp%XXr(L#yA-8Nc%m3jNoi%L2xwFXIrlF`p(PVm3vnR}@6{O&XC)|zGc z+^m=n$5WFjLS1BcgFA}NA_wP-Wlc%)uX-MGyTQ}^^YuXSj>A;_*O&T3<$&j+g9&gs zHr?Y7;;|g|=wrv995#zGTYe7)9nSkCH!<9O?fHY zh9BW}8~@p`{v~Zq|O~jy-o; zC#y|mzBgmEjlNGV;l*-10ou9*+=Zc&8EcZblYg0zEj-dX7COfduI)?gqvh0U6)*{e z{jxuHRr1nuzl< zp3YiCEbxQnXu1rbC&L3Q5vH3+^P_9AHB?uOo(Ze(eYxyQyxU!PUJbkmcs^-McTCvd z^bAPIU>AyeO7;F%7w{&()@ol>`rE#3lV&I!eI>lxwJcVxO$#Z5wIZqd`yXvB##20v zBgLz4_QZRYMs=y#JkDZVc7MnpwtO7>^SfRy`OS_Flydv>SV~)LjPLJTu^Dt!THu&n zWFpzDX31yzC;>3ncP9(dW0gjILTXjs&Kb`dUGWbfcMP3lkELRprOz(se^{3$NxlC9 zHZ5zvciajrUeFO$md1Ne3N+?Moj zr_Vk4v}+B)bHq}*+hBu@*o*z&p1qYjJuVn(GBuN_W2J0ri5|?}qEz2~8qMD%bh);r zbu6-2#j|+Vw4A-bQ{0-SM~1GX2AyuIdD?`9ArhFl!?&mOAG5k5S@j~<6nL*qA&#VP zWyy?Qvcexm{WHQJ)oaMGA#F@b8<0Pp54I@yqaZwjt2ToQZ-ykPuJ^SH9RE=&6o1wC zq2%ygn3=zAG6@Iy<)!UvyQ+7wN?#wL_M$(4#}t0G$2Eo6>#c*Q(RH1zFRw%q9K~iY z77i8k7qZdxh)rZF8vU1sc>;zaL={Qc?tAbX1)o*=C;C%sNo_e65kInhF-iGD>LWITU5b9sZri}l`=`CrWA<2XjYs-L#w1byzyXQH?- zU!TB-{Xwv59by1!*PEVS+6;eb5$mRo8Lr^ zpNNk$EOS+-Mr_w}^eu*YKTf{zkH0-^mIRm$QB6K%aYRe!JEUUKafO(EMVph0pXi ztIe{ni2vg*`m{(Cec#(}s5?wi;z1XMtPA}#KG0n)E$`0Gv8Pn7_bJ`X1s1(@94RUf znqKOP$7nP{+t_o;KFm8>R{iNx4UPu?dXG=IW0v=wTVa83#$e+pfat!#;>3w_Vn1Y) zKlQPt8m)$YBAeHhgKF@V#5w{E68S%~pkIuq(3_7XQrmF-Gd5lB@%o`WsgqU3TAR=NSV!8B!EDO z<@c@5A0wt*VS*;jgU7w-zR^ycA~&*OJIzX+W!8a!`3kSBdZEXE=r?O;0r7pW)J#Cs z%XO6iN3+91Q2jrz!Mp>X>3!+O zUgls4qtNqjaA4F0NglhSyus-FBa-22l%DxzIxf9_nQ?o;TxK7Bn~T%`&4 zyF-QkRHdP$#tC~fTU3o+PcRElOiwL9=FTGJtD(xwb#2$>XY%T^t9MaDzFUN+$E0@9 zFFV3M?naZjfAJv6jWiO2xG!6_UBjPOzS=HVzwcwT?zWJ?0DI~Kl8o5JEEG?wcL`ow zuZ9Q?rH{As1P)I9dS&Ca4ZS2=+EvAUS4_vUg>JTDqFJ^1{B>HLK$jtZs!ug1_-39o z>Attu=gLF=>`w-|7Emt_FFZ&34CEol50CK7u)agjb$9G~YD;q32WNF3MK^H)ui9xw z?f;S-5WL`q(1l;Q3lC0EJW0|ZS!CPgN0#IJmnMy3<+`|H&lz+Q#zWz6FAr~<0lx2H zV@dCYeNQ_f0oH%vnlc0JC!boa?{bsroaX{^ztH;9gl|8V)$-pTp(joO#+mzm3YHT1 zDmZ$cEld7J0rPG+Bldk5zN#ntKOPI4t^cO$L@%tBPhlwRWt>FMs%Jsy`*=s6_WDiD zP;^M3+so1{8&P2)y-ddEHtGtQwOu$!8g@q(o=#JDfq`iIk=p_dlC+WvL+~4D<^uX1 zj7m!PMn5?qp8dizN`^$a7m~~97ZfXW!)8Z#5Cdf9%axCMlZlhdku9w!j_C?Z4)!B^>kZiF6~fjFZYYy-+lrWF&fb? zRr;1wGzsZ%$y*$GcHso8rmOx)77qBx<`5B+q3e``z) zVmF=@Y9+5DfSqMq{!fG69&eL@eM9#^g2Cs31cTUWkApDEu=+n1o1N}#w#y7BTNPpN zqNd@{2s)WL%CVd^#x1pvX+ zljiT8x9TFqTAOPt9Oc;Of8J}brvnU21;N_7_2gW)&@o??@0(b+vBJZz_zN=8i@_&l zAF;aMDi04Qyp;C)g`U5%Tvlkup_@O}D{FS~d0x^|1B(EJ2fnXA-(%8KJn+K@R@sHW zsjgep5cm#bv$`&p`&;|f&!OC37@ow-z7ls|W&8djGXgQ&jK%|Qp3my4eydc>7sVdw ztN|9WoDW{ECdNrTA1OBX&)h~Tj7k*&oA0(8;1eg&mzL5e!*x^Oqy>h?c%7}@_(0vO=iSa-#s2MGmF z)ieIxT6P){WlN_ik(HxY8Ewazq(q)$Qh0w} z>67bV`{f1`;#d8hLuIQ6w_`sik^M|d=%PE&m$~5CU9Qq%RN>o*$UFuK)#Er8k6a5p z@g8-w;o?jd*YD+#MkM-lS$rfQiT8=mlEWY%UDj&Y6*lXrxin~n~|Fd9Mz}K_o zXI~d`d|hbp?3U-YAEAnji~W^@(BKZVQQKZcJmwPoq=aCfYa~3^&AP1Vx=hMA&H<$8 zOgUd|I%91#pQ5PiX*8P7^W%^0en0gO7!}#*pM$Qf`4l}Q7uopn)Y9njGzwYqG}Z4J zq)2i)EAu1E^%S(Ow}0p6OZ?nF{I!?~sJDGds@@P_dxwtm^efDMU6t}4883Z1s#gq28#0Z*cWMB0-j4te3ClcB|3YkYGjS(+pPuDc8@yWcs&Qv7 z3r+-wr7=y6@5!uhT)z+A$kxj|B!Atd*wkOCpd-6nrza!(Lndu#&@dS=mC5Z`OK2ME zLfs+;`w|qG%1BIc)#F1~e*XfAhKe2z`hRJw4#7V1OLC!R3#BoQwkx%P#kU+12uQt+ z$r543h`N7Tz>d$WQbo@zZ`4UfLbp8}_QYv!?>A{iOMTd%6R>bc%4CeikK2jYG0;*} zt`!@yLFarewNHxkfDqy9N#}#0U!TmDHJL>!FR(U1@lxz7OAmxGS&A5CP$%1pl zNA5qzCMok0$Gk0XWd)v)1jy7xb~e)FBK^sO27D?tCR6f$@D36F;GNw*kSYebACAuu zl7$*e5!xf)cpcxyb-vb^3V-Srv~~*0_zO3k!Nckw&SfnV8<647F(MWr+w@>7+>WTe z`Dl4GokLj?b*vTKK<4YKPLF%54WrMMC%Ug6jFwHw6naap)fV^I^Ho;iSQN62xjquHz~iwbTJytk9JNjf z{|tdz`~H@ut1*`q!2%wWkWT6n@o(sIkI3`x4={K>>#a(tXF=o_~~Y&uera`eTf94 zis__R@LiOE)2294v(NtxMlJg1e;W!%dl?%>fze60Tk7U`rmo=AWG^Zqk4U8!6C>(r za^lwJsg)BQ4hj6dHMt^*dXZcS*8H4T2pO-71ShlwaZ;l|eZt2CC{(5HryGgIw+ycu zwTkA&Dor(Sj~d3JaIPfhX+eU;wt{9WHN#52hhp<+i<{G`x>NU}Na=dLm;Vy*T088W zJ1C-petn2`0!r@nc=!vlUrR@PhT4~JfC_ZcM> zzucb`J%DzMDz!1*;?MbcJ>*EH)EzJ7o9n&J~wq_Bw70Ww4rtEr)vV z1R=PsSL>3xZT&mklUZgU&^Q|;V|O`_sUcEEt$nmIfo#{B>U1P_F`!rz`Z((TkNam5 zu@jso#$n^Da9!ny)iX~ABx#+;CQ_MzxUvmDZ95%tmV$es0wjslH=R$*14j z{pS=*ay|ZMsgUhJ_ddQ?jh?EPq_%qpMJpwTJ#}e)l+2JSuGef;a6+?GrJa_^X?tpC z)?_gy@DQ>C_7>2W8hd}F{FcTnt+mjjRw9@CBEBcC;{Y(iOj?25f%S56?nn1k*Mri` zTM71m3Hn~0U2zkL4#^PR$%G0UIQMgjOL?|l40CvhU}0=9WAp7Lf&-178Y7h?{1+&A z<^3ndZrqdNopLXGbQ-NPX-$ix#qDhQKl*uYHtASm=sxA@{}vWy_1FG0Xf$dRavQNZ zrg2=;HBp_JS^|20?wN>$lg6PuyFGv>G6D$dM|K5){i(o!VkEN2jh zZ(g`l$V|TgA6_qQ%89%ELr}BDu=&24&iYo@xxpN>eYX+<^GQX`OP~T`GDX#ZReN0XhBI5U!70UJ2=kZ~Dj3tM*LZ?n&uMxJ~OQ!$6&W$SVU ziDR5v8Fafvo^MYoUe1=P(h?Cz@`-0UTrCgQH1jfSrjfj^dWag|RxK%L7<}!DcUWGu zTkUiWe!CBt{T_2@-7j&P5q$W2$86Z$o=lf8LAG2EJe28hx&)bW8O7%cc2%L*xEzjm z_9^A?jsHSEKG=I&Xtci5`S8-Ljn^`y$$W%8p++=tw96L$NMhm+E)_?xgpG)tXSwGZ zR#<&JGYUY}iEF2)5edHcM%>x{h^_Gzx%*T&ePOSZgCc-NCv@*UOhYL$Ti%l!sLcO8 zxG$z}ZY#{zc>i~d5zI2B#|0xSJH8#j3B2WVmF#nQ-%{*?+#uiqVT4wtmS#y=lXfzKe%jE z#I+a+N-;lOs~ z5gn@*489~7NPVC##x9m&^ZDMO&qJ51&Sx#a&>DneQ2a=bJTT`+%Q=8Tc%VE@)Ge|# zQfxHS$>wZFg6n*1}6S#@+V7=Vx>GE&oL~LtEif*T#R}y*whu@rxa36HoBXi_)D%V!a<)>>& z*({a=RvRr+pIoK**M3=7=rHA(jos#Vdp&x2-Ob|4dVXxqw~NB@2Hdw#<_ayc4ml)5 zD&M8rt}w~=tWi^eDbc?Id)~)g6S-$h2^G$^0>V(x|8nYe`TqRgbrbt~$4oZy#4g=j z+{9~1MGRDJw75TC^=7me#@$8&0BU2*KkXF)3q(`Ds#3(%tMU97P>kVGRgY4#MHRhK zWhWsD%~B(iFHH`OrH4@iHzNE9vp+7pO3F9QMI#dhet1OxFFyV8g&{}r0C9Lul8OY$ z6CY~h@Ey7iv|f}JhmDx2nG-TsYc4o3FWQaxaON7SF?+z_F;ZTv5$f%!wN z<&uWqV}VG zfKw@xL$=j!l>(9xppjQAR!L8!OdN}2Ew@zR9j>;)Z*=Kt@q`4+oOWGyDn=qDveJ=GICMy`PoBX}eTSzaf9bA0 z{*Rlt)O7o+_BSnR!FMi@y93115w2*}Dm7!WXEoXYNG0uLtL*B;^Tyu!KHcyhJB26W zCtNbHPfVy|vbJW`2A~p)CQu3x5!roLYM&yE|K%$m z%!MmGJ@9(Q);(L5p8>anyc#P$?GPVneX1{tZXOG-9&O={Pe7TRTVUV-NPtDlB z+}N$Ml`M%Mj?0-#WM?Sj!aK|!II`?RdVHCBFV7r*U_j4JUgNB@F=_4E>hgMwlp0a^ zarQSTowMOji+w@uQ1xDnvNswHX$9Y;M8Z2T`x5TPJZX*+q2kHJY!Ae$#C0Z+AHQu8o5$^`RiWDAMC^5Q9qztk53vFf0GTO1S(PcDPy0DvqQdg02-L?@A!Y0j zhrCQGNbNpLA1!6RVioR2&KP102gZL5!`ML7WQp@@Q0AtH8ETvfPh^d!$s{e;dWtGr zhR0OXT17rv@naP1gbP#tlV99O;tw1WXl@`}rjSN%;;i1*7&0Lt#J#JL@zd?|@3GOO zT1=#hK@WRN{+cR2oh?-9WhXVA?XNC}J5do-^h)XqQKcf#zzN$ejt07ML3W!gl1$nB z)U?||49X8z-zd9UQ=NPGMrYBc%!d+JT@L4YdA)zsiQ~Vy`w)ZU%>70`+9br)J_AeS zJ>vxStbAkvG%&)DaSek)xx|{_LX1I6g{!DF>zAPi6byqnv*!x-55^$LYTc3hs}a@{ z5j70lCX=R8xA{ytX~Tf&jxe$@X|m0D*qJ&tvgLH()M9ggbP4Vg842 zsO)D$h+MFk0F9RZ zrF&EjcuK;~X0P^CLEIoD1LMw|D~x4G)H8d#0s8OqgF>Z#=W~U=kqc&z`nDq3wu$SI zNr>p!CS}xbxi#~B8H@cc5HQ}c-76Z`A%{l-V-s15PLn<`?D|WaoZsl5jVHlupLVzT zZG_=k=hS!8V$-Zj?@P!T6l|yqPf5jM_m`H>DUzoxfo@Zln$|OrrXQ#nxraF0jCja64wJ2*N31O~cVKzMZCMg~ ziu?d1x0GF9zB+Mye}8BnC`iD-9aPX8c#V_&$h~`Y*4gA+j<=gOj@dj?t^}G-q$-B` ziWF{|!b*o6V`cjNkQL*oKA@_WX19!IoMB3VfC10uGp_5zs8!ju;q_L&hh zzYzJ!ZG?EuhiA8}K`E1vW5_-UW1&JTrV6@Loh4}&HB*%(3m(e^YyN5`w+9*CRY=1l zKO}CGkRe_6FTA3Lb7e>|3zB_MyH%=4bC(ZEP>kvCpV!hUlm{yWgWt3sk!nOvQ%xj& z)vpJN6{Dl3J$f{jYw;-^yF2v_`Pvo39_(mMU)<9U*=b}~Ebhz?U&kP67Hng{jEyc| zTbskoqW?WD`$Ql#EJu0DBF+~(0wqMn{)DUAK$~Kh&{vm{i(ZVdyz?t2$w0AxejD3@%9-4y*0(ko^ii9G2I=K zltbWAlc^NjrT!b0)GWRHWO5A<0w44(rJ1V~oSVDb?e7nq7h%GZ69)#(+)%(x+kVju z;jHRYQ%`h{*j&UOv|W9bnrwS4(u^irTY{gRLoiBZl{~prSkQ3Y2u1eO+gf*g%U{Er zK(x+ZDV(Di)8-Ij0Hr=~u{idLHyI`uO9SjgJPyd!NH0`kC&q*2Ry_4yF+5+HO69F`FI5q`VhbEDFGsZ z2+^)P=MnCZ_RCT?yUl;=2I-@M~~IlBSXzwVzg~IU+F~% zl>7oI)ujlR;}dsCRSp(#Ci4_+R=$?<`heI$6Dv)JVz+ih2{XJ)J2LZ{3_4C1bUMADk+O$Ls1{6TNv_BXGO9wKO$ohNf# zpn1Hh^miaCo|626)IceE*l~NLm($?V|1FryzpDcVs^)79@?nv z_@L>FsxbrB7|g$MmM>MKB*T_wz2Z927I(=DwA-_@pI#NQyPFU?897q>hlhSrZbejP zrTZDKQ*e0s?Z!~xG;PX<6>Wjcs+U|Z`*X(;n;w_fJ-z9gqS-9<7v!w(^gG+GDy+M zBo<4jOI2lz|-{Qa_F+aXy?9@fY0r zHpgwKliAvg#X5c2MziT+(Ba{Jl%oxrCX=0TI_4MLMEu<~uY{yDx6{QjqcvJcz>ex` zoLs&;Clw(5Mm;ES{_C@F#b$7x0l#YROBVCLRNc`&-}@l(&u``fKOIi<#9%3K!bw4k zgC?DMdixf_7`U7*tq$o_U9D58Z$51k{8!nr;sVV`MegZzO=j{Z~v4|ubcSH+C(E1h{^lOjDlZDMP zEypBeC^2Vg%g~SG^6Mtc!+Wdlz0U`s$U?QHxOylFTj|D+KO>~sUJ6(YpV+)Ob{f4? zC>pKiHh5x)X0yo!mZk%m()1#}jnbY)^{6uq-J-x`^dc5t_i;x4fsMc`AUeobp zR|mP`1hNfF`AUoQE46NL2BI|}Ig#qk>hN^Q|1w>q+Sli^k8%tax!2?hf8&rxx+apK zLV`=7%Q!n)kH~%nSQtLpDOnqgXXELheNnLiiuH0y z78_(tA2WPGrLhLx1t0+H7=UmXfjRi+a1;Zp)3ISj&3}A(6UQusTR%}U`0Ax68B&=eyH8lNJAQEC z1Ltgh8mq!+@s`QJN<+LYkUgMAm@iY`1Z0c#vwrsT7fMKIZ^XDCFZ2?Dp^o~lF-3*{ z(*mqhy5RDNYIFzB(P)RBr_~gnOhU1M3D1hIf>&OJ2p-7@lcuFmUT`=~lnNs=oVr9M|ilUoX7+`7fISM6cX88@YZz zZ<>*-(yCcRF!Mg{pvDIp^!Xcf9sYpKE5zb*GZadL^(XpSpH4ljPy&EImRb4)-_R42 zCLyPDUga=l!d9*vA|d->h+5))w(Jag|7n#IiP?$u-(H0rcDI<fKC*S9jz808D0F5aw&2QpQ_dAN7+ne)6u8a@?r7bfY z0|$VnNSN%bKwwmaAeSxh@d}ocfcrdrw{7-g$IyDUy4%glK$5Seim6JQF;%^6@43D_ zs3?<#?Lpc%z$2ZLqLNrLMN+E|a{g zbvk(hZ-(dS;_1iOiMpfh3OO^DtdcBc^@0%!~1$}}0(A7TYW zAOr_WvH>Lof}dYq^BkwsLnB!cf_$LVX$97c&@1-46~;E!1mUN~x8N_rlz7t(iMZ@$ zL55A!pJIjjTnixHP7fEYBz>bS!T^KaTwy4!Dj?lsB#tZ&%nu`Nxv-=5@D!RPpT=Z83c`z|D*NAr-;U=Bz7)}566G5t zNT8G()|-R5pEKl&eYuTi)yMjwnlQjsRs%X8D!v#+m#P>tixCc!4cAwJ%)%+l47oI&)%>a?wkIT1o6nrFKu{JISjo)D2Jt7BTes1ohNF zd$(!*c(}E|Mm|)G3e*C8TOq9N@0gE(>C31f1-|MjeBQ}3;a5*c{)STeo&s&|M&2;o zFBtfR{yN63EN-i+uJ;>+CtPqsl3SV;pRv`ag6uPJ{Pq{x-_@i-)x~a|T}Wpg_DzSU zhv2nr4k1VyRKbz-?*kE{O7QK@&gT^V@MsVcTDRZ0hHD@hwB(-k@BZc|1!H4RV9$g- z+sGsI&enB~toLOX7hVJ1oT#+~rI`rin(svoe+iwf!%DMTThnCzk$dRk^x>KtRD^`1 zFc=b>(Gf87dG*4I7yCK{vTKUR;D)6$(IsEIr)L-;CIq|hq6lpaLI!I`6+^n91nx8e zA#(=5X}vi9m{H9DBSbCqD>hjD`oCeGENn8m+u|&=*OtbNkKLFfA0*Q|aj*t2_-(GG z%s1*%3rdCXQFFkMCB@4^MLq8Nj>H|h`#S)N12Lji28C8rD~mLMia!OC0e(?3{z@?r zO6IvZG9dCP^(NuJ@GkfxW_BvQcBG9TYr9{D(v6NLGe_o!!eE?GA+quwTvGh~g_TNt z%t}K-*H!PjYlprJG{rDQGDiRD-8x7{u3|Z!5Q%HwSEd^%Qt_*lPmShDYB zMB`4;=Km!-7Ry$+qWa!0x42W61r6fLJQle<22^4U$rZU6sK9LxIgDep4i)Izin82! zo3df<)h{rHYNZMpJf9A6Td$w(#i(NHv0`PAkSPiQF`^LmW;*-`&;J|M9GXHs82U2kl`tjklC#+PnQq574^4N8oqSd@3C@8j)C zFFfjdm)s#({_r#0tC%YSRX}e4c>dxawzCZ}nb02l;$S2hU;G0xnNNB;R3}U*di;AE z@(PJgYBGdCYT|1E!#sGlI09v-i=$?s?t znw$JnwAmO$9{+YkQJdN!pl{28B2|NqF4V&3L+GnCsyKR*31O|u_@we{c#k2FAvp=7|8nfLTwr}KkaMaUf=VY zW{8z764idW(#VacOqZGMN>Yr`RV38orxncqK_O?T&iRjB4r7u=`&dxcnXFtl*bUnJ z^^FemW_&Qd+#kh_h@ps`t$3k*;4Y8@Uv9#9s1c3VZ(LfZuICy30@pq@iON1L7b)x! z1NYdRA1268C^^1>Kei)2J=4x{dQ2l@2fm)UDLa{>Qb6J}`=2b%Z&e`Y+n63!TayOU z2>}D`?$IQ@cJ#tRQ`GrhKcBHo&Z_8onz5J&q_eQ|H8yrx#0lKOD{e@uK^B+&4fg3| z8iOv|UR2Q~PqpPrY?`*=231{eGp`|}Kyk0^@k)?!k+Y$ymH{G0dTOgCsQDR=PorsRR zP3X*(Ye+hso<}I`wNW;G&A+J*=!YjKGzi3IAdFypetP#i0(}x{cuf39vhi9N2|*w_x}1M zU|JbZz;0pHE@t;7O4XaR^^fA$d5TSSbQB=K%A5-bo&0(J0ZL2TL=PedkJ8JNiMc=n zpx3Dyk)lNuN(B^)<{C?w=*IdRTjAk=nswfiX+ACf=v$z)4z(l}?A z`e_*O^M>udz-_n9Nc*$T<%Vevy1ZMYb`h0J!H7c*vngiH8fr0dJ4h0a8g2=tP~6yWa(UBvSrk*zbl)0|W@GN1pC zBAY-y5+qCD#V4EngQGUQc)mo*g&N_?Ii-($AXFAP#RDfgb*jBYdYoM@1^fqTs*#q> zIGhBfPcJ15VnD04YA|JR*HmF)w>0=_5c@t=Zk%%35>8%WBmpUsyU z03OAe&i)NHH3^$<4<0}V?heyvReQE|x?E1O3bV#{ibGZ4=>i}ldq#}@87I>Ws6)Yh zV2g-*qvlel!iGq6H{d8-0p=_&|01tY4@P>Kz*V?Xw&O{(TSw{^2p~0zX_gx7nk)Q) z{AR}?;zDFO{rJ6wzsr>~qE*)FU~GhJj)^zvcgtLcXr?kt`II--Pirw?Zx#(U7tmf; zSaqw%UlW4j;w9F{_IWLKkZvh?j>c12u+KW*E)XwG%Wt$f<|z-kAXaIw@VVUQP-gZ; z>~NGNR6*|f8iJhgnXNX-Gg3R5Eu1#o%m>}M{N4HeV{B`)YAIaus|?3*bapp{9oMqS z3PtxeKU?ml!I>~vo@cSriR00WVnvRT{joc!T&aqg28>?>g-#LIGN4w#!GUuZTqS3t z41EWV%h--X2yEIG5ym8Sc0o6ct&vi)CWwL{6z z)07gIvBLQ}b@7ZVhV35vAmTqw3T@n|ilkzA z#5zb{gCj9bX1hnnTyaNzc#^7me<&m~&5j9i>} z-94#Qy`W+7Mb$7O+EKYFlM^vC^J(bBRIQAJJjq#Db z;#fpi(NfA^0DZK|U;l9h?SMt`TURO41>6nejhVjvParFU$5%Do)PiL250KY*`_V(! z;U$d%z@X*=ad+F9h?4{R-liu%(+)N=!g_r!u({fW4h!m1S z-+MD+;|#cPBjqzwJ@y+O#v%pYfACZ`N9ffsn6}>s0 zBDBoo`NIlpEdlL}SuJO6F+TUb%R|x1LR6Y`?PrH8g02+hXXZvRJq}y)h0>q@CfesV zi>(T1VeT!KLa$jAfoB zu~G6WS(EqqHs~LuZ)MDjhUtv&-m>x|m*>66?egzg7Y0f@=-dz$zW9`d4uL1NLR9*^ z^sUYPHj7UhtEm(xY6c0%1R10mXEJMR$#Jdc z{zj|g$8NHnZjT7xVhw{j{6pfdfu8*KGU~zKGiEDB`gKnTr`{7dUK)>s=200drtqn{ z7D57$TrVb3JQ08~7XJN?AzBmUlTT%M-~K{O7*((EWKLPv*C?(i4t}wcwV`70)Cokb zCPJJ-Zv7QVBd$a?Fvs;Z3sm)+smkqUIF2<>VuIP+f5&Y2i;+TlM&hoODorp67U&-o zVWBEYaExxO^sJZ3|Fo``0(9ERKdQI{H{{g?5HhE8Ls6$pxx3b^(e$kn%JQW?cIq(a zORo~oizhQGr1)KFt{&M{;42&UQmkO{wh|%_Z z&!b>?4T%#xnm|VlR{^EGj5WF3M${!l6FHEvvTy#xgys0wj4ua5$f_BF0VoVu+3$)h z8Cy(3C+T4KOURpqZ7z0*uXp-ya%Yj+O_~Vp>B*s}2>?~U&L&$ZLD;a{hfSZfWTpgl zB3TZ{?^>UaW=hR1CcR}oZ)1rT3H-yrQ$3WG)p1LuF&l_S8Xi6;Zwh#9M6@N3@;jQ$ z(5pr-6gy)-jsUSEb-6jvXK^!KPb9*ba+1w&NppM}9OS)Bh47sfzccZJZvQ(2Mzz|n zgpAf(o%-V>($S9yc12tJ(s`s1VYXQuKASE>bM|~QN>HWrTf#)dY;?VMn!-quiNrHO z+nhV9rfs&|34FxC9?jaX#=;so-k3d&_`z+QIBn%^yW)F@PECT~RcFKDpSwyGA=hcB5xcD<&{)Y~q;s%h>1^$w3O9=eWMKQS#Io z&2!t;LQm{$`C@jQK4M-!6^F&n?a2b{vT!bA5jK7Hf|vY}%C2j|AROd04RQiVS#Yrn zxdnW8c1NaIo^a)tmO=jPe%V@_Y=ipte4nT_m|BrbeS7vVCM3+W-_FRY?}l`if9T~HpGT&5~YZ;%M2Ds zK>XSkmOsd`^gOpv+2hNppq%YoMo&k`O#QHo{IBtJ+1lckhsSSayg4aZR(~23vWa`H z*R;uOZRnO5_m04V^mI@>n%PWZ@HZ~)F~--^U6E+q1_$QQtP4al4r%7!4%X{NA-shq zlMx@SVkXBu6+MWjI+L?<{J`1%O>ZmKvdkL%rzLu1;+EB*MC&P0txAlbLbtbhu~tXT zBKC~wEKR6p-ENy_>4RV0dqil(*rf@vO8Lq#wsdZtwa%B#OvTZ9lfq?ikagNMe213J z_>^pfcf#}XF{`zZz3CrB>9&{Uq@)j-iHDa6Ps-kA>l$SM6c2bO#eSg!VrHYtUaY?5 zlr~+j=3dBSf__OBiKE4~G7uR zT+}ovS202@pE9kgJ0NyZ4eG%Bv;G=e{y02{Qe2Aaw?v56*U4|8$k6JLS#pLreXu(s zA#V6%7cP9mUn3x5Rk=BIRZK5%HF5<>aSDmN`WGy5%ndd5Pz%@+KE0vU?mM4RTS4qf zrR3WiC`D+q=Ty6Bf97PNEabBR$U&+lY**ZSjO{qojN%THaL(mzFbI#n09n8jQHVl4 zI9=}RW2p|B=qkG}Pn+=b*Gm)%W{8HvbN)mEKo2+Nt7lIdVRs;lgC8MR8-#hy1^0U2 zSyGD-6(48ddZ!m$I%q(FQ!v7ZAwIR_`c51-iEVkLIr}#}s6;lAp2HgGh&J-CU%FkN zrKtt}Z~`K3g9}SzN$)BuyCNd3p?RQqjnr47Gd_boMLPws1G&)y!YhvARnkSb^BrVK ze3{R;F`8&_ZM6kz&ORUbDXh=z9~d@UCA3ysa>bcj2+!dvsMu7mGj{ueG)Gw3A8fzE zxm=zjS#Pu_(CPvl2K9Q(@{0;c)Ebecb?m^)SqSDW;x1wJq`oXU-H_fcJ=&iK=f+|h zFH^Ji5TfWJ{h?Rk6D7&I#?o1u9tPQ<91_H}RlPz%_6ZU*r20}s5o`>CLllrNKf)S= zlkAaf`fM@JS{3}wM(+ZFlHuQZspDcr27bC|9`j65;|~vX-9DFQ-`6>JgNK)^zKM(l z>08k}-jbwDS1ZiP<=tDF;UEexn%rXxIj)gn20flMZ01bu5}i2#wPGiLa-&$Gq|W2- z?m^t2EJboML3kAs>hIhbxJZ);IxKW>kXj;P%T($Gz8x>3nEF=OXxi0=GMs`zVHmVL z5(%o0(6Q8_z$a%2-k!aUa6y;UDPOlrjSM3A*S7Ucd$QaR23C1UaGwaDIJ#Rf19w_x zBlzS)gbaQ9#Kfi%W9cfkK?Z;z^pyYLn1SaOQ=G+E{z%tHZ`Z-xB!OFB@u5IAYYtys z1^SHVH!8E~+rTire97Hoiia87J_n#nU}YhQyFC=2ah$FUQ|pwXdNC|t8#iVY1DA_~ z1_!epzBFGOT*_^>JUJtdg&R8rvSEa{@N4-1hI6yRAG}8F1}H!hA25RAE-;e^8;A*< zT(mbaMt6xQFsPDyUlkgkP{{kE3h@HJwQcRu3o3AQ*vIZll%6#{kt&TRkJ7QzdM;Xg zK_y{NCj9=e$)@wP#@v(oQki<&&yF8Jy#yVU{}wS| zs>_$(%fw|ithT61o0TXs9_Y3P9e%Ikpb~t)2G0y2MOVU4e!~}0icb!Lw7T##VaDsS z{2!vuDlCpJ+|sx^3GPmCcX!v|?(Xiv2@augcXtTx?h@QJI0W~p|D2g;?)#!^cXid? z-&*Tk{dnxx``qRra_H$hCucHl2p0G$d4xLnMKmmMj|6o1S>VaC_=B^0EBYD4{2P{6 z?OB^ufF=x)|I!xxGmq)_>}ZXChZ&H2S(8O1WsK&g_r=#Oi|i$_044P4)awPLzshTl zeTY;2mkFLs3oZAq<(-m3w!Ta_+WfaTsxe>cD=_w?%$xpC-8UO;^ubC}o4un{ohDgn zqMsy`=WU<(Q(3BWxqbj1FDJLoBhPB_#v)UK6~dZ{1-439H4LZ@Dqw^*Sv$K#-~i7Eh3+JClOYa3JsT=ba# z;}$LENRu;+3o+p&unA1wA2IlKFIO^F)TdwU*iph-U}=fFRhS%*!{3x?r^h1Ky4qn| z{}H|&N4%=KzXE6u)%Sf!`BcSD`lI_*njN7qt5jjL8nI^yI>KV=9ot5-Qo!&c3bBN# z(Tuwo@5^^wB%Bq=LeeEj3?mToj@hwqON3ITWJoRDn(%~;)@S<>mr8HEi9eMvO5^?c z>PoqBX5DXNKk7{|lVUIu~g8zd3zD-AVRxnC72bA_H{b?Nqiaxwvu15#vnAJG(9 z;K_A9_oq1r$!ONgHQ5??y}L?XbPreV8^7pJE_-yTarPojA=bS!;b@f%)-j9&0q16A zy8SVQ=s{x330IQxP6*}oYUDCbKbNiJzQcgjg}bl79ty}pzA+1%%l-8H3tlgd^VNVr zO_%zNZlEa8?&ly(>Am=~|WCO)W(5HU_>OXye)^C|R^@J_;lXj5da% zeUg+!p^|Loi=r}QC<$-tRG%SyviS5M1&R?GvjsYqmL|c?F8<9mSRP|&_xKga6C9;Y zeT|kKduuD!0H6;fucoXHMsn#~#kuEO^;#|V8M|*KsUHqocMhs$!VV0rAs}A>mcY^D zdA^cgbm)F=l!V5-QtmDR)rn63#Wz8XCLT=DH#29`)E5VA-tzn&4*DL61h3yuEACJn zgHzD3V*?4({L+8trT$0lvcZhEaXpSQB-4ngB}7ZTDHphe$i;mmAJk8Hjz-4+cFk(q zKb9e5gs9dFaVg}EVE@?tTcgU#1EFPV-XL*f*u+`A?((tY%EzDmHkx%qelXmzeAwT%-{7%|_D-lE3LGzrk9Zne{u5qS zb;gfY08!yvGB!K93^BzqOEVamEuP5n@vq?j!qDfi*ty6Y`BZV%46dc_DLlYHynY~4 zuD)LhiULB4%nBo&$Xj^7$|=nkUD2dixeo$wK_ZTPVU_U?+yD6f^dZPpkveZWS?o%fnyACcpE@$88 z+)L$8FmghZwTwaa<_ieZ98Bb%5i){|s(<0Fw|-~I_W5=5UL$Qt-pige_%zEt$+X!N zLwwj1yEn=E3IVtn==U==KC=@8M<}*tAO+M;Sa0@Jlay4)-uuu8TP*woLRNK>BBR~t zsjVc&v63eQUn35*xo*L`w#uBnO2C^}Kb??qD=#*`9~kf{;1en_9#?)$gyh(BAF^}@ z51pZ@jLn;oC%v=LmTw6wBTvY8G=r`HmKMSJiWy&K-Rv`_%oBK2_V#aL=HCG7X9Bt7 zdE(b;F{MrnR31`jc9!B(8kK$SuCCFueAuhxa;4^lR-Y8vLw>W(bZ(2UqXa@&nB<4h z4_7(b*AO=*i?5{c8Id0AKj6lMrK`@?UklTU1(^#~NoIIf-#4~RKu^NIdi4K=XwO%q z)Qt9rIj;w|858NO*{UGgZeOOb*dl#MX)qC1q6X$<#q&a5Vk!7hU4&J@FX}$J{L65| zZvvC&V(OQv`r`I5@v+%gZSb!rv95vph%-BchElq|?N7)xfdS7+T&B$2`>?~HV~=-*R%)nn z0Mhfq*OB8(!%S}3dUD%82%ifbqnmXSjs0qH{Wd{QK0=K$FQ5VMp217WNq}$|bX%!< z(~!f|Q}}3I1m|r|N@ViuT(t~FPfzx@Prm8vBZvM-I6R}fQf@(%inI_5Nm&Yhn55Js zcC+_vIMQ(Jdm~Id220?jo)Mz`Ud@KJ7}f7ZLSv;s@yL}Lon7eLSx(z?Iwse<>+b(N z#cl50HFO3P9aQ|7fkQo3nrLaO5e(vqkAGF=ULMM*zmBK;qsSUW=qvVbUrr&)w*AKA zl^u~7cVRPz_^MIfWOrIAhH7lT$*q>kV939wq?Md|Ny>DtPwVT+;3B`<+c1W<)FjiD zeP2m%VV?hm;hZg{E7Vn|>zsD;GyG4o0Q}i3B7U|dnQG~46j&*rnF92}fApj>mBOYX zz}|a%G?xD{BGKqO;w=;Sa)YeRU)pNQ*m9d|Npsy$`YTa}5ONTCeiuH?5>?^{i{!Qf zzL`y3EO=4SEdd#cQ6|O&RT&=vToQ_9U&4)vjyt$4bDct_TuMHn8`A`?FaiwF2}Tp7L&G4 zyymX=RqeQ8Y+p5I5`7>XugqfgG{I^(0H z3j5qifKkF$?T=Z)L$&|VCrMRn{IkuBP^)Q5ZXMRNua2PCr$2+5TDQEBDFU4B>K-j` zBkYe~^f^kE-_g7s5w*dJ2nbhRt1dsAQy;xCmH;{XU~oOcY^LQqtGBc!?qYcx(#gCA z71Ak#fDUI;R0!`xL;C)~1(#uxCaV2hyMA~b5J;KZMhle>jvx-unn{FmZ4zcb!e3?@ z+>jww?0hfSI{ujEN$a5{n0x}a;t9o0vs}D)f=7V+A1>Q**|BvUM&6O;;!3+83Qi0%9z+ zV@a>Z%u6~4W2c3hXe+n>o(;;0;K=d&UWD5qD-5g~r8~t=r`=$~SvMl@r#|jb=w0m5 z)G2Qi#HV7}q2O;R6WFt8P&K%N!{Ts+&5$io&k92>&%e?}S+9MffbqK)yzOB@pUdeW z>3>Na4;Y;;uR8ji%>@>7Q(xwANGt?GM=)r{3mbC&S~U0))$Xk0MG7|ISE=NF^IgUy zY=-{%)NWI4;Q|_JG(aq)mm27AXE`bZ$AX9E=Q)PChv2BCpr(gp>Tj45@%+b(jfB5} z*awIBbwMr~a_yOi$eC=zjGdG1`vmj>crUR80y;m;ZL!akE%ZrgI&;0$i=SvHMs#0gQyb@2W%mPix0w^ zMc3*Iwl6}$zuG|mO!~QD?#B2#jiIcMM>*hWTAbZ)oB5Ge1Q^T9$26L((6b4Ie`3)V z99kk^GgiGCYv1e*x#2>fzqT+i0xm@jL&EACXB*fm&wvS^TfWw(hpTna{&jXj!d3UH zVvgVZay?a=FwJ5VDphDK+M=8d%2zG)Z+#9xB%~2+1s0Dy8Ah+L?;TI3)Z=^ehvmzh!IvO%VJYww7dqFQK%+|l4TjkEvr2~qW57My2M zE)hmNnpA&h2a%Fe>X@%ayTnks?mTJr--3lcBeW$JD3@Y^)v-2R;9ZZEhM$P80%JIf z^@b~}8O2Aox~L=>dI?6y8iEUX_lJ21u|-td|1#^!RI1M}h&et^qVAY?UhB&TL(u4H zWiffQDxRz^$`KL4_F@75`PUc=x4)n=zMMS+?FSf1RgM6m+PJB|9~2uWM*sMW6%6t+ z9FJ_{ULOU6Bkf0ytr3DcJL#p;)&2sO_z zFuHUm7#s{rWRAilL{7+zX50L746CPJVvWpA)H9QMTQ%*$DrU+X1GeZoE%c?6Xh%7C zCUTlbQaboy4F#i*`eAZGC1$`yUi8#l0cT;&v0*J~9v-opd12rLGPEZo75al?KkX3% zfnK$7^23*f>)98cqB%7p8TgS$T_?ojkwGfcna2q?mh@0>wH|O_Yv?>dFjlg|iNwfG z1{SOnU=ZehE;Vl#{kuRQUAuz-A?8(mfOM!&cu&fxN6jhcbAKzhV^i7`aQmt5a z3X&77L((NIaFHVu_a3wP0`e$rob>QPM^oUo9c)d=k%ulyXYC>q>auH2NaP+e_;Gz= zKd_EHc3c&+;=vcH-ns!~&VBxmEE;`Cud~D$S+0EL|2fw&Ys-J}K2hBQ_VA?h*daH(k#FO} zkZ51nU=qc{#Be+&)mi}#{6w`? z%wCo^mZhf8+H;tSvZ)fk5Yr0fS6=<)GTBmRx4guY6Pki1!_doM0-ImrCVn_>a>-I> zKQ)Bdw8xnB>6gXJH-=miIgnD<7e118022|i44L)iUnJXKU?ZAM{|66i^1Mc7>C#nt zDl}z*v})O4tArHY;NNg%$Hxr1h96b4Dnx;Yx$`8ZBpQO9DQwyny>Q(wJAF&NFJXA_ z>#joJr@$I%sb#7T@2jMQ!d~shdKhNOADJ{pL#o;VYGplc&#N4|(q=vmkX zT8o~f1ITeQNbRFk603U$q3=6K}uv5!b!u$1DcZqXi851F> zPkUKq+gpGihR`YTNjCDS6yJuqXf4Xclxdw|V zvL@CLKN>=X364uxDBU*E0EJSW4!hr-K2{xi+>b5i>y5G+jCf^KO|w9_Q?{ph!kI%4g91);i5^ zzsjr-@I1uT7-{{y>AB7Ac=D0aA!$!@%7ES$`yl!P{~cl$YcgO%bPZv%fY0qO31A>j zQKgKA@1`cW0cfNN8Nl4`$J;Z!4U;&r8uQLBj7ZE{psDJ$d)O4|V9b|DAS+PYY_>O}xRJ9@kf@tJ#IOJ{erO)&x5!^~ z`qGeQfE$+vAaVW17z=JwItu_)wQwMHsPt&qsH4r}f6DN_sb>0m!dgLfzSgb5XxL2; z`*7g|cSKqpqU3|QOZuh&RlG)_*X6^}_U>U={f6aU;hXezzQ+_l7DUYDpx3({1NvTJ z=8VfxRDN45Rde5O^3roKk}wfW2&Dh*ha8PYw5YdR-$z{ASzjvjY$VKM>r<%`;6^VU1em& zMYZ%u2=@NVq_Pu1Tp&fwpQQKnWzi+J&SkwoALSQ65?c)HE_;krMGY+}G`bU}NX@bS z&5}2Br$APZx+LQBs6wHTPm#T&%(A$r%sM}lTPfAm#}!y4MS8*D&B!^C<4)-gjUAV5 zslqkCIX75KO%R#>D8u=Ye(0{(`r8#A7?d)VD&>M2EoWX1t6R5Jr>MKzLg{Pu3$ygv z{1mr$~f>ML($%aNNY0Bsp zb@SM72lfGd*3$U54_y*(zn7?5oq;0f?rrkj-h%EK zHJb~pxf1Ng$iv0M1^AEO+hA)hTrvRnR&jF9J8^jh;iDA?y1 z8A5jSv@A|P3%7vFrTlQD3#H@Zb@Rp9l8hxWWS4*F&9}GYC(Sp(<$idECrfRKdR=}7 z#rATBW`a6#GAyEz#wO35+J%SX#f>g62WN5N-)3=dGSECXKvLt z<_G5|T!;UP*;tMJ4E14*FSgor;-C9Js-5AY<0jF16ts#yaTFMfWLC;rHoQkJPBqC> zG4r(^9Q&p@bZEYNSkV=KGWW}6N9I=_HSnj;6mSMuCoszU)kr)(Uv+-1n$xh zEmTpc66$2Jm`H$Bng+v!w7*nka8s_|8+tl>RS2NzB}cde;&;xhhoxSiDzK;E&i@!1 zA)5HM$@gbAb#m(%G^Ql^T?Pxzk-y_@BHxs%W^ z7hw;?KS~aG#<*UG7zKE$pfCbbvSpcIMcT0QD4Wu;%5v>yv#2ZN-t8Yc3YR1w!B+kJ zO-O@4{`c=dr(J-dc8^VPl>zVYvwZZepw4vYh1JmXjxe9Fl^?Uyj__wdjIve@K-+N! zQ5Um2Zfz{=#)DKVLA9YV=(Rr!`zT1iN;$h^nnU_<&6=Zu^qm(Kv^M#;5&*kvC^G+;T*2PCdm(l9i~8U;_ap9heJTSES>}>rBIWH1U6e{8 zy?=Yh`!PC-7F5%6|6SoB=mIvl?k~191MLRW90mQCWNB5iQOC)|3ql4WD>}4r;&%6E zVKy;U3gh%ac}SOVhn84mByAOl0kHKo&XLg}vSa29W>f~3SNqnobjgUXL~cZv0I^jz z9i#1SVJEx}K;)F{B2WnKKh^_`oK6d>#0qGIOwRAgh}9!*Hp8DOJgydmMo-CbDMm~2 z8{(l}WT2bca?Lo-KF*SlrBHaxMQ~K-L@CQS1w`Kf+ir5&#JbJ_JPk<#Zk;Y!c=x}= z{9ekH>?DX-^iGqg8U9nc`} z>%viA*=<6G|Lt;WN4i|j!{z*>HC0!j=GL9!h(TT0?4UWl@f&FC# zl~FV*osY2bqP`0CME7M$7jlZXiB=Rk?WQrc1G>LJ8+!deIK+Od6Ivm>u&Vl@*%8`p zYy*vz>6h+8&=)Fdym>%AW2o(Zso1WMf$6g&5+D5{7?OMn70Nl8E3_SGmvxhn_Z)}z zW+U6^1)aXuzwOv^Z$o_4OoX{i-1m%%J9Cv)+h94uug!0n zXE?CdWnYu!bwyhL>(VTVO*e8?cJ9@v*e(g-GJ*@E9#)+BM;)A{5g0l)RFp7l zs7M}*3KA-Ysjl=-W%yJ1bpKm?8%Ojz>+Zr$5e=rEw+5`rOm61_-U@4XiE?~bJ5gNu zj>=#3yDsq0-99(M+FgT`(Xdbo0g92KkfB49E#3y+yLc<1<`$UVErmaTNTTab7LR5V zy{Y+XD6~)=VW4Ic@H$9>j`LTD1pD*lNnVvLZwXn^9+ck@zF>n9BF#u6Gp0u~JrbF| zI%utwj$`Nerul1!8Fzm!_`e-?u(p&DZ7vI9)JQ+Y;C3)b{Evc3IY|q-RGbw9^-pk7 z8vy^0Nbe3eHqGB??IihGG9qONxR5C~XES(|cE81Tl>$p;kl z6?kda&=ihwjUP{xliy5Wk;^D02wSbd!h)2;obp0{@fZ$ce5V4tNvqTx(vT~*&(%+4 zFGv3v-!c<_fsvN^-?Psv3BKUA>x{sM7cGcoL95Nh9GQFQjT{dkWp(pPpw8_|AM*vT zMuNh%Ba?|EcmwDHA|zp)Z`uIdhmSmzA-00VlqdNOe2+9rxw>Gk24r)w*x5IfsO@65 zg1cZOAip?~&E^#@;z!X8CO3W|CO7tfNm7dC{~7i>B;YN1rqO3f6Tt- zO|88a+Q3jzIqOr@ZJ)j^8N~lDK@G&pUJm~dGI6dk&`#Nm$QpoAG7u%sq{fRRe{oraij>mDAzWE1Ci25b)JuF$ROz&~=HwEr_QnG)0T8gW90ggqYtA4;~fwaeB2MZ%(44eJ6+1w}> z25+?8;skB#aDeBkIo>kITN3!@;dbldW}d|9S4a=9z}Uk!mlg=w`jGUtU1D9Lp2(nK zl2T0$;u$A}VEO8_Z_=p%{RDN;ZbK1z_=RzVmVCA~vC{%-oMr(2dZ@i9I83 zY7ZE)Y^J>HNzdqp6)F=YU;hK%gR?q#Au&zKF20;m{hVyOJP5{S%d!hO_VV z;m-K-2hZb5t17#*EmwVOrOD#wWueOZ{D(hq4B{kqUZI;1rg|Sn7R9$Jk=2RglRN-m z1sux>7+;z;O?ZD@p!K7o?Qz2~ECI1; z#t&`5MpU1JbP}aES~S>@GS?0p9hC)fYeOKeDcA8^W>}i0{~I9Nvs)|cthH27Id(rw zO85IL^Gwf*WV`u(2=e7Ez#Sa}oCf~KAB$xG3M}q|CV9kDBb~h^WU*$KueDUFd1<() zB?fm%Z&{`Kj{;}fTAC?96^d+(JCmCch6A#6u1zmx<>EG)6#hW&y(fIgTday8-isZ= znk6FLJc~0w(j1pD*H3;KlWvkFJ4D9^hP0H2o?$|g>zi-IHp~rK9|@% z!0ssCZgWjD`Or+gjtC78p$taZV_EiNivl~KQ?bcNt4aVQoTnVDn^Y+aGKnPHei!wf z*TENq9wNSBnj~RdH^_F~IffCiu<#PbH_#XrEgFmxWGg~Rq@MzL_TnxgkgpU0wa0$vQ!DrqE}YoIh~g*f6yhle zjZ7|7GQu3iY+g=(tEG|im6=iP0UD;;4ne?0+ke_vi#4c*?mK;HhEJORk!OoCdG!6D zJi2!rq#$W%SR+yYEpIrwpB0iKOvSRGlcboB19g)w2|e7rEwOY*i~Yg;P@~KJIP}*H z;U;?(nLxP{{7g5req^mwoPJ&)75b^ucDOS4F01ua_g8QVF@&AsEh6pgmkgCs!avsN zX(9~}5>J8l4pySju`g#4oTcJ3=U%^DJ4z9r0PUdi) z_TxXRXPEpsa9#7!#-0j%+ZCwX6iZPdX!PF-E<^UwQO7(XJ#z=O*@Pasvhw+nS@aLo z|LJ~EsWnjj7tfgFNXsb6zg#3>CzFORapz)`s4VzQ%N#WN+>>C0y4&KS(YY3#O^%Hp zACKL$a9qb5T?8=IB`MTkN4dxlhSu>1FpjKSP9CHj!WT>()xWVP#dLviNxmrM>YLE# z`RgmmQIG#?N^Q_~mVxSTBgX28Auz6T9wZx`zFXX>=ycI0rmZ(Cp0rS;Yvf9*Q4sRN zcg~ueZ}+Df@nR^FBy?G$M;mr+XVdFVJ_A4%0K;md5Geq$zS)2s`uuk=O^Hh+U%C#w z83}zDFW&)}+g>lTKeBPB>!}l%akVzD^b#XsRllVez-;-Glxny^0nktM!#aiEg2U?o z-p*0lNVogw<%R2eXtPhBmo~3|QfXC=(43MMpU3%Z6LqkQw~FxH!S^KI1G=4M&FNf$ zqrkoofHUhJ*R1BBH0YOZi-vNro$&$cgu`W{0wk#-StHAopY_PnV(3_X^SeG4?II-YyCABS)5l^Iu}NfLk-oY9bzt9wM~j~Jfi?(gRR zq3r-O8MXJtpOAlVIh#4JI6%uv7XNb#5Pel|CFb~@4r(+eZegy(m0h=8FKK4`t28=< zSo%GVXzPr+D$F&U2g+m6v7yWLU)^K|r||Oq$(*>u#&4oL!i$x5dH713V$svU#^r3U z*945E0oIhJL zxYE9$OXM%i1pMfK0+IW7(@eqBN{SYf8me(}_}1FRB>h?p6Y}8@G5R{mu4WhKWf7Dw z7SX=pp<^Y2ACEi@iXX69OTYjhkPA;@r|?i?>DN~##pyTDX6oM?ob3iXWhhCe-H{l> z?bxrxKadx}$f^@5+a8RlL*h>Lare8go6V`KANwIHFzvML97uh<@A$dHAKDlFDzcK+ z&94XZbo>p3sE;gZgJ-@%j_EKf>{ut62Mb=UVs1ibNH#F4b@P>IDd9c~hI zJ_5V{lpyf^=pR$jxiclVY`~oj77PDRIK52!y~48JMfCrvYzT-T*j(o>oJxRq3O;F2 zQ4V5omqEmyK0)+C|=pC%GV-==KL)L-6soYj`@LWxw2X zbt#v(C9F(Xh4>vwLSPiyyRRd5KA&eSKW&^Zy%{j0R--qipMFP>dsO5omU}%tJ?P#? z*(NbEV&falBRS1l6-{0q@tLHqVBvq%Jt$n3rp6jNb>>=7C})azV#W7wHvB7MsKx(bW1*_()JlpnYTjC`t1JFn zX8U7T(7x0l6m@54r~Ks*VD)S|i02WiVYBbn;i@e&H_u?FFZ_du4B6H?aYV^B#r2s~jHQ%Xz<@g0(97q9D$TUU-tQW?By^JHnc zrZs#4Mf0}|DU#ru-k_z3j=?%bc-@9*UD2{&u(fB?Z@>a1YMIOTHeW60JL6B14@Vc# z821e$-0dkQYOI~d^=ObbFh(tF3~YQC=#!!`B4n{&#My6+wN(ck{6(Jl+ni5zWr0J@ zSzL}eOB4fvVcxdWOsY{(BLq{~*k!(|6IAq%Ugf&48QW45x7sCxLwVoboR`Ef@_Vbc zSfka0!5b4?hYp&IF+s0>%4TWJ>~QXa6bfS9yTD=4gi+;Zu~pw~1^UgZ72Ypvk!%Sy zk#!oKzrj6Oh&PIpMd^rf84b1|1_{IBA*~;W8rE-iUsMWoKMsi!v9=RaeMMg6J7= z>7{4Cj5msmpMds6II2X3LvW2VZJ&Yd;W&=}w(GLC1^H181S8f2vV;JhoE$A*@Pf1Ig+01vK%^-5hu zs=o4rZ~y|%x;Kt<$8p!u#E_rBf)g%}!Nqv<)oB1&x+*mGpJNa#-qom5S}AlOAd~X# zrPzGoAD;S{BkY4U4(5rV)^tRaTaWX;{%Xq{(3q3*deuQU28TF>Lfu+zEMj1l`t}Zu zco1cZp;4nJ5)I4h3WUw_WB_vjd_?5sugUnL)bxEHucWW6=2l#RU)4_|^Q%Q-()LUI z(_ZxkWQuwh8*^ED({`S3@tA^~M_n%i1i|qzd&DN3XBK@)1w)~!e_KwKOIS|-IrD>S z8fMsc7ks;TBaF1h$3jUoT=fciLbbp+H)3NFR!zvXKW^`{+b)W7hSW?(NI<19YpPQ2 zJw}sxx2=Wc&KFG-l>a&k2g@81b$CG5VyivIWUr&1)KJ{DUy9a*{n#B#v2+qQ;JuJh zYIY3L4zOM>sXrD>P^L1TIz23M*yPnA{JQI!t<#-8=a7v*>N<0=SP%ld1hcCC2+^g` zk#u-CplG!ouBM#2QCAr+jF&gqPq`?qHuyLQ7x}76+lYu#H9JrN;^2*M7~Q#46?P-4 zgGNgt0rr<<)~tbeZOO?YX*?YtfnNBpF7V~maaZF97zGOG+_J*oSma07M+_1zrZT)R zphTa|nqX^9&HVlbjDhY+z4vaUihS-XWWN}^k`x7>qIlo(m#?c`ru&U`5W0R_AV;-A zh)wMD4ry&z)~bQMR4ZWV7vxSIx*Zvh!W=mS$m8Ee;(HieE#hX~;elQOcBjQ|szhmK zdu*BiFVh7$eddxQogc+cjMah1noIYDtCm{S2RVVU)4X!E(CfCypRuVtm;vnuI)!6s z8h&J(V#P-|#yw9Hk$nHwV0DPRgDf(H(ykxTSgx8;ixe-u;Y~DKT{5S5v%yM-@OBTL zA4U(;(RKkXao?`GeHE}KZ`=zmi7>f+o|?12Id(P-tOlsd?^ucOT)(-HMlMuscliT` z`4;;uGO6vAeOlkF3xJxI@$;8Q%f&)9fT~|qZ}%vxxzYSpTHh+iK(d0F%<#YF)z>}- zy&aZ|B(YAE>Ta}2S_oM-fg}T1E{f12@n9!_kpbaH#huBLpO(LGI4LToRjSx|iT3qb zSMvZUCz)?BM^p+H2FBI?NUr?p+6dT_q=0L8uH3)YABk8{56A`OE!KS3ZY?GHWsPHu zxQ-EY^3jzD?DNK&Z8d+TB_xj+-owTz<}NB^O7pkcw;<$F$6uA5VI*hl8(1Q)i)f*- z2(rIA8pB}p;O3ruu9Vwz+;1m#PIpmsJItNu%-0!|2iYb9Rtw z#4(kR;PfefUr05N4I`|@xDf=vcqn+?E5K^*r)w#EmkjBvId&LLeYp4B3Y5Z?^Gd_q zRn)o{6M5}`BfFVVB|H(!W(ez@L-wFAJWrxvsN3LGwbjISa#%MSJvM9gfCyolNd3#Mp zBC_Kx@6EQ{QUV2sRLS<_BK;;OJM(!Uwn6rDpdWXtDhyc_dK808^nh;l2HH#UiiGMXjT^yMenuVZgi-0L*N+4^-_Jq!)q{R{7=}ovtqz$lpSTM(t`>nc z`8ao)O^*_jxQ(o3(+7l-^PzwEo1m2c!EAL~gWg_j&nNeQx*#!N8k8q+0dVhBEc??W zsW~FB3>b7QTjbkW9JwR|as`9o_dw;9W%TzDu`;A=2n$Pp8X|+~L{|>;t@H0h>wb~qs40n2$@uTYBB=nWY4E*`Xkg>^kgfiT( zZkv}>wJL}q&e|QRVTsRGPWcs%E3ZNWRI_A;A)`=D3JI|ji4PC_ivB&w=}KyXU9{xq(CwN)<+)Xg9so4L zi#@gfU8nij4jqX#HSjkC5CT;c!^j}``<71OL!;@GMf`O=MVrvB27|UxPOCDT+S*r^svQ^hH8pWMV$Z4VZ71MeeR;U_VwRn^n|)#YZEFB$9~>f=J1F2ZONN zAk?pccE#`Z=nWi3fp1g!KsAoZud>OgTAM!wKk)S0obRTozPA``K|J=>(8yXd*K4n$MT)07c}CI_(#K%itr7)% z{dgw32E~HAlzTeK@sdAEJWPe8K0*<9wg*a0l4KHPH$&0yVIhH<40J5zw)tqe+FrvN z%>DhM{XJnYSXJuksw66*65v99qAg0)1byKDvd?8B#oO_7lkwrTS1+x0rPgeAy>%UJL4qThlq%uFt_?^(E~8(30vc_1%O#@%tl<+j;2@a1XagA@`ab z?)jLGR3)jMiC-#_7~(#|Tf7;fPoYhuo8}E>aGn=a zTuf+Kp30fmUf%RRwr3qGaqP*thgbq2xvy_l0D>&F*wq)h%69vk%R+|l zT$8n0EEjoTA~qCHqC+zF?e%WNJZ(Lz*h#Um3*^uiL9Ie8@}-dG`Gz-U^DFa2W)LD-v@xO*rap11jrGd9abiA=qnca}6U)&7u!4UTg^=jRRBMDbX-DE0X2gRW=_Y1D<@)j* z1il8n9;LbpG{W3Zy(>ag1Ocq;QsHA`ye%vTX2Ohx7a?L24(l%hn>qXK#9!E3ot&uv zvmtk1pYN5xBZb!KA`Ly=af@dYf+5GGd1J?Do#3B?kJrl-ldzlwN;aLbpU>Uy(U$Is z-pQG~REu44t7!&U3bwRzmYz%Q6WQA{xoe^b2i|~)=b0NrsHdbcc~KOQVUFVL6!Y!S z^^AqDiJpAI^3{)bbYAh376-PDw=?FuXeRJJ?NShk#xmvb<+S_r>IFsUawub+Xdf@iU^ zmX8fMXPx@h1E;BT5;j&{pD34;S1C0g&bw!(dmcP>8-yNyyV)72GIr0)EHT*~Cy4NQ z`&;_1cC@75W>Obf6bHM!7{RW#Rm3*dbe(H2NKO-<(uDmxN+5_AB6Ym7r;cc8N)B6C zn`o3<8(+odlWuI6xcB3nw51t&XiAk>SfBX0YJadHM`-T!h~NWYNh`TW&i^K;@LBrv z@pSie(dTMtE;rjLi`H~5X>-!sk>6&Ub~jX4pX)BmBOHy9exLa26t}98W4NrbeBm;E zHk??aO5*8poTfBxyRJJi;Uh?Bb`iYfa`H!UzCy%#^Qs~p`QWKLuE9%^FCuGg6!%z9 z>antD*+M+`n@itwhsM;Q-`a$(FW=~kH}aldtu$qXE2B2i*n#!Gu;fLE@%GROX&ITw z@f1q=Jmv0N-U%#(P~p5wDhVVFlitie2Z1AK2l|XcK&r<1Z($*f52w;6SW0hs))WlJ zlF3UAwLnaojGw}LeEpU%-v%L!S^nBPV}iP-6|^4O5t%#z{+chL2`0!lTS4p6ozs|b z8{12Mkc!^-Ic1p-77f&eg1gz1bTE^xDS2N>bwzZ7QRlE9Ea@X~dpLd}P4w9uE&iMM za~&``Gp?08%0!jvYXg;n#h7Semw!y?+C+>9;$Dgz1#p9lUJ(;Xlk-|j6L5Jl6S5X(hs7V%o;Ii~}I#sIT7en4e zj5=-RHfiNZ3e>mMF=9*o?yOaJ{d5y=ckPRDiDIA0m;Ps$)Aj;rmy^egl%LYE2+;Sg z@`xUA>R}T=<}LBX6Av8+F=NZp*cJa~G@h#BF$9&Go-q>VN2U-_q){ z$1^V6?xs!iPLsE~R?A}3(YRM)rMCYuDRyZilhx3h*ibsEtI@+T4qOqrH%7rW>|9}>QL*;EY<$+onIl>C*e~+pd=dh1J|HXWe7#rpYJr<9XyDb)? zv~4|nWgeT?x76C5&SyNC2@8c{_voYf@kG#6rcCA0)IDE+JC;J`DeDr4?Yve7hr@xi zsr5$P4_QRZ%#v8VmmX?$ZpGyAtycg(B{OS!-BB{lbCbT^deCv}+1A<^c5&}DE%=Uleyx%(DOS#dK9;OUhA@W-&;O> z-v%>TCgMg;TH^s9PNaPQ8V@}>41)E7Y&^5&W;DH_NLtDUY7$d_# z#iu{$r3F~YO3K5cWvvWKgpmaU))f?2-_OVnezw6#V8YFpk;k75CX1KQMa)(xlSg-B z`o^#e>?-$i%Tk(*54D~T3OzZp_FA_Ck{hoGoQZs73*F|ijMO2@bi49mPBmr1A8Tlm zbMQ#98FO4=c2o%cuCjP?s8qg;#-F{lh=mHYyQ}mV%y^jJ1>BuzX@q?De!jcZkg_BO zKrY(PhuGWaH$Y)u_W4$~uuL??WhfeG`Kcdu@)q09kMe8U6c@t_*^lM6hM4*xttbl} z6gXdV=bR49H=IRvRuZ2qEb*f0l_IfA%o}<7fq02yq;cSk%`t3c=$1&;O^yR>!&Sj2 zKc-kB-&voo2LeyFMQ$}cXQ?G#o!`X7vzQu#EQCs48*ds}UU6mA>%6Vt3(RCchamAy zmj+EX$Kl&iFhi31}Qp zPRnY+F1039)_Q_cTiurs3V+R!wr3ak3%!5&JMs26q!Oqfa`Xl~cV3vlMUut*s2^hc z%hBzCm6k^4Fb6~H=r(06`qNn)J6l=72qPLe{4G)BM1jlM(%}Pf*F%)w2~akwQGG%5 zZnXy1oh;H5_2eU@nE&pBHxr&Js*2{Ekdi+mETG#mexq{*-^&h&7tu8l2FV)Ha)skb z0w;yF666UQ+BwMCSO$E{Q{M3k8e@f18oHyVIox)^&5Y5$kk?;z(}vs(SKXdG3I#L? zOX-c&K>1emVGLH z*_v$Im~3mZZBDi|lWp5|vfX6YWS)BW{NGPd?Q`1Cv(~!Tb-DZ-Gt1$ffw%!;J8;nM zzRBHV)Lgr=1`q*2w`3b7*ZyiZ5oG&TiSbB44uhaP;~w7#;ePt5&C?Q3?5w{S`aAjw zJTb*Pb&LH^Esl4?m$Wtr=2nDY-1z>z%XKV7D#f?bk=llJ=~jsWGS=KIJ2^h6EmQp> z2aj9jF^I%^;Uj{tjsM2)C+OTw4B&>d;?X$4x9^K)`yi%wQrV;X#nhu>PpJQnQYX&y zcVH$@(_E!|H2_R&(n`o;le462v#4gra9X7YFd#eq*RbgV`qNr{K5a{q=Dg-LVwubq27`<^)UqMA-pL{|A3w&;;T1nS>r{OSQNN+fnV(I?hf=JGqrv z$Yk#d3FteJlJkmcqXHy$2gl|Hq!cWk7DhTyZW&z^<#NiHB2voyRkj>ir71d7zn7PT zS{KoDbahdk`UaH~-48W7Qdxq@mF_glk*Buv*RM1{!_qW#d$AfTaRHb*P<$~GR;MQ8 ztP02rT>g(D#T;~~nU(qVC9KFXAe@Xyd)xobu@ZNfIdSgtpek^lsC7Co%iinBLWy|})S0irtBC?=%O2FX=T z-(H)o_Bh{96pEFB5gWOw+~8tG_s?f6*qiL2u0TY;Dn!NLkjsvtN-|Nt;MeMK0nr2kY{2I!HD$n8 zmGLR8GJ3(~ax5~*-V1#xcX5*K|vYZ_BRk#nU|1%go7x^VG>pyhZ*Hfxv0j+KlO*4JB#i?xxa|4xn^gK{3g}3g zK3*JP*}FYfv&Z9y~Gq4eIUTO(^@h z=Bh%@>7dc-wFR!YUMcfxN1)@#2sLA@_FaqWPq zcG3zG7k<#*NL%9Op_b^0xQPiuMU z$Fo*rq&AU^171nw$z+lSNnTT+0afc#?Ydv*>n%FVt0Cfls7+yvx^6{2ueKKcPNq3P z_#s4Gq5NB79K=NAba{eEqg@!$9dPU;Hh|io_x~yz=KEim!RQR>;aCL?a#QD8fZ#Fg zW+Fs^#ZC;tYPGTR3vIdvJ7crwQ^D)OiIMC6sI%?C0Yg=xMjEBl@eBgM#vODzxzX~p zdvsf^bB@a9_n+(8prlXAY%tO%>muq{ZhYYM6!+LstoK?%?ex4skya#QeoyC!nF zxzNad2p7kJWLQ`+_9sCC&PgTHqQ?{GA>2eG{)AkY2J$o1oScR?86=Xss!W<9G z(*>>xDL?;H{k>LamizW7SjWo$@v=N!@6v~=CD7A?<@eicA!NsOfB)Uh$wdP{gTqlN zbDkfUBDHoa`BKmKz^s|kuJUoOH;hB2@ec;x+v{Da`V{z_ipbYvlSt!9@Z+`vh>W>T z;sRYDBfuC}5qwHi7|k4Oq<&WZKeQyK{tRt53%*H61*c5c2Nzy;1cX53mljLe>o2w>F#S*&^2 zp(sAwJr{e54viM|lGnyasQte?%m2FsEY-HVUsO_*IJOgccL!HyZ!5Ex+?`x5Jy=8? z-aRCx^py~8&sZaUAAZ#?5f{-^<;oBE4EXe>*+$v-N964({nWL4kY0GVafZcA35XQb2~!*-cc8X*xDx}}J)*x6_odOJm~pXfIll6X3P z|FPOe%TXEl9+NaOD^i)~^ZXy{cwM3EbH5|t`-lUEp=`$ePQi%q?isj38>C~?ZnQco zLAW;#gw;xr#AFfkgeQLQZ;E)TGM}0|N`={g>;^iu#3ohE0t76`E>%iA_`&w~d^sSx zBHizWu0ZEj%*e_DZYXoO9mIC>3s5SKGcpGd$sE%{m^W4XS^kpJ zH&!HyGnKdhOwp~(R`x33I>jAA#gb>x_u0v>)M}E!Tdw%^_}esrKzn&&gHDD5 zqhAP2*RNXoWgUPtwt-0L$W?IaZ+?dUx}h#smk}rkIvP->FEs5g zwjbA9x1szn8nytn!|tozpZ5!AAx$g?y~>^u*_AD~c5EhHO-jY=(nk_aGPQmJyW3+) zOLFuOQo4ZeenU=IT5W}pi>jpZmEEf$m@LQ$ADAb!u0IUsgIs-@b+j>-gfei)QEs^@ z0u#UO+~E9%dmNBe3j@|2KtKYge49qJ-uuxm1K2L06cT*u?P94^WcNH-OUV&;wx>SHGfj|Ox zmQm)P0+;v^j$S zs?UC|_vLI$OBj3f55^k1#{+bUQx}b!2;5dgb(pW)Byg~Om6DnkQCfB|ZL3s0te~f~ zzM6e>QSHm=bCAu5y$`fwpSvIP>&?|V3G#Mxe55@QM}|kvZ!L>KRJ60nI-jHcb4@R*@A=??Z@O&tF=_a_$ug**@p}xSy zeEj2T-M+{5J+B|lN>fxONM7ClWj@bzv0Sa*>)skO)oeUj`m5J52`-;UZ6+q_Qgq~n z*?_SDf8{7UJrNu+qIoK=aUlJZP3kSvcFYQN{+Y2prK?@&WT}c;m$L)8j!Ur+*Z8i($XLZGZXqj%NDY zEn)SEOZxA_?rG-o_)=BcO{%44OI_aXRo}Er6bSW}nr(Hg0Edx3{ys2(EfYzl_tRTz z+Pr9EEQ)Aj>Yk<{D9fq+Yv6jhpzH*sQHmAtNHNC`Q}p?HxexDHwVPO+%?vzp+S zxw$?JA#3YXs+90T;np*Ql5uc0ct-b-O?7y-M4J7<~dg@-M%O9+4uCUM@F$`%_x*_QANZ}@fCr=Cpl+9k12I7x+@ zQxxj$?W%AYOpO9)e6gtjw%{+c&3Q$sA$lTb9iA%J2hW!!DVaxRrn@h?1|_BH3J-bJ|2&xIJ-B5OyJs z$TlYLhjT~Z3zv`y7e)W^-gQbRU8TvUiF~QYFl}o<4mx}uPhu-KklAZoNv(zXJ{J

A>l~Nr;K6tpsQF*~5b3Md@hpY2Vpq4e;3~pMjCrx!}<0bGY14T;s#s z$+kDwO(&`B|Bpyx(t7h}-Oc8<4-$-2Huw*?V(Mm##b1JR?C&4n%#x*YWk)Txw&n@n z^3>Gy$hff3Z<@FsJf$Y7&oDnWgl)uHTw!h(f4oik9C1#4ihG{$bInROsf)==pJ2}R z*BTa>e5_bDep8LD-Dt_v1YVPy0?-8xd|=y&Zep2+uB(7s5cX0< zgbcp+l<2PuQZiqdXgzQD6CivuM|W3!4|?@w{$r+mCo%8`r`T+=DW*=G99fz*xxfGp zH)?LzQ`yxzFh-Bf=1rt-*Gp41ug_DB&_4Zp2czwG&tvqErb+JO=j!BeJ_b+&B zG>Yj>Tn0<xUgr~ncJ^eL0`Vbasg>)p|XI`vumd7BtDBK05`KNBIP7nKZ zwB>K{Ff(M+r4UMCkczyU_o1rqy%eb>c^wqlLg2ppY_+AX zrDTbMKg|32SefYTrjuJyI>s9N04Ss4{5SDyzDMp7hI<%KpEXSTEnOIJJyrSR);kWQ zsdS$|2bck`Q@|1D{!Rq#VqV-C4bf-hHpsgz8S}<=xIX#c5ikLj0buh_RmAk1996y& zfaN!nyDf=6XOVHs2q}UD;gLmW<1D6C6e7A9vvtCosNlhNDdWBy>}7k@wIRFl+L+eS z^V#N1`zqBiq{+t(I|D4oRHk3lXgYpZyY(B`5+C({$4J-wI2pO(!Be+q$gsKeE&O8! zl1&v-;e^F2stxGC!ukn$VhO`U^rA1zcRlB(gVnhIn=nr!mo#GVK*Wh{b8EGSR}B^c zb|_5YduN0dOLVBoO#O3AK(Esm!g7IHCigvTKLf6h=YUVzhL^IP=5X9b9g;-6#d$>9 z*nvfy7|E@FAZJMPkmq=tUo+dc=mCnJ<_^^Y`9|xZ)d>0BCY#;(2vHXu=+2_7BP&S9^KsZ*mh9P z;BKi$u@xddE1j!{huR^$%X)^h53^kJ@hgLX!{hK|QW}AWNdp!OeQ-Y%2tAa(>hlY@ zOmy4t6&`+Dk|JSA=e$B-5P~H(d0`aEgkj^Rj0s1?t5Hx>jQNnGRD?g5GrN=>4Eb-b zpl>DtYvqu5Xjp1966>4%04CFKUp`K^sq^V3Qc~N~wr`vW0KWr<3xzuckE6;@=HXJG zqNAB90bnhhKyCe!=AL8-sVx><6r1W^V6N(%kO#8iP4=Q1tM!#ps%5Gwlb!wleN7u` z@U|X1yU02k59~T4koPSAP4l=+emqid7R_ly$bEiBkV3YO3$_V{&n;~K_8>=w6;v9$ zSOYJisVIn<293DOT6T~kdpyNntOLv&1t7_$xipn~3`0Uu)_esHyT!yb<1uqAlzEX_ zBT%6~9*!RZo$I!*kFY4%NxSlkZ`rusA5c_)P=31o7z)rZjx&{`0*DO`axh22%e7(M z^$zClN4C0)2LA=Xf2zVuOQs>K0EHB&6`3Y%SlM15kl*6Ync3l$QjT(yTi5KYd*-YLPGGX3K7R4lkmCyvG`O<)2 zJ#~at?}i@n;W}ZXZkrh@fw)ylbCquh9<3G+j*(GQ0;=7>Mp|vifw+3W0l8?R!Ai+; zc;a3itM)Z3Uc@wh@2A(V3}@zjehvw|c0FqUVDi>#OuOmWq2wb;8E-p?62LuCO1t7^ zAA_l%#Rv&=JZ)J^5EisSr!R5<+F#VRDEfJn3{>iHt!Yv|b$~ZPm?5&xmp9 z%Hm2b;|nwy5TFrQF7MUPhn`=osH3!?_CQ0$inlcqE{@FsvEqnBI9TZELY zcUFA5+K0PTM$OOtC9ZrOf0`4a;ag^z6#|5BlAsnQygtDGR@5-|wC=CZ`yrl|W9QSr zC}G2KgzzP&)V+H?`u4KpYRO+ZpnH>~5#G#6dRyV3P~){;h1`D%XfjFwJnpHBEUCQe zm?D$2H5Foi0YRf#*~A6>U#nv(hMqBa?1ezsTibJB39weH5?lZa zX-(*w;rPXdTet7%->4Dn&LF}$*LQU-yeSK83`Hn8h|+e`)4iizW5q{Ygc2aexo!O( z@cAt!G~lT|J&}HYNzyi)|8tb*djx-NyZTo3GIEZ4*XF!u9e>yzvQT@x1Yx8MI~}2c zi;MhKzJ!;PRu==F5zn8zh^f`1w6OU%Q(GUD_v=LqsM&Vi6tIS5|8;7`@%!%{3o|0>^2vW}vvnN*AyQmXkm2v+ou+b;N@B0t!>V3tjdQd>9ScJLw z?AC>toUJtngbdNIE5N3I1RO%>r(Gl6>kXDYyA8Z_wL29!{Q~bBr?H<{s=n_aN zINMNL)*{{$P2Q{0hAmY(qr7;j!km&$AvoNrgpARD+j}NE$DH{-PJoH*KAYPepT6bH zRv8?+ZQ=NEE0#KciXb`rEuWg&j~@T9d+so8Bz zWkIznWFCghkKfQ<9noMigZ>`xAh`uzZm18#5DBuW-aDm&iRBJSF_nPCrMFYSM z)fhlF81jE1M_S}8DwKp+jXRVU-5uN4jo_q_*!Yac9Nxkqi%By{ii?0J11Kkxd!eFE zzWF>kWU!e1eBra}0dwH;mG(sAvZ{d90UL-i`fuH_-x;i<$;|Qxqt4w@j{uV%6@^?Z zcDIP`Xn*%$^gu-pT#+ni*vD3RwCtK-*1#jZNL%z45-JGvX$x-d=J$#uAE$1f_EuHr zGXXBeOI>1c?WcEAf`x(rL4=;~)a0frbltrp=i*`<>GX!fvk1U12H)S`hJ8XWArt6n zNfYTa&F}t?gFT)vfMmKBf*cz;EAHi5#-PY|_(LR+QX+ESPmj*3We4dNPwF|*)1Jpj zm=V!bYCJ2#$8^vO_T+|r+k&Xf69XUQvyaKC4L1LoRST4}86QRP{iM32b6g3@kfNGw zw52L_`NMi>eC^iPN?L7}wUwGH8g$WzV;Ms|wq8d_x#<0PL1>EqcLxDqt75bLCh>d;a)R`pw@iaMQc~6K@n{0mX!017XEkfR%h=gm#gV|Yt3>Xm z%OJDuqgQoQoXwWcV4FYzT^c~U63OITCt>P-N-{mWeiA^#XVyo81urq|FI`IW?TcqBN?HQ%ZRbD*UDYu5<~e8 z{n}XzV0}%Bvn1YabVS-;!`HL>iGpyWTs2NoBJ}Gf0dBV<_`jVeIRU2m*n2;gIbSaA z3=`T+-=|o!2aFCvymb4l)}vGcV+{2Y-BX)2k+r6#-DpXAf4Z1t6wJdt zxS)f4zK)@U=6sgQ&N53<>F2v9sp{ymmbvL?wdj}9c-2g4xLRALQ>4GiJ;i*)yWgga z$L_O)TRHO9W6<*8YW0U+(B)YEqaL{P&OcA`a66H^b^Ml$lb)y40e}P8U=TWOgL!x1 zQJ*7k<2DUb*B5V_*!k93bFFV52LaoS)@^!+6Wm{FZ3h2>=ejQ*0?e)x@>3RijqJ ztP3B!be^hKr;9*+V7+ozt=E0$fU?qcXmmrTNO?`d^_HZd=Nr)BkgeJ693zXFF6Uyl z^-?8?V%!B~5+TyrjoDGACML6i_u{Nu_JN6{ORUDwtn(2ga1mc8tTOTMy%~zyavEM& zINAPCOTnOGgs!w-yvd))drbY{eYILX{BLu4-Tt#(hw~9lnU1%6wsUM;=gl~`r1Wah ztJm!$!d%T&#az`H$;XRUL#%Yx5)<^Bd2>VbZN|49%ibFVY)08G9&gjM1}1OMLi9Rm zsV|Hf2OLstVZ^_1sfOf6R+tM+6o^&l(A!;Jh!svh;U0#(U`+o9Fua{t6y_pBNh+;V zOxWndv(GK{8>W)5zJZm1A`g(9CNK;uNvti z1$&uLC#GXBZ|_22*_;63c#{i6mLi|U$V=|I@&QiKu;YS$DF5(|I%fySbkf z^m)>wg(HFY4Eq5Hl3RC>thE!0`?$3V~Wy`WjhyT|W~P z-H9LS*`-Ih&jP=8Cltq2djU@g&>*BjdMfZj-vv%&K4+*Su%}4&JndqSJwHWq^$4%{ zouC_Fs_BS;DYF4at%IpqK!zDhqdjFOEJDNLl=oWGt^Hhkkvo4uVUWD$zx@IVgIt@r z4jsaOa06Vy`l4G0jg*OuuMwMvivG!xtQN_;p-#MsvQGTZV)Z;F(!)g_{LKc7PU{lbe&$JOeI|~+!ogC_KIzJN50RxeL*hqC8 zLO?8=nq5E|z6ulhrC@vrXJrpTupZ2}4y#@T;jU2Yvn}O2*y>w4#p1P4qKz8gd~eR3 zq@|x<7^4yL+OqwwQIR~1{c-zx)dxrSMJtEv-6TMjtB)=qa9upv7g zyZ38BqBSTWG8D*=>?3S>f%5+4#FxS_d{A^1VZ~tn1y7S{6D6IfSdD}!pMJd=k5V8S z;fC|>Hf=>*JCig|PsrL}ER+ zTR&+LbpfV+kp3zlbSUi!j}kqA8FZ=HVRg-T#@<$+6~TTxpiIO|(4CnUe4Kn&qj%S` z$2&6Hl3EyIR6GBL^`A*`QVRq*j{FJ=r)LOo*e#VKVbZBD96vhl4ND)4r-0W@J^tw9 zuJ*Kdc6T*(ww8(4XN6cl=>4QXYQ%3~MDI7|t+|)bw2#Hkt@VkaIKMhZ|BFt=f(9w{091GM?{ayRc{a?|wcgR*2NZJMvGHBuLV#VQfhonrYcQ$Vr0 zHkCa`ZoAf)@NXhCFvY>OSt7V7gKTG$b?&IC4;?f%-0l#9Stf0n<))D{t-p?Av>vdh z9SgPuPF}s^xeHV*g~z>Dp3z~7oI;y2U5Ljo^`z;^(+gZ#Jg()G?H?zKb(xx6`32vs z)EZ|zY0@9F{f6}*a4h)SeM>>aP>)X{8MSn8DoL>xetTgx_XfN)nObh+OrM=k-VT_0 zBvk35+SSh2?fi@a{tLmf6na8kSGmf$<-41EEa&>v3Wd(=MQ(@mDuvp1>6L_Pkit#@ za6Mr|#8v25-%!=Bwz>|+sPYy#onG!vT(efJkqDETv_+{Wr7BoLNa&X`d_Ai;`)%?` z2p_y@Mg>;$R*}(}L9?wBj=xC4YNJu;jxZEyjV?476{w`f)5b6y6iF&CH#=mfvbh%t zfB;Di-|Yk|V6eyi0II1J9%fKFF3NvW@J>;w9m4@Qa%?rr1_(LPNKy{PnnofC5}L{Z zU$Dc1|d&7unlla(D9|8;nBGgR2FLyIC^(cI( zyti4vuJFaU#J``xKKibZA z+V*un@%`l}#eQT~Zz$nj)hcX_`J4{~S{A<0y>^#i{Xs-oQl_FH{eOXwh!ntZTN+2y zSyD^|PuC=Yz12Z4DZgE`*0C@TQU$@vE%KMu-0{NHtW)XUHrQ--rz(Hk(rUt%>QUL4 zo13O7lBv;#Ck)qi(4=YffuxOSswB(v0H$R$2xR^ot+g)rQYNOq%RyCWrNNdkldIOVPQC56i(9>UGu$l zpK&E$1A-aXq>9!@M;6Np$vytq>(9?M{?99($FHEEj7|1&{!OsE>@@O$=}0~0&3S*A zN`dOlm%j)W!??E88*Ydm%?KqitB`F4j@LTmIFZk=^OBW?e?4rIG=Uyao8scqYn_KR z|JWre+O@jq3;SGjXiFSn^0xmYcjpKA%70Auv(G^gPg4~hvyn1f^0f&x!w6s27j5Al$e7j5yRX;AA`Y zVjC#92y}ZZQSz2nnDGZK9sL^XN}w3UFS}j}C@3aG*IR|H*zrfnTug3XtlFy``bK;e z9_uC(yTn*Rb|}$xq9q0b9<=R4e8fb#WbD-CGzx>Tu;pG^GVu?Md>R|1hU7Je!^QQF zmdq}SPgR0@ z5e=Z8!GS!2z(%ElDceGX?yAp5?X!hx^efT%Obow;th;xCTJ_cmymaR~Y?5}W_wYuo zgBziF>vPo2F4n`SdIy1b64F`99On&)$u1VyUXJ-uTq; zVs+_97XzYK!?aSdIagq-51z)kC*DYpcQbPtIgSy3OL5LiDWLN$&vCm0($KECAHBVM zaRRO7A@_HsPwtZ>#L2}y4^Prl*W%Ht^TP!r*yBQgJw#=2Ut>@s^{?LqEfXqIkF(^l z@gtl#5T%gY{dr(e4$$%@9ZLji2{TRD07jI^e_!3d?(5h44QW2#L<#bm4_-}0{o#D> z#RcYrk11{Q?c<^-TSr+G*&E90(qiGSQuu5sA8?F{U8mK7I}Ir66o|y=SKO- zeez1|Tw5m4(POexk@LTd1S!~iaXD=Qzvfc)dwd`uT@V}(JkmJ6;b5R0%Bm$sXsj?q z0_wgI>_Mq~3u;ucDQ*>lq+N(RrN)$ueK9c&xA|fF#%Ge*YCFUE#A4?LgeQm^T@fk7 zpnjCUlbj#32v;2VNqC0^U6Wp;Wk>HXpsf9wK6YfS`+2jNv$VMkDs%Ka++`ugt~F`6 z3iBdJWioo0PPFcDRs>&G@9v98p2xM}2wS`xdt+(PR+_)o7lJFh{_!2urFYlKgO?q~ zoBqQG;QRcVL3Q+d3Zb+_)Y#V)p!Yl7#Sqq8U5MQq$mgvHUzzy8A=LL?DAym0PfxKV zQHi_zh(lJQ4A6#P8PbKwMem_cOSjsT>vP@DGCLaB<-iwiX!|9Wad|MRcq^4vbS z1R*h>ma$%0>MWZGvg}*JIBT$<7ZxDfJlD9**}SA$CZ`;@y=wDe^AQQFKsI&_?V7B24xNs5)Mz<7-Z z^Q4r(F;Vz%!w@r}a*c?VXC zOMY~z{u{Wnxh@pES{O>b8ag}EIrz4 zs+u5!J$6bzZVMUI8X?OSW4}d3v5L&`r@BU%sW5C6D{Gde$>rptZl)C znzNtMyrt)y=Zocw0A`)`Sf33x@;@U+;h=My?|O?0@gsK*H?-!bG4}4p7=4_Q*X@tX z3eQl%bW?MgSk^s1Rv-i?!2Zrk__k6Z@s|ohAW7OTmDAo!bSn3n(IA1Kw}vHGS4URvVW9A2@7FuK=%>-DSNM=jjh4LjX2YZz+KnAwrL&FAaEk%{1BVs23n0OyTRfo`WEKkJ@6H}$Ul?^Y%hf813G=Vo0r0YFX?!Bq3AcHNLw<}; zo<7luvotpjEk4e-+{7O~;-_TYKF=1uJI;*GM@nF}&`|cmFMrLYV-2SZfhh(W%Tw8m zP(S@xJ^k;mSkjH=_^>~Q2V?7vo9$C;6&CxE+hQXUrEyB-GmL#@2$pWRoM_ZL0)=dL zqr_%fiFrhY!g`5Wmps8R%mqDw?3nR=(j zaTuXgr^Sv1z*1QOo=E?!g`g)n>mq1igAVjx6J1y_3{X~ti08F;dfw6+8L23hL42RJ z`E7&*443Oy*$R$<9X-s1S+Z~{1f$i=?}e0juhOtqxPkfKu3=%3N>*_%1L;WbWPS3d&d%EW8PkKn*e{aM^s|^-oYfTk}2HUwR z9qO)HJ$5-00CPZIyg|)C!3~9c`%84 zV{-4dU#0xxTz(iRV98fAIOmlYH4Xk2*F^N#>*X+>K5b*KH8fuKZGoep`H$r;Cn@d= z_mw3E5GN(6tb?LG1E=$pr|wT>4Efhc&7RB@|CH!r%H8}9_!H@3PE!&)u5Q$}z9j-z z$61Y3wjd=#2}Wk*_I=Vy2mj9zY;fy-4rj}ZB)}=P^d;_@)qA{Oi=W-i;yODQkaOA~ z{oSuz`eXJY3||?HO1hXCZEo&|9Vv}l_LN!vGCGzgiz8|%%@9`0hFtOEuQk%i{3cn_ za8qPt(HX;S@#BIw=rOPhpKEQ|_Wd;@tWXjtB?20;i`lz`NKJdX>o)T<0?C|~x8BE7 z@|tk?fscI4_c6_*2^AqVSsD@RzM`u*T$-Z^qw)l?f7{3&REgYFCtZyE8KB_+miCFP zCAB4bLQ)IGo}KJ+BgQS!&qs&}dKkK&OD3TqBm@c- zC8%|eG2OiACJ=Yw%P*?LY@zRK??KRI9HA5Q9xlW7K+SypmWK zsQhLwP_C_czICFi-K+RWH*%jd>hG@7SrRti)v0ri7 z`;Gsw@*Y#d4>IncN3ZY=k+je)8%GWkg!|5fKsqyLi{_a$bghQ-JCF64_ee8v7`a|- zjOD%gSjzHhap%>BZCE2uc@{^Rj6b?v>Jvx$0KP;EPonUdHE}sjOSM7P>xnhAOBiUY z_V2F00)c>Mw1xgI4Fs^*5*b^iJ!p-g%J;1p7n>IpTq2U`S=hVMH43z)h19FwXb*Mf zg0zJT;f44BI;=MF>}+r^U!v@0p>%9PR%@%w+Nb&*u+RhWQ4e^mXgO=Y#}YV&-a z-Z6U)2YM_Ny2{&rJ=Fo=t%x8j{b;&Dq*Ej1sRIzx$8U!8yisDqh4q?;iF!PFkVhrsg<9>vK% z5-|Q4q5DQLpeM3%_H^~;_17FoSDu9A@Cz0RqNGzhsAM@zaBu~EYM3N6DAK4e`Op-o#v+z@7$NhZO4^DHA?VbXzghv(8)Re%%RDiI zC>sEq@Apv&>m(+Auu9VWM!M&5_{iZYA!>sZH8m~P&XlFDaW!%{G}$Bq^%$8w-Mx8M z&Jhau5oO^J>#c!6{)X3&{TNjwplgftwLj>~=s^*C>P0MoBx31KCmcbs5t&*%T zmTu+y-M*pVzC|{t!?-9lH?$xHC13{ZTN)4=0P~Oy6zHbLm@))h04*A1X!;*9_f6-& zudPI`$D2{iW&!CzD;h(g*6;e8KTvhH-5%b8@d7#iv^ktUjij5K=u`W_rif*Knb>PO zn`NV0rz7`pw$&PqYit}b)VH$R-X3>n{ly72TT3&l2CjcAs} zfy4PYTlT$pTvr~Wm}AaZ0F1RX_7EMcr8E)t!CIoMI>R=2=GZ~LQ9_o@!T8QI$MmVpH;?XD#4?ioOZbN#mvWNY|>de3Q{UiYOxDDaC+7MKw z(_K=4QUI_=|AYTB(->2d=cnE90{Dn(HuHFaT!;IHW4PU|)UXSSua9q=V`0Tht+fUX z`Q9)kkr9ciU9I#WgPr_{JbfgZcTaq{)>LJI)>rvD_DTgppM=Y&+EyY-H}{20$wR+X zMm=q}%Z-yBcU2o=if|`kb9{1wQs$xCp_TFE_d>si%;eow*$6rc8ev_EYK;EW^otR( zF0I%{U~_4%QlI}#GVVonQVgmQGkqn3KUk^~Ao-D)>5~i?uEip0`#5d@?hmyOSIKH; zKbt+6MX3w;Lg>*||8PP+nO*{Ii&`OVsMkJDl0NJk!?` z!?QWklxhpo*#_L($pNs+-=GJ2q=j|O{hPPPs}{w-L&8;b`KSIpzC`A6{?Sq{2@sX` zsp!%3r9&>ay1aWic6#MHz@4OhkW#-1qs(-03VNS*%!p1NW`*|KD-g0hsOQH%g%g_N zRRyY$ModwmGU}=_bHWjAEYQ?pp!ETdA9X1LjqHx3=O9&Q9|-rSfnOibMD3cHjgVx` z-I8y^c{aZEi;z+fH8QM|O!pvqz3E(M$eZf;S;X4MPTuU3(gCZ@=5V)1Q)Hhx8sl>+ z*3O{ejF2Aq5A+{S7iItLw2C#kU1(=;+Uxgnl>K*iO}!U|59MR{g|;K3 zk^uRs+fo}BKD{L!(2`)Rq1e?K4>hjf7n%L_T_{x+{ilc{hw-dK3SkGIEZw}VHFL@j zuo#b0p%bMr*^s1aKG_!TAH3S;`~Tb)(Y`#G#mcHJT{7&)i{;f6K6iQU&Hki<;Prvmy?YmzNf9uk23XwUU@QlGF0Wl;;#Vq+^a=>pNwhFrLums zJje5M>K1(+96}N*(Ngh$F?W9FI@^@J;rBD5xP=mn^>aP$2q!DenG4nWs`X}*)b889 zY5w@+{|J(aID8%sL~B%Iq@2Bp=l&V7i$pvQBp^%xt1a z_G_8psSkR*JCX@wR>+1eBnLeymu8Q3+yO1+c#u?v?MDf$(rJo&*Bytmm27lKu5V1|Sx zl%wn?<6opuu_wqETaS{5EUcRCPvWb!0zMM0*gzXoHQwR#%Fg*wcJw!K8+SMofhcGT zNEryvP_erP2DmMYt!sJOx0kako+fT8r)ma3_z?d4d~1 z=@y3*%?z&f@mGw3bhO9b?->eZ+TLh@Sh#VPH|~M6Af?CwM`L0dvr@n^A%c-L z#0r~XXtt71^DW_TaqFjPYAaTo>4qOpCNze7h;M{D=3Nk7aNLShX&J69Olgj% zi#a@HBO0T0pimOZGOxu7W?AFFrG*A>8#`jtP^ernqd9|gVe;fpy|shVjw;vUz`$-K zXq8w$#F?evQzZ`+K+MHEmbHHvi6Jm=>&c7eE&@rLuZM#I|3A_v`mBO@*g(z2zn164 z^wg~D5WHZS!lRWUkX(;oO8aZhv-!dF6VO<-yCnLwIi1n(oCFi@ubTaDlJuftM448O zc=;_@QLsQ;)INi++jcNS+!c*QI)YV9=hwu9bB9lGrbWGdUfdn-M*D#d(kRDsO~9J1 zTPPa(ou~S0ZoR_(GoE~?ZyH@rYw!0tr_oEH-+MluC%=(!zmW{J2B&XGonB)Cx;O=N z-XWqZ%*ZUkG!sbZNbAobEb)L{qiP%zDK(18gV$pbq5gUZ`(rjrd{5fF@c$~i?svA{ zux}H4)TZ{TO|2?wRc%!xsG^8!>^*9h+G-Su+1ewB#4NQ56;icF)ow-YQcCMReZTKN z@aC73>pIstxu5$yd7k^+*JpHcTHbmxS@10Sj1^BqVzao!G-x1J^sfYbc}FPc&6D}I ze@RC$W@@{h51OYD7VL};#wjsRc8thP1n53x&Itr zL~K=+5NU_1|2?dgfG^pp-qSMxd#&1nthl0&+&-^A7_2fWcu3Yo(3d$+#|zjTH9|%} zq?5lYGix8-r|8|El-$1%IX$Nga|JO9e4G^zB#4a$y^LX#ES-3$Pm}0Ss^zXlFY$JQ z;Pl2!78O%6vc3IHzU-v{Z*FW<-`VShl*(r!kx!pytuO)Bj^hQYbrShA+KLD+$&weF zV`YPJ?E!y11G_g6TjMlNY9|(Up+UZ!lG54t!K30a>If-wUehN+h`HdP3|Id@_2K({V7(B`5;M9m8XNp zCxeO;03T*ly}?Q4TdzFUcG#v*hiYt+X^yWdYxHrOi~%{JzLA0e?p zyJVbH?n}Oag$3tewYXi4Nz zXi`LQ94wEGqP&LKPNA9ef6ZQ90-_qJ(pbedF%lb1m-8m<+p1^6+oi0ZNkBM>jJi#JvkZf-u~U0F2(L6aU)RaR5;wDI!gQV01H6^w zCag^b;0v=42}>}|ntgad_<={^7PC*{_s9>XU5}49!z>0YM8#gVwm3q9**|r5-_4z| zzBTfoT*hTc-fciwe5o(((PGLAY8%gGdL-vnRw~CkHS$^V9aaP01CfBziu# z07I^^)Z9ya^m+B`S}Y*3Q;t#6AzHU&*fhHoJti1aogw|*l7yz7s)VaobLTX8UVlp9 zRaEUJD=_7S0709=`)M5dfYnsXjZuNucT4--(A-D1^#wPw70{d`$?T^Uwio7X4Ol)@@21~OqFK`imaQzLsMr848SOb(W9d=d{D)VQNn$ZW3&RxM{J`dA z(%S*aR~;k=q&L6?N))WLlIa`Ht&5Hv3si4jC?qYMgJ5jPYg(z|n!7Oq*%^rd`*&R1 z(CwSom-nOVLn%4!)fKm$`bmt71KVm#Kl2^(y8Y%9t6Gp2+b9e$QgmSLtR9bags6tM4XQTFo#O zMJ^0%i3_vbC0JV_xbFGjAJbH;yb;30PgapUt0zepWAE~=%ZVW~;VyHI7PCikB4L0H zy$qS|&8+HZjvJZ0hK}zfNqO`gCT;oai8vpdA>Im>f(%H+7Vm#5?R(}?`AaFdC)_Qe z<6CiOr~d-ycF7B;4!5&q^vQV%+`Icg>Pok(sx zQ?oC!!ovFICGI`cp%Wv0=QKi`4yJD95KDxQK; z7PXK9{8ZV4gPZ1+L-F70?7a5NZWhYwsL4cBzi(|0=SAGL4SSVC%@vRQc)(V@~MZ|Pg%5o z=Vrmx+!5svSXyjS+t_`#A!t8D-xBel*f>PfSR?^ykgWP$^K*wb<{miocDVk0hjWq_ z`Jy&ON?EtCF{iYEW6Z0&w7~F8+EBn;qs*Kn0t`4bgJ`$%%vxKV{(a zN@wuf!wNBXy8rpzRbU>{yLbE>>ac_IdrLXrz1MSRna?1NPs+)a(;-fU{?6JW1+RL_ zAq^pJ1f2zy*jgADtVsOXA?kv#$%+FFHfuUodep?0w9W_GdNKL(pjt+AMJH|-9uSao ziOkdANN`PY=hyRz%(bUo;eUZKE?b#fV{wUI@)gNbXq*M*UjR>s^Zw7z+*cJE_4T@| zSC2cwV!H2dHq*~q>gtAN&?DI>#G@cgET<0USOy1OvHtg~nDL)Ko{uN94sT+4WBhqQH0;y){VBHBDsGt!M#!w zs7$TlX0S!*OCi2={?zCsb;!EAUY8cTtoalbBCMiTG%x-ahd#zaLeu+jZ$1i)fYF6~ zqLWSQw?$ScQJK;r6UpRTF#c>CK7|pJk>oFwgdN%)2>6DDC|c=}N^Dzn;diV&WAjIU z)KCH4gDU1w_+I06$F>27wAYh{#?$@cH(ztut@Iht2-+Cr@iRpyAqNiK{PsAc)N|kN zFu$Xs=UdrRj1eD#jHW~qvX14junk5Q!V<(?l0o|gcA-=>)ZpusuZeJ??8WgYAMrn)$a z3Q`b?o{djc82d?gpOpGcfw^P{o>No*(uywCFit#Fn}`B>aU8WHR;+K;OYXF=8Z4;7 z`A}m;uAFV5hPa!zD5zJVs5xpQ{;RYhVlsQ`8OPRijrTO389j}!s;Wq@W9`=xBPh_o zT|YeS%d%QZ2z0BZ!3yzVrln#2(5F^+wIdGys*1&~e#I9xeh(`4{gu`P8YAl~z*-n( z;D_gzdNlT~0k`)zc#FrXUxr9FW3N&>s9ne~FrS!;YIgWd^6m4mqxeOUK>)gMCL%0b z*vZBWyt^R-nC~_pJ}B4n9nNQlK#Ghjd>3VjB6PZ`V6&O*6Gqrn%&ol+Q~SuZ2HTIt zM3t!JycUJ39T)9}xFK6MPYJt6n4H~Bs?YA3>6+7Nac);P!&jCYf~>E#)qZsfg{g#? zE~Neb?$0N2CG4zsttCx!5@-=2la0(uE}Pc4&)B>Zz@yk+P|VzDAKJKRb83BxQ&XLp zmBiHq)ku+_lZJze_dx(;5SA>ind&?hJw>A7Kt?BwyVYPbZax+ z@cveAY)y5*;{X-s>c`J~2!A^J-p25!y3Dt3V6l>sO^-@c;TX_(NE4)sH_#m#i; zz1DfDQNoX~@2qQ;4&;@3oBMOe^YrIkdKfhV}fO48;kF{l^!0YEr3`*i24l-)fdv#b5MpPyAdhtes^ zgBCn|QmHWpc{9}`ACZ6Zd*NBIX%S+-8;S~Q|0OOt{s7#}(D6=Cb1I$H;e{{$rx*1o zd&7~x;_8#8OT>@LCWKaI42~^o8}X_rEQm1v%^|R51>rZq|GtwLVNg{t?S;zp&rD>z1-+ z=9W#o;bzTlL_t*=wheb{)*?p90nxt#NG2BJ1xjnGkJONyj!5w&5@W zPPimq?h(SZWIUJbtFm5`fG=!(ug7rTaCxNv|CI zqTPk*Us_t%zi;Qgr^v~W88(>itVq&-Ou#3UI$xa*>JG{|HNZ_aSMGsLO- zuOie3)0@A(sn)!&BrkDCV~kQAy4324-{Ynb@5vQ+S__W@L_|0$;;#{ZxAcE z^VlDR6O7bpRS>46Ch9u#qj7fAGWRCgn2tZMB+uZ*Bd0{HwK|kAjLz+2%J%evIDtj$Nk{rG9Vm9GLpl@wGD?xef_H&L~8VCQ!v7 zDf5trrdbfz*6{x#KyUCLw+0`q?PE$%jam z3k}$4J#vV=a7}IpL{jXEe#-`o(ErQvJ+S+UF8GhZCI0MUzw_tl7l#)|@hk_>1=NGA z&l1BCzrLBtA-oP)0bTLJWi^qD*){ja*(+FJJ`f)e1}pPWl0 z@-YvMtDbg&6>C2p{1~C10?!RLd_iZZIOp#o_W%>x$QESzbaeZ@oA65``(LBa6%5_y z)S5*5wE_bM6B(Xg|NWyN$-T-6EMIX4J=ae>7f`x}Ki+Q!?rMSit_o6+;PtlWGX^|` zVaF~%cg6^5Qh?% 0) + while(inputEvent.eventCounter > 0) { - float data = syncPulse.data; + float data = inputEvent.data; // ToDo: consider adding EmotiBitPacket::TypeTag::DIGITAL_INPUT_0 - emotibit.addPacket(syncPulse.timestamp, "D0", &data, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// - syncPulse.eventCounter--; + emotibit.addPacket(inputEvent.timestamp, "D0", &data, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// + inputEvent.eventCounter--; Serial.print("D0: "); Serial.println((int) data); From 0cda5c8e9b60ec9a2f252a76759d7a5a03c66ed1 Mon Sep 17 00:00:00 2001 From: "Sean M. Montgomery" Date: Sat, 18 Mar 2023 07:39:38 -0700 Subject: [PATCH 04/15] Update README.md --- examples/EmotiBit_examples/input_digitalPinLogging/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/README.md b/examples/EmotiBit_examples/input_digitalPinLogging/README.md index 0af68ab5..78462d34 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/README.md +++ b/examples/EmotiBit_examples/input_digitalPinLogging/README.md @@ -1,4 +1,4 @@ # Digit Input Pin Logging # Instructions for use -- Wire up an input to the shown pin +- Wire up an input to the specified pin From 0421f5c329ada27d44b8e755faac9de824dffdb3 Mon Sep 17 00:00:00 2001 From: "Sean M. Montgomery" Date: Sat, 18 Mar 2023 07:39:49 -0700 Subject: [PATCH 05/15] Update README.md --- examples/EmotiBit_examples/input_digitalPinLogging/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/README.md b/examples/EmotiBit_examples/input_digitalPinLogging/README.md index 78462d34..4bf24db2 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/README.md +++ b/examples/EmotiBit_examples/input_digitalPinLogging/README.md @@ -1,4 +1,4 @@ # Digit Input Pin Logging # Instructions for use -- Wire up an input to the specified pin +- Wire up an input to the specified pin From 0a81a7be50eba9918c26496cbe813c9def9ed042 Mon Sep 17 00:00:00 2001 From: "Sean M. Montgomery" Date: Sat, 18 Mar 2023 07:40:01 -0700 Subject: [PATCH 06/15] Update README.md --- examples/EmotiBit_examples/input_digitalPinLogging/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/README.md b/examples/EmotiBit_examples/input_digitalPinLogging/README.md index 4bf24db2..1b3109b5 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/README.md +++ b/examples/EmotiBit_examples/input_digitalPinLogging/README.md @@ -1,4 +1,5 @@ # Digit Input Pin Logging # Instructions for use -- Wire up an input to the specified pin +- Wire up an input to the specified pin + - From b84e9f526f45571acf45fd1f0c0c488bc2db9a67 Mon Sep 17 00:00:00 2001 From: "Sean M. Montgomery" Date: Sat, 18 Mar 2023 07:40:20 -0700 Subject: [PATCH 07/15] Update README.md --- examples/EmotiBit_examples/input_digitalPinLogging/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/README.md b/examples/EmotiBit_examples/input_digitalPinLogging/README.md index 1b3109b5..381687fd 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/README.md +++ b/examples/EmotiBit_examples/input_digitalPinLogging/README.md @@ -1,4 +1,4 @@ -# Digit Input Pin Logging +# Digital Input Pin Logging # Instructions for use - Wire up an input to the specified pin From e2730effd6f014c12f485fc1861685ac2c1c221b Mon Sep 17 00:00:00 2001 From: "Sean M. Montgomery" Date: Sat, 18 Mar 2023 08:45:03 -0700 Subject: [PATCH 08/15] Update README.md --- examples/EmotiBit_examples/input_digitalPinLogging/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/README.md b/examples/EmotiBit_examples/input_digitalPinLogging/README.md index 381687fd..42bc16eb 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/README.md +++ b/examples/EmotiBit_examples/input_digitalPinLogging/README.md @@ -1,5 +1,8 @@ # Digital Input Pin Logging # Instructions for use -- Wire up an input to the specified pin +- Wire up an switch between 3V3 and the specified pin - +- Open the serial monitor with baud 2000000 and toggle the switch observe detected digital pin changes + - [ToDo: insert image] +- Once recording is started from the `EmotiBit Oscilloscope`, timestamped events with the TypeTag `D0` will be logged to the SD card with other data streams From 9af0ec13e0fd72a34f7791d9bf61b20e91593839 Mon Sep 17 00:00:00 2001 From: Sean Montgomery Date: Sun, 19 Mar 2023 07:26:00 -0700 Subject: [PATCH 09/15] Added mutex not working. Fixed wifi. --- EmotiBitWiFi.cpp | 2 +- .../input_digitalPinLogging.ino | 27 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/EmotiBitWiFi.cpp b/EmotiBitWiFi.cpp index 27556fb3..172d79cd 100644 --- a/EmotiBitWiFi.cpp +++ b/EmotiBitWiFi.cpp @@ -93,7 +93,7 @@ uint8_t EmotiBitWiFi::begin(const String &ssid, const String &pass, uint8_t maxA Serial.println(millis() - beginDuration); wifiStatus = status(); _needsAdvertisingBegin = true; - while((wifiStatus == WL_IDLE_STATUS) && (millis() - beginDuration < attemptDelay)); // This is necessary for ESP32 unless callback is utilized + while((wifiStatus == WL_IDLE_STATUS || wifiStatus == WL_DISCONNECTED) && (millis() - beginDuration < attemptDelay)) // This is necessary for ESP32 unless callback is utilized { delay(attemptDelay / 5); wifiStatus = status(); diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino index fa48d2b8..825fef0d 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino +++ b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino @@ -1,5 +1,8 @@ +#include #include "EmotiBit.h" +std::mutex eventMtx; // mutex to protect collisions storing/reading DIO events + #if defined ARDUINO_FEATHER_ESP32 const int digitalInputPin = 33; // Pin on which to read digital input #endif @@ -9,7 +12,7 @@ const int digitalInputPin = 10; // Pin on which to read digital input struct InputEvent { - // ToDo: This should be put in a templated ring buffer + // ToDo: This should be put in a templated fifo or ring buffer unsigned long long timestamp; float data; unsigned int eventCounter; // hack to capture number of events without a buffer @@ -46,6 +49,7 @@ void onLongButtonPress() void digitalInputChange() { // ToDo: consider debouncing + std::lock_guard lck(eventMtx); inputEvent.timestamp = millis(); inputEvent.data = digitalRead(digitalInputPin); inputEvent.eventCounter++; @@ -92,16 +96,19 @@ void loop() //Serial.println("emotibit.update()"); emotibit.update(); - while(inputEvent.eventCounter > 0) - { - float data = inputEvent.data; - // ToDo: consider adding EmotiBitPacket::TypeTag::DIGITAL_INPUT_0 - emotibit.addPacket(inputEvent.timestamp, "D0", &data, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// - inputEvent.eventCounter--; + { + std::lock_guard lck(eventMtx); + while(inputEvent.eventCounter > 0) + { + float data = inputEvent.data; + // ToDo: consider adding EmotiBitPacket::TypeTag::DIGITAL_INPUT_0 + emotibit.addPacket(inputEvent.timestamp, "D0", &data, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// + inputEvent.eventCounter--; - Serial.print("D0: "); - Serial.println((int) data); - } + Serial.print("D0: "); + Serial.println((int) data); + } + } size_t dataAvailable = emotibit.readData(EmotiBit::DataType::PPG_GREEN, &data[0], dataSize); if (dataAvailable > 0) From 47e9db8b30b677e92ea28e23bdc9bbed8957c5ef Mon Sep 17 00:00:00 2001 From: Sean Montgomery Date: Sun, 19 Mar 2023 08:04:09 -0700 Subject: [PATCH 10/15] Added DoubleBuffer --- .../input_digitalPinLogging.ino | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino index 825fef0d..534cb5b5 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino +++ b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino @@ -10,14 +10,8 @@ const int digitalInputPin = 33; // Pin on which to read digital input const int digitalInputPin = 10; // Pin on which to read digital input #endif -struct InputEvent -{ - // ToDo: This should be put in a templated fifo or ring buffer - unsigned long long timestamp; - float data; - unsigned int eventCounter; // hack to capture number of events without a buffer -}; -volatile struct InputEvent inputEvent; +// ToDo: use a templated ring buffer instead of DoubleBufferFloat +DoubleBufferFloat dioEvents = DoubleBufferFloat(2); // Size determines max events per loop cycle #define SerialUSB SERIAL_PORT_USBVIRTUAL // Required to work in Visual Micro / Visual Studio IDE const uint32_t SERIAL_BAUD = 2000000; //115200 @@ -49,10 +43,7 @@ void onLongButtonPress() void digitalInputChange() { // ToDo: consider debouncing - std::lock_guard lck(eventMtx); - inputEvent.timestamp = millis(); - inputEvent.data = digitalRead(digitalInputPin); - inputEvent.eventCounter++; + dioEvents.push_back(digitalRead(digitalInputPin)); } void setup() @@ -96,20 +87,20 @@ void loop() //Serial.println("emotibit.update()"); emotibit.update(); + // Handle DIO event data + float * dioData; + uint32_t dioTimestamp; + size_t nDio = dioEvents.getData(&dioData, &dioTimestamp); + for (int i = 0; i < nDio; i++) { - std::lock_guard lck(eventMtx); - while(inputEvent.eventCounter > 0) - { - float data = inputEvent.data; - // ToDo: consider adding EmotiBitPacket::TypeTag::DIGITAL_INPUT_0 - emotibit.addPacket(inputEvent.timestamp, "D0", &data, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// - inputEvent.eventCounter--; - - Serial.print("D0: "); - Serial.println((int) data); - } + // ToDo: consider adding EmotiBitPacket::TypeTag::DIGITAL_INPUT_0 + emotibit.addPacket(dioTimestamp, "D0", dioData, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// + + Serial.print("D0: "); + Serial.println((int) dioData[i]); } + // Grab some EmotiBit sensor data and do something with it! size_t dataAvailable = emotibit.readData(EmotiBit::DataType::PPG_GREEN, &data[0], dataSize); if (dataAvailable > 0) { From e080c1dd2f43e6c42ffd313e5d346d46007ae9b9 Mon Sep 17 00:00:00 2001 From: Sean Montgomery Date: Sun, 19 Mar 2023 08:04:36 -0700 Subject: [PATCH 11/15] Added WL_DISCONNECT --- EmotiBitWiFi.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EmotiBitWiFi.cpp b/EmotiBitWiFi.cpp index 172d79cd..5b1d4d66 100644 --- a/EmotiBitWiFi.cpp +++ b/EmotiBitWiFi.cpp @@ -97,6 +97,8 @@ uint8_t EmotiBitWiFi::begin(const String &ssid, const String &pass, uint8_t maxA { delay(attemptDelay / 5); wifiStatus = status(); + Serial.print("WiFi.status() = "); + Serial.print(wifiStatus); } Serial.print("WiFi.status() = "); Serial.print(wifiStatus); From 3c92c0b3ecfcd43844efc847e7e610fefdfdf04c Mon Sep 17 00:00:00 2001 From: Sean Montgomery Date: Sun, 19 Mar 2023 08:50:38 -0700 Subject: [PATCH 12/15] Added 'R' ESP.restart() --- EmotiBit.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/EmotiBit.cpp b/EmotiBit.cpp index 4e3b0fc1..c13ac044 100644 --- a/EmotiBit.cpp +++ b/EmotiBit.cpp @@ -172,6 +172,14 @@ uint8_t EmotiBit::setup(String firmwareVariant) break; } } + else if (input == 'R') + { + // restart ESP + #ifdef ARDUINO_FEATHER_ESP32 + Serial.println("\n\**** nRESTARTING MCU ****\n\n"); + ESP.restart(); + #endif + } // remove any other char in the buffer before proceeding while (Serial.available()) { From e845bea705fdce58863aa5e287b6a7a8b645bcc7 Mon Sep 17 00:00:00 2001 From: Sean Montgomery Date: Sun, 19 Mar 2023 09:01:25 -0700 Subject: [PATCH 13/15] Added loop dio read and works --- .../input_digitalPinLogging.ino | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino index 534cb5b5..70b78554 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino +++ b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino @@ -1,8 +1,6 @@ -#include #include "EmotiBit.h" -std::mutex eventMtx; // mutex to protect collisions storing/reading DIO events - +bool pinStatus; // stores digital pin status to detect changes #if defined ARDUINO_FEATHER_ESP32 const int digitalInputPin = 33; // Pin on which to read digital input #endif @@ -10,9 +8,6 @@ const int digitalInputPin = 33; // Pin on which to read digital input const int digitalInputPin = 10; // Pin on which to read digital input #endif -// ToDo: use a templated ring buffer instead of DoubleBufferFloat -DoubleBufferFloat dioEvents = DoubleBufferFloat(2); // Size determines max events per loop cycle - #define SerialUSB SERIAL_PORT_USBVIRTUAL // Required to work in Visual Micro / Visual Studio IDE const uint32_t SERIAL_BAUD = 2000000; //115200 @@ -40,12 +35,6 @@ void onLongButtonPress() emotibit.sleep(); } -void digitalInputChange() -{ - // ToDo: consider debouncing - dioEvents.push_back(digitalRead(digitalInputPin)); -} - void setup() { Serial.begin(SERIAL_BAUD); @@ -76,10 +65,10 @@ void setup() // - separate ino/bin (present method) // - reading field from SD card // - control message from EmotiBit Oscilloscope - Serial.print("Attaching interrupt to digital pin "); + Serial.print("INPUT_PULLDOWN to digital pin "); Serial.println(digitalInputPin); pinMode(digitalInputPin, INPUT_PULLDOWN); - attachInterrupt(digitalPinToInterrupt(digitalInputPin), digitalInputChange, CHANGE); + //attachInterrupt(digitalPinToInterrupt(digitalInputPin), digitalInputChange, CHANGE); // Interrupt seems to crash ESP32 } void loop() @@ -88,16 +77,17 @@ void loop() emotibit.update(); // Handle DIO event data - float * dioData; - uint32_t dioTimestamp; - size_t nDio = dioEvents.getData(&dioData, &dioTimestamp); - for (int i = 0; i < nDio; i++) + bool temp = digitalRead(digitalInputPin); + if (pinStatus != temp) { + // Pin change detected + pinStatus = temp; + float dioData = (float) pinStatus; // cast pin status to a float for compatibility with addPacket // ToDo: consider adding EmotiBitPacket::TypeTag::DIGITAL_INPUT_0 - emotibit.addPacket(dioTimestamp, "D0", dioData, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// + emotibit.addPacket(millis(), "D0", &dioData, 1); // See EmotiBitPacket for available TypeTags https://github.com/EmotiBit/EmotiBit_XPlat_Utils/blob/master/src/EmotiBitPacket.cpp// Serial.print("D0: "); - Serial.println((int) dioData[i]); + Serial.println((int) dioData); } // Grab some EmotiBit sensor data and do something with it! From 32ea31839e02c6126842e081a11b2e161992a52a Mon Sep 17 00:00:00 2001 From: Nitin Nair Date: Thu, 13 Apr 2023 14:59:21 -0400 Subject: [PATCH 14/15] keeping changes from the master --- EmotiBit.cpp | 12 ++++-------- EmotiBitWiFi.cpp | 2 -- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/EmotiBit.cpp b/EmotiBit.cpp index 8c5cd88b..12974d10 100644 --- a/EmotiBit.cpp +++ b/EmotiBit.cpp @@ -180,14 +180,10 @@ uint8_t EmotiBit::setup(String firmwareVariant) break; } } - else if (input == 'R') - { - // restart ESP - #ifdef ARDUINO_FEATHER_ESP32 - Serial.println("\n\**** nRESTARTING MCU ****\n\n"); - ESP.restart(); - #endif - } + else + { + // do nothing. Junk input. + } // remove any other char in the buffer before proceeding while (Serial.available()) { diff --git a/EmotiBitWiFi.cpp b/EmotiBitWiFi.cpp index 1a67cbaf..0057bc04 100644 --- a/EmotiBitWiFi.cpp +++ b/EmotiBitWiFi.cpp @@ -149,8 +149,6 @@ uint8_t EmotiBitWiFi::begin(const Credential credential, uint8_t maxAttempts, ui { delay(attemptDelay / 10); wifiStatus = status(); - Serial.print("WiFi.status() = "); - Serial.print(wifiStatus); } Serial.print("WiFi.status() = "); Serial.print(wifiStatus); From 2f4fefef1ed41b71149bc097548f51bc8463b952 Mon Sep 17 00:00:00 2001 From: Nitin Nair Date: Fri, 14 Apr 2023 15:56:13 -0400 Subject: [PATCH 15/15] include arduino.h in ino file. Needed for platformio compile. Add minor modification to file name read --- .../input_digitalPinLogging.ino | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino index 70b78554..5163e9cb 100644 --- a/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino +++ b/examples/EmotiBit_examples/input_digitalPinLogging/input_digitalPinLogging.ino @@ -1,3 +1,4 @@ +#include #include "EmotiBit.h" bool pinStatus; // stores digital pin status to detect changes @@ -42,9 +43,13 @@ void setup() delay(2000); // short delay to allow user to connect to serial, if desired // Capture the calling ino into firmware_variant information - String inoFilename = __FILE__; - inoFilename = (inoFilename.substring((inoFilename.indexOf(".")), (inoFilename.lastIndexOf("\\")) + 1)); - + String inoFilename = __FILE__; // returns absolute path of ino file + inoFilename.replace("/","\\"); // conform to standard directory separator + // extract filename only if directory separator found in absolute path + if(inoFilename.lastIndexOf("\\") != -1) + { + inoFilename = inoFilename.substring((inoFilename.lastIndexOf("\\")) + 1,(inoFilename.indexOf("."))); + } emotibit.setup(inoFilename); // Attach callback functions