From 1b31587202a51a017f50ff57b992f6dec72f8c36 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Sun, 23 Feb 2025 20:40:16 +0100 Subject: [PATCH] Refactoring --- DoxyGen/DoxyWarnLogfile.txt | 71 +++++++++++++++- Messages/Messages.py => Messages.py | 78 ++++++++++++++++++ Messages/NetworkIdMsg.py | 35 +------- Messages/ParticipantMsg.py | 66 +++++++-------- Messages/__pycache__/Messages.cpython-312.pyc | Bin 4747 -> 6303 bytes .../ParticipantMsg.cpython-312.pyc | Bin 1830 -> 170 bytes 6 files changed, 181 insertions(+), 69 deletions(-) rename Messages/Messages.py => Messages.py (50%) diff --git a/DoxyGen/DoxyWarnLogfile.txt b/DoxyGen/DoxyWarnLogfile.txt index ecb30be..6613bdb 100644 --- a/DoxyGen/DoxyWarnLogfile.txt +++ b/DoxyGen/DoxyWarnLogfile.txt @@ -1,2 +1,69 @@ -error: tag OUTPUT_DIRECTORY: Output directory '//intranet/web/passer_life/apis/ControlCore/Python/' does not exist and cannot be created - Exiting... +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:42: warning: documented symbol 'controlcore.Participant.Participant::bool' was not declared or defined. +error: Project logo '//intranet/home/Afbeeldingen/PasserVR/Logos/Logo3NameRight100.png' specified by PROJECT_LOGO does not exist! +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:13: warning: Member SendTo(self, participant) (function) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:19: warning: Member Publish(self, participant) (function) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:67: warning: Member length (variable) of class controlcore.Messages.NetworkIdMsg is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:69: warning: Member network_id (variable) of class controlcore.Messages.NetworkIdMsg is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:5: warning: Member id (variable) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:13: warning: Member SendTo(self, participant) (function) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:19: warning: Member Publish(self, participant) (function) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:5: warning: Member id (variable) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:115: warning: Member __init__(self, network_id, thing) (function) of class controlcore.Messages.PoseMsg is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:119: warning: Member Serialize(self, buffer_ref) (function) of class controlcore.Messages.PoseMsg is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:13: warning: Member SendTo(self, participant) (function) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:19: warning: Member Publish(self, participant) (function) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:116: warning: Member network_id (variable) of class controlcore.Messages.PoseMsg is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:117: warning: Member thing (variable) of class controlcore.Messages.PoseMsg is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Messages.py:5: warning: Member id (variable) of class controlcore.Messages.IMessage is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:27: warning: Member __init__(self, ipAddress="0.0.0.0", port=7681, remote=False, udp_socket=None) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:50: warning: Member GetParticipant(self, ip_address, port) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:60: warning: Member AddParticipant(self, ip_address, port) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:67: warning: Member Update(self, currentTimeMs=None) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:82: warning: Member SendThingInfo(self, thing) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:87: warning: Member Send(self, msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:96: warning: Member Publish(self, msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:109: warning: Member Receiver(self) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:121: warning: Member ReceiveData(self, data, remote_participant) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:141: warning: Member ProcessClientMsg(self, sender, ParticipantMsg msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:144: warning: Member ProcessNetworkIdMsg(self, sender, NetworkIdMsg msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:153: warning: Member ProcessInvestigateMsg(self, bytearray data) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:156: warning: Member ProcessThingMsg(self, ThingMsg msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:168: warning: Member ProcessNameMsg(self, NameMsg msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:171: warning: Member ProcessModelUrlMsg(self, ModelUrlMsg msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:174: warning: Member ProcessBinary(self, BinaryMsg msg) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:180: warning: Member Register(self, constructor, thing_type) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:183: warning: Member OnNewThing(self, event_handler) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:186: warning: Member OnNewThingType(self, thing_type, event_handler) (function) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:28: warning: Member ip_address (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:29: warning: Member port (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:33: warning: Member thing_msg_processors (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:34: warning: Member new_thing_handlers (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:37: warning: Member udp_socket (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:17: warning: Member publishInterval (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:19: warning: Member buffer (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:22: warning: Member nextPublishMe (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:23: warning: Member others (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:24: warning: Member thread (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Participant.py:25: warning: Member name (variable) of class controlcore.Participant.Participant is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:22: warning: Member __init__(self, network_id=0, thing_id=0, type=Type.Undetermined, parent=None, name=None) (function) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:43: warning: Member update(self, currentTime) (function) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:46: warning: Member ProcessBinary(self, data) (function) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:53: warning: Member Add(thing) (function) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:58: warning: Member Get(network_id, thing_id) (function) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:23: warning: Member network_id (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:24: warning: Member id (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:25: warning: Member type (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:27: warning: Member parent_id (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:31: warning: Member name (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:32: warning: Member model_url (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:34: warning: Member position (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:35: warning: Member orientation (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:36: warning: Member linearVelocity (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:37: warning: Member angularVelocity (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:39: warning: Member pose_updated (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:17: warning: Member Position (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:18: warning: Member Orientation (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:19: warning: Member LinearVelocity (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:20: warning: Member AngularVelocity (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/Thing.py:50: warning: Member allThings (variable) of class controlcore.Thing.Thing is not documented. +/Users/pascal/Documents/Dev/Python/controlcore/LinearAlgebra/SwingTwist.py:6: warning: Member __init__(self, Direction swing, float twist) (function) of class SwingTwist.SwingTwist is not documented. diff --git a/Messages/Messages.py b/Messages.py similarity index 50% rename from Messages/Messages.py rename to Messages.py index 26932dc..0cfa123 100644 --- a/Messages/Messages.py +++ b/Messages.py @@ -22,6 +22,77 @@ class IMessage: return False return participant.PublishBuffer(bufferSize) +class ParticipantMsg(IMessage): + """! A participant messages notifies other participants of its presence. + + When received by another participant, it can be followed by a NetworkIdMsg + to announce that participant to this client such that it can join privately + """ + ## The message ID + id: int = 0xA0 + ## The length of the message + length: int = 2 + ## The network ID known by the participant. + network_id: int = None + + def __init__(self, network_id: int): + """! Create a new message for sending + @param network_id The network ID known by the participant. Use 0 if it is unknown + """ + if isinstance(network_id, int): + self.network_id = network_id + elif isinstance(network_id, bytes): + self.network_id = network_id[1] + + def Serialize(self, buffer_ref): + """! Serialize the message into a byte array. + @param buffer_ref The buffer to serialize into + @return The length of the message in the buffer + """ + if buffer_ref is None or self.network_id is None: + return 0 + + buffer: bytearray = buffer_ref[0] + buffer[0:ParticipantMsg.length] = [ + ParticipantMsg.id, + self.network_id + ] + return ParticipantMsg.length + +## A network id message invites another participant to a site +# +## This can be sent in response to a ClientMsg +class NetworkIdMsg(IMessage): + id = 0xA1 + length = 2 + + network_id = None + + ## Create a network id message + # + # @param network_id The network id assigned to the remote participant. + def __init__(self, network_id): + self.network_id = None + if isinstance(network_id, int): + self.network_id = network_id + elif isinstance(network_id, bytes): + self.network_id = network_id[1] + + ## Serialize the message into the given buffer + # + ## @param buffer_ref A reference to the buffer to use. This should be a list with the buffer as its first and only element + ## @returns the length of the message + def Serialize(self, buffer_ref): + if self.network_id is None: + return 0 + + buffer: bytearray = buffer_ref[0] + buffer[0:NetworkIdMsg.length] = [ + NetworkIdMsg.id, + self.network_id + ] + return NetworkIdMsg.length + class InvestigateMsg(): id = 0x81 length = 3 @@ -31,7 +102,14 @@ class InvestigateMsg(): self.thing_id = buffer[2] class PoseMsg(IMessage): + """! Message to communicate the pose of the thing + + The pose is in local space relative to the parent. + If there is not parent (the thing is a root thing), the pose will be in world space. + """ + ## The message ID id = 0x10 + ## The length of the message length = 4 def __init__(self, network_id, thing): diff --git a/Messages/NetworkIdMsg.py b/Messages/NetworkIdMsg.py index d5f455d..a1e6baf 100644 --- a/Messages/NetworkIdMsg.py +++ b/Messages/NetworkIdMsg.py @@ -1,38 +1,5 @@ -from Messages.Messages import IMessage +# from Messages.Messages import IMessage -## A network id message invites another participant to a site -# -## This can be sent in response to a ClientMsg -class NetworkIdMsg(IMessage): - id = 0xA1 - length = 2 - - network_id = None - - ## Create a network id message - # - # @param network_id The network id assigned to the remote participant. - def __init__(self, network_id): - self.network_id = None - if isinstance(network_id, int): - self.network_id = network_id - elif isinstance(network_id, bytes): - self.network_id = network_id[1] - - ## Serialize the message into the given buffer - # - ## @param buffer_ref A reference to the buffer to use. This should be a list with the buffer as its first and only element - ## @returns the length of the message - def Serialize(self, buffer_ref): - if self.network_id is None: - return 0 - - buffer: bytearray = buffer_ref[0] - buffer[0:NetworkIdMsg.length] = [ - NetworkIdMsg.id, - self.network_id - ] - return NetworkIdMsg.length # def SendTo(participant, network_id): # if network_id is None: diff --git a/Messages/ParticipantMsg.py b/Messages/ParticipantMsg.py index f665cf8..d1a5e8e 100644 --- a/Messages/ParticipantMsg.py +++ b/Messages/ParticipantMsg.py @@ -1,41 +1,41 @@ -from Messages.Messages import IMessage +# from Messages.Messages import IMessage -class ParticipantMsg(IMessage): - """! A participant messages notifies other participants of its presence. +# class ParticipantMsg(IMessage): +# """! A participant messages notifies other participants of its presence. - When received by another participant, it can be followed by a NetworkIdMsg - to announce that participant to this client such that it can join privately - """ - ## The message ID - id: int = 0xA0 - ## The length of the message - length: int = 2 - ## The network ID known by the participant. - network_id: int = None +# When received by another participant, it can be followed by a NetworkIdMsg +# to announce that participant to this client such that it can join privately +# """ +# ## The message ID +# id: int = 0xA0 +# ## The length of the message +# length: int = 2 +# ## The network ID known by the participant. +# network_id: int = None - def __init__(self, network_id: int): - """! Create a new message for sending - @param network_id The network ID known by the participant. Use 0 if it is unknown - """ - if isinstance(network_id, int): - self.network_id = network_id - elif isinstance(network_id, bytes): - self.network_id = network_id[1] +# def __init__(self, network_id: int): +# """! Create a new message for sending +# @param network_id The network ID known by the participant. Use 0 if it is unknown +# """ +# if isinstance(network_id, int): +# self.network_id = network_id +# elif isinstance(network_id, bytes): +# self.network_id = network_id[1] - def Serialize(self, buffer_ref): - """! Serialize the message into a byte array. - @param buffer_ref The buffer to serialize into - @return The length of the message in the buffer - """ - if buffer_ref is None or self.network_id is None: - return 0 +# def Serialize(self, buffer_ref): +# """! Serialize the message into a byte array. +# @param buffer_ref The buffer to serialize into +# @return The length of the message in the buffer +# """ +# if buffer_ref is None or self.network_id is None: +# return 0 - buffer: bytearray = buffer_ref[0] - buffer[0:ParticipantMsg.length] = [ - ParticipantMsg.id, - self.network_id - ] - return ParticipantMsg.length +# buffer: bytearray = buffer_ref[0] +# buffer[0:ParticipantMsg.length] = [ +# ParticipantMsg.id, +# self.network_id +# ] +# return ParticipantMsg.length # @staticmethod # def Serialized(buffer_ref, network_id): diff --git a/Messages/__pycache__/Messages.cpython-312.pyc b/Messages/__pycache__/Messages.cpython-312.pyc index 5323ede8afec7e7556f1c0e3011af273fae73dc8..0fda623279abd6005e5f353626c16006acf1360d 100644 GIT binary patch delta 2111 zcmZuyUuaWT7(X}nPvT9|G^zC8+UC^8w9!(PGB=nwTV4Hwrfw=5dAZ!?o+P)nH}%}x zmV`n&ROlFE${kb3U>yn@_%sT8DTBQX24hf}poBg6Fb3{nR9e^`_nnjEHg#Uech33# zf8XyrCm-+s>PX8k;joI}TVGhu+mYKXox+XVgKwpY_)uhQgffy3okoWL1~LK9e`qTWPVOLrGJ=6JzAMNOGNR$jNJJ)zAsz#% zA!YphB=eJ!3GkDjpFooH8G##8W{&|GWYm(9QmZW&b?TT|b56IM3wFNzS3e%Zb2~g- znI*QZ=ZTH2qGRSv*c6=tq0LIb%3;&7@f;;Kv9e@DRWW?;7l?%^$r5vc7Nep)l8$3t%C;& z2ubi`fNV_zxq}=57XB>>j;GfEkp`B8C8T-$l5dy3(y;aPgG+)TbOF1`s)9maKFUoMcw5uZJUuUf@LXn6@b zM4G!eg0I*FAI2ub6GJ!WD;C$~{bH`4vy#&(sj8Z`Y1xhrU{poZawrBtRh}w2#7_BW z1Wue~v-&Zndzd(&X{Kd5npW=EJ$NGxK@!yLLqL|%b^wLiFWj1bFz`5-eA+j(a_W=G z-@_eu)d%l94j%x%6YqhkygZ@a+17%ur$NWQ; zyl=^8G+{XHp#!${?=`f8@vG#QP|8=n-;Xa5YU(p)nGGrNaDo=W_(IPaf|Tl|5$rYf zM5PAU)O;>Ss76VS16Dh-$+kV0%*~D+CC)sxxN>cF*-hLXl^<)KJUhzDPe~jf+5`Iv zzXdeT*doWSs_rC11HiZ0+`|BHASrwN%AGG^=oQZJv)=`>j5bvOaU{=yit4!VHc+A*EFM;)wEh23C478A6e^YLa=Pb!t#Ee6zy^6q%Wg%A9L9U1a1L_#ZAcjWXeLi7v(Nt+?|$>C2Gm=JnAWc z5xXLExIvD)zshl87@T&wic%WGAgIdl###9~Mzvzz0RC=pnA>ve#iC8%<@9dWxwRja z9x3)Z2vco4rgYT(TkR0yt`huSrb8fge-0iJ(rf<)7la|+v;VcLk?SaEQ${A-&%+5} zbZtEx7BsH`bcDrHYOxM8T{c5i@icKL%epEVx}(!0ux)-Nc(2N_ansUiskwqYQ+(Sk z%3bb>$RXkU+FT?e9A`l$_(WfB#5x14+9a^at%`6rXbbF8GHqod7Mz}EB<}vudQ_No zw_EQEN%wAaK;^cK817Heq{4Qofcqla6K8*;yaFn-9lJL*w0IlNxP!4?^*vy+7t$Vg Z)3MIT_JILm|E&+U5iI|l6Wl^<;6FkC^(p`W delta 624 zcmY+BL1+^}6ozNA$;QkkO=HqzTT`1f+1L#dDHstfDF(4Uw9td6qAsC3Y?qcznO#$& z-V{9a6dr#{{Or;Z(q#s8DpPQDMsW| zoO$QmW`i-EdV>qsuI@)rBxF4rAxp%LKPL7WuIwv+)YwQ(NR^#B)jl<~H?O}bgD(kq z$sXy4RJsrGATts&j|aP5v1Pe7G__f{6Hmfjtw5)tr!BBh-R7PXYzhNvtPG)c4xX?n zNGJQ(XJtN&1)Hwtn2JctN}wbzO87WWsZvN*1H_ zy8LKn|3<|eMy4df{3bmlGGNMzt^rcTY_&rFZ1H8dMgW;z??5M_9l zt%YEQ{XwbPI|WBX?{k-?Fcl>`+Ue>q04ZTe?<*=UZ}7Z z%7{hySg0-Fn;8!$SGn(Z9PT$(y1Og9$G1-eF^>VfhKM1Gh|wBa(9ox=%d*B_?KdU9 ZE0od$a`}K1j-y%H{6Qp+>+n#o`~pfnjST<* diff --git a/Messages/__pycache__/ParticipantMsg.cpython-312.pyc b/Messages/__pycache__/ParticipantMsg.cpython-312.pyc index 0f48b9ee6952f358f93076165af67634ac97120b..bc78bfa7e6cfcd97c9cbfe1f63261594e4ccbee5 100644 GIT binary patch delta 105 zcmZ3+w~EpBG%qg~0}$LS+npZA$-wX!#6bt2S%4zb87dhx8U0o=6fpsLpFwIS8!>w; h{o=66%}*)KNwq6t1&T2OaWRPTk(rT^v4|PS0sscg5@`Sc literal 1830 zcmZux-D@LN6uW~+7E-m=|j+@%o&@nI2lt5Tuq%DO0d8KyHg&FxNR+Iw$W zCPavA7vh812chm;#e&NI3H}HA(&9qPpit14`V`6fvQM5nlcXQ?KAbt{o^yWpe9mu~ zjDg_%I`hlw^?ro@l0x?+I!rqY%r0_}qqwM|6cq)j=p*E)+sM&~@>GlMifW+e5~otg zDPd}HiEwVM5Lfvuj&=vMj$Z7Gq(meoi>XNJ zizLvLR428q7yF(5ZB#UZWX=c&?^#Sxo32})SmLX-e`fJ}c>U}SSK^R3_IyE0lyK~e zGGXU!;HreF;CP)8PCT2;8wQ5+S($j45u4CW;^374TYz!N_cl0U+w$-V!6n~y{jH8E zE)cQhvxkcggcZRF9{@bR3J+jWw#4}mFepWta%{VlcmngPU5<@9@M}KxAU?Wj3E~D3 z-sv8cEL5p;s!As55^q(M3!&k~FPqe{rKWpyU}Q7eYe069P`Zk`B6@aDI~+^Zl{zwe z_knuBKH2r{*$>neM|l~pFM0)PPOCkh#djHj$gzbzveoSg6pUdgxI?|TLbB-ZLi4N& zm_^lt9Pp=Q(iQRI0)FWETTt!*%0teVa2`M41iyi)>?MX$R=vnHs+B}Ol?fMedT3Bi zJuWP0M5s|uFu4z5VkHoS=hRT=#4Sa4T&9oli^V)ZGoD|!xNW)l1>de#pi4ZzKsNLD z0#Ww8yzK*!@7g{i`OX^f{Kes%Uk}2RX;P00)2vNgQg#)?@Fvd#X`tsRl)kpJwtwT< zK=ye0wdTUt%YS4hzBBeec$Rq`E`Az$QjwP}4GrFEgA2O4;rpQ3MRn!NbREg&Up@^b zP`d5=LOmOXH90bu&eaI3YF%~CjnP_fK+fD>LFbUK(BDTnwf4g-zE2pnTw0S`LVB|T zeS-agzRM|M%nIglud|(*S*eyvgqe(#qM34x&Ukb7MqQnHL$y%OigT7axtp z7^&ySlz>vaG#yX%KoExlQ~N zAPv+qU=j`nruN2vocVs{VD|0fvGJ4Z*}aV?OU>lp>B*z?)M0w+I6eH$@>k2Pgm%kl zCYu}IP9KeA4@a^GsaIi?hNq8)<_?GE4pMV$3{Z0eavD9WLQFF>Ota!URaf$9)7+?9 zZb#E+nvQRqW}M`p41UNo<)2Jgg8Ci@l}tS@$Ef5cfc%W2N1|-wBFRe08t}J(JVyVj zdLq?IqoJ|J`%Udp;be5I@nQ4sqvexplZ}sewBPl~mfn}Rz4vAt!KXc%N!*MfB~T%! zg(KZPo9{AA;>WK|NlvC2MerhZCr