From 7ec2d3425c3b65d1dbac007385910ef3d0e42963 Mon Sep 17 00:00:00 2001 From: Sven Van de Velde Date: Sat, 6 Aug 2016 21:22:19 +0200 Subject: [PATCH] Progress --- Moose Development/Moose/Cargo.lua | 41 ++++--------- Moose Development/Moose/Database.lua | 57 ++++++++++-------- Moose Development/Moose/Point.lua | 41 ++++++++++--- Moose Development/Moose/Positionable.lua | 1 + Moose Development/Moose/Spawn.lua | 12 ++-- Moose Development/Moose/Unit.lua | 15 ++++- .../MOOSE_Test_CARGO_UnBoard.miz | Bin 17602 -> 17597 bytes .../Moose_Test_CARGO_UnBoard.lua | 2 +- 8 files changed, 96 insertions(+), 73 deletions(-) diff --git a/Moose Development/Moose/Cargo.lua b/Moose Development/Moose/Cargo.lua index 439d15f73..edcfa94b1 100644 --- a/Moose Development/Moose/Cargo.lua +++ b/Moose Development/Moose/Cargo.lua @@ -110,10 +110,10 @@ end -- @param #CARGO self -- @param Unit#UNIT CargoCarrier -- @param #number Speed -function CARGO:UnBoard( Speed ) +function CARGO:UnBoard( Speed, Distance, Angle ) self:F() - self:_NextEvent( self.FsmP.UnBoard, Speed ) + self:_NextEvent( self.FsmP.UnBoard, Speed, Distance, Angle ) end --- Load Cargo to a Carrier. @@ -181,13 +181,12 @@ function CARGO:OnUnLoaded( FsmP, Event, From, To ) self:F() self:T( "Cargo " .. self.Name .. " unloaded from " .. self.CargoCarrier:GetName() ) - self.CargoCarrier = nil end --- @param #CARGO self function CARGO:_NextEvent( NextEvent, ... ) self:F( self.Name ) - self.CargoScheduler:Schedule( self.FsmP, NextEvent, arg, 1 ) -- This schedules the next event, but only if scheduling is activated. + SCHEDULER:New( self.FsmP, NextEvent, arg, 1 ) -- This schedules the next event, but only if scheduling is activated. end end @@ -224,10 +223,9 @@ function CARGO_REPRESENTABLE:New( Mission, CargoObject, Type, Name, Weight, Repo { name = 'Boarded', from = 'Boarding', to = 'Boarding' }, { name = 'Load', from = 'Boarding', to = 'Loaded' }, { name = 'Load', from = 'UnLoaded', to = 'Loaded' }, - { name = 'UnBoard', from = 'Loaded', to = 'UnLoading' }, - { name = 'UnLoad', from = 'UnLoading', to = 'UnBoarding' }, - { name = 'UnBoard', from = 'UnBoarding', to = 'UnBoarding' }, - { name = 'UnBoarded', from = 'UnBoarding', to = 'UnLoaded' }, + { name = 'UnBoard', from = 'Loaded', to = 'UnBoarding' }, + { name = 'UnBoarded', from = 'UnBoarding', to = 'UnBoarding' }, + { name = 'UnLoad', from = 'UnBoarding', to = 'UnLoaded' }, { name = 'UnLoad', from = 'Loaded', to = 'UnLoaded' }, }, callbacks = { @@ -316,45 +314,30 @@ function CARGO_REPRESENTABLE:OnUnBoard( FsmP, Event, From, To, Speed, Distance, -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). if not self.CargoInAir then - if self.FsmP:is( "Loaded" ) then - self:_NextEvent( FsmP.UnLoad, Distance, Angle ) + if self.FsmP:is( "UnLoading" ) then + self:_NextEvent( FsmP.UnLoad, 3, Angle ) + self:_NextEvent( FsmP.UnBoard, Speed, Distance, Angle ) else local Points = {} local StartPointVec2 = self.CargoCarrier:GetPointVec2() local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + self:T( { CargoCarrierHeading, CargoDeployHeading } ) local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) + local CargoDeployPointVec2 = CargoDeployPointVec2:GetRandomPointVec2InRadius( self.NearRadius ) Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 4 ) - - self:_NextEvent( FsmP.UnBoarded ) + self.CargoObject:SetTask( TaskRoute, 1 ) end end end ---- UnBoarded Event. --- @param #CARGO self --- @param StateMachine#STATEMACHINE_PROCESS FsmP --- @param #string Event --- @param #string From --- @param #string To --- @param Unit#UNIT CargoCarrier -function CARGO_REPRESENTABLE:OnUnBoarded( FsmP, Event, From, To ) - self:F() - - if self.CargoObject:GetVelocityKMH() <= 0.1 then - else - self:_NextEvent( FsmP.UnBoarded ) - end -end - --- Load Event. -- @param #CARGO self -- @param StateMachine#STATEMACHINE_PROCESS FsmP diff --git a/Moose Development/Moose/Database.lua b/Moose Development/Moose/Database.lua index 14de9a4c7..04e8d52b1 100644 --- a/Moose Development/Moose/Database.lua +++ b/Moose Development/Moose/Database.lua @@ -264,19 +264,19 @@ end -- @param #table SpawnTemplate -- @return #DATABASE self function DATABASE:Spawn( SpawnTemplate ) - self:F2( SpawnTemplate.name ) + self:F( SpawnTemplate.name ) - self:T2( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID } ) + self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID } ) -- Copy the spawn variables of the template in temporary storage, nullify, and restore the spawn variables. - local SpawnCoalitionID = SpawnTemplate.SpawnCoalitionID - local SpawnCountryID = SpawnTemplate.SpawnCountryID - local SpawnCategoryID = SpawnTemplate.SpawnCategoryID + local SpawnCoalitionID = SpawnTemplate.CoalitionID + local SpawnCountryID = SpawnTemplate.CountryID + local SpawnCategoryID = SpawnTemplate.CategoryID -- Nullify - SpawnTemplate.SpawnCoalitionID = nil - SpawnTemplate.SpawnCountryID = nil - SpawnTemplate.SpawnCategoryID = nil + SpawnTemplate.CoalitionID = nil + SpawnTemplate.CountryID = nil + SpawnTemplate.CategoryID = nil self:_RegisterTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID ) @@ -284,9 +284,9 @@ function DATABASE:Spawn( SpawnTemplate ) coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate ) -- Restore - SpawnTemplate.SpawnCoalitionID = SpawnCoalitionID - SpawnTemplate.SpawnCountryID = SpawnCountryID - SpawnTemplate.SpawnCategoryID = SpawnCategoryID + SpawnTemplate.CoalitionID = SpawnCoalitionID + SpawnTemplate.CountryID = SpawnCountryID + SpawnTemplate.CategoryID = SpawnCategoryID local SpawnGroup = self:AddGroup( SpawnTemplate.name ) return SpawnGroup @@ -330,6 +330,10 @@ function DATABASE:_RegisterTemplate( GroupTemplate, CoalitionID, CategoryID, Cou GroupTemplate.route.spans = nil end + GroupTemplate.CategoryID = CategoryID + GroupTemplate.CoalitionID = CoalitionID + GroupTemplate.CountryID = CountryID + self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName self.Templates.Groups[GroupTemplateName].Template = GroupTemplate self.Templates.Groups[GroupTemplateName].groupId = GroupTemplate.groupId @@ -354,26 +358,27 @@ function DATABASE:_RegisterTemplate( GroupTemplate, CoalitionID, CategoryID, Cou for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do - local UnitTemplateName = env.getValueDictByKey(UnitTemplate.name) - self.Templates.Units[UnitTemplateName] = {} - self.Templates.Units[UnitTemplateName].UnitName = UnitTemplateName - self.Templates.Units[UnitTemplateName].Template = UnitTemplate - self.Templates.Units[UnitTemplateName].GroupName = GroupTemplateName - self.Templates.Units[UnitTemplateName].GroupTemplate = GroupTemplate - self.Templates.Units[UnitTemplateName].GroupId = GroupTemplate.groupId - self.Templates.Units[UnitTemplateName].CategoryID = CategoryID - self.Templates.Units[UnitTemplateName].CoalitionID = CoalitionID - self.Templates.Units[UnitTemplateName].CountryID = CountryID + UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name) + + self.Templates.Units[UnitTemplate.name] = {} + self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name + self.Templates.Units[UnitTemplate.name].Template = UnitTemplate + self.Templates.Units[UnitTemplate.name].GroupName = GroupTemplateName + self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate + self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId + self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID + self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID + self.Templates.Units[UnitTemplate.name].CountryID = CountryID if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then - self.Templates.ClientsByName[UnitTemplateName] = UnitTemplate - self.Templates.ClientsByName[UnitTemplateName].CategoryID = CategoryID - self.Templates.ClientsByName[UnitTemplateName].CoalitionID = CoalitionID - self.Templates.ClientsByName[UnitTemplateName].CountryID = CountryID + self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate + self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID + self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID + self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate end - TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplateName].UnitName + TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName end self:E( TraceTable ) diff --git a/Moose Development/Moose/Point.lua b/Moose Development/Moose/Point.lua index 05e647667..d2223ad14 100644 --- a/Moose Development/Moose/Point.lua +++ b/Moose Development/Moose/Point.lua @@ -185,7 +185,7 @@ function POINT_VEC3:SetZ( z ) self.z = z end ---- Return a random Vec3 point within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +--- Return a random Vec2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. -- @param #POINT_VEC3 self -- @param DCSTypes#Distance OuterRadius -- @param DCSTypes#Distance InnerRadius @@ -206,17 +206,28 @@ function POINT_VEC3:GetRandomVec2InRadius( OuterRadius, InnerRadius ) RadialMultiplier = OuterRadius * Radials end - local RandomVec3 + local RandomVec2 if OuterRadius > 0 then - RandomVec3 = { x = math.cos( Theta ) * RadialMultiplier + self:GetX(), y = math.sin( Theta ) * RadialMultiplier + self:GetZ() } + RandomVec2 = { x = math.cos( Theta ) * RadialMultiplier + self:GetX(), y = math.sin( Theta ) * RadialMultiplier + self:GetZ() } else - RandomVec3 = { x = self:GetX(), y = self:GetZ() } + RandomVec2 = { x = self:GetX(), y = self:GetZ() } end - return RandomVec3 + return RandomVec2 end ---- Return a random Vec3 point within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +--- Return a random POINT_VEC2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param DCSTypes#Distance OuterRadius +-- @param DCSTypes#Distance InnerRadius +-- @return #POINT_VEC2 +function POINT_VEC3:GetRandomPointVec2InRadius( OuterRadius, InnerRadius ) + self:F2( { OuterRadius, InnerRadius } ) + + return POINT_VEC2:NewFromVec2( self:GetRandomPointVec2InRadius( OuterRadius, InnerRadius ) ) +end + +--- Return a random Vec3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. -- @param #POINT_VEC3 self -- @param DCSTypes#Distance OuterRadius -- @param DCSTypes#Distance InnerRadius @@ -230,6 +241,16 @@ function POINT_VEC3:GetRandomVec3InRadius( OuterRadius, InnerRadius ) return RandomVec3 end +--- Return a random POINT_VEC3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param DCSTypes#Distance OuterRadius +-- @param DCSTypes#Distance InnerRadius +-- @return #POINT_VEC3 +function POINT_VEC3:GetRandomPointVec3InRadius( OuterRadius, InnerRadius ) + + return POINT_VEC3:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) ) +end + --- Return a direction vector Vec3 from POINT_VEC3 to the POINT_VEC3. -- @param #POINT_VEC3 self @@ -295,8 +316,10 @@ function POINT_VEC3:Translate( Distance, Angle ) local TX = Distance * math.cos( Radians ) + SX local TY = Distance * math.sin( Radians ) + SY - local SourceVec3 = self:GetVec3() - return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 + self:SetX( TX ) + self:SetY( TY ) + + return self end --- Provides a Bearing / Range string @@ -626,7 +649,7 @@ end --- Set the x coordinate of the POINT_VEC2. -- @param #number x The x coordinate. function POINT_VEC2:SetX( x ) - elf.x = x + self.x = x end --- Set the y coordinate of the POINT_VEC2. diff --git a/Moose Development/Moose/Positionable.lua b/Moose Development/Moose/Positionable.lua index 97d0776c8..87c0629ac 100644 --- a/Moose Development/Moose/Positionable.lua +++ b/Moose Development/Moose/Positionable.lua @@ -209,6 +209,7 @@ function POSITIONABLE:GetHeading() if PositionableHeading < 0 then PositionableHeading = PositionableHeading + 2 * math.pi end + PositionableHeading = PositionableHeading * 180 / math.pi self:T2( PositionableHeading ) return PositionableHeading end diff --git a/Moose Development/Moose/Spawn.lua b/Moose Development/Moose/Spawn.lua index 8b64db423..721a658e1 100644 --- a/Moose Development/Moose/Spawn.lua +++ b/Moose Development/Moose/Spawn.lua @@ -1003,9 +1003,9 @@ function SPAWN:_GetTemplate( SpawnTemplatePrefix ) error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix ) end - SpawnTemplate.SpawnCoalitionID = self:_GetGroupCoalitionID( SpawnTemplatePrefix ) - SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnTemplatePrefix ) - SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnTemplatePrefix ) + --SpawnTemplate.SpawnCoalitionID = self:_GetGroupCoalitionID( SpawnTemplatePrefix ) + --SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnTemplatePrefix ) + --SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnTemplatePrefix ) self:T3( { SpawnTemplate } ) return SpawnTemplate @@ -1026,12 +1026,12 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --SpawnTemplate.lateActivation = false SpawnTemplate.lateActivation = false - if SpawnTemplate.SpawnCategoryID == Group.Category.GROUND then + if SpawnTemplate.CategoryID == Group.Category.GROUND then self:T3( "For ground units, visible needs to be false..." ) SpawnTemplate.visible = false end - if SpawnTemplate.SpawnCategoryID == Group.Category.HELICOPTER or SpawnTemplate.SpawnCategoryID == Group.Category.AIRPLANE then + if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then SpawnTemplate.uncontrolled = false end @@ -1064,7 +1064,7 @@ function SPAWN:_RandomizeRoute( SpawnIndex ) SpawnTemplate.route.points[t].y = SpawnTemplate.route.points[t].y + math.random( self.SpawnRandomizeRouteRadius * -1, self.SpawnRandomizeRouteRadius ) -- Manage randomization of altitude for airborne units ... - if SpawnTemplate.SpawnCategoryID == Group.Category.AIRPLANE or SpawnTemplate.SpawnCategoryID == Group.Category.HELICOPTER then + if SpawnTemplate.CategoryID == Group.Category.AIRPLANE or SpawnTemplate.CategoryID == Group.Category.HELICOPTER then if SpawnTemplate.route.points[t].alt and self.SpawnRandomizeRouteHeight then SpawnTemplate.route.points[t].alt = SpawnTemplate.route.points[t].alt + math.random( 1, self.SpawnRandomizeRouteHeight ) end diff --git a/Moose Development/Moose/Unit.lua b/Moose Development/Moose/Unit.lua index 5c91f9b0e..a4aaf6d29 100644 --- a/Moose Development/Moose/Unit.lua +++ b/Moose Development/Moose/Unit.lua @@ -152,6 +152,14 @@ function UNIT:FindByName( UnitName ) return UnitFound end +--- Return the name of the UNIT. +-- @param #UNIT self +-- @return #string The UNIT name. +function UNIT:Name() + + return self.UnitName +end + --- @param #UNIT self -- @return DCSUnit#Unit @@ -179,7 +187,8 @@ end -- @param #number Heading The heading of the unit respawn. function UNIT:ReSpawn( SpawnVec3, Heading ) - local SpawnGroupTemplate = _DATABASE:GetGroupTemplateFromUnitName( self:GetName() ) + local SpawnGroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplateFromUnitName( self:Name() ) ) + self:T( SpawnGroupTemplate ) local SpawnGroup = self:GetGroup() if SpawnGroup then @@ -205,7 +214,9 @@ function UNIT:ReSpawn( SpawnVec3, Heading ) end for UnitTemplateID, UnitTemplateData in pairs( SpawnGroupTemplate.units ) do - if UnitTemplateData.name == self:GetName() then + self:T( UnitTemplateData.name ) + if UnitTemplateData.name == self:Name() then + self:T("Adjusting") SpawnGroupTemplate.units[UnitTemplateID].alt = SpawnVec3.y SpawnGroupTemplate.units[UnitTemplateID].x = SpawnVec3.x SpawnGroupTemplate.units[UnitTemplateID].y = SpawnVec3.z diff --git a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UnBoard/MOOSE_Test_CARGO_UnBoard.miz b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UnBoard/MOOSE_Test_CARGO_UnBoard.miz index 3fb0237910958ef6c8f453d6f69d90e66f0c4aa9..cde3f57847f1e4367260eac0af5aa1740c950b34 100644 GIT binary patch delta 3336 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 SL^J^%lb=K#2E#!B0001RFm}QK delta 3409 zcmV-X4X*ONi2=fi0kD}W4(Gn|VrT&X0QUj_04V^IPeUtzb&*?Z!axv(--Y~#Ax{cx z8Vdyxe5ls8ff|dK=dyJt$zrlAyGh0V`c5ulLg>rpa^{@#W#SA{edH;urL|Hkn8P~Q z?Sf4>3-K}p_fsBE#Tk~|#M))xzRNf%uY0sPMB3B})MF$ZHBV(uNuHGgz3u7+M$W)# zTB_ldilst-G}LtngZ=DPDzUhRJVWZciEe4DO@WHI%FVTIn#1yW`?mS2tQBK}&bsNW zmDRe3-4Ckr#dJdFqwo84KJ^&sF!CS7MssV^cnteQTDZtGg%8aI$I`;U zV9bq3(UKuSgY9AKIfKr(&dRu97pUKPP~Vy|TS<{_(OJ9JYaBPdvYA5l27z!noHcP1 zd!>ZP&6W#USl~t%O7w&K02i4j6lBkc0(1luA5Pgr!hkfYpshoOIT{O-sSg5UgJ^p+ z3?xBt_|*!_6#7k#Yj~#`^_F%}ixQ{1H%1KA?`Boy=nqg!0|b+RLmIPIEP?@OEoV@rTwinBxDkKPr{L%*nXwds)Zgj!LAK+><2Z3`CGK7B zMgx(Mg^D6{An8Qz+;=YskP-=kBuG0tx3!*ZV6pgNcd=M30Isp`W8xWqH(vewlRz#q zFO7T>QX3s_FVOb&Z!Pve`(rlYoM*uLt@Y;3-&#jmo~F!m$L}YA-~8f03V5D}<7g5=G97kfd5J6V>!hW^6ox*YHOac$^Cf zg8orlen&~@IVa2)P~xiRH}!}@(1L8{eDZwFgAJO}NLkel%qinr| zeuvbV9UfA?=fVjgEKoHiBwLSXK(J2fnW9Fh!Z*7<2lM2(rkMdME-=0X8j3TWuXrnUcY&amm7Z z=;>PbP1rX3Q%&NJZELL7;@NE*jJu~}owR=mqtFaRf$?lD(?ph%J~b6Ctn%f!seM5-5ROz9PQ zaPFeng50Th8$NU*vE71;y`4G z%)U&2;2_UWYKO%sERs!xicotR(m8W3o~@X(Qpbh(9UQsXm_szDiuIRfnO28OLZ@O= znw65-&B-Y(hFs+w`U0PoZ-_S(*_*)2$zQgD7^TWx?hG*T(Mwhk+w*=cOt$nMD%{XW zd^41B>owfStzt2v$PRxI8AGc(9*#RbbJQPyf}WYy>jQ}o06olPLAhbN7JT*_0vBdM^*8OWu5UOJFU2b`@Xl@6m) zd4i2Nsmx%U%FFJD&`sxV_QgQ8mqKy$!5Z(V95d&LXa^CH4jy4 zwsJz}dbV=v=cBW7%HYH6$>3r==hQFsoKpuMVK3JuAEKFKGAv&W_PRUERKEWpf!H@;(T;=d$RH^Th%xA1^C)sq;>0gSWC==8=RXn&r8 zGMkJX$1KP>!p!ZOLaS@quGq?d|L+Yvq=0j0+iJR)TkQM3G|>-EhkF>snuF)o(yV$P8)>mK~G%_r!8rv!I){w3$K@Ak3hD|{At1+EXp6#uIG*mzuHIkEt z4&Ng}?=%c+qyRN;0!j;i6J0}ZTZw6`z$CI1wI!vYy>p*J$OS8(ogGT;+tbuF;vAlOsU{bkt(9ExEC~>+(#wQdV8AZx}^sC{i96V^`;WbvB zX-HQ{!|+uu9yIdtia1#Y_2r@(kjlM-M*h9fJ=}}iwT<>;{Lpn%+_bzoXQB4M`V0gP zehwQCLOQcAZWL|)Zjg)YAU-F^zsONHWP=V$1Xd5cVCiq5YGeO6ww!gffSWOHz`TA3 zypv@AX#rq@xj_@pHbm7X~W!h>pdII-<@-(g`vr&#u2W~e(bdoq5 zHqp(@CHAV;;+AExzk}EB^i#ir&0;Ylkt7u(`@C2f*958}{&FVeY2%__6aN{#yoHLWR_# zJehp0YVSL0drkRaiJ0UX?x3OOnrlp@spx^khO4UR%14%iADtV|0=zDK*P3s$ ziqMSa%)IQoVn(7GpWAkBwZQJ zJxPsk>c1)=sQ=x@CJ!L2AyB3r61xJRFK@D+$Mc6s8V7&