From 0123bbc1de2316d21f6e653f8f587e1a99c5bbee Mon Sep 17 00:00:00 2001 From: shivam Date: Tue, 23 Aug 2022 11:42:38 +0530 Subject: [PATCH 1/2] Added supplicant logs in client_connectivity_test() Signed-off-by: shivam --- lf_libs/lf_libs.py | 43 +++++++++++++++++++++++++++++--- lf_libs/lf_tests.py | 61 +++++++++++++++++++++++---------------------- 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/lf_libs/lf_libs.py b/lf_libs/lf_libs.py index 07bcaf0c..d741a2b0 100644 --- a/lf_libs/lf_libs.py +++ b/lf_libs/lf_libs.py @@ -160,7 +160,7 @@ class lf_libs: self.scenario = lf_data.get("scenario") self.setup_lf_data() self.setup_relevent_profiles() - # self.load_scenario() + self.load_scenario() self.setup_metadata() if self.scenario == "dhcp-bridge": logging.info("Scenario name: " + str(self.scenario)) @@ -171,9 +171,8 @@ class lf_libs: self.create_dhcp_external() self.chamber_view(raw_lines=self.default_scenario_raw_lines) self.setup_dut() - # except Exception as e: - logging.error("lf_data has bad values: " + str(lf_data)) + # logging.error("lf_data has bad values: " + str(lf_data)) # logging.error(e) """ @@ -1193,6 +1192,44 @@ class lf_libs: else: logging.error("Radio name is wrong") + def get_supplicant_logs(self, radio="1.1.wiphy0", attach_allure=True): + try: + resource = radio.split(".")[1] + radio = radio.split(".")[2] + ip = self.get_manager_from_resource(resource=int(resource)) + if ip is not None: + supplicant = "/home/lanforge/wifi/wpa_supplicant_log_" + radio + ".txt" + obj = SCP_File(ip=ip, port=22, username="root", password="lanforge", + remote_path=supplicant, + local_path=".") + obj.pull_file() + if attach_allure: + allure.attach.file(source="wpa_supplicant_log_" + radio + ".txt", + name="wpa_supplicant_log - " + str(radio)) + except Exception as e: + logging.error("get_supplicant_logs() - Error in getting supplicant Logs: " + str(e)) + + def get_resources(self): + try: + d = self.json_get("/port/?fields=alias,ip") + resource_data = dict() + for i in d["interfaces"]: + if str(list(dict(i).keys())[0]).__contains__("eth0"): + resource_data[str(list(dict(i).keys())[0]).split(".")[1]] = i[str(list(dict(i).keys())[0])]["ip"] + logging.info("Resource ID and Management port Mapping: " + str(resource_data)) + except Exception as e: + logging.error(str(e)) + return resource_data + + def get_manager_from_resource(self, resource=1): + resource_data = self.get_resources() + try: + ip = resource_data[str(resource)] + except Exception as e: + logging.error("Resource is Unavailable when reading manager: " + str(e)) + ip = None + return ip + class Report: def __init__(self, key1=None, diff --git a/lf_libs/lf_tests.py b/lf_libs/lf_tests.py index 45fbaf0e..0e6871f6 100644 --- a/lf_libs/lf_tests.py +++ b/lf_libs/lf_tests.py @@ -94,7 +94,6 @@ class lf_tests(lf_libs): logging.info("ssid scan data : " + str(result)) if not result: # Sniffer required - # print("sniff radio", data["sniff_radio"].split(".")[2]) for duts in self.dut_data: identifier = duts["identifier"] if dut_data.keys().__contains__(identifier): @@ -172,9 +171,9 @@ class lf_tests(lf_libs): self.stop_sniffer() else: for obj in sta_connect_obj: - print(obj) + obj.start() - print("napping %f sec" % runtime_secs) + logging.info("napping %f sec" % runtime_secs) time.sleep(runtime_secs) pass_fail_result = [] for obj in sta_connect_obj: @@ -260,7 +259,11 @@ class lf_tests(lf_libs): else: logging.info("client connection to" + str(obj.dut_ssid) + "unsuccessful. Test Failed") result = "FAIL" - + for obj in sta_connect_obj: + try: + self.get_supplicant_logs(radio="1." + str(obj.resource) + "." + str(obj.radio)) + except Exception as e: + logging.error("client_cpnnectivity_tests() -- Error in getting Supplicant Logs:" + str(e)) result = "PASS" description = "" for i in pass_fail_result: @@ -318,7 +321,6 @@ class lf_tests(lf_libs): for obj in client_connect_obj: obj.build() result = obj.wait_for_ip(station_list=obj.sta_list, timeout_sec=50) - # print(self.client_connect.wait_for_ip(station_name)) pass_fail.append(result) station_data_ = self.get_station_data(sta_name=obj.sta_list, rows=station_data, allure_attach=False) @@ -353,17 +355,17 @@ class lf_tests(lf_libs): if __name__ == '__main__': basic_04 = { "target": "tip_2x", - "controller": { + "controller" : { "url": "https://sec-qa01.cicd.lab.wlan.tip.build:16001", "username": "tip@ucentral.com", "password": "OpenWifi%123" }, "device_under_tests": [{ - "model": "edgecore_ecw5211", - "supported_bands": ["2G", "5G"], + "model": "cig_wf196", + "supported_bands": ["2G", "5G", "6G"], "supported_modes": ["BRIDGE", "NAT", "VLAN"], - "wan_port": "1.1.eth2", - "lan_port": "1.1.eth1", + "wan_port": "1.3.eth2", + "lan_port": None, "ssid": { "2g-ssid": "OpenWifi", "5g-ssid": "OpenWifi", @@ -371,21 +373,21 @@ if __name__ == '__main__': "2g-password": "OpenWifi", "5g-password": "OpenWifi", "6g-password": "OpenWifi", - "2g-encryption": "OPEN", - "5g-encryption": "OPEN", - "6g-encryption": "OPEN", + "2g-encryption": "WPA2", + "5g-encryption": "WPA2", + "6g-encryption": "WPA3", "2g-bssid": "68:7d:b4:5f:5c:31", "5g-bssid": "68:7d:b4:5f:5c:3c", "6g-bssid": "68:7d:b4:5f:5c:38" }, - "mode": "wifi5", - "identifier": "68215fda456d", + "mode": "wifi6e", + "identifier": "824f816011e4", "method": "serial", "host_ip": "localhost", "host_username": "lanforge", "host_password": "pumpkin77", - "host_ssh_port": 8832, - "serial_tty": "/dev/ttyAP5", + "host_ssh_port": 8902, + "serial_tty": "/dev/ttyAP0", "firmware_version": "next-latest" }], "traffic_generator": { @@ -394,26 +396,24 @@ if __name__ == '__main__': "scenario": "dhcp-bridge", "details": { "manager_ip": "localhost", - "http_port": 8830, - "ssh_port": 8831, + "http_port": 8900, + "ssh_port": 8901, "setup": {"method": "build", "DB": "Test_Scenario_Automation"}, "wan_ports": { - "1.1.eth2": {"addressing": "dhcp-server", "subnet": "172.16.0.1/16", "dhcp": { + "1.3.eth2": {"addressing": "dhcp-server", "subnet": "172.16.0.1/16", "dhcp": { "lease-first": 10, "lease-count": 10000, "lease-time": "6h" + } } - } }, "lan_ports": { - "1.1.eth1": { - "addressing": "dynamic" - } + }, "uplink_nat_ports": { - "1.1.eth3": { + "1.3.eth3": { "addressing": "static", - "ip": "10.28.2.9", + "ip": "10.28.2.39", "gateway_ip": "10.28.2.1/24", "ip_mask": "255.255.255.0", "dns_servers": "BLANK" @@ -425,6 +425,7 @@ if __name__ == '__main__': obj = lf_tests(lf_data=dict(basic_04["traffic_generator"]), dut_data=list(basic_04["device_under_tests"]), log_level=logging.DEBUG, run_lf=False) + obj.get_supplicant_logs(radio="1.1.wiphy1") # A =obj.setup_interfaces(band="fiveg", vlan_id=100, mode="NAT-WAN", num_sta=1) # print(A) # obj.setup_relevent_profiles() @@ -436,14 +437,14 @@ if __name__ == '__main__': # obj.create_dhcp_external()obj.add_vlan(vlan_ids=[100, 200, 300, 400, 500, 600]) # obj.get_cx_data() # obj.chamber_view() - dut = {'0000c1018812': [['ssid_open_2g_nat', 'open', 'something', '2G', '6A:21:5F:DA:45:6F'], - {'2G': [6, 40, 2437], '5G': None, '6G': None}]} - + # dut = {'0000c1018812': [['ssid_open_2g_nat', 'open', 'something', '2G', '6A:21:5F:DA:45:6F'], + # {'2G': [6, 40, 2437], '5G': None, '6G': None}]} + # passes, result = obj.client_connectivity_test(ssid="ssid_open_2g_nat", passkey="something", security="open", extra_securities=[], num_sta=1, mode="NAT-WAN", dut_data=dut, band="twog") - print(passes == "PASS", result) + # print(passes == "PASS", result) # obj.start_sniffer(radio_channel=1, radio="wiphy7", test_name="sniff_radio", duration=30) # print("started") # time.sleep(30) From 3576d2334def58ac45123f17b7cb8ed83e145492 Mon Sep 17 00:00:00 2001 From: shivam Date: Wed, 24 Aug 2022 03:52:07 +0530 Subject: [PATCH 2/2] added supplicant logs and updated the schema for dut_data Signed-off-by: shivam --- lf_libs/__pycache__/lf_libs.cpython-39.pyc | Bin 0 -> 34712 bytes lf_libs/lf_libs.py | 2 +- lf_libs/lf_tests.py | 62 ++++++++++++--------- lf_libs/scan_ssid.csv | 4 ++ lf_libs/sh-results.csv | 1 + 5 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 lf_libs/__pycache__/lf_libs.cpython-39.pyc create mode 100644 lf_libs/scan_ssid.csv create mode 100644 lf_libs/sh-results.csv diff --git a/lf_libs/__pycache__/lf_libs.cpython-39.pyc b/lf_libs/__pycache__/lf_libs.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6205d4016d7312074b17a7ba9a01d70c61a6ab22 GIT binary patch literal 34712 zcmd6Q36vbidEVUj?0w+o00amuiCrwfLnH)JI4P2%mJk4v;)vvMur<4w#q7*(O)r3L z&p-z#nUYPJw&h!TUfPOm+K%HWevacjD~_IC4#&=m&*#^1636y)L_b?joJ7t;A~E0h zS9eeM?gEq_Z6`b1)m7DXb=6;g{a002i^W_7e?R@J@!8HFMI!hQ|78$7j;sBVXe6Q{ zD%yyY%{^L=mG?<_0O7l8cP;EM@0ai(!Ut*x7ADFQ z5*|YM?%Lf8_mmI5H=>5s$jcEmawArrL}*lvAvA{26hh-_3qo5EI;5iKBNJQShYIuGvNJp{`XMi}tt|oV`-9YHh2sSZ!A4YuX<29yI1EcqVyw zBd$HG>q}O9Y8LseT4nZ9b@5_NU#ZuwR@91R@4Rgism?2*ZB;9?t!A?}YaQveV@bE> z>Wx}u#i}>z)~daAV}ZzM)mzQbBeb&Jtk2C=bXC<`_Le{{*3+J?Hs$?#6?reLYfCL{ zwP)Gu!9Raid?FSB^l>I&7DUVOTH;2eoK!KudknB12b{;sSzI|>d0YitMO=Nj`sX9% z0o(_14Z%N*`v|U4Tw}P#ac#l171uVEC~sHE@(z_M?^NmXF2vn|tAuMeu06H%@ zxF1$m)sPxS$|Gt-jUwh=HKxXKzfWCLTh%r^xnHfS?P>>n52&4L7oNRK*{Y;=Bj!Pc zR?WrKooX*a52=0XE<8V~_NxQ9zgvBqnoxJ+$uV`0I*6Eu)ufuj{SnnshtxElyhnA_ zed>Prj;rhHLG=)PC)82(ZlpS?KCF(ZhY@p1eMB8sC*V6h&$m1>7gs0MDTL4X;nV62 z!jGzts`skL;Crw7n0j120pDZled4TPRkH`JnP!dF%=tCm`V??dY2YFTOco>y&UA^!{N z6KX|WLClLP2Hf!NP8xvTs9$VXUjeSpmGHO6($%@S`fO#s)~xBO)zW*8mcC6M@iG7Q zG^>j>#O`TSn}QJb91K5i&(@k%U2ieX`e&+URqKuRhC-!a7h6>7OU!z#zBE}?O4r)$ zN7fZ1sV`a9QiZb(i65MPa5~%yNz!g#@=_c*vdME*o2#xgtV+9Ptt?eepJcTch_}vr zudqp`tC;*U$&va)dk#+>o~l`wj_i41lceaOjY$vhc_GwaT|Z=eGmn;YRqN8>>C2TP z^V7cne)!WTK6vEtbj5h4;h9YakPQ6^T&Hlg&%v=G3sDvABvkCxSTthAI?)@^ZnP8Y zL@M!49B!f$T}!I?>rwbq;!lV_E&inVGo8p<_VozYR=`YZ#@@Q`K(#$9D@nUFS=x7C z5hDaFKhd6uIVnKIV%2hzjoOu3!%4g2?WDOJT&yW4<3Yzn4&c|CpRYIPojewV`s}Gz zbFMz`BvgIY!g94@Rj_1Los?c_RvL3oe7x_Ag{#sXH6_93gjbm%JToAm1R zma9YVwDIm!ORG+%QmHrVR;BWTD6!3oBGJBRCYp+-VudJw_JEsh%1b(nS?B*@U5M~? zWc0oQkNsLFvJhFr2+BBM)Fc#>5JpczX6zDf$c$dn4Vm#vxuKLhvL+vBAB=g%$}Z&a zoMp#V=2b#Q-YR%8HyAF?N8t878);4@B3A$Em!gqwG#atTtbw(`j!;w2MxFz7bfed! z&78SUN2U$DWM`aQZ(2K9f6@XF+{uX*ZQV31tN_-iV!!yl|x(wFq^DH9}at6Wt0Lek)+b^~VGLM8Ka6 z_>o?vUQKsno!DBMI0pBO+zF-G4qzR4E4P*>tsadmj|mRS%xF#=Cs$V(`1)MErk#Pg zx?a3m)wRl%nr@@#oWx>F)tn^V#zYzjX>M^|I|;&tK`vazoLu{=pCfmv=g&&MN^@lq zNou-|;f3EW$lwBHl}VWQyViKWblwgD8?=6ubGH)>5mH%=Uh1n%^mY;RJ!-N|B6 ztF+s7)pkffu#i_{ z?~26mUJ@#(F{@Y3IMd&VjzlB{a6Qr&ZsD#&&;K2^b>KGrI)Hv1y=7asp{)u12Y!EVcOhkm#6R;l z_6~2?!m$l4^jfmhwD4PO$=gHe+qGnTLrc8bvkNVW0)zek1A|+ zn5Kv$)$Z{K{AmwgO1eFW0S*Yo-6?T}P~2XLD~96sNnBqj?krzcOYnDBD;tKe|>cvK_bQX`> zM@#lYo}j7JUTs^o#gb~(+Rgn|3E~|vkIi-onM<{6OCY0as`TuM8OeIIRI;bNK&jp? z^-69vOMaQGrSyIymip^ghGKe^d4X@avVlV)Pol(Wr7fM5zEo|h2I!agimp2u5HL*; z7i}lKga=k@(Mep;D-g$#&aqZYb!BfqN0Ah(tT#(;suD}A;cX^L2hTQY5X_apOIg)f z>u9OHvc!Hr4v`fIAtalst z4?cKpq8EDT!TTo4h1u#-^&-V;^;+95JUD%1>hR%<^UcWIQHKccU;5P(+ z25t;gaL|`P3NYdRFM+4K5C@JZx+OY>U+k?^Yzsnr++P9lxAJ>WdTDyTJ;G=0LjB&) z9t+dm-V20?Z%#e3T|#`5Uj_08+YeXRAEMSbqBCF&4&WJ}u2offAG~iwrPtT@RgnoG zqBb(PNtE8EXdx2qv45cyv+|TF@JI0x#VOL3Pav-qq0mT0LEb~~d>$c?!O<5M$P{$Q zzJat=2|S&KfJmPEv1AFpZodqsAgUmIP+$;!e>&jLz;DXRZl$;b$`(m$;`08}!X{6P zs2w6`HSpOi1Y41{n4(C6!mjvQ!Z3}l;3B#Dmk?aUMR1W?OB?cB1Q)Sx{CXUM3%OHp zu{;uZw;{a6i2az~^4q)x6*Fq|v&mbxWO)Q4l;msC)$6xw%Q8gzY?En=h-$~|Etmop z8PAoa5+;|do+V;-SzIAyaYdy_V&~PR*`-Oatw8WjN-)~26P?meVPxOra67U3(#_~0 zCtY8Hil%+p$<1SBxLRF>=oLI|vki$TGq)QA2=g}(sqZ=-iA-d{$6lgnEd$AHYemo2 zWOhqgY=e`=x-NyL-9q&eN^pv^D_T=fGuNnMh06$e0HNT`p+k`1h>GbD-chgy_}*2p z=k?h?>cFSx#2)G?oaUXv!)P->B7= z^g*Tnlvt%t4Gla z;tgDwJ+B(}nxR-I6gMFe-4MgXMVNE*`B*o~8BOLE0%71Cnb)!Lh#v-%KOO7ur_N5E)O9sq1MVfr=mk3H`iRUe-Jq`p$H}ZLVfn9B7Xe}SGFE`~ zetG0cG;bC?^(4ibC3_rm+hm&L1TGye&79!BzKm=)^9N5nec`FnBxCK}NXkr;kcA@M zeh8Y5`ngH$mh9wy=Dis`Xs1l3iK6}}Te41+8Mo_8y2}R-)1e4a#8vtc`rbq59y-V2 zOytaTks?G8TJ)N1=IxLl^pHcloOi{xL{?=_hTD6L5=5%oUbzUwA-$&w((C8nkgFqR z*HkXbC_Kxl_axFrVn*IMh6z}bi($&bFulH!NgRxB3#CMF@S z-aYYFDq(N)CgH{kL-UWQ(Vu@d0)VC4%|EQ1FPz2Nz?lX?S!kAdVKaj$+)rSRB|C9I zG@#p0k989 zqsr2sWIdmvvkpOy1pBLY4a{G&+F0QbjUhF)A${n04v;q#xtP6Uv(EN1>qX?-K%cPR z1?QFE0eu3Dhbsom7Guv+{0xPc;4<_~d1e!^{0^%`T=QN(rCaEn&SJwTU=+Fq?y1>XfW9K z()SrU>)OubF9+M+7Z4-+i)&~`u<^WPbiNADy2b;h&R7@YodIGU+YWWxxm0V3gUxMb#Kzt10E=0?$ z2jX16o}xuHmxxSmQ{x`2f3l{$j+IXJN!>r&Nvst+ad*D`tkt*HuliA%FQOLF$H0s( z;eGAlC#!91^5jarVNITQNpL_|f>IBA?;#72eQ1*;Qw?ORTx2$=J8QEot&j(aooLQ3 zdW#T{{bKEA^r%^DxG2~oGd1gKOJAM@zweVJ_I6XzX3wU|h2WxN-+3N<9;`2n2Cj7K znUdFR#EGi@XlY`=NxSwfJ#cdR+Lu~aVFhyy4R5qA3araI;*4%kZHcO75Xz3mD$Req z7t$ZbJLr$lIZuaJ$4Sh#mR4o8>G9Go*p^es3~h@*t`k*GAH+jT;2B-T**Xw*2Cx9D zV1=I~Jabl=xtIgHNCn9@%*!0E5ebud1gvlIFw^=%oXBjJMYw-^apy9?S=|0&5z9bQ zMWM~uW|5hRL2H)uq+}h~_u$EW@+5&LJ-J={Mg)WqkU0Q*kZeOR*jYD0X;#y9@(hbwg_o>WUz5{EwZhxoWO<6>% zUM4BWdZDv>87(xr5lGDgE&R?6E&M{Lg>L9?r-jX2uZ57W-i0>yqZecPCA6_%dU36Y z`#@&^eZRh~F?}x3RzLK2($?QZTL;kAxPGDo8_AUjTKy?OORyRQ5+u}#ulXy0r-4pt zKB|UXMA(Cm&#&wKIFM`)K6)XL8h}$loZ+`45#l}hn}VCrsKk~(kMiSFY$6fz!EMi*#H(Ote zFFVMEnmXeseb2FowXKu65rrFB*nT5=Ie~JYka4@SlNmGmL5`gtYQALcK-xiwU#M?P z=%14C&<$#JjDK|9vypY-;Xs%R*Ipk&#MjAmw{-^bULWgj?~HVymFe#2Y(s5q+ZR#W zAmgMAiRs|!mPmJ}iATOi(H}dJK8e06bhdRyJHQjF(A^e=u5|f}%{}rIe*LG&D^HPX z2g-nJ%0jw7Wm>%H&Q7v3s`i1d8S9Lhk-SJDi|6C7rS&e{!y_>f zm=kvg=EObzoJcKy4Y^92j>K*miL`$4wj;4udfw~pwEmc+KIr$R_@p<7H|@c3N?6UTBM%V779YyyJ zq}tobppPeCjeRm=?Ry2WpNxDv?LDW|p_enAJ5DoQ32iR{hwSJOZaEq+TXE|yDG6)+ zjVPYNzM{LUvkPzW!EPRw3%h}(^9FY-h){{Q{V>*e!%ia4p3bfg1SZHg0&K8*ZGUG^ zXS=aAcrCO1E1lhZek=n2EAVYm(|`%mCC>l{AOwOO6bZ^djCkNXKMc&rx$K95ZxIGw zanlpFwx}I`7`=l!2q)vO74$FS4k&vq{=$ph9Ny+mtlKVCL+S{WO;%s%8R7MEdz zzjOL~Kts9M8np>Mg%<8YjV2zLI}m@wj|UbH#NX@3-xrF%A2>bcmV_KPqH70UkEjPQ zE;&8jxpQs5dRMQ0^z(!0c~dXS@mTog*-cVDBx|cl>z9lYj`}5_<+mykJvM=Q&^w(w z)w^l=>0;45EKN+A$3pMX>yL*+@xA_dBoyE4kN1S)gZ+UVf&R$rlPwI1c%qCZT^V1M`}hx!98zg3AF`{T9j@`dKt%}jgYYqywZ1^p$+9m2CH9tg8{ z5`i##B^C&q-T>R|&yu2^aiM~i44565O~77!?!WzmffVMg-4filrGRYHoG8ny>%^4^ zFv*uTdGEsVmpWNUP)6sH3CSiJDJdnORiD%%3v%epPh=J_-5ctK3JSu`Epp(2PxAaoA z-G)Nh$<>;(dexYKQsCwcZV;^M8;mcw`f8E+fG6+mT7m919KL^D_}5zzlwCxi*VC}{#O9tQU7M?4v-h5=ip_}_^Op9t#l`|A3+)oj z7CeJ+d;0~zOiA?E?2%^6Dpfs$7Ffe4E&^tpA#aR~zFW-E{~jB)LtyO|+4UEs-4A%} zhNstV1bXeZw-Z=zQ4CsZvXQs@Y zZY|Q7#2JHiNrm!uf6h}--PY%jOqc0UM(@OzT1!r1p;d319Gq?Ia{MS07wAyg>11em z%vpKM`DkY2023!0t*cNU=ZO{FNufW)qMoKBs#bT;g&-XyEeJS!X`f*sc|xWa^DHwG zew@@5Xa->DKEOBiW`{ASsY7p|Ut!AQOqqoF5?isdgpsLnQ(${yuaRMMUdzz;U_v0= zNxO(gA7+YQl45iPRXTCxccOJCu4`7gr@E3EDR@tCDkQIqOXVSML#gykR)9}8#@)Y3 z+ynDvG4t`>3+*>%E#+Jf0ib7ks9OJHwlT|QRLtfV4^m}X(Ne1IL>J0=nhCkZa+}QD z9CiS*m8M*82A2C_fj$od9II7vmEqo_ijx(QDf_w%2`=>bP=2^-{4cY+L<{iC^vM(+ zSU*EQOA#tJF-Bsvw&6v68n?QP#3?$>z`BOYY}%dYBN{gCW{hd&fV^j*B>IIo?i-l|?W+E^ zb8JD+o7R~YvreyNp3mrMp{w;;mgF1v#PsU{RcM%yZjH+irSzw8wP{QRije&74oL4{ zm%l(Grxa+`cm>y5oTdoNkg#IyQ%DR2;8EN(b@)P4h;H0d3vvn3GJ#n7Iz@#3J;ePR zu7DYMXtb6C2-?HmDi}a+q2-yWY2_ge{sTr>IRh% zO(^|I@h4ypbr4oanN@U97u)Ua5tV|bE!D-7=OQZIO*2VeryR=g;(RzNOJ&nhGIGi{hNr(qV8Ufq$J(HSGg9|Jpl)naUf0@SOh;;m#TWAazFYgS)SeF1 z{)Is8h~KpKG)nk2seL$5`!H%xhu%C8qtakRMyh);%%uxYoqo#S6h390soX95wminX zEoEwR;$RJL8hborv*HX2bs|akn#PLm&rzKI3p!!@0?(dKgMYX}vp}!J-zAU}54icXiyg;MR(}UukfRa7k)!UqB6qGUY83cx%)SqH1`V7` z0?SrGMfA8NZo5Pb)~K%5bm?C1{tycXvf%c8rwG+=lPQ#EYHG^fX?CZ)2NH{hYClY_ z>K;zsgVjd8+SZR^fQ{tiz3^e0KZcu~d-m~1AD=u&7SxH&oN$to*uL`&5ofryx)zoI zTp$uM^Ut8!`FrK>x87rKJAKQywuj{zur8zy=gsLP?GQu)24N5z0c8S+B$?j9X3fjk zIf{GC+|R=@8~vM@(U0S~ege*;G6TV?r)RHWegd_vn~|Ag4IICss*fB1sQ-85h}io) z5(QF`$}F~)G*^~_Ji1A54;-4kcF5~iG4@D;g~E9&_xQae!+5WZD0aLql}gyF8}6+Q zugD2EjH^v1852MZy=cIS7mLm4|A|;I?+0+h*4xF(?6nCj+X(47I`VSt9Q{{tCQ+FF zU+`?Gg;b%`vIiakcvx)!;3GeRF8mz!Jma4DTx<>|NjF$?awb#+$ARJyDPkKuo(RQl za8yNJbwwx>QNTkIcKJAi$8C2S?Phl%{7;d0)8_v(JecyDZ$I=cjYx2eJUNOTn>>N* zr0E&<-ew);*EBOR5LipjGP%fpew)7IbSMKb-OtzHZ0Z^GIB9n;6HbJHRTEhF_+r(y zzNRb!;=B>u%2}BhWNMx0ij!d>vLPg6;v4q{Y_VlnIigNJ0FGnmn)WneBf>-sfmzuB zEME}zhYVa_94t;WBbz)5u`#S9vA1$qQF`=uptO*+ApwxrDO`qO0N!7LX%8?tW}2~* zrnTC6h|91FB#74{ zj+kKjVjD!TtMr?6#PEIHyzL`I;iMLqkH424Le_yCI+o2?Zx>29VF-@-p1$qg1q7@J zOp<6>$rb2iH->{m#O#nJNwC=Cz7O_A!T6C5?+-;U_z_s_d9i+uCvhsNV;SrLwiO9ar!$^xfm(GkuY1T`WZ1qhZ3+i-0pA~@$cz`yF>pf;@-_ZAlitC zwJ*8;F>t%~E^qd1E@JzC(IXl>Sj2txm-#xo=%f&-({$Fo-LK>6nQ!IoKvJ#~2Zoqo z0thLaQ@GkMp&~_#S)e}90oO5_WR9Vh;kb$mMGO3}$nPdBZsq5ObK$x32>n--TP%(&1X1vj@-f zoS~9P{*1VOMpP7b@dP-#Bd!SFY?rn73CRH(X#F}VOqP^^X{1GwAo=h2^M3(jYRY`T zi<{`XwaiyA%?ac&B59G(#vx8I0%yVUMA`Z!I4)-(f>zBlNA!P!V|W51g@l+i*Qm|8 zLdoD02up=`FzKLvS_j&{fs&pgXx|4P_PhAnSO=$7xQszxcl7!w z1Ws}%V_=PA;eiF%+LjJa>KO0DF}1z|%LQ7zMD;INTNk#e{?51>AS2Z5lklJyMh|V5 z9*QjN=m7P=_K{Yd5QSl+(w%$^tvVlBW{fHCrWyvZ+=mG|V(+?e30gcXrk7gEOtV=m zPE-t)L`MJ^arLEKzsuBlO-~=jM(I8t3Fz@HkVRzYs+Vh$(Mhy$#EYH&&`Bsx-}eHo zxq+BjaxF^AE4-$>We@4k5gj^LR50wGup})k~9CB135Ltp2BP-=_XIuTN zm@`gPm*Y5uYX&-BuL4nKy%7__0jkKBS}l)+A42wT=~WP)gLpF$YCbx#(_jIiL5`!= z01^0ZHX;p{G^O!YQ8E zG7ZOxfW37LNJ(W4=~`2U6%PD-Z(2L^f2B#8b^t_B+pog-2eB)R|(WE4U-R6rAB zMFj)J{ePq^upa}*Md8pnth10;L+${I8HmHeeq2Kl@W}#paR_Q#7b^#q!NddyMq%2^ zu8Z`Hot#?2IRxd@Vyjud7stNo-DrX)E2m|&)80T9m;ywy;e65ikvCl}b{Yk6RGora z!HI`Zwqf_{EKD=9ELze#x%1T4$%@>Ad(2WMz}TC;avx@`AA#ef-O8wOU96K1gT9ZT zZ;lm3Ge?-LXjVeEiKfBO&jG5WJvai-v}ZjC6a!_|^ydf$B#)_Bz*31FZqy)=^$9G9 zz1nL!MCP(9NDRsVYIraRAi#Kjle?aYsEe^{Ni#5J11Dl|PAP{KK5Wy(a3)^`-D>3* z3PQx?aNbjXp>LsIrKuj^d2uRZ(V9Ewt&a2q^J4qjWz_6sK(xw{k~jO!k$hhGkZ?^C zDJMg0DRYoS0=8K~h%CVZCse;Xjc7!`f%NBeIQ+n#6Yo+v|zCEB(Q zAG;n6(>oHiM?9`4m@&i+kQ1PcQ-I(iJoXf6S&=>taMy1q0j^H=$S>!h5xNTtKe%4F z;Oel*^Ju`x>hr$r58xA!{l#6`pWH?EC$cH~k>GNBwGJ9sFu7T9eN0}$)>|6Zz{H5F zS8q9f^a4*skOf0X*nnK2x1a&vV!yc&tPs_%n@f5(y8h?chn$g-SPbZs`d{uHO@ZXZ zMxX;;@4ekJb2G=oK(E%9F0H~YhP!n`eVj%4ejk4Z0sAG9BVc-QS16BI6AldIC3;+B z$Kal#E(Qf=#Po`FQ#iOY0kQ_VK9$CX2k=4*Nf3}}=$U{Q1(zlaaV4XYS^YFdB_o6v zH|2<2StPQEy`GT+8*!IW0bw+ea|IOW7I#xKXQnRE`Aay!UCZ;e{)NC zC;wHLh8fcY2e!_2$nYxC7T@!bQDbCIFPs0v?`7K7+p@0E7F(4t=x1*xu>^!-g_u6U^`ak=O9Y zno}GG-wB?D0dm{!VuKi1grv)2c5#x^yV1Sqm zYRJ0t6{F0JTr|GKW~>F=0Wt99+?g6*{RO~8USI+%G0AL~7|(R`*Yki0xeGC#0I#1# zyL?_B^%Tha^Pons1ObaEw z+tfrOOEYC|W-Zz`e2w4xMzpu_(#iTZYcnAJjgTG~ zYOV$1-?Pb-wWAjzNe612*wx9q)F)RL%nCvELUD_nHH^~C2|DD;4MTpM1q_=dt0E*K zt(4Fs6a9v)NU$^XK2DQ6;Ru^z?22$CQPoMaN3h%3@!E-lYv)=xbDWk$Y@}-=#BdL9 zmVGNmQ>8rp6E^CP=!9AMuwfU={2k6P;@?P$oANW!lQPeUY|YFnVZJ3mkDktCgj zsew}^DJn%xAM9o!SAYl<{xR;hTuWiE6ArIo%`!E9xRVtT*;lX&FRwURKaCiQ#C}&| z*doS2RHZ*HF>LLpu@v9LBm!ScGYl>Oog^kv!QSG|o!M*arj4C~ss`{fV?zyOAT)Dv z31aGNrD{2I8Z-@02eQ4mi{;eQOLFAU_oG`Sk5EX=%wfDunK~|q<%07e0 zzmCF04<%&~N_hfW1Bcxc2%(>1JdPNZ6Gd-4_}s!ri*+i)=c zaiCF%MF9hsNK(n6N>i{j5;h5nVIRdpSPr@xBmJcNG_m1n98VYAr&KBj^7cpoltV%* zX%D;hAs(V4=W2|jDLyoo#zopHQyFnpx0>@9QgZwHIGuk-M{v|{()U|*dK8y?q`)sR z_7~|;R$+!Hj1~0n;K2}?g2l5SK)HhNBxQt^&PpjtsYUy3#B=T>Pp>Zcv@2G&0PUJ|X;--mmBa~_vhQ&x zm|(-+sx(DVEx{mTrJ+g}Yb8SEl;CaHOD83985$BQvnX{wKa9txFW!2RlH3^>&Z2*<@ka zz%QaQ1KFf`ds z?>nu<=@%89&qA~x3e@Ps%(^u1xY9v)YRri@PjUmzOwF`l2ebgFG5;Eo>f8fhGn?PaY4QR#((*_*3sN&rOXf$vP zM)pY-dm#>5?O%b#Ce8K$xdy7M;XlyLg3iwxI$yqe00B1G_mt85!366ljjETAE`z=k zD*i4h!$ujP)_G!!{sfrpL=$JHBb-I}Gb#tFFuBGf@}O)EmPZZ&XUb<(zLSQW6$jwS z(Re)aj$s~om&OinDAjqgJYsObo!1uk;3ADPPRMMh)S#GdyR|}}w$Mr9jh?3phIn%{xdp%PUmZM{({cO;oOXt?0D&L$xiSCm|b2YiQcDEBbpN9pXO)8kNtzREN1I34ohG~JWWk>N<>+EpDEPjD(Acl@FCD6^6iC41kS@wR=1h-h|I5|?l&AAzTX^JD=dfPc8) zPFy&l`i5#8%o2}`hVe&Ws{!-KAzaXx15O!&Xb3Ps6V-$tmsg+^0i*F?8m4CHa}Xxu z+d>#j|FkO++JI>GX-D@sEu1^*p7&(u&sDFMp5!M}jvBbYCpq-pcok>RAcEjoQ!==Z z;Nf}^`xXowgd(fWSsWD=5J7$xXLVDf zfwZ?h$82Y!YNjWU4?a>8B-|5N6_s~f*PiEqwEYz|B4KG z#XBqaRewFo^q8ql(uF1=7bJfYHV`293ah#oLl%b6!(geRISQ?%_|YyCf{YjoR!kq` zKA0xXJNC2#K=YZ;!j=hBD+;rcw6Pg)<|x22R^wu&Sg;>>9Q(}Wz<5==xH2yiO!oHG zrRpSizT;z%IEP+_lZvC^RUztv`ql*$wbTP>1(isn8w%1rmyinjm=SET>7Y68Ky1=b-vuQ_DgXh~DBqJ>dFuXt~7B?YQZjpGmORrT08XU`I2C?s%}z{N*Q__kkjH^& zx@GBO7=9Q46W)#C%XULd~ zle3jXxc6Nz?zHZ0d!;pslff5JE003qi`AQYTQSn;31UP`>&sxA z+k%2n^NA2HHDa8M@X``i5tstx4Jk<(ni0$OsK_$oM2{nA>jZ-b=?DUI1*L0JgWi znGt&_eGp+u71QryyPuS>Su{V79P%tGCBStz#{`)7?yUfzH!(o}u$B9Ribnj*e&xd__Syi!%$%nJUJFhIF`-4^Zai ztPkJ4gJE=)MOEm$MCU~~Fubv>T62Y8rImdrLdiSH(`QaT{a(G5$%g5irZY=tp3X<< zdg_I*-%YP3I{(&(V2- z4%HhXW7jV+Sfz834l%GuO|_!0MrV%BJe^B)>U5xki0I378gv%vkU7-kD)cIyE}d_u zBXfn&9zYqgs*v;0RFO>JYX1@(EERn;X!&dZ@`+?3kw_;}fnPEa8`+&1$@FJFkcsE^ zXLemoPb?{`D`_aC19k2 zs90t;STB;*I>pjR{J{`AQo&*Z7t0=8EIV-HzLEpSKJk-3hsDMDE}$~uhkL}e>eJuN zG5H=k-%IB+;USXIA*}v3-ok9tNtln**!}0kSZwpp!^V+?*jrjk5(3IZkc?0>gMAi1 z7HRksb$rXg0?|k<7&KpTvpW*HHKHf8dJ|{vu+UZx`Ly66M!noO46dSX#b*ABve} zx!xb&&woc^Ff$rrN6Inb*DD~V6FU)X0Q`RB2f}1)v^39MU?qZYrhkCW57G(KTcT(C z!(Kc2!H#e{j}V0ek;iBB4>Ld8ithOo{og_7JLw3{`62p5ao4M)Hxa4U`z_YQ^(Yg? zB;oHHxojpW@VEiE*>lHnweN!C19wqjpMU^2L7KpAzQmqX1%P&+zJY3BeMl21u_wRI zMv>0e57Qx`6WaSglU*P14h45--+fVNcJW{ka+(HEBGiKpNyYK8#TYI z(iDI79_e24UU&JE;!XAxmwoQr@_yJi;}Yk$o*KSn_Z8&jHf9htAZLsfEAG&}lY$j# zRMh`!Eg57=WV4toR2tKIHHXxB(z@SukW*)YUqj}WBzzGRoEg>!Y;fu)$Mq~oAAj$| zz+tHQrxD8^cRq;BGdc4pfaZ}<-w4Me20%DI9TxleEEhi6)Vf@O6s5xRpDtjUeZ=ci z2se3XRU3!W;TU#o3()v1&gGVqJ%9c&e5ioAM~zlUzLh6mL6%aS?G*km)?p~#ocE(4 zxCcuQ>-Q5YR_laPXH78eZmu?Dl|PJzIV0wAgbu}r+Hm9>_jwK?F3`y2Yy*6>iyrXd zv-Tx8vrFq|-OG5ZzvKv$L?LZPMq9qWmFR=Xk3Hm%v(JNZ>Gc2T=Os80m(_33>A|_* zESaxgWg|$V30imyD4`(n6Vos+TVy{s>K6@-6T|1);`kh*5l^z=#!BEvS^mFd@F(fx zPzfqT0T7p2tyZHghqY;($PDhAoU{>e{~A&{>FUL{Fxnt8$?$@(ESid4N)sG7zo%V+ zaIa=QCqbkHk?a*A2|XHG{|IA|mS^oVtVl{vUDj=dJ1~H&E_(&x`PmrqKVD8H%PP*UrExo|1x*&sc-Y zhA_%5Tl!vh2u;fA@?Xm}+I9v!^K;*f`%(5XF|;w)AlBV%c%95KL#lJ?V|yhW iBg3alqZe~GQu~rC**Efi%J^@4#rsHOg@5<