From 74e3b15fe316cf98112661071c150205516e5106 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 15 Apr 2016 14:31:09 +0200 Subject: [PATCH] Updated the escort function and added APIs --- Documentation/Escort.html | 1323 ++++++++++++++++- Moose/Escort.lua | 1065 ++++++++----- .../Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua | 34 +- .../Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz | Bin 130793 -> 144754 bytes ...t 2 - Using Eclipse and MOOSE - Copy.pptx} | Bin ...d - MOOSE - Escorting - Part 2 - APIs.pptx | Bin 0 -> 776546 bytes 6 files changed, 2028 insertions(+), 394 deletions(-) rename Tools and Installation/{DCS World - MOOSE - Development - Part 2 - Using Eclipse and MOOSE.pptx => DCS World - MOOSE - Development - Part 2 - Using Eclipse and MOOSE - Copy.pptx} (100%) create mode 100644 Tools and Installation/DCS World - MOOSE - Escorting - Part 2 - APIs.pptx diff --git a/Documentation/Escort.html b/Documentation/Escort.html index 5a5ed26f5..3afd42ee6 100644 --- a/Documentation/Escort.html +++ b/Documentation/Escort.html @@ -76,17 +76,19 @@ Ships and Ground troops will have a more limited set, but they can provide suppo

1. Navigation ...: Escort group navigation functions:

-

2. Report targets ...: Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below).

+

2. Hold position ...: Escort group navigation functions:

+ + + +

3. Report targets ...: Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below).

-

3. Scan targets ...: Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task.

+

4. Scan targets ...: Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task.

-

4. Attack targets ...: This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed.

+

5. Attack targets ...: This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed.

-

5. Request assistance from ...: This menu item will list all detected targets within a 15km range, as with the menu item Attack Targets. +

6. Request assistance from ...: This menu item will list all detected targets within a 15km range, as with the menu item Attack Targets. This menu item allows to request attack support from other escorts supporting the current client group. eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area.

-

6. ROE ...: Defines the Rules of Engagement of the escort group when in flight.

+

7. ROE ...: Defines the Rules of Engagement of the escort group when in flight.

-

7. Evasion ...: Will define the evasion techniques that the escort group will perform during flight or combat.

+

8. Evasion ...: Will define the evasion techniques that the escort group will perform during flight or combat.

-

8. Resume Mission ...: Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. +

9. Resume Mission ...: Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.

-

9. Abort Current Task: Cancel the current task and rejoin formation.

+

10. Abort Current Task: Cancel the current task and rejoin formation.

  1. ESCORT object construction methods.

    Create a new SPAWN object with the ESCORT.New method:

  2. ESCORT.New: Creates a new ESCORT object from a Group#GROUP for a Client#CLIENT, with an optional briefing text.

  3. ESCORT object initialization methods.

    -

    None.

  4. +

    The following menus can be setup:

    +
  5. ESCORT.MenuFollowAt: Creates a menu to make the escort follow the client.

  6. +
  7. ESCORT.MenuHoldAtEscortPosition: Creates a menu to hold the escort at its current position.

  8. +
  9. ESCORT.MenuHoldAtLeaderPosition: Creates a menu to hold the escort at the client position.

  10. +
  11. ESCORT.MenuScanForTargets: Creates a menu so that the escort scans targets.

  12. +
  13. ESCORT.MenuFlare: Creates a menu to disperse flares.

  14. +
  15. ESCORT.MenuSmoke: Creates a menu to disparse smoke.

  16. +
  17. ESCORT.MenuReportTargets: Creates a menu so that the escort reports targets.

  18. +
  19. ESCORT.MenuReportPosition: Creates a menu so that the escort reports its current position from bullseye.

  20. +
  21. ESCORT.MenuAssistedAttack: Creates a menu structure so that the escort can resume from a waypoint.

-

Global(s)

+ + + +
ESCORT +
_Resume(EscortGroup) +
@@ -168,12 +184,222 @@ Note that this is really fantastic, as you now have the dynamic of taking contro ESCORT.EscortGroup + + + + ESCORT.EscortMenuAttackNearbyTargets + + + + + + ESCORT.EscortMenuEvasion + + + + + + ESCORT.EscortMenuEvasionEvadeFire + + + + + + ESCORT.EscortMenuEvasionNoReaction + + + + + + ESCORT.EscortMenuEvasionPassiveDefense + + + + + + ESCORT.EscortMenuFlare + + + + + + ESCORT.EscortMenuFlareGreen + + + + + + ESCORT.EscortMenuFlareRed + + + + + + ESCORT.EscortMenuFlareWhite + + + + + + ESCORT.EscortMenuFlareYellow + + + + + + ESCORT.EscortMenuHold + + + + + + ESCORT.EscortMenuHoldAtLeaderPosition + + + + + + ESCORT.EscortMenuHoldPosition + + + + + + ESCORT.EscortMenuJoinUpAndFollow + + + + + + ESCORT.EscortMenuOptionEvasionVertical + + + + + + ESCORT.EscortMenuROE + + + + + + ESCORT.EscortMenuROEHoldFire + + + + + + ESCORT.EscortMenuROEOpenFire + + + + + + ESCORT.EscortMenuROEReturnFire + + + + + + ESCORT.EscortMenuROEWeaponFree + + + + + + ESCORT.EscortMenuReportNavigation + + + + + + ESCORT.EscortMenuReportNearbyTargets + + + + + + ESCORT.EscortMenuReportNearbyTargetsNow + + + + + + ESCORT.EscortMenuReportNearbyTargetsOff + + + + + + ESCORT.EscortMenuReportNearbyTargetsOn + + ESCORT.EscortMenuResumeMission + + + + ESCORT.EscortMenuScan + + + + + + ESCORT.EscortMenuScanForTargets + + + + + + ESCORT.EscortMenuSmoke + + + + + + ESCORT.EscortMenuSmokeBlue + + + + + + ESCORT.EscortMenuSmokeGreen + + + + + + ESCORT.EscortMenuSmokeOrange + + + + + + ESCORT.EscortMenuSmokeRed + + + + + + ESCORT.EscortMenuSmokeWhite + + + + + + ESCORT.EscortMenuTargetAssistance + + + + + + ESCORT.EscortMode + +

The mode the escort is in.

@@ -192,6 +418,84 @@ Note that this is really fantastic, as you now have the dynamic of taking contro ESCORT:JoinUpAndFollow(EscortGroup, EscortClient, Distance)

JoinsUp and Follows a CLIENT.

+ + + + ESCORT.MODE + + + + + + ESCORT:MenuAssistedAttack() + +

Defines a menu slot to let the escort attack its detected targets using assisted attack from another escort joined also with the client.

+ + + + ESCORT:MenuEvasion(MenuTextFormat) + +

Defines a menu to let the escort set its evasion when under threat.

+ + + + ESCORT:MenuFlare(MenuTextFormat) + +

Defines a menu slot to let the escort disperse a flare in a certain color.

+ + + + ESCORT:MenuFollowAt(Distance) + +

Defines a menu slot to let the escort Join and Follow you at a certain distance.

+ + + + ESCORT:MenuHoldAtEscortPosition(Height, Seconds, MenuTextFormat) + +

Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds.

+ + + + ESCORT:MenuHoldAtLeaderPosition(Height, Seconds, MenuTextFormat) + +

Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds.

+ + + + ESCORT:MenuROE(MenuTextFormat) + +

Defines a menu to let the escort set its rules of engagement.

+ + + + ESCORT:MenuReportTargets(Seconds) + +

Defines a menu slot to let the escort report their current detected targets with a specified time interval in seconds.

+ + + + ESCORT:MenuResumeMission() + +

Defines a menu to let the escort resume its mission from a waypoint on its route.

+ + + + ESCORT:MenuScanForTargets(Height, Seconds, MenuTextFormat) + +

Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds.

+ + + + ESCORT:MenuSmoke(MenuTextFormat) + +

Defines a menu slot to let the escort disperse a smoke in a certain color.

+ + + + ESCORT:Menus() + +

Defines the default menus

@@ -270,12 +574,6 @@ Note that this is really fantastic, as you now have the dynamic of taking contro ESCORT._HoldPosition(MenuParam) - - - - ESCORT._HoldPositionNearBy(MenuParam) - - @@ -330,6 +628,22 @@ Note that this is really fantastic, as you now have the dynamic of taking contro ESCORT._SwitchReportNearbyTargets(MenuParam) + + + + +

Type ESCORT.MODE

+ + + + + + + +
ESCORT.MODE.FOLLOW + +
ESCORT.MODE.MISSION +
@@ -375,6 +689,27 @@ Note that this is really fantastic, as you now have the dynamic of taking contro + + +
+
+ + +_Resume(EscortGroup) + +
+
+ + + +

Parameter

+
    +
  • + +

    EscortGroup :

    + +
  • +

Type Escort

@@ -426,6 +761,368 @@ Note that this is really fantastic, as you now have the dynamic of taking contro + + +
+
+ + + +ESCORT.EscortMenuAttackNearbyTargets + +
+
+ + + + +

Attack Targets

+ +
+
+
+
+ + + +ESCORT.EscortMenuEvasion + +
+
+ + + + +

Reaction to Threats

+ +
+
+
+
+ + + +ESCORT.EscortMenuEvasionEvadeFire + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuEvasionNoReaction + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuEvasionPassiveDefense + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuFlare + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuFlareGreen + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuFlareRed + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuFlareWhite + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuFlareYellow + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuHold + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuHoldAtLeaderPosition + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuHoldPosition + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuJoinUpAndFollow + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuOptionEvasionVertical + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuROE + +
+
+ + + + +

Rules of Engagement

+ +
+
+
+
+ + + +ESCORT.EscortMenuROEHoldFire + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuROEOpenFire + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuROEReturnFire + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuROEWeaponFree + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuReportNavigation + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuReportNearbyTargets + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuReportNearbyTargetsNow + +
+
+ + + + +

Report Targets

+ +
+
+
+
+ + + +ESCORT.EscortMenuReportNearbyTargetsOff + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuReportNearbyTargetsOn + +
+
+ + +
@@ -440,6 +1137,150 @@ Note that this is really fantastic, as you now have the dynamic of taking contro + +
+
+
+ + + +ESCORT.EscortMenuScan + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuScanForTargets + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuSmoke + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuSmokeBlue + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuSmokeGreen + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuSmokeOrange + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuSmokeRed + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuSmokeWhite + +
+
+ + + +
+
+
+
+ + + +ESCORT.EscortMenuTargetAssistance + +
+
+ + + + +

Request assistance from other escorts. + This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane...

+ +
+
+
+
+ + #ESCORT.MODE + +ESCORT.EscortMode + +
+
+ +

The mode the escort is in.

+
@@ -499,6 +1340,389 @@ Note that this is really fantastic, as you now have the dynamic of taking contro + +
+
+
+ + + +ESCORT.MODE + +
+
+ + + +
+
+
+
+ + +ESCORT:MenuAssistedAttack() + +
+
+ +

Defines a menu slot to let the escort attack its detected targets using assisted attack from another escort joined also with the client.

+ + +

This menu will appear under Request assistance from. +Note that this method needs to be preceded with the method MenuReportTargets.

+ +

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuEvasion(MenuTextFormat) + +
+
+ +

Defines a menu to let the escort set its evasion when under threat.

+ + +

All rules of engagement will appear under the menu Evasion.

+ +

Parameter

+
    +
  • + +

    MenuTextFormat :

    + +
  • +
+

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuFlare(MenuTextFormat) + +
+
+ +

Defines a menu slot to let the escort disperse a flare in a certain color.

+ + +

This menu will appear under Navigation. +The flare will be fired from the first unit in the group.

+ +

Parameter

+
    +
  • + +

    #string MenuTextFormat : +Optional parameter that shows the menu option text. If no text is given, the default text will be displayed.

    + +
  • +
+

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuFollowAt(Distance) + +
+
+ +

Defines a menu slot to let the escort Join and Follow you at a certain distance.

+ + +

This menu will appear under Navigation.

+ +

Parameter

+
    +
  • + +

    DCSTypes#Distance Distance : +The distance in meters that the escort needs to follow the client.

    + +
  • +
+

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuHoldAtEscortPosition(Height, Seconds, MenuTextFormat) + +
+
+ +

Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds.

+ + +

This menu will appear under Hold position.

+ +

Parameters

+
    +
  • + +

    DCSTypes#Distance Height : +Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.

    + +
  • +
  • + +

    DCSTypes#Time Seconds : +Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.

    + +
  • +
  • + +

    #string MenuTextFormat : +Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.

    + +
  • +
+

Return value

+ +

#ESCORT: +TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.

+ +
+
+
+
+ + +ESCORT:MenuHoldAtLeaderPosition(Height, Seconds, MenuTextFormat) + +
+
+ +

Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds.

+ + +

This menu will appear under Navigation.

+ +

Parameters

+
    +
  • + +

    DCSTypes#Distance Height : +Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.

    + +
  • +
  • + +

    DCSTypes#Time Seconds : +Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.

    + +
  • +
  • + +

    #string MenuTextFormat : +Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.

    + +
  • +
+

Return value

+ +

#ESCORT: +TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.

+ +
+
+
+
+ + +ESCORT:MenuROE(MenuTextFormat) + +
+
+ +

Defines a menu to let the escort set its rules of engagement.

+ + +

All rules of engagement will appear under the menu ROE.

+ +

Parameter

+
    +
  • + +

    MenuTextFormat :

    + +
  • +
+

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuReportTargets(Seconds) + +
+
+ +

Defines a menu slot to let the escort report their current detected targets with a specified time interval in seconds.

+ + +

This menu will appear under Report targets. +Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed.

+ +

Parameter

+
    +
  • + +

    DCSTypes#Time Seconds : +Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds.

    + +
  • +
+

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuResumeMission() + +
+
+ +

Defines a menu to let the escort resume its mission from a waypoint on its route.

+ + +

All rules of engagement will appear under the menu Resume mission from.

+ +

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuScanForTargets(Height, Seconds, MenuTextFormat) + +
+
+ +

Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds.

+ + +

This menu will appear under Scan targets.

+ +

Parameters

+
    +
  • + +

    DCSTypes#Distance Height : +Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.

    + +
  • +
  • + +

    DCSTypes#Time Seconds : +Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.

    + +
  • +
  • + +

    #string MenuTextFormat : +Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.

    + +
  • +
+

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:MenuSmoke(MenuTextFormat) + +
+
+ +

Defines a menu slot to let the escort disperse a smoke in a certain color.

+ + +

This menu will appear under Navigation. +Note that smoke menu options will only be displayed for ships and ground units. Not for air units. +The smoke will be fired from the first unit in the group.

+ +

Parameter

+
    +
  • + +

    #string MenuTextFormat : +Optional parameter that shows the menu option text. If no text is given, the default text will be displayed.

    + +
  • +
+

Return value

+ +

#ESCORT:

+ + +
+
+
+
+ + +ESCORT:Menus() + +
+
+ +

Defines the default menus

+ +

Return value

+ +

#ESCORT:

+ +
@@ -741,27 +1965,6 @@ self

-

Parameter

- - -
-
-
- - -ESCORT._HoldPositionNearBy(MenuParam) - -
-
- - -

Parameter

  • @@ -951,6 +2154,40 @@ self

+
+
+ +

Type ESCORT.MODE

+ +

ESCORT.Mode class

+ +

Field(s)

+
+
+ + #number + +ESCORT.MODE.FOLLOW + +
+
+ + + +
+
+
+
+ + #number + +ESCORT.MODE.MISSION + +
+
+ + +
diff --git a/Moose/Escort.lua b/Moose/Escort.lua index dd195b277..2e654db49 100644 --- a/Moose/Escort.lua +++ b/Moose/Escort.lua @@ -1,71 +1,83 @@ --- Taking the lead of AI escorting your flight. -- The ESCORT class allows you to interact with escorting AI on your flight and take the lead. -- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10). --- +-- -- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes. -- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts. --- +-- -- Find a summary below of the current available commands: --- +-- -- **1. Navigation ...:** Escort group navigation functions: --- --- * **"Hold Position and Stay Low":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. --- * **"Join-Up and Hold Position NearBy":** The escort group will stop nearby you, and then the group will hover. --- * **"Join-Up and Follow at 100":** The escort group fill follow you at about 100 meters, and they will follow you. --- * **"Join-Up and Follow at 200":** The escort group fill follow you at about 200 meters, and they will follow you. --- * **"Join-Up and Follow at 400":** The escort group fill follow you at about 400 meters, and they will follow you. --- * **"Join-Up and Follow at 800":** The escort group fill follow you at about 800 meters, and they will follow you. +-- +-- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you. -- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color. -- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops. --- --- **2. Report targets ...:** Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below). --- +-- +-- **2. Hold position ...:** Escort group navigation functions: +-- +-- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. +-- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. +-- +-- **3. Report targets ...:** Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below). +-- -- * **"Report now":** Will report the current detected targets. -- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list. -- * **"Report targets off":** Will stop detecting targets. --- --- **3. Scan targets ...:** Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task. --- +-- +-- **4. Scan targets ...:** Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task. +-- -- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. -- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. --- --- **4. Attack targets ...:** This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. --- --- **5. Request assistance from ...:** This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**. +-- +-- **5. Attack targets ...:** This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. +-- +-- **6. Request assistance from ...:** This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**. -- This menu item allows to request attack support from other escorts supporting the current client group. -- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. -- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area. --- --- **6. ROE ...:** Defines the Rules of Engagement of the escort group when in flight. --- +-- +-- **7. ROE ...:** Defines the Rules of Engagement of the escort group when in flight. +-- -- * **"Hold Fire":** The escort group will hold fire. -- * **"Return Fire":** The escort group will return fire. -- * **"Open Fire":** The escort group will open fire on designated targets. -- * **"Weapon Free":** The escort group will engage with any target. --- --- **7. Evasion ...:** Will define the evasion techniques that the escort group will perform during flight or combat. --- +-- +-- **8. Evasion ...:** Will define the evasion techniques that the escort group will perform during flight or combat. +-- -- * **"Fight until death":** The escort group will have no reaction to threats. -- * **"Use flares, chaff and jammers":** The escort group will use passive defense using flares and jammers. No evasive manoeuvres are executed. -- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing. -- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres. --- --- **8. Resume Mission ...:** Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. +-- +-- **9. Resume Mission ...:** Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. -- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission. --- --- **9. Abort Current Task:** Cancel the current task and rejoin formation. --- +-- +-- **10. Abort Current Task:** Cancel the current task and rejoin formation. +-- -- 1. ESCORT object construction methods. -- -------------------------------------- -- Create a new SPAWN object with the @{#ESCORT.New} method: --- +-- -- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Group#GROUP} for a @{Client#CLIENT}, with an optional briefing text. --- +-- -- 2. ESCORT object initialization methods. -- ---------------------------------------- --- None. --- --- +-- The following menus can be setup: +-- +-- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client. +-- * @{#ESCORT.MenuHoldAtEscortPosition}: Creates a menu to hold the escort at its current position. +-- * @{#ESCORT.MenuHoldAtLeaderPosition}: Creates a menu to hold the escort at the client position. +-- * @{#ESCORT.MenuScanForTargets}: Creates a menu so that the escort scans targets. +-- * @{#ESCORT.MenuFlare}: Creates a menu to disperse flares. +-- * @{#ESCORT.MenuSmoke}: Creates a menu to disparse smoke. +-- * @{#ESCORT.MenuReportTargets}: Creates a menu so that the escort reports targets. +-- * @{#ESCORT.MenuReportPosition}: Creates a menu so that the escort reports its current position from bullseye. +-- * @{#ESCORT.MenuAssistedAttack: Creates a menu so that the escort supportes assisted attack from other escorts with the client. +-- * @{#ESCORT.MenuROE: Creates a menu structure to set the rules of engagement of the escort. +-- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat. +-- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint. +-- -- @module Escort -- @author FlightControl @@ -82,6 +94,7 @@ Include.File( "Zone" ) -- @field Client#CLIENT EscortClient -- @field Group#GROUP EscortGroup -- @field #string EscortName +-- @field #ESCORT.MODE EscortMode The mode the escort is in. -- @field #number FollowScheduler The id of the _FollowScheduler function. -- @field #boolean ReportTargets If true, nearby targets are reported. -- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. @@ -92,6 +105,11 @@ ESCORT = { EscortName = nil, -- The Escort Name EscortClient = nil, EscortGroup = nil, + EscortMode = nil, + MODE = { + FOLLOW = 1, + MISSION = 2, + }, Targets = {}, -- The identified targets FollowScheduler = nil, ReportTargets = true, @@ -100,6 +118,11 @@ ESCORT = { TaskPoints = {} } +--- ESCORT.Mode class +-- @type ESCORT.MODE +-- @field #number FOLLOW +-- @field #number MISSION + --- MENUPARAM type -- @type MENUPARAM -- @field #ESCORT ParamSelf @@ -115,127 +138,465 @@ ESCORT = { -- @return #ESCORT self function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing ) local self = BASE:Inherit( self, BASE:New() ) - self:F( { EscortClient, EscortGroup, EscortName } ) - + self:F( { EscortClient, EscortGroup, EscortName } ) + self.EscortClient = EscortClient -- Client#CLIENT self.EscortGroup = EscortGroup -- Group#GROUP self.EscortName = EscortName self.EscortBriefing = EscortBriefing - + self:T( EscortGroup:GetClassNameAndID() ) - + -- Set EscortGroup known at EscortClient. if not self.EscortClient._EscortGroups then - self.EscortClient._EscortGroups = {} + self.EscortClient._EscortGroups = {} end if not self.EscortClient._EscortGroups[EscortGroup:GetName()] then - self.EscortClient._EscortGroups[EscortGroup:GetName()] = {} - self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup - self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName - self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {} - + self.EscortClient._EscortGroups[EscortGroup:GetName()] = {} + self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup + self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName + self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {} + self.EscortMode = ESCORT.MODE.FOLLOW end - - + + self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName ) - - self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) - if EscortGroup:IsHelicopter() or EscortGroup:IsAirPlane() then - -- Escort Navigation - self.EscortMenuHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Position and Stay Low", self.EscortMenuReportNavigation, ESCORT._HoldPosition, { ParamSelf = self } ) - self.EscortMenuJoinUpAndHoldPosition = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Hold Position NearBy", self.EscortMenuReportNavigation, ESCORT._HoldPositionNearBy, { ParamSelf = self } ) - self.EscortMenuJoinUpAndFollow50Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 100", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 100 } ) - self.EscortMenuJoinUpAndFollow100Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 200", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 200 } ) - self.EscortMenuJoinUpAndFollow150Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 400", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 400 } ) - self.EscortMenuJoinUpAndFollow200Meters = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at 800", self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = 800 } ) - end - self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, "Flare", self.EscortMenuReportNavigation, ESCORT._Flare, { ParamSelf = self } ) - self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Green, ParamMessage = "Released a green flare!" } ) - self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Red, ParamMessage = "Released a red flare!" } ) - self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.White, ParamMessage = "Released a white flare!" } ) - self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Yellow, ParamMessage = "Released a yellow flare!" } ) - if EscortGroup:IsGround() or EscortGroup:IsShip() then - self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, { ParamSelf = self } ) - self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Green, ParamMessage = "Releasing green smoke!" } ) - self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Red, ParamMessage = "Releasing red smoke!" } ) - self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.White, ParamMessage = "Releasing white smoke!" } ) - self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Orange, ParamMessage = "Releasing orange smoke!" } ) - self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Blue, ParamMessage = "Releasing blue smoke!" } ) + self.EscortGroup:WayPointInitialize(1) + + self.EscortGroup:OptionROTVertical() + self.EscortGroup:OptionROEOpenFire() + + EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. + "We're escorting your flight. " .. + "Use the Radio Menu and F10 and use the options under + " .. EscortName .. "\n", + 60, EscortClient + ) + + return self +end + + +--- Defines the default menus +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:Menus() + self:F() + + self:MenuFollowAt( 100 ) + self:MenuFollowAt( 200 ) + self:MenuFollowAt( 300 ) + self:MenuFollowAt( 400 ) + + self:MenuScanForTargets( 100, 60 ) + + self:MenuHoldAtEscortPosition( 30 ) + self:MenuHoldAtLeaderPosition( 30 ) + + self:MenuFlare() + self:MenuSmoke() + + self:MenuReportTargets( 60 ) + self:MenuAssistedAttack() + self:MenuROE() + self:MenuEvasion() + self:MenuResumeMission() + + return self +end + + + +--- Defines a menu slot to let the escort Join and Follow you at a certain distance. +-- This menu will appear under **Navigation**. +-- @param #ESCORT self +-- @param DCSTypes#Distance Distance The distance in meters that the escort needs to follow the client. +-- @return #ESCORT +function ESCORT:MenuFollowAt( Distance ) + self:F(Distance) + + if self.EscortGroup:IsAir() then + if not self.EscortMenuReportNavigation then + self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) + end + + if not self.EscortMenuJoinUpAndFollow then + self.EscortMenuJoinUpAndFollow = {} + end + + self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = Distance } ) + + self.EscortMode = ESCORT.MODE.FOLLOW end - - if EscortGroup:IsHelicopter() or EscortGroup:IsAirPlane() or EscortGroup:IsGround() or EscortGroup:IsShip() then - -- Report Targets + + return self +end + +--- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds. +-- This menu will appear under **Hold position**. +-- @param #ESCORT self +-- @param DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. +-- @return #ESCORT +-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. +function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat ) + self:F( { Height, Seconds, MenuTextFormat } ) + + if self.EscortGroup:IsAir() then + + if not self.EscortMenuHold then + self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) + end + + if not Height then + Height = 30 + end + + if not Seconds then + Seconds = 0 + end + + local MenuText = "" + if not MenuTextFormat then + if Seconds == 0 then + MenuText = string.format( "Hold at %d meter", Height ) + else + MenuText = string.format( "Hold at %d meter for %d seconds", Height, Seconds ) + end + else + if Seconds == 0 then + MenuText = string.format( MenuTextFormat, Height ) + else + MenuText = string.format( MenuTextFormat, Height, Seconds ) + end + end + + if not self.EscortMenuHoldPosition then + self.EscortMenuHoldPosition = {} + end + + self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_CLIENT_COMMAND + :New( + self.EscortClient, + MenuText, + self.EscortMenuHold, + ESCORT._HoldPosition, + { ParamSelf = self, + ParamOrbitGroup = self.EscortGroup, + ParamHeight = Height, + ParamSeconds = Seconds + } + ) + end + + return self +end + + +--- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds. +-- This menu will appear under **Navigation**. +-- @param #ESCORT self +-- @param DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. +-- @return #ESCORT +-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. +function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat ) + self:F( { Height, Seconds, MenuTextFormat } ) + + if self.EscortGroup:IsAir() then + + if not self.EscortMenuHold then + self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) + end + + if not Height then + Height = 30 + end + + if not Seconds then + Seconds = 0 + end + + local MenuText = "" + if not MenuTextFormat then + if Seconds == 0 then + MenuText = string.format( "Rejoin and hold at %d meter", Height ) + else + MenuText = string.format( "Rejoin and hold at %d meter for %d seconds", Height, Seconds ) + end + else + if Seconds == 0 then + MenuText = string.format( MenuTextFormat, Height ) + else + MenuText = string.format( MenuTextFormat, Height, Seconds ) + end + end + + if not self.EscortMenuHoldAtLeaderPosition then + self.EscortMenuHoldAtLeaderPosition = {} + end + + self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_CLIENT_COMMAND + :New( + self.EscortClient, + MenuText, + self.EscortMenuHold, + ESCORT._HoldPosition, + { ParamSelf = self, + ParamOrbitGroup = self.EscortClient, + ParamHeight = Height, + ParamSeconds = Seconds + } + ) + end + + return self +end + +--- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds. +-- This menu will appear under **Scan targets**. +-- @param #ESCORT self +-- @param DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. +-- @return #ESCORT +function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) + self:F( { Height, Seconds, MenuTextFormat } ) + + if self.EscortGroup:IsAir() then + if not self.EscortMenuScan then + self.EscortMenuScan = MENU_CLIENT:New( self.EscortClient, "Scan for targets", self.EscortMenu ) + end + + if not Height then + Height = 100 + end + + if not Seconds then + Seconds = 30 + end + + local MenuText = "" + if not MenuTextFormat then + if Seconds == 0 then + MenuText = string.format( "At %d meter", Height ) + else + MenuText = string.format( "At %d meter for %d seconds", Height, Seconds ) + end + else + if Seconds == 0 then + MenuText = string.format( MenuTextFormat, Height ) + else + MenuText = string.format( MenuTextFormat, Height, Seconds ) + end + end + + if not self.EscortMenuScanForTargets then + self.EscortMenuScanForTargets = {} + end + + self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_CLIENT_COMMAND + :New( + self.EscortClient, + MenuText, + self.EscortMenuScan, + ESCORT._ScanTargets, + { ParamSelf = self, + ParamScanDuration = 30 + } + ) + end + + return self +end + + + +--- Defines a menu slot to let the escort disperse a flare in a certain color. +-- This menu will appear under **Navigation**. +-- The flare will be fired from the first unit in the group. +-- @param #ESCORT self +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. +-- @return #ESCORT +function ESCORT:MenuFlare( MenuTextFormat ) + self:F() + + if not self.EscortMenuReportNavigation then + self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) + end + + local MenuText = "" + if not MenuTextFormat then + MenuText = "Flare" + else + MenuText = MenuTextFormat + end + + if not self.EscortMenuFlare then + self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, { ParamSelf = self } ) + self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Green, ParamMessage = "Released a green flare!" } ) + self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Red, ParamMessage = "Released a red flare!" } ) + self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.White, ParamMessage = "Released a white flare!" } ) + self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Yellow, ParamMessage = "Released a yellow flare!" } ) + end + + return self +end + +--- Defines a menu slot to let the escort disperse a smoke in a certain color. +-- This menu will appear under **Navigation**. +-- Note that smoke menu options will only be displayed for ships and ground units. Not for air units. +-- The smoke will be fired from the first unit in the group. +-- @param #ESCORT self +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. +-- @return #ESCORT +function ESCORT:MenuSmoke( MenuTextFormat ) + self:F() + + if not self.EscortGroup:IsAir() then + if not self.EscortMenuReportNavigation then + self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) + end + + local MenuText = "" + if not MenuTextFormat then + MenuText = "Smoke" + else + MenuText = MenuTextFormat + end + + if not self.EscortMenuSmoke then + self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, { ParamSelf = self } ) + self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Green, ParamMessage = "Releasing green smoke!" } ) + self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Red, ParamMessage = "Releasing red smoke!" } ) + self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.White, ParamMessage = "Releasing white smoke!" } ) + self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Orange, ParamMessage = "Releasing orange smoke!" } ) + self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Blue, ParamMessage = "Releasing blue smoke!" } ) + end + end + + return self +end + +--- Defines a menu slot to let the escort report their current detected targets with a specified time interval in seconds. +-- This menu will appear under **Report targets**. +-- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed. +-- @param #ESCORT self +-- @param DCSTypes#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds. +-- @return #ESCORT +function ESCORT:MenuReportTargets( Seconds ) + self:F( { Seconds } ) + + if not self.EscortMenuReportNearbyTargets then self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) - self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, { ParamSelf = self } ) - self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) end - if EscortGroup:IsHelicopter() then - -- Scanning Targets - self.EscortMenuScanForTargets = MENU_CLIENT:New( self.EscortClient, "Scan targets", self.EscortMenu ) - self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Scan targets 30 seconds", self.EscortMenuScanForTargets, ESCORT._ScanTargets, { ParamSelf = self, ParamScanDuration = 30 } ) - self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Scan targets 60 seconds", self.EscortMenuScanForTargets, ESCORT._ScanTargets, { ParamSelf = self, ParamScanDuration = 60 } ) + if not Seconds then + Seconds = 30 end - + + -- Report Targets + self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, { ParamSelf = self } ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) + self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) + -- Attack Targets self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu ) - -- Request assistance from other escorts. + + self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, Seconds ) + + return self +end + +--- Defines a menu slot to let the escort attack its detected targets using assisted attack from another escort joined also with the client. +-- This menu will appear under **Request assistance from**. +-- Note that this method needs to be preceded with the method MenuReportTargets. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuAssistedAttack() + self:F() + + -- Request assistance from other escorts. -- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane... self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Request assistance from", self.EscortMenu ) - - -- Rules of Engagement - self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) - if EscortGroup:OptionROEHoldFirePossible() then - self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = EscortGroup:OptionROEHoldFire(), ParamMessage = "Holding weapons!" } ) - end - if EscortGroup:OptionROEReturnFirePossible() then - self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = EscortGroup:OptionROEReturnFire(), ParamMessage = "Returning fire!" } ) - end - if EscortGroup:OptionROEOpenFirePossible() then - self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = EscortGroup:OptionROEOpenFire(), ParamMessage = "Opening fire on designated targets!!" } ) - end - if EscortGroup:OptionROEWeaponFreePossible() then - self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = EscortGroup:OptionROEWeaponFree(), ParamMessage = "Opening fire on targets of opportunity!" } ) + return self +end + +--- Defines a menu to let the escort set its rules of engagement. +-- All rules of engagement will appear under the menu **ROE**. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuROE( MenuTextFormat ) + self:F( MenuTextFormat ) + + if not self.EscortMenuROE then + -- Rules of Engagement + self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) + if self.EscortGroup:OptionROEHoldFirePossible() then + self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEHoldFire(), ParamMessage = "Holding weapons!" } ) + end + if self.EscortGroup:OptionROEReturnFirePossible() then + self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEReturnFire(), ParamMessage = "Returning fire!" } ) + end + if self.EscortGroup:OptionROEOpenFirePossible() then + self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEOpenFire(), ParamMessage = "Opening fire on designated targets!!" } ) + end + if self.EscortGroup:OptionROEWeaponFreePossible() then + self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEWeaponFree(), ParamMessage = "Opening fire on targets of opportunity!" } ) + end end - -- Reaction to Threats - self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) - if EscortGroup:OptionROTNoReactionPossible() then - self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = EscortGroup:OptionROTNoReaction(), ParamMessage = "Fighting until death!" } ) - end - if EscortGroup:OptionROTPassiveDefensePossible() then - self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = EscortGroup:OptionROTPassiveDefense(), ParamMessage = "Defending using jammers, chaff and flares!" } ) - end - if EscortGroup:OptionROTEvadeFirePossible() then - self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = EscortGroup:OptionROTEvadeFire(), ParamMessage = "Evading on enemy fire!" } ) - end - if EscortGroup:OptionROTVerticalPossible() then - self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = EscortGroup:OptionROTVertical(), ParamMessage = "Evading on enemy fire with vertical manoeuvres!" } ) - end - - -- Mission Resume Menu Root - self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume the escort mission", self.EscortMenu ) + return self +end - -- Initialize the EscortGroup - - self.EscortGroup:WayPointInitialize(1) - - self.EscortGroup:OptionROTVertical() - self.EscortGroup:OptionROEOpenFire() - - - self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, 30 ) - - EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. - "We're escorting your flight. " .. - "Use the Radio Menu and F10 and use the options under + " .. EscortName .. "\n", - 60, EscortClient - ) + +--- Defines a menu to let the escort set its evasion when under threat. +-- All rules of engagement will appear under the menu **Evasion**. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuEvasion( MenuTextFormat ) + self:F( MenuTextFormat ) + + if self.EscortGroup:IsAir() then + if not self.EscortMenuEvasion then + -- Reaction to Threats + self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) + if self.EscortGroup:OptionROTNoReactionPossible() then + self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTNoReaction(), ParamMessage = "Fighting until death!" } ) + end + if self.EscortGroup:OptionROTPassiveDefensePossible() then + self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTPassiveDefense(), ParamMessage = "Defending using jammers, chaff and flares!" } ) + end + if self.EscortGroup:OptionROTEvadeFirePossible() then + self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTEvadeFire(), ParamMessage = "Evading on enemy fire!" } ) + end + if self.EscortGroup:OptionROTVerticalPossible() then + self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTVertical(), ParamMessage = "Evading on enemy fire with vertical manoeuvres!" } ) + end + end + end + + return self +end + +--- Defines a menu to let the escort resume its mission from a waypoint on its route. +-- All rules of engagement will appear under the menu **Resume mission from**. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuResumeMission() + self:F() + + if not self.EscortMenuResumeMission then + -- Mission Resume Menu Root + self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume mission from", self.EscortMenu ) + end + + return self end @@ -245,48 +606,41 @@ function ESCORT._HoldPosition( MenuParam ) local self = MenuParam.ParamSelf local EscortGroup = self.EscortGroup local EscortClient = self.EscortClient - - routines.removeFunction( self.FollowScheduler ) - EscortGroup:SetTask( EscortGroup:TaskHoldPosition( 300 ) ) - EscortGroup:MessageToClient( "Holding Position.", 10, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._HoldPositionNearBy( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - --MenuParam.ParamSelf.EscortGroup:TaskOrbitCircleAtVec2( MenuParam.ParamSelf.EscortClient:GetPointVec2(), 300, 30, 0 ) + local OrbitGroup = MenuParam.ParamOrbitGroup -- Group#GROUP + local OrbitUnit = OrbitGroup:GetUnit(1) -- Unit#UNIT + local OrbitHeight = MenuParam.ParamHeight + local OrbitSeconds = MenuParam.ParamSeconds -- Not implemented yet routines.removeFunction( self.FollowScheduler ) - + local PointFrom = {} - local GroupPoint = EscortGroup:GetPointVec2() + local GroupPoint = EscortGroup:GetUnit(1):GetPositionVec3() PointFrom = {} PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.y + PointFrom.y = GroupPoint.z PointFrom.speed = 250 PointFrom.type = AI.Task.WaypointType.TURNING_POINT - PointFrom.alt = EscortClient:GetAltitude() + PointFrom.alt = GroupPoint.y PointFrom.alt_type = AI.Task.AltitudeType.BARO - local ClientPoint = MenuParam.ParamSelf.EscortClient:GetPointVec2() + local OrbitPoint = OrbitUnit:GetPointVec2() local PointTo = {} - PointTo.x = ClientPoint.x - PointTo.y = ClientPoint.y + PointTo.x = OrbitPoint.x + PointTo.y = OrbitPoint.y PointTo.speed = 250 PointTo.type = AI.Task.WaypointType.TURNING_POINT - PointTo.alt = EscortClient:GetAltitude() + PointTo.alt = OrbitHeight PointTo.alt_type = AI.Task.AltitudeType.BARO - PointTo.task = EscortGroup:TaskOrbitCircleAtVec2( EscortClient:GetPointVec2(), 300, 30, 0 ) - + PointTo.task = EscortGroup:TaskOrbitCircleAtVec2( OrbitPoint, OrbitHeight, 0 ) + local Points = { PointFrom, PointTo } - + + EscortGroup:OptionROEHoldFire() + EscortGroup:OptionROTPassiveDefense() + EscortGroup:SetTask( EscortGroup:TaskRoute( Points ) ) - EscortGroup:MessageToClient( "Rejoining to your location. Please hold at your location.", 10, EscortClient ) + EscortGroup:MessageToClient( "Orbiting at location.", 10, EscortClient ) end --- @param #MENUPARAM MenuParam @@ -295,10 +649,10 @@ function ESCORT._JoinUpAndFollow( MenuParam ) local self = MenuParam.ParamSelf local EscortGroup = self.EscortGroup local EscortClient = self.EscortClient - - local Distance = MenuParam.ParamDistance - - self:JoinUpAndFollow( EscortGroup, EscortClient, Distance ) + + self.Distance = MenuParam.ParamDistance + + self:JoinUpAndFollow( EscortGroup, EscortClient, self.Distance ) end --- JoinsUp and Follows a CLIENT. @@ -312,10 +666,12 @@ function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance ) if self.FollowScheduler then routines.removeFunction( self.FollowScheduler ) end - + EscortGroup:OptionROEHoldFire() EscortGroup:OptionROTPassiveDefense() - + + self.EscortMode = ESCORT.MODE.FOLLOW + self.CT1 = 0 self.GT1 = 0 self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + 1, .5 ) @@ -328,7 +684,7 @@ function ESCORT._Flare( MenuParam ) local self = MenuParam.ParamSelf local EscortGroup = self.EscortGroup local EscortClient = self.EscortClient - + local Color = MenuParam.ParamColor local Message = MenuParam.ParamMessage @@ -345,7 +701,7 @@ function ESCORT._Smoke( MenuParam ) local Color = MenuParam.ParamColor local Message = MenuParam.ParamMessage - + EscortGroup:GetUnit(1):Smoke( Color ) EscortGroup:MessageToClient( Message, 10, EscortClient ) end @@ -359,7 +715,7 @@ function ESCORT._ReportNearbyTargetsNow( MenuParam ) local EscortClient = self.EscortClient self:_ReportTargetsScheduler() - + end function ESCORT._SwitchReportNearbyTargets( MenuParam ) @@ -367,9 +723,9 @@ function ESCORT._SwitchReportNearbyTargets( MenuParam ) local self = MenuParam.ParamSelf local EscortGroup = self.EscortGroup local EscortClient = self.EscortClient - + self.ReportTargets = MenuParam.ParamReportTargets - + if self.ReportTargets then if not self.ReportTargetsScheduler then self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, 30 ) @@ -386,45 +742,56 @@ function ESCORT._ScanTargets( MenuParam ) local self = MenuParam.ParamSelf local EscortGroup = self.EscortGroup local EscortClient = self.EscortClient - + local ScanDuration = MenuParam.ParamScanDuration if self.FollowScheduler then routines.removeFunction( self.FollowScheduler ) end - + self:T( { "FollowScheduler after removefunction: ", self.FollowScheduler } ) - + if EscortGroup:IsHelicopter() then routines.scheduleFunction( EscortGroup.PushTask, - { EscortGroup, - EscortGroup:TaskControlled( - EscortGroup:TaskOrbitCircle( 200, 20 ), - EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) - ) - }, - timer.getTime() + 1 - ) + { EscortGroup, + EscortGroup:TaskControlled( + EscortGroup:TaskOrbitCircle( 200, 20 ), + EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) + ) + }, + timer.getTime() + 1 + ) elseif EscortGroup:IsAirPlane() then routines.scheduleFunction( EscortGroup.PushTask, - { EscortGroup, - EscortGroup:TaskControlled( - EscortGroup:TaskOrbitCircle( 1000, 500 ), - EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) - ) - }, - timer.getTime() + 1 - ) - end - + { EscortGroup, + EscortGroup:TaskControlled( + EscortGroup:TaskOrbitCircle( 1000, 500 ), + EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) + ) + }, + timer.getTime() + 1 + ) + end + EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient ) - if self.FollowScheduler then + if self.EscortMode == ESCORT.MODE.FOLLOW then self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + ScanDuration, 1 ) end end +function _Resume( EscortGroup ) + env.info( '_Resume' ) + + local Escort = EscortGroup.Escort -- #ESCORT + env.info( "EscortMode = " .. Escort.EscortMode ) + if Escort.EscortMode == ESCORT.MODE.FOLLOW then + Escort:JoinUpAndFollow( EscortGroup, Escort.EscortClient, Escort.Distance ) + end + +end + --- @param #MENUPARAM MenuParam function ESCORT._AttackTarget( MenuParam ) @@ -436,40 +803,37 @@ function ESCORT._AttackTarget( MenuParam ) if self.FollowScheduler then routines.removeFunction( self.FollowScheduler ) end - + self:T( AttackUnit ) - + if EscortGroup:IsAir() then EscortGroup:OptionROEOpenFire() - EscortGroup:OptionROTVertical() - routines.scheduleFunction( - EscortGroup.PushTask, - { EscortGroup, + EscortGroup:OptionROTPassiveDefense() + EscortGroup.Escort = self -- Need to do this trick to get the reference for the escort in the _Resume function. + routines.scheduleFunction( + EscortGroup.PushTask, + { EscortGroup, EscortGroup:TaskCombo( { EscortGroup:TaskAttackUnit( AttackUnit ), - EscortGroup:TaskOrbitCircle( 500, 350 ) + EscortGroup:TaskFunction( 1, 2, "_Resume", {"''"} ) } ) }, timer.getTime() + 10 ) else - routines.scheduleFunction( - EscortGroup.PushTask, - { EscortGroup, + routines.scheduleFunction( + EscortGroup.PushTask, + { EscortGroup, EscortGroup:TaskCombo( { EscortGroup:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) } ) - }, timer.getTime() + 10 + }, timer.getTime() + 10 ) - end + end EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient ) - if self.FollowScheduler then - self.FollowScheduler = routines.scheduleFunction( self._FollowScheduler, { self, Distance }, timer.getTime() + ScanDuration, 1 ) - end - end --- @param #MENUPARAM MenuParam @@ -484,34 +848,34 @@ function ESCORT._AssistTarget( MenuParam ) if self.FollowScheduler then routines.removeFunction( self.FollowScheduler ) end - - + + self:T( AttackUnit ) - + if EscortGroupAttack:IsAir() then EscortGroupAttack:OptionROEOpenFire() EscortGroupAttack:OptionROTVertical() - routines.scheduleFunction( - EscortGroupAttack.PushTask, - { EscortGroupAttack, + routines.scheduleFunction( + EscortGroupAttack.PushTask, + { EscortGroupAttack, EscortGroupAttack:TaskCombo( { EscortGroupAttack:TaskAttackUnit( AttackUnit ), EscortGroupAttack:TaskOrbitCircle( 500, 350 ) } ) - }, timer.getTime() + 10 + }, timer.getTime() + 10 ) else - routines.scheduleFunction( - EscortGroupAttack.PushTask, - { EscortGroupAttack, + routines.scheduleFunction( + EscortGroupAttack.PushTask, + { EscortGroupAttack, EscortGroupAttack:TaskCombo( { EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) } ) - }, timer.getTime() + 10 + }, timer.getTime() + 10 ) - end + end EscortGroupAttack:MessageToClient( "Assisting with the destroying the enemy unit!", 10, EscortClient ) end @@ -522,10 +886,10 @@ function ESCORT._ROE( MenuParam ) local self = MenuParam.ParamSelf local EscortGroup = self.EscortGroup local EscortClient = self.EscortClient - + local EscortROEFunction = MenuParam.ParamFunction local EscortROEMessage = MenuParam.ParamMessage - + pcall( function() EscortROEFunction() end ) EscortGroup:MessageToClient( EscortROEMessage, 10, EscortClient ) end @@ -550,21 +914,21 @@ function ESCORT._ResumeMission( MenuParam ) local self = MenuParam.ParamSelf local EscortGroup = self.EscortGroup local EscortClient = self.EscortClient - + local WayPoint = MenuParam.ParamWayPoint - + routines.removeFunction( self.FollowScheduler ) self.FollowScheduler = nil local WayPoints = EscortGroup:GetTaskRoute() self:T( WayPoint, WayPoints ) - + for WayPointIgnore = 1, WayPoint do table.remove( WayPoints, 1 ) end - + routines.scheduleFunction( EscortGroup.SetTask, {EscortGroup, EscortGroup:TaskRoute( WayPoints ) }, timer.getTime() + 1 ) - + EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) end @@ -575,9 +939,9 @@ function ESCORT:RegisterRoute() self:F() local EscortGroup = self.EscortGroup -- Group#GROUP - + local TaskPoints = EscortGroup:GetTaskRoute() - + self:T( TaskPoints ) return TaskPoints @@ -588,7 +952,7 @@ function ESCORT:_FollowScheduler( FollowDistance ) self:F( { FollowDistance }) if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then - + local ClientUnit = self.EscortClient:GetClientGroupUnit() local GroupUnit = self.EscortGroup:GetUnit( 1 ) @@ -604,70 +968,70 @@ function ESCORT:_FollowScheduler( FollowDistance ) local CV2 = ClientUnit:GetPositionVec3() self.CT1 = CT2 self.CV1 = CV2 - + local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 local CT = CT2 - CT1 - + local CS = ( 3600 / CT ) * ( CD / 1000 ) - + self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) - + local GT1 = self.GT1 local GT2 = timer.getTime() local GV1 = self.GV1 local GV2 = GroupUnit:GetPositionVec3() self.GT1 = GT2 self.GV1 = GV2 - + local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 local GT = GT2 - GT1 - + local GS = ( 3600 / GT ) * ( GD / 1000 ) - + self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) - + -- Calculate the group direction vector local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } - + -- Calculate GH2, GH2 with the same height as CV2. local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } - + -- Calculate the angle of GV to the orthonormal plane local alpha = math.atan2( GV.z, GV.x ) - + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) - local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), - y = GH2.y, - z = CV2.z + FollowDistance * math.sin(alpha), - } - + local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), + y = GH2.y, + z = CV2.z + FollowDistance * math.sin(alpha), + } + -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } - + -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... local DVu = { x = DV.x / FollowDistance, y = DV.y / FollowDistance, z = DV.z / FollowDistance } - + -- Now we can calculate the group destination vector GDV. local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z } self:T2( { "CV2:", CV2 } ) self:T2( { "CVI:", CVI } ) self:T2( { "GDV:", GDV } ) - + -- Measure distance between client and group local CatchUpDistance = ( ( GDV.x - GV2.x )^2 + ( GDV.y - GV2.y )^2 + ( GDV.z - GV2.z )^2 ) ^ 0.5 - - -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome + + -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome -- the requested Distance). local Time = 10 - local CatchUpSpeed = ( CatchUpDistance - ( CS * 8.4 ) ) / Time - + local CatchUpSpeed = ( CatchUpDistance - ( CS * 8.4 ) ) / Time + local Speed = CS + CatchUpSpeed - if Speed < 0 then + if Speed < 0 then Speed = 0 - end + end self:T( { "Client Speed, Escort Speed, Speed, FlyDistance, Time:", CS, GS, Speed, Distance, Time } ) @@ -684,90 +1048,93 @@ end --- Report Targets Scheduler. -- @param #ESCORT self function ESCORT:_ReportTargetsScheduler() - self:F( self.EscortGroup:GetName() ) + self:F( self.EscortGroup:GetName() ) if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then local EscortGroupName = self.EscortGroup:GetName() local EscortTargets = self.EscortGroup:GetDetectedTargets() - + local ClientEscortTargets = self.EscortClient._EscortGroups[EscortGroupName].Targets - + local EscortTargetMessages = "" for EscortTargetID, EscortTarget in pairs( EscortTargets ) do local EscortObject = EscortTarget.object self:T( EscortObject ) if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then - - local EscortTargetUnit = UNIT:New( EscortObject ) - local EscortTargetUnitName = EscortTargetUnit:GetName() - - - --- local EscortTargetIsDetected, --- EscortTargetIsVisible, --- EscortTargetLastTime, --- EscortTargetKnowType, --- EscortTargetKnowDistance, --- EscortTargetLastPos, --- EscortTargetLastVelocity --- = self.EscortGroup:IsTargetDetected( EscortObject ) --- --- self:T( { EscortTargetIsDetected, --- EscortTargetIsVisible, --- EscortTargetLastTime, --- EscortTargetKnowType, --- EscortTargetKnowDistance, --- EscortTargetLastPos, --- EscortTargetLastVelocity } ) - - local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() - local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + - ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + - ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 - ) ^ 0.5 / 1000 + local EscortTargetUnit = UNIT:New( EscortObject ) + local EscortTargetUnitName = EscortTargetUnit:GetName() - self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget } ) - if Distance <= 15 then - if not ClientEscortTargets[EscortTargetUnitName] then - ClientEscortTargets[EscortTargetUnitName] = {} - end - ClientEscortTargets[EscortTargetUnitName].AttackUnit = EscortTargetUnit - ClientEscortTargets[EscortTargetUnitName].visible = EscortTarget.visible - ClientEscortTargets[EscortTargetUnitName].type = EscortTarget.type - ClientEscortTargets[EscortTargetUnitName].distance = EscortTarget.distance - else - if ClientEscortTargets[EscortTargetUnitName] then - ClientEscortTargets[EscortTargetUnitName] = nil - end + -- local EscortTargetIsDetected, + -- EscortTargetIsVisible, + -- EscortTargetLastTime, + -- EscortTargetKnowType, + -- EscortTargetKnowDistance, + -- EscortTargetLastPos, + -- EscortTargetLastVelocity + -- = self.EscortGroup:IsTargetDetected( EscortObject ) + -- + -- self:T( { EscortTargetIsDetected, + -- EscortTargetIsVisible, + -- EscortTargetLastTime, + -- EscortTargetKnowType, + -- EscortTargetKnowDistance, + -- EscortTargetLastPos, + -- EscortTargetLastVelocity } ) + + + local EscortTargetUnitPositionVec3 = EscortTargetUnit:GetPositionVec3() + local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + + ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + + ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 + ) ^ 0.5 / 1000 + + self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget } ) + + if Distance <= 15 then + + if not ClientEscortTargets[EscortTargetUnitName] then + ClientEscortTargets[EscortTargetUnitName] = {} end + ClientEscortTargets[EscortTargetUnitName].AttackUnit = EscortTargetUnit + ClientEscortTargets[EscortTargetUnitName].visible = EscortTarget.visible + ClientEscortTargets[EscortTargetUnitName].type = EscortTarget.type + ClientEscortTargets[EscortTargetUnitName].distance = EscortTarget.distance + else + if ClientEscortTargets[EscortTargetUnitName] then + ClientEscortTargets[EscortTargetUnitName] = nil + end + end end end - + self:T( { "Sorting Targets Table:", ClientEscortTargets } ) table.sort( ClientEscortTargets, function( a, b ) return a.Distance < b.Distance end ) self:T( { "Sorted Targets Table:", ClientEscortTargets } ) -- Remove the sub menus of the Attack menu of the Escort for the EscortGroup. self.EscortMenuAttackNearbyTargets:RemoveSubMenus() - self.EscortMenuTargetAssistance:RemoveSubMenus() - + + if self.EscortMenuTargetAssistance then + self.EscortMenuTargetAssistance:RemoveSubMenus() + end + --for MenuIndex = 1, #self.EscortMenuAttackTargets do -- self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } ) -- self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove() --end - + if ClientEscortTargets then for ClientEscortTargetUnitName, ClientEscortTargetData in pairs( ClientEscortTargets ) do - + for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do - + if ClientEscortTargetData and ClientEscortTargetData.AttackUnit:IsAlive() then - + local EscortTargetMessage = "" local EscortTargetCategoryName = ClientEscortTargetData.AttackUnit:GetCategoryName() local EscortTargetCategoryType = ClientEscortTargetData.AttackUnit:GetTypeName() @@ -776,54 +1143,56 @@ function ESCORT:_ReportTargetsScheduler() else EscortTargetMessage = EscortTargetMessage .. "Unknown target at " end - + local EscortTargetUnitPositionVec3 = ClientEscortTargetData.AttackUnit:GetPositionVec3() local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() - local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + - ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + - ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 - ) ^ 0.5 / 1000 - + local Distance = ( ( EscortTargetUnitPositionVec3.x - EscortPositionVec3.x )^2 + + ( EscortTargetUnitPositionVec3.y - EscortPositionVec3.y )^2 + + ( EscortTargetUnitPositionVec3.z - EscortPositionVec3.z )^2 + ) ^ 0.5 / 1000 + self:T( { self.EscortGroup:GetName(), ClientEscortTargetData.AttackUnit:GetName(), Distance, ClientEscortTargetData.AttackUnit } ) if ClientEscortTargetData.visible == false then EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " estimated km" else EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" end - + if ClientEscortTargetData.visible then EscortTargetMessage = EscortTargetMessage .. ", visual" end - + if ClientEscortGroupName == EscortGroupName then - + MENU_CLIENT_COMMAND:New( self.EscortClient, - EscortTargetMessage, - self.EscortMenuAttackNearbyTargets, - ESCORT._AttackTarget, - { ParamSelf = self, - ParamUnit = ClientEscortTargetData.AttackUnit - } - ) - EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage + EscortTargetMessage, + self.EscortMenuAttackNearbyTargets, + ESCORT._AttackTarget, + { ParamSelf = self, + ParamUnit = ClientEscortTargetData.AttackUnit + } + ) + EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage else - local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance ) - MENU_CLIENT_COMMAND:New( self.EscortClient, - EscortTargetMessage, - MenuTargetAssistance, - ESCORT._AssistTarget, - { ParamSelf = self, - ParamEscortGroup = EscortGroupData.EscortGroup, - ParamUnit = ClientEscortTargetData.AttackUnit - } - ) + if self.EscortMenuTargetAssistance then + local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance ) + MENU_CLIENT_COMMAND:New( self.EscortClient, + EscortTargetMessage, + MenuTargetAssistance, + ESCORT._AssistTarget, + { ParamSelf = self, + ParamEscortGroup = EscortGroupData.EscortGroup, + ParamUnit = ClientEscortTargetData.AttackUnit + } + ) + end end else ClientEscortTargetData = nil end end end - + if EscortTargetMessages ~= "" and self.ReportTargets == true then self.EscortGroup:MessageToClient( "Detected targets within 15 km range:" .. EscortTargetMessages:gsub("\n$",""), 20, self.EscortClient ) else @@ -831,22 +1200,24 @@ function ESCORT:_ReportTargetsScheduler() end end - self.EscortMenuResumeMission:RemoveSubMenus() - --- if self.EscortMenuResumeWayPoints then --- for MenuIndex = 1, #self.EscortMenuResumeWayPoints do --- self:T( { "Remove Menu:", self.EscortMenuResumeWayPoints[MenuIndex] } ) --- self.EscortMenuResumeWayPoints[MenuIndex] = self.EscortMenuResumeWayPoints[MenuIndex]:Remove() --- end --- end + if self.EscortMenuResumeMission then + self.EscortMenuResumeMission:RemoveSubMenus() - local TaskPoints = self:RegisterRoute() - for WayPointID, WayPoint in pairs( TaskPoints ) do - local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() - local Distance = ( ( WayPoint.x - EscortPositionVec3.x )^2 + - ( WayPoint.y - EscortPositionVec3.z )^2 - ) ^ 0.5 / 1000 - MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } ) + -- if self.EscortMenuResumeWayPoints then + -- for MenuIndex = 1, #self.EscortMenuResumeWayPoints do + -- self:T( { "Remove Menu:", self.EscortMenuResumeWayPoints[MenuIndex] } ) + -- self.EscortMenuResumeWayPoints[MenuIndex] = self.EscortMenuResumeWayPoints[MenuIndex]:Remove() + -- end + -- end + + local TaskPoints = self:RegisterRoute() + for WayPointID, WayPoint in pairs( TaskPoints ) do + local EscortPositionVec3 = self.EscortGroup:GetPositionVec3() + local Distance = ( ( WayPoint.x - EscortPositionVec3.x )^2 + + ( WayPoint.y - EscortPositionVec3.z )^2 + ) ^ 0.5 / 1000 + MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } ) + end end else diff --git a/Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua b/Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua index e53577029..6e5e36e0b 100644 --- a/Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua +++ b/Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua @@ -8,18 +8,44 @@ Include.File( "Escort" ) do local function EventAliveHelicopter( Client ) local EscortGroupHeli1 = SpawnEscortHeli:ReSpawn(1) - local EscortHeli1 = ESCORT:New( Client, EscortGroupHeli1, "Escort Alpha" ) + local EscortHeli1 = ESCORT + :New( Client, EscortGroupHeli1, "Escort Helicopter" ) + :MenuFollowAt( 100 ) + :MenuFollowAt( 200 ) + :MenuHoldAtEscortPosition( 20, 10, "Hold at %d meters for %d seconds" ) + :MenuHoldAtLeaderPosition( 120 ) + :MenuFlare( "Disperse Flares" ) + :MenuSmoke() + :MenuReportTargets( 60, 20 ) + :MenuResumeMission() + :MenuAssistedAttack() end local function EventAlivePlane( Client ) local EscortGroupPlane2 = SpawnEscortPlane:ReSpawn(1) - local EscortPlane2 = ESCORT:New( Client, EscortGroupPlane2, "Escort Test Plane" ) + local EscortPlane2 = ESCORT + :New( Client, EscortGroupPlane2, "Escort Test Plane" ) + :MenuFollowAt( 100 ) + :MenuFollowAt( 200 ) + :MenuHoldAtEscortPosition( 20, 10, "Hold at %d meters for %d seconds" ) + :MenuHoldAtLeaderPosition( 120 ) + :MenuFlare( "Disperse Flares" ) + :MenuSmoke() + :MenuReportTargets( 60, 20 ) + :MenuResumeMission() + :MenuAssistedAttack() + :MenuROE() + :MenuEvasion() local EscortGroupGround2 = SpawnEscortGround:ReSpawn(1) - local EscortGround2 = ESCORT:New( Client, EscortGroupGround2, "Test Ground" ) + local EscortGround2 = ESCORT + :New( Client, EscortGroupGround2, "Test Ground" ) + :Menus() local EscortGroupShip2 = SpawnEscortShip:ReSpawn(1) - local EscortShip2 = ESCORT:New( Client, EscortGroupShip2, "Test Ship" ) + local EscortShip2 = ESCORT + :New( Client, EscortGroupShip2, "Test Ship" ) + :Menus() end SpawnEscortHeli = SPAWN:New( "Escort Helicopter" ) diff --git a/Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz b/Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz index c0f47f11282ad8f61ae7f43a007a6e21cd2e53e2..2b8e5b65841a574d27fac7b5330385d1b73754f6 100644 GIT binary patch delta 141474 zcmV)MK)Ao@{Ri^u2oz9D0|XQR000O80RR91=+2S~^D>tXn*l3-97mGn^YmB9^xTma z_shdP#3fVeC8^ekY-y+0*4hd{k%SRK$pBEhpltqqk5?5a02P4>5|tt}3t6j0vH${J zp6=)P<@ovH*V8wPtJBr_zyIa8zx><(`ub#Xwfy>j|NCG54Zp%Kua}Dp{8Dlu{<{8+ zlf^ZDz5T_{tMjXWxA>*SFaPVW^y$n0`^)LY`s@AckzeUz`37GFzxDOk>tFw$#q}?% z)AOs#TVL}xThu80lvv4JFnx03nDEo}P z-@dy3g}zz2{pI=MXZq#W&n_01=c|*&1^a$+`S#uF*UNW**I#d6bG$e^yF7if{uZD8 zP(J?l+2WGE$FF1h;cqYh_0#s-{#RNqj`8zsU-irC^7Lx+^U-gtzd8K&+3Nhw>DBua z`pZ=q1ipQ5L(txYzuvqA*4@5Bn}JL2mE_h)?rvUjyn26eNq^37e&_A-^v&BV`kH#s z+y}{}_uSim^`DcuH~)e`$LK;Zd19_`&-9U4u%N79Vp5Si6}^#D)u76Yz1ECxR#of8 zZ{{!_R~jEiTWNL8czO_O^P#COx9zEo(AJm4 zqB4eQI30^)PHc2Grocl;Jk=c(@9BQ`{C0V9xjJWm8UKI2I$A7$eYdC?_}iCBCHl%OC@@Y{PO*~x9@*GWodEr{_^eOVsXcw z+fNYpOtf^zp2mQv05h9R2 zpQ5F7GUy=tVuHY<@3gke3RRd^!m*@yVKPX6XGC$+luOm1LGI63-(Q^myt=r2w_@?# z+p7ist7hD9emZlP-Qvr+NZHmpxU|DI2Gmmx!!dNXxu+hB+T$ z*HOl)j8%IYJZAgsnO0|)Z$6ZJxf*!mNVB;MTwvgtA=%(x4G-tXV1P}oL|0MTt66r4{2X+;fBcL-1sW0 z!V`_WW)Rqn(Yy9#$b6Ou5v=f*Tf1X!;mx3ocRC>LS<^DL5c0OMUCIt{udu)~jD4a4 z3wH9%yUCXczsIGi8e59}Kp~zlep#@8A5X8Y7ax|tu4#mF} zVl1Ko+;cbHlBtE0&Uqn&ael|t+6`WF6NFZHCv?lyyfM84Vjv0c{8z5g303 z6Qk44O?p&g!`5Eyck9#h<;CLc{CfG-kE@d^;C*p;w^jq!Rs`TuYfTk9=s{|K4 z6>itoa^ONLwcxmy3&^7hq*ohkp6P99BjMB}i+e|2>1D83Dt2N=OZ40mA{I1}|;Jl|Ld2?&yuG zAd4mL?7uP@6Iq)3eHE8^QFapWE#VmpXP<2RU zwh~=A!b6}RO8^j?%Jc8wzFJCegt4-hSa2Sr$VD>|GF+3}BM^(I89GyD+7mE~tR0hXVUh?7atZEOT^pN zvS#Mzhp(6+;3~ED1I?wbA_g@CK}MEJC@Xe-ddINV57L@-kx01U`T%dx3Sr1FyyYB0 zLLM>TIqf;6wxi@Ga1R1VDiKpV3_D2imMHrb$UX940v1EM^gTMOc^89K|m;V@pdn$k% z13d4zZ5iBy0vn;cHoFXt_y*oD#AyXO;dcXvgu%TgssWz8O`JVZI_ao#U@>`W6d`6r z#bJMwjLk`ZPNmeNw9@;l?63ZLzPhM}=2w3|d~mh^4pc(N^QwIn2g8KxD!aCT4?V!) zGb@-sEO_So)oSOk^CoaAd43a!*8@h}4~0j=*^4*>xg&8i?Q z{@LvT0p5ZSBM|{(DAR0N+#wXQOhy`bCr>3Yy)c1)1)VM986dmJ41`!OmKbFHeGqK=UxV|TUKi(d;a2jN+rW;HZrXjg2jX=t@iFuQU%FhPfoMoBiwiyz;abq%odtc$za~94#N-zlzEJapUu#)gpmWF z6QC_}ebsegWb3G`=z}s9Y`fRU&2o*pZP#ai@2?i1P(5kt=B1yKrpz40E;#`ENGc>l}Jy*SFQOEX(^ZrZ*SEHAL=eh>e^T@9Rjpzg3&vF zaTJVq3bL#xJQUN4YFWkwR*Vf`fl`D}ANVi_>Wfq6&>I1*w(mdd@P^?}z=T@7}I1 zmRBFDA@v{M&eB|8=XwqBUq=IG@Y^YW5oKi$p8D+Jg*=7ibzpu3B+y(bpn)uz%LYMR zjCsuUimdCHvU#<5vpBz4yK*2^>ySw3dLDS1_3u@1f$0xt1nj#@Q!8_5ENX!WJ}cm7X;WCBFAoj$yN*o ze@0MDdSm2{eI*|PxP!sdt#0Vtew>9E;;E;J2<(8f5RyO~@UN1ELrP0oq&nR?RPXWd z$qi^rhM@5SITKWaYT;)lK8DGb4 z8!{_mDsXP&nV%A8*@zUQ6t2~Ox_NrE!4Ckl)SRUTZq>%r9+MV;$-!Og12^Q*$bnYZ z8jvtCOfNOQ3U7DE?$@@Es+6ZXVnC+TN5E)d%rJPi#qj8Ik>bxdM}|1K?v=aNEGgg| zuop-|ouF|d7s&bH*6{xAUhhDG1HlFCsadAEYwGRjMo<5|Ipoponyc-9aK&MXgdV^k zEEs~u|EewB^#F)dKxI}dzhg-;(3n5G8ed1r$~c}Or-uiE=D9WmzFqIS)otxC<-@(% zmO1q{8ywV{>!z(hl!aR&Z`Iw>IIsa4(Qv-ngA5>c1`sJw334~e_VKbf8l_A0Y?>zG zWhbv0K*>n|!cRVGD@Rv<2ex7VB1z8^Kg($DlX&FsPtV+AR6P&>eiGJ<0#?bx`z`S^ zc%+3#S}7WSE2X3D2c>G0qO>~^q_o;te`}qmUY32pZw0V}3X@@zF345OlN08%ax9v0 zq9zQD)qHlP_SGqn?k}seYA5FKbc{Mtn*=IEqo801znLXhK~&&>?cwNHP)@s?9JA5` z(jF}&IBsz)7ssRG)a$5^EGilH+V#8BcdN6-@>llk{n=4-AoO{jV+(52-r(9v->`7l z&|PWfoz}NVph=~~1Q!IgsK?-7YbgyMkvWkR8gm|cKgNm|KQDegz4(fKwV`M=`~Eb; zShLs;+l;%SD8t9UU)ASX%y|v48n%pchavEaer*kno zC;$=qW94nL;&_)Je786|?u4~BFZ~2?;LIEyaWz;_4^2CEPB(_`ji3sjbUer!rlna< zcp}(wu&UA$SAF2XMDF+~6mud|9c=NMB?KLo5OPxlIf01e(N~*Dlt+=8%qdmQVJNs>Jt`(&diNc1W~-rxn7A8>xH?`UL2W$ zjKMW6QB+!GuJ1BX-9QRNg`k41m2Nk60|y%gyF15!B@B($A>$*C->f?HEIi4S0T43F zG;y!ZiD4ilNMTz0h;#{{U58-@+T)w0bgPJUNw}h`o0?J?b@-J)0I2jG_LXjx8I)Uh zKDE6WCGW7cDaDQ<6q@rGDROA$6;0d1#Ya%+=5m?x`{Txss}JYP%jJ0;Fua(-&Hz=L zcq~MJXwA}?O*n>;Dox76fn7Hl?VNN>OqRedqO*6C1Pv}lWSw~q_3fv=nB0La4jGGW zkj`-$Lh+3Xqft6gi(GnN-S`zm?+_*QjSJp&Uk4s-U?fFzFr85BH)K6c@QnppGXoAJ z@ftm`5?#qs^C(-CSnMy6jc2EqSJlGU%Nc}!74)!GQlYJy#_qpzo7W&j?DB~N78*dt zM$a`vDwDKFtyz?#Whr`L{ODYs>KIL_{S)}$z8{unRhIUT!|&_iap&9W3>U3og zrkQ7DzhHyeM3)&U0x-RRfrHDyYynXs7oI2n7-sfKax4ceFBl8*W$4MS`mG$irnIMj zwYxP;TT@&KPE^L2gr^xYLG$}GbKV&mM!Y%3xRFf=y~Km53RxVBV>DpK*|lm7eb(-P z5woC(C$W5b&(tPO+D+Os4q(Q#J~?K=^O0GdZA?~9qp2%2f!_3}vAkPc{&L;eC;9%_ z95F*~XK<7i4P7QF*E{Oo^oiVjZp;vWZn6czi@B))p6O%BJfbj52KWq*6PGsB>9TrE zE$8qn4NqnscV~Re_$kRE8J-7)s2n_~a}vy|WGAY)d-s^#zAr?bDHhAMo*b{1d-Nbk zcFapIg{Z)_kG&vJa8ucUP+Sdo0m2NP`Q8Pc>?eb03@clO1nB)Si(xcO$*6OGF{8@1 zUZn`m_1HQsu8;t0CQh$rDXd%0HO-OIxNObJc!i+83^mO|&n#I$rqjev6wNNRSEp}V zb#ft3B{{}rrnXQ3gG)Iv>rLSyf!>*Vo7nRG(f8SVFu1D^tA;Axv%~j;G~ae397m9> zn$-<@;|^fUa?a=*RY*4H%w$S`n(3u7EGe(qq)If}D@5UXCsUb@A+kCMPBXMBK;H;D zNg<7q)p#HW4r(T7hR^AqCZ=mQgYTHI=n{%eiSa@(EC@?;-=X_=HXvTUfVPD>IfL;fZ$86$V=X2x2;Fa%zjFtfcQk4B4sqPdQ&I8t&I z3(H~w8FnG6F$ZJE#{MHc6MIWJ%gg0iHGTbbcx6n)0Jka9Ap5vR3=rEgj`4g>GCcWI zke>>hfCrGdoM&;OHR>$K(M?HBEpSWmXT3zq5Azp0AFsQ3a4 ze?M7XUM@Zk-?a84{yu{UIhmLw>ZB*wP&cvSq*D$eUCaN7fVi;MvukiJZ}0;cO{=M&4!wjQ>_gH(_v3-2 ziG^Y$lOa;;{WZKcPL8FijI=EkM0kwM$2ad!7Vqm_h&h6RaXtXm0@v~?>{8$fffiCN zRdRM?F1`Y%g;nJ&*QU~Rm(5skzqMmZK%h0unUT<}IALLbG?pa~%AF<~isY?D>HUE= zE#54aEsdHqi*B~suv$V^)ga&owGqZ7IqNwQt`y95b?%`RJUzs=WL&8XR)h5kmObdRoBrc z!x|10?~sjlF#(CQk(9Fb0%ur7VgR|=Z zs{smss*8z2PO>BJdUR!)@wDcgZ;j|TKsyk z`ek*-UVi(_Vy$pjpEI3f*jx_6ulJHvc`2mtH$@mIQaD?)EiZYa@J4f|ZfN;Qe- zxMHFxhb*^5fbbx0N!bYMi*InM_j;AwZ`kLHlhuc}&CwN0S+!>o zMx;6z_ynjQ8V^lq>rAX04JZB}tR3?wx;x%TbnpESQZU(KcFOKI6Y=yH^_@b1se1T(RGAf4E+J zcwqJSe;z)EAs%c(t%cjF)&$758mVg|&^vZruM@)>iqvp@=UA@g%4chtkB+(xv{g+j ze|pNUq)|$d>e5V|T!PABES{V#s|$YfL|HuLo+K+o!+AA{>XQU{)pv=G1-gfSByQoi z-)%f77x1ZuJLOHU%$=H?z`Ly(T%W8g1-Kiquj8eRfMi^k`j&+3*re>$8h$>9wE?mO z7(0-8olqD&>C{g!Rx4MXz}q7>?1x~2!RH&rUGM#e-|#)9h_{eg5fiCkDY`mYSWJ_O zW-?rl^)jRo9XIA)Eq^&%T`Z4(-!5C7%2zXBGny%1t6nPF<7u!rvuV9)S<}1Ov97dg zu!7E@Z~&^Nb??{9iu9msQLa0ci(^Kru`DMu@o5}|ZU{LG&ii&MAJE8qHAB%%BHORm zdK4c0#>g&7z0uwd$!7ON;=WlWGCQ0R!C*`v!VAA(o`&{;7E%!jh$hv4K|=`pE00|R z&@+^FpUedGPODN;Io~;Ecn*~6mMjJkV-T?*BG`;?Ool1HpHRdz7`fhbn}Q5 zw*0O@mTHzF?k>MuBgfGi#wQ+`K0Y}n@#l#FUj#V?4TAU>&iqAxZ*V*fSbUF$Ofi_^ zMnDath(aG7vuJ~2qcl2CY9dMbKj9M4(^w_GZ)**Tm=*G2E}Us$0Fx!D#R`+tl%g)G zUT1sy&P{W^#D00RM9d{!w09)0*A5=dgK5OE5#I6jh3W0peYg5`b+NjC82NpE> zAXI%gT@Qp4L_lWJl`X;jn``aGmHVW_N$}?A4ReWTo^;^P%Ftmt+RviDL)78gA&ZzZ zj8;FDgtl{k0aWFp?Ub3w2*LVz@tOrZLd@AQafBK>Hb$%e1PJ13++4lCF*J^2^cogk zD@t17SaOPr#x4bud74CHcC|x~@5SQc^nF9A^TiBz7TusXXTym}H?}bNwuD6Dz8yjN zvy~n)2)O~V^J`HZtsV0bAfqUqBK~EkSnq!HT%t>V%ZroiMMG03%}^AwgWGoHWT;DM z*kLoAVrl1X&e@a6OH=R+FzZM_a&g32%%!lRa~=r``o^VO-QlnwFH*GiIbY2%KjpXQ zJm9?zwE;J5#;53lD4$hrAPZMK)#GEPla33WLikDXxi+6A9 zP5n53gS?sBF0P0m>pO&YJ3I^mq1~K^R3@vu&L*%VL!?;=B({_dixV}tO5)Def!ZOf zmw&%r&5_xVx10qPP|`H6)o?oIZiKDi;Qg0C?LZuag!AddSTB${>s1Q)AW5n5M~*V0qq}g=6wKC4wKF#_r-JLzOd=or{BAL z^tU}K*5(pj=XieClbVVO#@9_mcNCC_( zrSU=Z?ksby#00NrSrrGgw$Pw>LLt|=s8!A}#@2CX+jrdgOAe|8L}7$eX=PngjyxIf z34p4r9~t{xPgZxaM96@|X<{mW(|Ms2f5c)^B!A}A7?d!Rt0%h9W8u}$r_}gsGbIMUrY$akvc?Tel(J4=L}0;f>cB+M?Q{8t49&F_N4nPW9}jl zKA@gZL-i2&faC)t_(N@fv=U*&tgk78F7L(yg=hmJO!^XZZLl{YNLftMflVe9AHAusc>c#MyNGn$D$warQ4I-tSoegCQQTH)lePW& z!63kBp{PvJx8kXTFHjCT~#a_e8q!P(*nUU9(A#CXI+MiFaE?OG1Wgg6B{6_E8)TMjPK*d^o zC_LdkyNHT_g%r|~7!B`K;!&aCofuh4lC-DYG4n22zyzC8nPSShE{^&*zrB7xkG{7K zps|3B^*MHeW(Wd*NGZlvr0Ms{dpkbBt4U_^Q{=gL2uUPs8PFWb@+=+m!bKKFKontk zNsXB^!F%Y!^5XbyH8dQ4ZA;l3*<++MQ7zV(t;m!GLanHJSDY5q0uYotU^)|;U5UG; z^JJaYSu=$&0;d&$#lk%hL$Ohe9+9^`GO2w>Gjjn%+Y+09K0KyXieS`w;aGa!AYXnx zH6jsB!<@4XJlX7Z9GQ%?P;aR|Be(+oGTGWGOjb68CA*G~UVS+IP@Nb#{HC`IgW7c7 zjWqSLq8Y*#FbXGT9BJ5=Q#MVXcek0Tt#;mwF|qAggpLR2u@a zkJI7Z86^)Q86`;o!^4*9^$818Kq$p~l=7Hm9vdP=9fOO{uiqb?{@j91&u3@`=)rHd zvAt}6Njq(3*EsFO_drpz)^bs_aprGMSM8mvLzG7RoxnoF$n{gN)AiDz=@?>s;O^~z;khb3=aK|-By6M_=dfLn+NpJmu-41k zcleeTSwPYQctg7~xDzFcm^4Wj7R3`xe4-F+6XHd2#b}%SXzDFm>G#(IUM#NPt$tz8 zzI{OUsT^Kmp3<4O$`TWBwi+w+U}<-hDg&W5hdahN84*OYXcbM&9Fq=ma`10QC#6XhqLtq|2031wzFVCwP8&h_yBXGc1VRTL_ONuM zwF&Qjrs4A~?zl^6ljKKlU8vu~H@r^j!Xja8^` zW*7q1v@AlME80(Qlw5>g=M1U6=uvg*>uqIVVlmmmtRWR?u~f95BN<88+Q8FTWW$g? z>~F<>dwOxbXn5`n-B`s3={E%wEkYG2(3!OLVOyj+-(|+nd)jaKd&g7Wam`?Vr^+(N z!@ZV$MYf=U6z8i0-;}_$G(<)#8k)Ci0JOMQ(ameu0PZZHha!t32%Ag5(`^@cuwyW^ zG**fiJdTZ;N)%AIG zTjBc|7D|DqHa#GJ`|#1db%jkCyS|J5xru5Vjg*s5%maDQguntcAWN2o1qTp0#YQ{Z z`u(`{<-5fRjkZ+t)C{OpZdIUxN<&>5$kKN7`Xf{n#SYhCQMC6Jl43!BPE^ERJEsgx znJH)*))ynVx#qrU)Yy zrM=Le-oD$!ru(xpOf*;Q=(MljlnFKW$*Vjfz|=deJP zakJ&DetS+v@-XKv?kHn_l#*r!MMBOxT5uM0(ac3U;wqw!yxtk`9lN*>DUQxi)OsqD zSUdF=E&Mc=3~J@5-g2~HDbopiUxXPEeUpET9$UMpHAhLyDhEUW*Oju-G;r&oSV!u& zRS{Cs3_^;Qq$9E0H4w%RP9xYL;Dk1Jy}$Y8Wp+s=W<2Q_)!JsL{Ur!L&I-2GCM^Q zga+i&%|mInql@^3>V~B4uK9ZPOSWY0EHJR7^?p%-xHJf7IVlB^@`~M+2m^s?nfUI; zK~gS^0-+e*3XZ0Kd|*CIbn(Qfk!o#DKSr143#kYq7}H4{XKu|8-<#J0w>1cnUevU; z_o)ajvhog1wmrlbb-pNB@3g5bGtF{5x$&ML*c`8q`lJ*XV;5r zkN4ROGGX@SiZzX6)Z@jbiKevgQZN5(JsMGRwo_qoq&dTX*ECg>f@Z|RLB@reOg%(A z+52fvWjFMm_a3l*BYmxgq@1v6t{_d496GXv$W-nnC(U z3}B)TAC|8F*6}b2TT!n|`fxZ3Tx6OM+a(K%mb{kIuvEmvf=eOL`nfRmFkm_;@UzA7 z+xmpz;m3`Cz|yu?Pb}hWL+WyKtcSLaDg)gWv3-07H`aR^#Ik+odJ?B;@n~3{CPCH3 zBj#-iY?4JsWn-G--UTe*Q?(1l@X0R=O^^Bw1140IT6wYc7Puo~@wih+FJ~x;J&|KbJ7W6lO^lBISbJxq)gB9c zhV~eLEpr5*ClEyI>di$u)#U*Fy?{NcBZ%8AB(**lQDFxyl~!_fcCZEEU9@q{$iE zufk#6RA|X-qEj1M9D#;~B3Q|O9BrJud6aB_T93W|8(aInmYNnZm?^Uo_DlS!+3MHT$se}3NT_RjCKdR+5qg8(@L}5U>cC}qf(PM@p>DYCE!wXACkNSpfT@h)NJg}q`X)4;+v;#7-De7X(7~(WGisc={ zw$B!4i}#n+{iOeKcwaTc=2WsX1Q!}GVawW-s|?vzHtA@#K?k|@)-H=$lbjn3XC9;$ zDQ)3NU)(Si0Zw%GHp)85^&Rtv-(0MJ&Ocm##U4Hg{?iQU%?xgn4V;zr5oWdB4^!IM zuDidVS@`;>Nz?jos9&H(WT4>cm)o&YuN@;*wA2^x3~F@Ra|vEWH)l`uYnJ%PnTsZB6jF@BkM<-ooyV5a~+dMFBa$5$8Q^T*B3K1 z%=vba+ZY-`uUXj*d|Nd9c-3uxmJkXCMyIk$Vp5ZI=LxA;hfyi>m7w0g7#Z#LWz%N{=6V zPM73_rj-)a30QsQvb`y!tnVbf@!%V9&_cX>+tLxm2ly;0U5NxxW*MC zPla+Vh0+ym$-Q@HrJ^RU5HtwNdvAaLE>f76=U06TxSuNE`-cpPljNc15((ean0SMI zc}p^p>oJ9DuDelFcBVFe&)io9OA>G)T5{Nl4m}yo!sHE`M$U^+5pQ6fDD#X^H<^=-Sb;a_`ov19AK!l>2`S_va)&cJqWl>=W`ms4Srq7!5bty!{BvC&7LZIQ(Qf`VczcPT$A3p!!pX~teQyL6V^U|;fevdMMissh!i;*QJ18p#fQVh z+!r%6(rFeEaF}N5ZT%hqqOSC$Uu(Ut3^>wquvEx>BxY4nr+Xmi-rajZz==tL!KpyX z6YdC(4Ya~^^fWd`2c7COj;2GY`o;TqZ!a43xJ zIKLi$PH2;hdxc1kJeDHkKCT6S6-$D;>60sX!r+#!rJdTbh~86%j6eQ2E=2B#{~Efy zg18_+N> zvm+>rX~j^y;gW9jqBYyOC@AC`H>|%QiJ}r1va*kP0>y;GNMjuus7L% zaj^UJ;`;sZ+v~+w&sOylBL6vq#+|#_g0R}xtC!|xJ&j8}>#R2|?YT>k1GpN!IT)P(Gsqb1;<&X}VvnxgizU zPnaq-j?%DAOv))SeMAC{k<&H3F!^GCv$eUg=i~Pu((4Gy-_4Nq)IcMS(yw)8tFEjE z1eFlHw6tU6@jR0MT7acb- z9-2oxykz@RIjFZ&il0)LA^?UH8Ybo%o~(>#u6R(9$xSBJmw=w=(LzoZ(nMH)TMWd5 zOlvx-^BFeggHhB{aRg6#BZkT$7Lsluu@!HyPX^p&^ zp`u2cCl)^=yj9l=7Njz!fbfj6&i6G!f4Akwg0GmAj#evKNWX)MLpT*wttk zbLa*h()w<*ZT^{1=ep-_$+*1lI@V;!B zO|&%aj}=SGbC%0EY3+f&Y`wbRJ5cP4#k;qQk9w?qg4O^5C8xGLqt_CQ$>{~E25C|Zv0=acB@AAgb$Zp$QDg{#s0*BC}9S&t>t`)K6; z+3Yo*&zF%J-sjqM~jF1#b)GYHod(|MvGY(uVCH`7`4H09k7>V8Xqb<^MdV1>`T@L3c-%fe?>_)K!2y;HoO$H`ssA};2u z?WrBXr_q1ru{+x%t}l;1Y({7E_|{!)8whJT(OhUM*>?M6db^e<*xsBit7tHFq{>4r76n{k>yqi`1G&*^44zb{_XU*Y3oK8=%AmHE5vi)4Gn zo(7^>^s{*XvrTaL!br+pdFRR0KLqh6OdaG$7sEaw?pSX_3U)^@dj{Pj4RMe%LAm{LN84h)CuVknco z`K_jIS2w%-4M?S(`qn$00pQDjGZ;Sh$Kx>dk4I-;JH!6qr1SOoOXtYjp8Nu%y1Q{l zV+L%T8c{wfEgm&oEOyLt$9zb)lER$)Xa$h|gk&6##&=;HN3+7D?6wJS=>L{S?w{p; z2-*ODd>tqjMv37Ff!#_1Wk9&L%n}9v=caB6qyo68N1)NvklfL#2uuxVy?jA)W0#KZA_Z=b7hWPwqzU;=N9aaN6^=2GQ0J&&W% ziZsTtWS?2MK$_#Ie51_S9|?dwkWNOxzd7CbEPOnmR4|AGsi1lJxM7cJO+`KSG{mTRX}bq|zA;u&a3LvER&q>*(x%w?J3mqPv2zJ)3BLYC#59itH=>P`Bm7< zOy}*vX9KH*q)KtCiS=WQecd299jUZ7L<>xno}N~b=%!k(DUn1`OqD8SbDN$=(JGzy zsn3$=GqWbqGtdk~)&hvWN63MwHCF+DwTc;#=m?0mV5V(wIPCU2XT9UI!TH%|j7H|1 znL@-UL?U(Jt_FJNnGQg383nSVX>8B)~q0v;+$N~Z?(13K*AaW5J&n~J( zDHCuvH75c*LN$$237S)wFNhI~%fdc5mh3cxlD7aQ_f8=XrO`aFnz;;gHIll2V5@B) zc{ccXb>6*1ouhMpY~y`O&XLMpIF={B3XZBGxAr!0G~U?0{?I5cG&onT6qYB&{Gnym z3a~a<5fB2o7PMxb)YUv16PPp0j6TrHr0p3q%3ZT7m_Jm;7seekQwqG`LTBn>&@}`;1e1crUk!TPPay2 zSf2bUEHdAtyeSx!4YagOD8m$O9vF(iN&&8jx)vNPFubVri!=Zs%cOz(r3mI172`Pq zUjQbvB6lMD_{EZ)uIbc&EmSKsUag?Q2IQHvX;bG|S*`fi`QGdFF>#v8OWZpWvrC*- zOnx0AnK$cA5ebS2f-@%oLFP9nQU(OvBvD2fYjcHnkH|hoB(nr08nK)p^+U$;s`CYz z8fkNz_TkYt(5z39i0Vpyt=_GyyX*zlwyS*$LfG?R_qtoZfr~bOw>MgCZv?ZqV_0Jt zfz@AXSY!x|jtQ$F(C~DPr!j^js3f&~o*EMZY>MVlb6}{341XYrTS~sAiGOaLsEb1uNFmtx;xCQ43953T@gl zAYlSfqH0IeR^xJYb<@`1w9`MoI>kaEyH}e?dDa0uUvPoSrf{dFgc~oLrv^d3ahKa; zf^t?n1QJ$Q2x+Zw9hAxyQc+r(@P&3o8=INVxh_B25YL7~KhLJ2{kkf8B}!lJ@g z$p?1&oiCl^Z@tUw&Ufr#f;7D2HMMEQtOJL8R;rPIr+IV$&>2{@8ARU*d7rSSd5Exz zSP4f!`b3n~wq~K)2*Vn;FqbSckt{)!|5GJGfc-FL6>zSwNK6NqvTni+t z>jx`l9r*JlXyZ&MgfLbR2A0u0FAO-F~JO$ld+Q3Emd2lNMqMmGRX|U z7Fs2LCE6+}Es=pFuJKJ_67*FZV1Mv!@O3a8_O6GR5M_K<%N7b?dDa0y-vKrUPzPEY z#*KnFj$zspd!k$^LzHoEQ^1~Q<=KlSYDiD_bYN5dN*0;%*Fv+T#G550XYOf#sx2x& zbA{IyJ>c~Pj-D$j3td-xmS-K%^U!Nv1qAeetQ8QoXa%t!R(rB=I-BBGXL;6vKi~H?&%2m_ zP_Pzegdk`w9`k)tGtCX9RvV;6nNf&?>fy)hKcG{_uV9cFd@U3nBwlzR)VStQO1bxn zsXTnDV4Zd0tE&GE2cJIojyosk-LDvbd}$d06P^@)c9j1rCLb7VH}_%#aDT!WShl&v zlAqZN0SgTBK){bHJ!s1j{izi-HTz*GQ6x|FUZwcFVHV%4=rdTW{qcqNwX65B*Y92a z@ntaVUA~Fe*U{z+efgb}HH@tI-pR6&ZQeXtLubjFt&TO`Shs$EoAN~YtH5i0q4UD zuuap^;2oI<6t34HS+Z$tblTS}CX;{;qveDMX(MdCb95zL(>@&Aw(U%8+r~r_+t!J# ziEZ1Q*!Dyddty8Jo%?z5t@~ZyAHDXe>OS3d)$ZM=&sDo>+wZ!-vH{SBFy0<^LAMDIc~sk{>O;gur^wADz**4&x~Y-zKit=gB<>xhp0lF>13C~jiSvp+ z(y7Twd=orBcCqo`XG()4NTqT6(J^%NLUB&8WuG~6eo~+$=z>(m|GqLzUw)G`drS=t zP~zlaIrM%s9oyG5&j$ouHGhoz5-?k$j8({S`{bKqhBg#z4UZfnd+cwmHjR2%EEI3* zGl?iv_T_Tvml2Gme>Jsfj{<{J2bgKwvPr!1ov2Smv!uplS`tfOOy@&eIL< zQ_-?44?_(tm7l3xm=|@K-9dsk`{Z~yzFk!ktHY%Cl1k*fXs2bc=mzjV^ko;v2SJ0f z@PmlHy5q9;q()njI+t>PZ1|%Up*UCk@Whso8D49SLUC~H z2sy=%OcBZzEfEv}SAis{pt0fBWW$y}n~dXaEbxfa*4}`wG|lB}Y1H^zRG)!~q|9L> z_5_}$m`hrDG5{lN2!WUJq&UM)E<~g$x2o*elQxPk?{V^orBg7#7K$tMR`sMSVyM=LCNDH&#w}F`6ZzduE413;%Mx6} zi!=aHzgd?qF;m8BrS?h0;7bypf(lyL2{`2jg&5uk2hepqgUvcpLqU4`#AfSjvcpT& zbo!3K_GK7_3B2kNLxZzd*y|(t^-hk)I zw@asHT-S`gP9*g>^H6i`?;(1(dO@qk)~`yu0fQM?@Ad*tNxQ) zXOAQo)3Sc9Idg9&A(CC9UB-ECE1mY=x?SnJ=EnDD|9<7Zd!O=p-FKfQ52=PbI2m05 zs%w3J&|li5`YbWt9KhTDOm-)V$_aH||9Ehd(P@_u%C*5R+P@umFG+5OPwjYMuwkN< zinQ-S^r+CUu5?$_szVcav{7h=ZftUWwHhWkZ+~XQTujz-+$)zT8ewp zd|m~o9xl83Kz?qo@bGX5bO@TYOOlEKs1cw)Oe-`A=}s8_rH7vSiTJ1Wc+sbh*P>F6 zuOo1S58dBe^IXx?B6OusM@88E-LIClmFwz_Wy1#%yC|2{5t??B(8fqJS_QpjjP-m; z1pDoe2s*y2EUluPuU?e(&Z#>le@ngF`WNWGehQ#Kl=23Xp3_M7K^Xyd z4)~*}qlOy+y@RB6x+HDuYdLGs`Lssdv4#*L(UsHqMKqStiK}zPBC77oWZT_M&8Cwc zP0(9w9>rOR3EI1n_wN=K7687tzRs;F=9R3KrcHZ)mF^6Ozgf%1TKZG&P1bF-1~XMF zXVKO^U7OQ}T4`CszHSY_YI6B&&o%)M#^3dsQtzU^^lGXOz1=vr)i=%_rf5FfXzV~~1N9C6O>(jM4VPr zKA%ajHHG6h;@rFai#6g;|If1C&zl&D9D(n3OxRi$r(&~$zMZ;TQ@Q+~&uM;IA5SaL zUtfD!WgI7E+wbH8p104C=Kz3_*cO9D+j#HfLv0XsJn^Q$ZXQwhA(x=Oena0Cos{g= z*Gp?H;Q4O$^ycAnjoiQdD(_iC}V}|?C^H0Ivm+w z;mhlX_#G>qMfOwoRJ<+^JeBc=FAScEZKmNJ_*u(f>BoEDTp(CAO&`G8jNB^308Cj2 zJr>Ch^fx}T2ueOIhe{VHQY*2fTj2Si}VbK3}? z3B+40vZN1f0Lq8{m>axfBS;*iy-rLwp78wA$4Xw|n~$f^*eRRiCoC23xWE5c_flpn zi1JDIFn7V13E++G^B9n978B1>@{s?QWyn|8mvwT3@s9jNe&^i%S(15Cd6>;p@%(4&Z2dVD1V+6ucVKN2`JF zkU3DJk=+oR+#D;0E`xSC=lwQZFpqc0p^MQJMtWFCzK9ht@dmQ4NJ|19s}JVUU!2~fzl^a({V=^C+`PU~n`{CcqB2#}AxN=``UC-n4^EF~}VH68My$i^BO1vfl$x=Wn^BK#w%m-;~ru}wJ=rsK18q_qV z8&Oci(C_2P&QM$l7QDFc33?BiD5zBysYZz{I8Ju~!;*FB!lHF+=CLwiZ6Z6h&<^Q^ ztCr{@JjBDAMahl0OIc!y)5u_pcrX{7nIE{ersuc)k;{iAc8nb$h>&pAf0kd~ycR8A~m3XXEk+{yMIul#JgOK{=VpL6$=@ zz$GM~JEqE4mkc$!FgJ` z=4ql`Ok5(GQUVn3UE{Ly*JO3VkZADN>HDl8=jP{MbH)Y3qS2vP@QiU(`TryI`s=>m zw0S=c|3$iU>9Vq!au6n*{yd*g`@9qid%@K_|0dLx^+E&oP0A2zSZNdhbu@oIo9&B> zCN#<-1eG*2one=1$PF05? zWq5zixPl>dV$V?{B3Qq=srkXYgsZeH zQvYlw7fl{%HMsYpU}yPE#vYG9kKt^$a*%$S9}>;gTTMjVdm_T;ru#oF+P>I@g3aKYiwg^1euv~u*{Xq}&ZpidpGBEt z)iuaz;(s@Lzp9uLHp6XV`gAnICo`c!p)jG%b>K4jre-40e_puIMbE5F(HSeYDLiqE z(C7oc>C&5H6)ajtDjE!N1h(9iZ%yD3 zMx*b;3CIjMACBgY<#xu~fhAWGw>_&2Z$6$v|C#X(*;KQji&r>?E+Bd-CO^SGh~>w` zxN2$bn2P|6ZrqpN)25bYkTw?K(yIk4zY=A!T5J6NB`F9bgsPbVbroXy7(-5 zoe`*e$w!mTI6nzbyDweb6eqHwVltdde=^g%LjaJyB(M;gYcF|&-rj0NY|Pjv(dyL6 zWqn2p?dFYlKou67QMPSRJLNQ{+34+M3Xh84X&R9VhPjLDVcudu+&g=ciiY#xn6UKt zk(hK9d&M*O`&drL$RgXz?HtuE3Fz9j9UFFx`-g*~A+Z6I?I+=Rj-bP|)58XGI=^X( zQ2+z51da`-kH<#Cp~~{#7ie0s3t8@Jp^-ai`xA=n5O> zwO@Qy;Lv5OmTIb;7-`XKgx;NRZj|TgUHjLkK#R)RaaKM>QPo2P6+2V2c(xOPZka`SrF{$t)TD8%vj=8Tfqo=VA2|0s|=E0wvPQ zxxE$P=>HRLZHoaG9D@AccxynIK`AyW2uOwlC)%IQX^*T4N*mTP!$JgJLG2m8fr zt8QU*dYfzKO62-!V{~WJfQzP!@wb8Io#fL3Av1r2trLL%?MO0otIE)O@WP?DbHmty z6_72zx#h{~@2nMlczBj}tW!)Ih*xWn*GA_c`>U|xZ7?U(fRy%Ue0_|k830SeIMfbK zHs(5`&F;I!U5QVdtCokM;T4ggzv@D{#XCSR>eH>`0-&o@hZ};{jHgukH|V|W^0;Yq zoNM0Ytn>Z2aMbv$I5*bEvO^aptNzpEZjqP=Fcy|Yy7t(uyAFE}cazl(fT;JS5 zFirGl*!5dc9#J)=+lUPf7GPsqvEVn}r_I~ehI_s2w{gm!2WHs^sxb$ec1sDkdZf&gp?#s?E4DR*EX>E{OzpD9D}iUS_9^8Gbo^TjYv zjKDC-{3_+!SmAhl+fXYl4j;jhinasnOne_?mJVduCEeL^6vdO#DCzofY9KYpMBFLH zA|W)$MKeguSZc z`q9u3*}X~=oP0ZhCIkG1rp&z3A&*Y|u))Z;nZ>gUWc>L(>%*+Ei2>eNnY?-!O@z4{ z9F?wjg?;NK)QJ!wLtcu4tz}Ww^8I%^9+n`NZuPb?(X@%Nj+hLS#lo^!Yn6_H)%60? zMp~$QxDDf^kgPLhmI$zd5dA&RID-=Hc&YTQ(71{2+QUdb%Q?WHsZj@Bc)YdA=AnF4 zwswL-E3}4FwXJimPXEK8{H{7t5?qoldwAR)p_V_}FD@QxO1=m*iEh9W#8U_dQO}6o zF>qdZZWag8RF7N|+&BXV5y;#WRYd z&^jcFv=hw}dSK@{X_Xu_Z%dlkU1^4+a(h55zb;+~di1k-cAQWZFcKj@7LiCpgqmPPVJbXIczl0S@1JG^ zluC9BA3?~-i3u><1x&&H%4>*&gAZ8=wfQBpSM)`eE5zD2QvNc~1#42vkf+E*t>*3v7#@3aH#Fq-7 zTU8giStxdLl`eOsTt%ajcB;0$R&I3I`^&a5yJLk1$&_-1t-o`s#JzjF_ZaBRX#Y5s`vfVGMQZWRaEiOi*uU5;jYpy_|_3&iDpskbwSY@TKaY|Y@b%(4PD z5UtbY1FacIwpmtvtr=9dS+D@y0X))a6~eS%B1TmRt2F3+(@91;^>?!QcShbN8c==~ z8TnTT(2qH0%6`xdwih_hu)0u-1fe%{U0|f9ak7l#{Y|orG2>X(py~&fKk}rpiyH-S z-s6In%6m@&lCHSa?wL?~Cm&NOy;m@RtqRX@m+h5C@?ROuoc zg`a8coxd^W<%+Cp&aio6D-lVn-StM=E6RET{(7Rek|I30+j_~Z-u@X`TUQe)Nj>K; z^gYZ9NKxEegVIQDViDQ}fy2zHQU~Z-oFKJ+gdXoLU1NFh(rUgX2^^(zC$QvJP|2u8 zOF*D;0fz0$nDG2XTHLZs;KXhuvFN4T(Z~rl>O)k2f!xF8L0Cwq9~)D0ZLaMMPwU3 zs~3K?@Z2MkkOs&&i0}r;o_{w;JOy?jV~>6f!Fvjj7yyuQ$nm%w9l?*aZ=mdVh9XB1 z3I6oSQ1bCCsP;tYTY+2T)rsu&*G0qgKf6^AwO%);Au9TmbY>tZ`9N-lmvvt^uV@b18g>1S!F{wTpxH47Q_UpX0$i+=Kdl zi2poI80aagb=`Yr^EAt@Om@nj#Z9(Z-0fs&$+MtDPUIK5(aVFF-26IwD=Y)kuvGZg z?OypDVY;|?CM0G4pl+YH^lLHh$3jiPyB~Oqju#;BN@Tx!N+@fyx|(oi!Aj>$JaF+g zP@q10W=hwh(pPatcXP8yai$}kFr~M%usP!7{B8|XPkcy1Tx1ZrDZ-M*P_0%HB1l}A zESmzgv3q=W+-<9Lr`bIr@_xjIR*>0Ts*hG;KmBh)I-Ew!F^DtnBm|WnE3_kmXCK{T z-!@==D!RUj4D2QrJ6j-8AlG#Q;Bi+8~F=@weOMUf|&gFU86LAr(L`x&hXn?S_{o9{&UjtdQm^xt zpicfV-*%pGFa7E#Q^!oZ@0o^j(EpppLIqH@hUe{sV~4n&iQdd{m3yCI9)q6b!NOw3 zkG_z{jfAc?f_Rwh#6fb~gbaonSPpzI<&jHFj)21m-oFPvQ;lV5=*lQ6M1Rf>3)7Hc zXylh?V-&+le0GHacNW57EH66CQ&QYwYi)!}6h0Gx@39F8x_Ij;Q?sFAu{0Bn01}Sv zERsrA&VIuOOTNQ}Rpc5Jnj<~43$R05BFzzGNAM^sB`LE(`*z}Hg8!pa93m*ERxZx~ z7qo+$2K`4zZH%s^AQz9AL zFH--dvPuV+`{)6%bGY_E!tdM|hZ>bkYx^z-{jewtDxD=-=mQ z-8ufMljs2q7H4CZTBbki5wOcISj@8&{16=+!Y{3Ef|&HR$1;aK64d1NPtE`8-DbQS zcAxXpu&=OkVeS38tQ7@j4VR7I621TWdPQq}Z++$mT<-#=T%8(zzXo$_E{SEKCG{n0 zx~!hC^W_b6Zj-?l^42j)6`M-hZKrDM$z;%0tSeV*?WnH>okR*p*4>rW<>zddYch{K zZJz=#Xx~qrO?j2mlzQB413}$x3`zCEpZCPUe)Urgg<*PAVusU_uAU6$on;-R za}m@=x#a;C2oGZUPr#5VCdZdBjSJRFU%MVF^l4q}{%C?!`ew&rqb_lglU05-a?s%` z?@qpsv1bH1Lt-@pJYw*c#_8)z`YL*U=DX9Qib$l1lYE~_5Wgj z8qlV+#}&S$4Pi#yB5Iu^ep7R{trez9K>JQ|09ON$Bhw;#YdVBuFp^&iqu-qkpua{8 zuPPi0_8G)9Qbun_+hf^*+Z^$%72XNVlUag&KrRP||GiWYK~jkH5QgS9HKZdYnKPC< zUM}{u@m7k&HBF%=^~OG^BK0FvB_E0Ahef2CaE}|v!G7`2!{WfPS*VvoaSvE_8vSC_ z=?oD-F{+y*hLs~am?YjCD(Sq>9vR|{k19DBx)n@BJ=-lZDvdhIOT>GVcu(vWk~g2l z=>>NrCo%b-Y;vLbG4fl9u{yF_)EA3LU)6Q^R~6!-u3$be?Bf=4l2W8gF^eIJKjHp$ zZ*y7AaYyIjeBY$d)|W+<3v5#S3B?%&)1fKyTLD>RrOV_$Fi;Z>!hHVTh!kIeL? zuBVJR3>1!RB+-?lWKC|ik(R9(urtpCA;UoPZ4+5I=qn! z!`l02Dfo`p#~qg$Uq9q*7+dtX)*1SD#vl#enDXY^O7A;75q;Xn8k#==I-;vyCJ__? zi=SEf1NGX89hh-C>1`5e+Io@wfpsnS>|WY()waDdD5p47Ssz`?7Z@Uwr&Qid;QIBa zmyf;@h@#3>Ge@@7%!}bGxqo&|Hu^cnI4swyTR(b;*9^jBp!C;W;4^xjEBc zSB(Ox$ng^psr#Vl8Sx{&;ZNj`kA>Oxz{c3lO@uYZc@{YH^7nb}#%QD9GppZE!#>Kf{(xhzb-|LUpWS4I%w5UkQs!y>z_qOEDhVtdmIAb7T)Re zO(Q=F;dY7h?Y0U@<|d&$5l?_nTmqJAulyTAl0V&r9u&fS5P$;Z$wo}iSzSWEGw_C)yJzy}x_g*J2mZ7tIRI)pbC-5KZ(;#|=N?Tpvj&33&-*`^ zpY=V`1}`}nv|~t19V8#RK7Bb1e!Vt(>kRZemtA_EwsO(H$Xws+eQz3o^WY@TCw|Zagsqall4l-R(RPs zoLYl8Wnqo-9{7eEw=u#5-GAC+N&b_LI<$2#G=FWEkw!rO*U#=7bMeY-+O5RYK~#q` zoyUv8{}Y=8q3^NkTL3OD(FO?uf(8Nt0FjZD6chUw(^8{88CS%D!XG}Hes>NBBR2M< zhXPLr(KSNLfBcdKzvlMJM$FTbv+A%OJET(Xu(7L?5Y1`1fcy|S4=~-=1k{mv>Aa^CX&$JkJNrgx}AUqB|xJJTLbiDIe8e^ zoAzQQ=Shl{KSQJM&2mu*k%WAz9xKXj@wtydvW_Mp(u<&y++LbM`G__Qy8& z=>RRK;})mm1R@}N5NdWAYQ||$N9R>(!S6(P(Qy#3hTzrHs;Rlu#@8VR1oNBTFO5;_ z6vPBow$2P?`sm7uiT!LzVgU=sn8BjEeQxf4JZ(|V!W^dpv_qZzzb9y;K-#3`JJjCd zvrU1~%%JGdNZt?AKzgB)c@AvsGrhQSWSfu?a2qX1p;JJ$HX1+J9LiN0B1@ni>bk#w z7_55_U(%M}{M2Wi`E+ECM6(bP`5*mdZ}1#I>+CD{6h|960qv6RZ$ru+hEfif2k*d_ z>O-{gTk}%LyR(^^?7AVaDpVLw19LH>!;Y+0Lw`?&%W;Q)MW{i%UQI96fGnGN+S4Sc z+y9bq#_VSCO+fW8Fc1(dV5=Z0CeG|)=IUx?Z{cESYi92HPwGR-OgCIG3r5)Pnx3S2 zxMWRha4?B09foTXTC+d|3SzoR+Ftk5^P+J-V=&6rU0^)uP-&II)YcSjJ7-EYl=vpD ze|(16JZ(sN?p+p@_9I6=!1e+CXxuwLItZKQR864W##%0TPVHv1SEZhiar~`hUjMUr z0uDnX_fTeL#qxemNEj`dX&2+zi`3WWU>+*Ne8m=~Nh^$V;@x>eDwlJtj|f+X zG|83N>yzvhe+~NI@b44 z*^6?z&;MUY+kB@%cfg?kJEWdixvH9@A~hJOj8 zrLE6{(f}w&ox-lLSHJ4H+hD2ni9g(S;U(RJNaAdx;ev!&V5}8r#UBS(OHgqFzp8vu zN$O38A6o*8j~TS~)HSrYe6+B2HJ`F~r`VR4uQmjZ|K8r6RROv?Ki`PI4i+b?s<4GT zQFDd5UY`f^E`j;feqcUMRr*?cqh%n}-MU)g{2s{wHTO zfoOX-OkkXyP_K`l&&Olc*`(p;?egYi7W0*X-#JE`D!g<1M-@up%jwG3_0eHf7Z=wP zz{6oXyKAW?Io)|(NGki z+t2XFc-T?FFIS(tqu1N%4dk|SGJ6PCfD3!vCo%CXNO_o)qc3P8c=`@V959{4d1ohS zk+qzg=6fr5047r3VSpSH$lhMSpvdaLOMLq+ODHHePP31!HffR50TFaNXo~pSiSrN% z7u*i0!A-O~t*{KJqH=%~+zHO9Ie0Uz5j#yECfr;J2zqMY-rmk4t#EKqF^zCM0PIf$ zDHy)grAk8UREja@j3EWM?F&bX%Qs!Yf&8UWoP?nODwce5DBl&XMq|4LCoe z=14hOp8Z?|g%ZLEEXXs2gpho5fMgxgxG$eHf*wVj7;K_pVt_=DFo-(^zEFt5ajfQ% zJ?N8Cmpq?Yo#)Rl7r1+-OAu-ufe=9tO7QzoIDj1|3 z_Y)i@t;|F@aL(M>G6v2IGUPlc!RzY~66WO;7Fbm{s3(m+KhH^|_>)WMu8 z%C{-x1#2KzbFGP*Ahf#$J5%R zC7Mo3Gk~=bG5L)nppM2`#z|HUqmV2i!VQv=#ci1LhH*H+SV8+fWjKn5>P3AZs+qfj z(RKBg4o0Dz91+uk0Jl~PGyBwQ6;gNH0%Ndl^608zp`5Yq=E`U3*1K@hEUY<0nc zV+2846}LYPccYl3ssqB4cmI+%S(=!tP{W|osqngZ#NE;|L(XadIFEc5%S48z3_X8% zq@C4hffiDqCV3r(&6ymg8?`Xv0UBA&`HuyrX6`k|D1bAtQZFiK0GrUnRK1Xpp*)U- znr}eZ1EM%_spuRw-p*MCoQh+|@({Jn?_|t;vK9nU);k3E0yX3rMrNq(7 zOvLhM0zjhLK`qnypf*P*cr=j+wudBR;BsgDtRr7Kh*Abm9)VqEqEBO!Ln--BRb6%^ zm`rry+|gPANGq+tVD7m<_djg~?d9;Z^2^s%%b@)8Yl@ zWKr5&8u=CG&RxADcsP2hZ1aYAxI9oPbO1+@=^-8tbbXE{1zfpunK%n>ZK4e4H%1EJ zQa4kN?V;+0YmLaE|8<@Y@kH_JUj7+%wzWq=Cz)w+!)f`JX^>^OCP)tS<0bj~<*DRv z8p9#I>WMar6QB|`<_l1vO$)N~h71*2a*B*;7}ivc5pGh*?8{S~yY_H&6u$w#tQz6sBYkN7>5&C4hX$ihV~FAXlUsr)xOwuUHe!1W13*MX^mfUkgyVa5O}EtRi8 z6Cz<~ad`~9Hx)qFyOh=4)7w1D+i?qf9ItFYIRlovGKbQVq4ywG&c|_T|EWOPn`-7H zgXUfyj_kJ*Mrp3j)20LzhMYImt2dQYwQT1=XlVL>IlNUokXGYi3VCVj@j6(RDK!(; z?m)OAzo^38|LbXQ?+5esXYcjihS29@FYxW>>gyH|?(lgv{Pp>{A@p$x++LUgAA88# zpR<6En=EX{8_xt~S(?Y>x%fOsOUo-LN!qZ9)xrK+fTs(<<=gDeYN6kp(C6L5J|QFr zBCqf5}L$u@}&QlSsXocZHs@KO5ku zkyCufp+)PPC-!|xHR2BK_35aIsu>D%fN`}9{1c8e1{n$^Q+u{BW%3Nad!qN`r1d1J zurc2VtGOFcSHZ|q!4uiK(p-ZYVeCwfNM&SKoS@q8mUD81t}Mc3WV3@T2KYWuCq0f^ z;G5_(9&-(nI=FK|j*7C}Z9GpQcOzbKI+%n9u*Yw3v7*(IpbHZ(wc#3L!|!fBfc#)s zUI$S3xf_bi*L-@+TyJ1pT%YEKK~!MQ38vHjhw1%j%9ZV*bNfXp;asgTJ014zMF3Gi zE}`ShiHZZQVLiC?8Yt&UE@3_OJzA9POfEi1ml(u2KOu+QplpS7WIO`f4vJc~iQmq9 z!kp7shd-^@td?>%yaQ>Ja=Z&3z!`{RreDaEx}fO9)b4%nx{oJ%MCtes8}|%scliTU z^KB}OnIro|?25Q2loWHp+hhw{cx4sp;C3IQaTda)aV`R2A9w+90SqQrGzGtz6b(^< zDsd;K^F#_!ff=u{4*LQgJRg0JSDy9d6M}t<(gCPrJ zO^xSuxzQsLfKV{(xdH0{$&!z!g79>Kl7&t@t1vCKyB7qI)b;K0{Dlycye}m%swBYX zj4g)MFd7dLnf@hxf)(aXE@WT2I;-OP&Ha(u#qqj(bc=k~E1sALwuL4D>z9=3R*?X= z=N7r0nPHH5uHx5bK*7*sUUo&MgMS4NK5zUF0V3m6Pw-YBm=Q}_w)_!rNxYzV z8m~oCZ`ByoZ55m*uSt|q%~9n#2G8f^Ib&irYqF{4P4_o8`P{1-@t#wj4l`3Odf8JB_v=;Lg)AUU( z>5IB>WP+qQOV1f|vsrV2qL~R|<5_b%4PFcgo%N=d&R1#BMDKdStQ5PfWePvbrp87c zuixfo9ih?U)l#o>796@bo&3nW=^EacIn`H(B=lv>FV+0lIN%*J>_xe>Rig1 zpq~8{bk&W;f;t6`>|*Ts@yvMLI^;vjvJ_}VdeWq|8jFRh_4@(fAShox zO^+T}sn`9Ew-H$)wsNIcX5)<2~DE^%@L9!Pd1 zgo2)We!AG}^=o?eypR~SYUP~Q)4ty1u+x4%ViQ8=Y$>8Zgj+1XgTxN1s$Zltp zyi+xS7NbAS7JqWs=jYv|U`{q^GE8!nLITUt{>NyszT;n-RV(Z}a^~~^(HDy zTdx|Zo!pgm&_7MOR&o`xeTaE2(Czz8ji*g`TyxNRFQxovS&jD!B17H*$bM=?!zkB0 z$4h@X5T6s>CdAH`Kz#do4|&d#KkBAfK%cVJwzw-1>{m+#`Up3Y6*iXI0|j>`7!P&Y zl1sivk^KhuJxRr53=5bAyp(9xS@oqMs1f0nLhZnZ(S8rB0Da!s5N7BT=xv_nkuh@| zq`v^Y^enOUE*U|*2i2mYoy{y}P*6o{Alea2TC!w?@SUM*@m2uuIY_$gqvilLyq58r zp*EYPz5uygD}EbbNa;U*DrnsQ*?9UBhy{|L&V_v@vq;5XA1)f84SmhcE)|PK-Z#x8 z)@L$G%mErN_i0J+QUtZ*)K47i@@aYhu7ZDkvR3pXnug7j{V6XqKxz~}wv@~Ik1(;L zS=5M*8v8_@f8;-?ETjH|YOU};pnT`KZzUM}uz~GywB#%{&>jFJV&K%ye7(3&0AH#l zJ0n14AL=!Lo|%2dyFkVNr^0_gG5;4R#Q%UY4IlYQXblQ1f6YGAQ84c!#uxBrZdpzj zjIU^k>^KS=TZ#@e1pT^d@@&Nc;I#4iu{>S%)Ha)^ZxBiRF7$8a3FcJTln+R5lY{?< z*8@>&bDIMN7B%=ElB+DanMVY;{|!ij{ZrIMUF83xH~(Qa4^z7Bfy`#;@iopAVSu`I z8UiXKI++}ox(?T&aW(JALp+)K;iiqMasZXsa1en)J z^$RJkVq#@$AxYh;{kq{}V*ui1D7%1Wlm2DxVqk^8_o{{5jHOw`8&(j&k;<`g_md!G z5btHE*k}%Ngu}xwO=<<6OrLVRLppgU?okZm?k+##lQhcg-BrY6?~y%%^q4hrhdy%0 zha#*cz5wU7cZ}@2Svanv0Fzh8OX_JA|XV z%*GVRuY$w^z5O4LODX>^q5O}>=@l7i$EW0&TMsLb_F^>QoLpU9rfA0*Xcc5MfQ;iD zC~W78CzRJwN^vPRWvc1XG3YR2|K3a_PlgN%>-JJ&%sWPVjE}K-u8Y5cjEX;!-V`jUYJZ2>JRJs_^9;NZ{vo+Fq$LeiMZ{&4{uKn#pPNJq zVnGSrZQ+Nq!9pM>fzKU65pz^WV~}G|B&Td2)7wTGM*d;{Z*} z<<>j^^ksXRzAz4@gY{+&p?f$$rk2ZTlaO9V@zmy*hbL}v*4wYfIZdJv^JsgK;I5zBaXz;~U8$RU`6xpPL&HSnekknl$_R zc?Uv*(?g{qRO=)jJs(#+{~yxXDgkCQ9|&n5*sK2oP4d5?0sh^y3FAO)7!oVDxV8G% z1iTFIi6c0Lb&RmXbnTXSU)?Ci>jv(}EWgkReCjTyTlN?mEcF`>wV&`hL4$_~if2(orYuN2S8^6S!JP7Y;j>xu z&0`3p-@$7K6$Bv;RO+)ZN~EbzVEI}9lO?e}ktL}Bpd0LP%@vSEMdN%Z?-A%2{0R*sLjZ6(ivkdy zklPP=Q@o8iCjQ_m1$Udjb#pqu>>*i3W8QbqtQGtNKEaf{Iy5W9>4hNm#yFfcq4-B> z2<1o*tnvj;1O+x99%OqWF?NO3UQ5*fxDSrB$P=lpbOu^IV-0{R=s__9v!3NYCCt>#E%AURl`$}E?ZXH;4)Ne8k*Y&#IoMR|4ERaP` zhph-8#wl8`w6wX!scQa~Wji_=jrZaU|Uq$&|0@FqvFZ-sK z?z4nW8U<6V)j>r&{TnWE+)L2gLUxnmq9fN2Z+@=9dClAnn-qo*fp`EsLCq=YAi*7_ zKNGiw1u&X4N#Iwg}=b}Zt)2voMOTZJFa;&VPBTz{I#)2zUp&k&?3pH?nTx&#h1KD9-X zmb?|{ue36-Th6X%SaShGSX-dPkWhG7RJNn+t$_D$k?UEjB@=_f7iQMKhkw`LKPOm0 zhxuS##868Xcakd2U3_2e=sb`AoaoM9Hk8Ol;p`C7|aQpms z4lGDV{j8;#Lei8xJ>bm+zoUWXy-D@(3$(yS?tp1H<*LWx;!Z02|Zc4G64)&rcd$QH{?@_;*-;VFJqGEj1sEUlm#&W-e^(>=5tSCwo z{$M%roUo)CRsMJ%83CFj>TCc8rcpLA50Dso5#BR`TuGEu*-|vlq4?Zx zwIm6Gf{}nDvGLMVyi-SkDIQWKG7~Y_#y#w*N`?a^jdO+hLh-Zm-B0Ys8tS$K1wB%Y z@=8S7kGH!a#ZxeOA*E7D#4hC+M37-EnJNF!E{A+R!Ix{p(TH;Ap%`_-{V`uEvVf(< zufGgA45(n|_yU~6(Pyecwc^=YB(+|<;AEaghZ^dL?{qai$sE0AB`l{sr)Qtz4Ch`QME;yNl_n< z+jfL0wb5vZjSq7Kf%9QC(Ac zehu3i(gLZ3v!@!z58@dBu76rrRVbNmOOdqVjO`z0y!WKAm$J1{kzR0a@QAW+w5NY1{)l1ahi;b zDw5g<%&AzK1mZfHOk!yjip{blH#P!)W@Mv?E@P^?A&{Mx`xTSYWj8k{3#eQQ zVgUjuwV07SMNs3vhr#`}=2q zf7<*})^^>QBnDjt*-11^qI5noh3H3#v<{hE;mEaVKRZ0&=qQ!pqXdcQr>%LIUd3^_ z2(Hb}^UXi}sSexWK|eb{K#uG1fZ;hj_hxjCCfh-f^yo`a|J$2tsu?|};0s)<7irZOb>jm-HGXsSgfDXHR;i5!*u z{E-u6<`lne(fjzYa7Lo*2(G2LmSmUazziwHS<+L8YbnZ-@{Jhw z#Kj=Xb7|g4i*lI250GEnOC`oeqfFX3a(tH(R{qne7jubxH_4k4s7-}`ZI4RSl46`1 zrM-}D0Z`|zjR-#i7y-cFKUlO9;h{9Lu6Kw;5EO$~G7_NwEH(`^4TSn%On^~`HEMHe-g05vSCt4vIn>iN>i!0h|8N;u29RHj9OcW=9UB;$0=-G z4Uh{+-R2L;s;XdcHW1p4ai{VXaXaw>IN;k@l%JzM6f$aGH!KqxdA7LLmt*v*k#< zipu1J+ow5X!Cb#+K9!uhY__Ts86M{$uFB$IW8?WQ%ut}l z#!;F~rlW|q(zz6Wne!w^wB&-D6E2gUq3YtYh@uBMQt*Btdq{~LCf@2qC32W}rxRh) z^ruUxxR_onRq;ls;*C(n8*?g_y%OaIBrm-FHi|)@`p(DiA;;9*xmDk)(#{=z&#doU z31|%|l~PiM=W&M^^F6VJ*e!WN-?#evj=t~0v<>Fh@=2I~PEfcNhYjvq)+KkEoDGM( zJJvxTHH8}v){iyple*8Nkr9V;?ZfbkMQvQmA!bh$2 z307Ot!fy43H=U1ik$uGkgg%XYz^ABbV4jsxiAx=i7->vP^-xBk3b#NeL8lF}qDfF@ zFi=L3q$3=>C#Yx!3Jy86cy z%qiGk5iqw)L6-cJ3z|Q)VKVrMAFu1}n}c6YPC3uv8&*IArJm(4u!c8%Ee&v;H~j-J ze`)^^w+%5F{@P8h@@R5h)!_>kWLf@}(I%z>VE{9KTyOiP1P}uah90ib|7b+J8w1U)K>ZE3=*O=Y-N&}DqWeO^QgCwPO zbtySX1zO+#ag$@o(kd3L$O33AlAH}yz+jPojh9TOQ!`le3~}=lJPSx#+PGx4a-k1j zv(a#0(?^6V7E_YjCYjc_gY2Ey1t(#FO(#%~(bZFn*Rwu{9cbi+ob>~!t zh`LFJC2XQThfN=e8SrgB>pXw9DPY!#O1S`t6qM8xe{3Ud@y7@jM&XK3eNqWfpdCk@ zUamWw(Yyb?3f=;>t47o;RjuJb2oUanzk-mK#I}+Qf^HzJ);w5`5bN$NQBx<4)A_WK zfG$cK%9TT#R;5bKxmrMXyPZ3jPzOg3<(j$Pif$MhbE`uOi&TadAu>aY6rcJL9$Fzh znjkZ@6dw8!9$K>f%MLBYvIh+dTDw9Kd{rgIXyW zx7k#A0N;QqB_UudC@EVV7nwwpCj$X~XC>}w0H|Da5dkn)Lv;z92I1Ej%TIDCW9T4! zlZ-|ZeKwKCQ69^JG~ls+#Nh#u^?uw5nrkmloU=^1`h<$xP-|Ne2g5$Ps~hn( z$E^|-nzh;}QSG#wv_)Bm5%PX~wz(;1=q`w!s8cyxP z(iw;PsZ=}n{ng6~nKh6W;jpuRRA&48P4Bz`i8;rmkA>WqkVj~O{{Ty0WnA;kPdb}m zh3%d&Y|rovv%QSx7u>yn7^jR#4qQ1PqbI*ZM`@Ydf87%Y-MvHc>doO!fA8oJl)Mn# z!5}UQ$w(>pqJ)bDKNfh(vc|3qBu>9z2Lou{DF)XuT%>rV^PEC$@#(%T2vT-oU;b#e za6|VQcB@nvs=T;N@&dKZAS&>91RU@2fCwu4lKUA@8*mPU1U6oO;V`f$r%Er@cbe)Q%y2(p&ykdu1_`lUIn^tV8LN%-FSSl0=gK5SVo{Ar{dWnHrqs-~ zmNO_zN@iP292!(@!SUX=*wR9!F-uGed>)Up4>7E4j25@!_acHx5!4T?&9r%07uCw&Z3u7$se-E6+di-Gowm=yVE&sND!o*XmP4hIdp8f;`wIsS1bT={kjT0_s6%HJ30olFHq%Pkl5+-03frJTO}@_$H#ppRibOSLJAr}BEy<;)0<0E8`v zijlQ{gctxNMigLd=<5rR5#d}F!Dyc38Azn+dL}+4p!JOnb}7Kx7m^%Z3M!zCJid(c zI2|aVlFTt3+6cGy1x$!`z@b1S+DUts=xSP|9JI9vZHtc+z}K`4L?SzvO)*U;AV&B} zDnw2#gnt};Ol?N1)dGu+ouV*#H}{K(*WfRIz_`QPyIwnQw#lTe84{#c&0uox2FMCj zdzNYr?!jfK#6SnO;e&*BAbA^usYm#&KJXNRA%STOCN^rXfPdG>5#B6-RV(oDN z#g_~Zr(;^&;hcnyU^t-Q&YBce#aTZ6$aQTG@?KZx@=F*K(uj~Vm)EUBr8`MJ7{#=&)yBQ*DQL`pG>!8U z{IHu{=!_!iHa@TPZ!VE#2Kjt1jw)d8 zZ4Ivu2NQ?qTfmm`%1&^0B7Zt}rLJVAT-;40Rm|lpDb(!wiS!SgHXS5Ifx8FDKiI`6 zGyo3#*nF)iFW|~%z7E3C#Oe^y+CBb*fAgyVNLSbeAG0L#U*KODP%m$P52LXz^2FUr z#>5?5{^8FT5`Kq*&VUkAW5GZKTfg4S?-d?&|+h;c61?)r7c)-SEKMf zkLQPAc ziIs)`^G*E-vCY6)#VU`Nt7^?lj!lvp>5YXi9$mo6YBfXD zWvKKp0VhyNsP+MHwuWlW^-7^(5{8sq(~i#i%kIF970z0LM+3pJ6p)O+YCFc*xgee3cRV`lBO>VU_&QF`0ttY`r zDnJ%gq38%r71hCD@EYo!&ZSh{w;BeHr$)ChU17(#$)YCxoYI5CU#!291&<(}j3G?R z0>e@g@yK6)zXp{jW@VnM%o-Xhys1${0k}nV57#`t-T_nZf0WAk={Jq@O=_I2-!#q_ z(Kw4LoX@6laK+otPH?9Q3vj)Io3~G#rMWtArh?KGJ5es025O>^AQXLoPm>3w_Gc8B z`l1*MCa|B~qf%h*j+0$k>U{hSgH{{nYI~M$)@vw#{fSpj*)H4nW~a_CNiLLyhd`wo zU_C+*hCb-J@Qh_7)7sM_h9yv8#}pzOCI#%OW0sL24GU)=YEwf=4a;%1KyCL#=+jKQ z3Aj1ywozAMndSnxk#x8k&?SCmd!F^^#D?Jf4)5i06}9|EtU;$jcsTxFldL!`qrCL0 z*q79Q9cP8vo09NU8Yj}A^QYM$v@L6DCT+D^;(IyELHq>OCfE(cs4xm|ttYS9pVWAN zn2q;V;e{SPdy4(+#~*YzjhdPVZN5LFrBe2&6(*81oba1XWlo^0B_Zg1Y~lUYrZz2D z)?G_oXca%}QUASo)_HD3V{v*vovnXde}|KQovs&(JZp=y^*cA?4m0lCY=^_PZ<#tR zkIcr#!w^w-htcTK`&d?N{Zzw>t)K4wPBues`6hUX7Du3EwJLD-C`#>ldmG(m7OR=U zXaa-46sPg%(%CSd>_%mz{phJ)HKJG>j8dr62Z)8mMu^_Wf2Ytgs8sZK$4qSK9`DV6 zG0(w?9$e{LyojDL)rmoY=LHyb!iK^q=-ePYZ(}eU-A;|RwypD6$+3nQc{dBWJr5v; zg%1QUFLWYcxXk926$JPRhYDgbi(tCFW8JqX@-yDMQV%^v?C-o5gw6a~%b+qsbv$0{ zH^@w|Z9!bqsYU=?XR9VAsX; z4J%-kqq{_(@XDe)bax`w$2m-7UCMmXRlArF)LKV_hOlPC3~jKa5QFP@fNm0hmlzHz zEy_LFT>OEf#~i+6RIt-&ei;p7TokjDcV}ItkRUBihD#}Wzxu_@V4hLX_pnr6s}7sm zx+%)v(($WgqqNFAHx#<%9d&0t>i`{a4*qo+=hmT^_F!%=!EQy#a;(N?IBru5b2;ce zqyD}`M{qf|_RPZq$Tm=Y9LOf(x7;Xf;5^ z;zEEjkOMn4K10{jEB-b}8;P=G7fIwZ0z^3fGecwb2}hl1&p)TFbvgue0l~qn3k;L< zcJCuZiKFzE<;Xa?#Rm|7MoC#>B7-c#R@hCagN@ZsRA6c7g<};jrP=CCbiMo* zvAOlc|15L_EZ zgm8D;Uf$A|r#6uhKf#8?U^Fd~53v`W#UZYK$4v{PrQKvdu!2&5ISu!gG@cEm3*$=VL`= z_H|z+2eV{JLIq=g5LHA*bp$TJm`p?zs1>9_cXJ-Y#YnLGpM$Hop882VVE-S&7ozaN z(m;C|{)ZM4j2@r@u(t*6dJWac9l|}RQJIwT7y37`?oA1Z+@1j&; zB@Yk$C`~XOolwvF%Wb#!XDvj99V;EHBc>qat(_xl$HL2#rX;c^!h_xtv=_kE z>!judIrhJQARa@H!9y)G1{DtQ6)M_)lM(nJ-TO_AvlZxeHYh3IACM~58;mOT3k*c6 zY2F~zR6cqbdf{rtiN54|9aI0|449-5#3E9m`ywgw(N!!=kUy0UZ=}R&nVXmBNUp{i z1$h7veb!^5es^YCPy{Vox`2VJAnYlXsY4HA?d(r~_K^#(my>L;6*mdE-kH$laIs>j z4@D~mjv@6y!z_G;Ye!+=IGKbz)Q0Mzq$h3qU6E#>ba=@q+tt4qnbQDRjL8q!5vE4b z0?fk8Ok5|~^(ZYSlXqIE5ek+O@Z*JEPq7UkTkY9XMuIwm!BW+QlfQ1`C4c6DvtTM2 zXSw=+iyCo>hdF>n0$^;Cw){t3PegiWin8UvIQmF}u))@_em1N`X~l@Z8|uz^F8`rQ zY-IdlEXjz6;^J1<`hOUbZL>aRU835o7RE}7FrMvD1++CX;fA`c1pCpieX#zJy=Zow zT6*Q(1O-o2wdi07+x2H&tyH#lL2kI@0Ps9gwOFsL%c+axavGoR#D^|*7s=_At{>oh z4k>EM&F2m!g5F_>?VUH&R3&Dr(T1dV3|Qim^M?HU7XQ9$OC?dNt9fnxf3xvg-$6)D z-IQP{Y73KbYZiZP1?JYmsJZX10&}M~X?1hekGdO;Yi8D_NXbClk5tCYySFAmSE~{z zl!SI1GMH*R$B!{*dflJy=1e?GZLoaV`G@TQ=y)Uew!}{X1F+JX`Y9@WLQE5z0Yz6m z->?dA*gSmGW%7_67ot^fHax1++HN;}-p<2E86f;|Wz&BKH>R6|D5Y?F^t40E*~YPz z>c}Jz4G`l1N`QKKn7=2pN@;j*Gb?*GbHl8yVAEwG$q4`W2LVU|OTwCk zD3wtQQL_$pm%Xs+{Snu-CQgBJ#;p~s`3ug63l^9uBQzh_3ZZoaI+Z1TZk} z@E{vux*N|nch>Lk^-gm==><+SU;lK(a!pnb|EPaOgyO9N;H-lXt)oi_$Tf=O>O0GC z_2?%)%KSk#@ef{9gIBQ4Zjx1Bn--W1x1;?A*u5Ox?~HmcENb}N=#!=u|7|P!1Hi^=d1)&~=0dz-w(1TIJiN%RdP0@Pd+KfAp#w6nT_7lF&D;Tl8{nh@F5OJGg_+iB^0CbkIq4>U5uvjzn$Wn zj-;^O2K_&Lw_?o~@_mFQqFMJEma$R3`?3IU5r_l@et)B#3sqHzZey;w-EV4DzSuKr zhJJWp)zpRcb$?N>1%n0$gS&tI6%j{GvKvq@u8wmtvv z`Ev1jHRjBBr|%VvIFk+l+gdx4;ALe198TLY4C?-=3@7 zzHVC{=zqJ@b=L-V^+v#N+e<4l{EQNtqh$8?ztLls*{bGqp4C-r{(Oq;>+eB*Z8i3d zY<9V)v7cAB{kCzo>h-N}!GA+)tg20xJvk0&!bJ~}t3~IZCx2#*_x1PRzL>_F?LZyg zxm)Gt;MdWib^CoQ(V^b? z(*8caEhvLn58r}Zl_3%1`m^iaa9tE(&Yr^GKcGMHd!Z^<_+_VIjrN%g*x3Mun@N^m z+`>SYe@~*K(0hiY_TlUw35cXZXd8T)K7>?Tlv(c6Zfc|*1ognPdUOKdn*iHpucx*z zT7NpyKb8bGL9O`EhGG?YP1YdOFiy+$o%L&oIuPe@tjXS{vs?ye)=f&#ciGu9M!H7! z&V@<3B;(UFw=q0auDPHt+?i&ZToBdS{x;iGK=jqwVbq^;QFoY>UiuRKkomN)K5m=gKvC z1slk{-M0O(0?SeHtIie_WX^m+4g1L@JQ(xyws_WIZ&$DR4Pl%@0vr}WN|i&(S=q(J zoR2T$#HXG=sSnFw8J#ypqtV9yK6yy*1q)B_WI0ZKp>B5?)6b){fI#)(2H7r0LVvJOU8puw0vMWl9agOF7?eNSP`!sXa}^1bn6s9~vvB6DX_h z3*yfDJ0GCX=Ssk)SV~LiE662!Bt@>Ep$a z!Q1wu>?#>F^kb3S&oxlX6ML_C@fxn9e5fi=m`P1@<03T2oR;vsZ*`WT^tqHvhFmWs~Z>(V2c+9LZW77CmR8dtIna)^H8(H|(OdE^O8gmUvHPRnCUwk8d z^o{ka4MeR%WD<2?NZpcF(s35)NFLI^ zf{J7-L=rq_@#ZQ-4Q(4M;VUigOsFwRnlx$@Aq#AT$K>C+`HrxhII_XF5=^klNF|va z1l7q1Fmv{F7UoXhs+IX_I#;KdnlT|NW30ukv0*=?G*ije*N_oUM1SUNBG3kx-9#8J zxQSqAYLhir7$qNY+oc+_CD@}c9Ml+M9G_wJQf11zn|2q3ywj>=(GjsUxdscSJ2Z!~ zknn28U45B5yN{q1zsHRF@yZtli;h`$1F$k~;g6bU*~Z%J(Ht7jdQ{Q&dsCL6kW;Oy- zNiDaCiiNpFHLRXn3-C)#CCjpF&68tTi)u5hmMf(G=QAZjbblYB(KP=k(v~97kjJ#6nAwO*8|E)$9wGldsfl6=fmN>)0BDvXW#+6^5xN1| zd)mna$AV}8=diHOh@*UP4QJ1a5JVV_M%j&%g1-+HQGZD~nX;SSR{*pvY)hVafu}Li zjXtfPktj2oY8^oP@&zJ32kE+qinxQUD9$YGyN>#;N8s9%->IPV(Rqr41AYx1c?Jt! z-L&Y)+z}f1EK++@7q)js7)E=Yqh+7;)0I?$?@NWDb+U%(P=tb89f6yLw>CL|fb=6a z1`^K`2!B+Mzue~dc5Oi9yVY1JzD(oUq{8#X&YH!2=W^-JV_aVMc26`%7!=P#-WKt2+yA$F%`k=hK3ZhTbiM`gOm#umGcy~~5IoT>o zJigOZE!<&2(>aRf(-4xM#b(Po;9#GwLziOi?|&U)v0E_x92GbHbo(Pn$uQ$s%**an z)QnPA1cuKxjZYKr9q;%gbXSc?zmbDFkI`ocoKG&%eTMmbQhg7HwpOW{3f*+|1~Iq~ zhkw?G4INq~# z*rd8bpwlMNkd-khbwxriiG~T%&r;Si5PxP%Irq;NF@!J`%8xl6NWy<+hKqh`ELJaK z)E9L=lvP96c#c;}zfr;SQBY@TDOCQUG*G&j24CwID>SpRn+*F@T z_K0g0%1JcDuzCMD&psr>n6KnHLAgT+-C+(;xW@Tiv%+&qGS3s|5n4uiu1L1Q?Pfl` zYWQssoh|r8CxchBlAC7V?esaOpMTNSJ#1JD(N|6+&}r~>-}Rwfc}_>AeQbE5o-0Q< z`mnezFX2_CSM14Ro)pBFrIjLSU5Pd7a<6Sl9LS8dy~_>PW&1_{XL$S6bos*1sj`;0 zT`n8PUmXtE677U*hGfMU0|B9TnLT0wb^ke#)|}HzTBnP)EqB>Gu|T!jkbeM#={$T+ z53e7k0zTJ$JWcQ6y-LNT)o@!TB7N__)mK}@lvuO?Jz(1kGsU)t+F+If9LBQQX{g!l zMGM3c3apy8R{Y-3ed`pc;>Ev~7g^4Swh_9vl`8Igx2BXUjeHn#4o@faWFSgHHkFg? zMKpNNnnUtBnC2A?Oz|&=aeqA7$tJf=O+4-3>cR3tubMv*@w}q zJk9D=&uP+A;&$awCCFrA$oKd7q+>y=Jq$H3-X6n?XLy$n5=RlHRj1`aU#=vcyLLeu z-yEaKp_5I5ninlaPNp#m=m#A5qfG#9rFzbus`?Z^*L{XEQ>VFJTYt>!=PZr)<>zUf zC(@X@i<^d|88x>odeBXHl?9%hh{`6V+S_~}yM0=H;q@fkA6|c(!=0yL7yDto4HMTI zJkBwQ+MXyF4|qA)-2fv*=?ln)Pzs}p)CS!K%vfq(uf45B+i9WBaa9P|9sNpzE*QUo$R+Mv#Z zIGrBD)AMc;fNXl+IFQ#ZOF838#*KbW(n3Eh3ge7P-&i7`%TA#p4J%_<7+?a+Ms~nt z3rKYgV`dcRs+7S1C3j42)1-TqSuz4uHr||qOpJtrc)Gdy45@Xi?G$l&G@%1nH-D!s zx_ceU>U5L5lMFj2M?F9FLo|Zq&e3u2@ch-@Nl!esj$U`Czjt(aF8|+uEx-D~Dl1T( z-ml%=o+UwV%rPeYKlc>fBXTk=u3-jgdL(|LS&e!gxh!WxHWQko2){m1M0>lG*)| z8TT_evYOsq==JZ47h=6_B^*@=H42VJ2Bbc?$jJP*c(&OV>k=PTjhe=hWnZ(~LGm^( z%HW8?yMqlE@T-oa)9YjcL_Dh*MvyN6zz(87>8(XdZ~adkf|kEuWCWV(R)0GH{nl)K z+16}*QFXHQNOh8=A1I0h?AI4MI5@m1{Yb5HnC0d5%!#_;0e^MXf>g}ZEeKJoTrhX0 zb}{9*YRf-gsQmN)sp?7f(H9%hRNv!p6Gx1twDzJ-!# z!yF#sY#y$xG#U64YCQ@SKJY_Z>(q68z5>pNr+j4hv{;C~hmmiB)1K0dm< zoGwSUZ1f$e#|WP5Pnbw|kuf6P^yVh}Y!r5ckErJhq7lK_! zF-9$7Gv_@Hu*tVieLu0+t%6rII0EM?4$BDl@?NnUN5f|IW=+r<{1E3KlK6($-mDV` z7mV?7takCOuA@+8=Cokbioee9!14T7MtAtfOkxbP9rhL4Au| zsg6}x-{P4z3WgSfkUTx1Gk=0JXZhfU=eBfPJY${<#25G*f=D`}p#h_z(dI+2Qlc?u zBe(HHdtZbI+4?Mms5|~On?SQEdj44`nz=lhP0$}!NYFB7>};xjS|L@HDR6exe_UbJ z!8vPo_5W*y)qk^zWp<^1T4ANu6jgP4f!)4JqY1En>i1oG^o+z#bUXYsS5_8^gz#np z_ZeTRLY0|kEj-b9CPT1JY3Kap+64hq;9y!LgOga=uuX9}x~kkMUDH=`$-M=P-8V&? zzZykX&Hw#VTNVi*JqG71&U`v{%?AZ9#?HYJZrSpk^GeSfFd4ez*C2*l1U7 z4I2WXqLwleoK|Gh5~2-T(%R291C5PT6L5ZO`lgN*h8mL*j@xSv{X(t}rieG!g1y&T zrzv;YMHHD>vrSN#eDNNb5OX277KVJjFytQ=hWv?pX>%V356-zB4nBt6;DNM^RcP8!*dC z!3Y14qM-pO6rcR#sFStYmMuqFEn$sUNC&yP*dY*L1|}&xZY@x``n^=;WP*fDGtHNp z_Oo2y^F(DC*w09J#e7?qYB<0ATJ)lMw=BW9`G5Z3h~CFpY|bxl|xC`O$+Fbd3XM;^nC(7iGqJM9Rxpbj@D#CdaYLmXWc*(fe! z;|WTySG1BjBw3?zHkC1`Kd3>3C>{HMS zoqu=`ee@!2qq|$9Rhd0qyf4JMcKZw9-+}94Qk^~xhyy(FEGZoRx-xC4IFnuayG%&YephI$>UtIHlH z>-znw-P7+U{05G#Di~9*Qgtg-TE#X8?c}Cn3>=oEqnXPA&n;vQp#r3TFMl?kIsK*s ziC62m4c2k@s5+kT(|h70b0bpDK~U234N~{2TngL9QVi*9~I@>=oT+(>9k&Y6r}?ueKm5 zb@feq$sU#Uhyz9IxTWnxw|eCxsvi2{$Q|!dm_uBt<6mkXcQ7k9y7QRZE|_(nQi}Ml zSZ_N$(5hfm;ebS?nkuCAQB`}WZuTfD_4xy_(O4NS9C!tu#_${=WN@ZVg=?wq>=gS(QvNth?osIezj>#l3FD;cCztB23oSwc3<6FoiKb@;{I4G57<~8s1JyT#kSl zv2z`zSMl&5N~ic%@M`)1{#c#q&mid3zuKmd&RH>1WoBuHta*Q8$Eu-?%~|$N6+_8P zpY5tSw1VbLvPTOY{8@qE!5t<4oQ3;ujuB{FykV->jW@qg{&6rUwOYe?=l-aQVf zhY;1sV{kh7o;?teOB7Cj520xlZL5+37+|QODNC+`!(lVHR?(&@*|NcR^iE}haeh&X z%wGm+Lzlp69t?06BHm3ZQ$fJw_R%Z%Tb20Z%mt0zkE!_Kcr_jrSE@Go3tz^@AMgk^ z{O}!iS-UXAihnL1j_AkMRASw&SuW7B^h2D3L9CG|BULo8Z6+1W(+0g69ti_D9hB1? z;;o}$YJdZdDkjg{=QinHr;tewTu_1LY1>pMbks}YieFBa`=YpFqyu4I75^mk6Y!r5 zCG6ECIYe29Vh9h0MH%&~gNW66;N|nCZAQ!A>a28#7JuU+PVtD<>4jR-aL04wX9JCI zv)dzuTKNNH6sLt&7|V*EF8TF)&rq_WUYgCf?r79pj#&r2)6?!Ry%&e^4J+AD7#krZ zFQm#d=lP;~pg#xV<^G#q&vau})ng`qw$SSAX*vkEL{8C8M|qr2pqMp4P$d=o5jE z7x$H1+=4ZHnhsCm%QpNAW$*{io&f>iOmon@P-rwS)R!_LW)*@uStbsdJ$r9~B7*fK9wc`3-Qx42=B_kY05giq;u-Q`k8%gdH_4B?>Gi(>(jo%1`E zWQ-6$g zx-LvdtMMVLl7q@RC@Er*H{g`wJbkhNL!&~(<4Jkj5jZizPDE4+I{tU6Uo$oPZn`0U z>Qekg9&DCIQd5pSFy!`}(&SWLO%-~s@Sb~NFVr(xcYfMmb67;g8li(v!;x7<4Kp#B z%Gb9Br!X{>fJY?9SVVBif`bHGdw=!P6^e{psoUY_oy}60?Y4;*P8|rolW6c2rc1zB7ibdXs6*o!Ubs?BiBeerA{H=$8$=>3*@o zd_r2H?Q^i|$webvtkmAFM+1n|Vnt2gN!eJegqb9^`INC(Sru=ZHO=#Utbg9TaOW?h z)h%lmo2zue7wfLogqcTE6Q)Z~S*#&v>)3$xcif|-Zk`J5G*@VFtQl@dum}U(;;OjX zGTOBeZ+hveC1^kK%*SxbS*RCQQX(v+W=|{LRVa)Cd`74-zwLO zzaho(b^#l;n!|u7)$zHsgRMurjYb%$0*wYTS32t?J}Vr`Mv>1po`3yuUu!H^n!&BE zbz>WOE9Ld|c1XLl$+NsQZ%?1VthCvk0C&`tYptOsjvm(AU3?#mnw# zPYgy;QJ{GjjnL|#l(-PX_%calQFv!qGWg)==(N{?(&8`U44NrkMj*+M5KYT#iGr>e zD+gt$YA+p(rb7~hrhjOhxNjJc%0BOdh#sY8u<_*m_(Kd4@SnNKJ4iLXsIjrJ+wFI; zF~$i>CZ6`XyH3Jx@3en%^fv(PcTfN7z;q&#!Bzd-BUsHRZgDj?$02JAd_Qp?{py{k_9q_K&>AQ(lGI zo&8?-(5pc5;mvt~M3#QOb98XfJ#?$+o$ef+@FMqtK0An|pbU-gtRspDK=OodZ$ct{ zUMBHqNclM7LJ>UA%Py_Rb}F#aHUvodkMbb%z?ICPTa87&EgFzPPHP&E_Dkt~i0vb` zP7_|4H@f|Hyni}6Ip{)UH-|v*)9-@2e{7%kmNXe)Ll`;qH{jof@G6BzvjGPk!Do3# zrrOtk%WQ)G(HNJFhapbGd*}~ud|TEI@ostxuLP;0X&es=IEB85Ww|{0Aj@6m*_hrM zwkl+jXA=zIb1i|;<4Sc3dXO0`aGr z_+UKa0Uu6zmrZg7fK@07vY@>5Wa zQ*@0mj8EX9GgT5WV*lPXkYOCLL6p@t<&&;$z-Z5#W+mwV?3Cav7DK%&_t9Y zDlOn@4S&z*9Ln+SwnMSl@Em6hl+0|HVZTDRCh3Q`D3hzGlyfPuT|cb_vLvlca7qN| zc-WCP*>0AugW;2;??sWhSG_Gy%|c`6IvEW`{p(%SMHc=zf|DM-t}Wtn9G4Lufi?+O zTZ2FuOzE7TC&~j6zp&R;-)Hj%xbj{Pb=gK2~yYz3}e+`R~*c+tM=Z45<&n05veV~>VWfgEbr~X&XcTK z(SIT%Ov?wKI{XyaJnPV@A{RC#o-g`nuOV}^N~I++62b7a#Dir@mXex?Lh(6$yMRQo zJ`Kqg5`1%=46dt!!{-c5!Z08)HL?OeDYcz`RqZ%Z;P$YQvDHj}em|HVg0|K0-LjqX z9KQb&tFd9=e=rsUw>8Y9M(yv{6iEtY3V#6AktFH6;^}vr|9iOJ5sOTt%3-e#dmTY8 z`(=|%;chyl-84IoxEEIpfo&wmDGVFCP9kj+&*9$;u05pn%eUEWu9*;=%c~XAXLt9K zgfHDyejhor7$f;qk{qFpHG=c^RB8z@+I$0=sP#1fN$&(@njXDHGcM#ef;q3oi!Z7An)j3@b#xw%!6dd z>0aaJmF$_@Id+HDG09l>5G-~_jP&VVDrR)kER)*jG*v+KH9227;flRbBPQ(asvcpR zEDpHZUct}KDcRaYk52SB;k+%)P<38M>2QC9_k83WCUtbABtxZJGqHw=#KzsE_{@A% zHB=diqfmYl`4o^T+=55)S6_b&u~%=Dd%K1nr)WZj4IC`KlMUlSuQ)|R8@Q*hkNWEJ zmPvcPS4rx3|Jplx^~z7)?;h^@X*(y~)7O4t@Bj8N^0}XW(tGu$2iqBb#%`}$!F+$b zw|^AQflfQ$=^pprob)Q02YaWd5On>t-#w``OlS704e1{p{q=n3=&*lsv|mfN#CmjG zAqQ3s6|TNH=pLTG>hA4JA}jnk{AKU3M??giN<=?Ou zRRgf!>;BrC1ps?K^3%_iGIG?Xwg!JVXmSHAJm~&^kR(+#nm1Xh=7CRV&)#kO>^j?e zxBcm?QA{t6N6{c|yxab%eb#_Av;4U!eCCQ+H?4FpVv=kmw1KmO@YfB3_nHrw|S zVxkI~+@Ch(pFdD$G6ZnIxtAu|yGAC#3sJ8&p8d4*my_g%L;>Q7 zlduJeTONkBgJ=S13*6z3$#S{^n=itBm4(f|;94i9Rf5}(nhBU$IY1TbDqoO$pW1__ z1MQ47QWFwedV>lf^u~Ww)jCw7H`_+UI3O0aYu^r_Vkfzp{T|#Y?-CcM87FY!?WF}>GvNRi!CcMh7v+!K z`(A>kc4Y-=oN4C1YpYRuZ~TAs)+)@lKIe4q5^Kfb zRyWrn3UmV;B}z1E0gh?=*_E6X(9=OQvvhPTitFqq6*rO%Dp@LvENw9rbr8LeRh}8x z(*m^2hbT{QFrYG!S}ZR*d<%sNjo@HbcD>^bA1Qst9aayfa}5WOp||(*!mX6_13I`O>@`J_FXOQ$57D+ zh5-w={`t4i`sWL^{`rbpPt6cJQHrfjZ>3?A$J}%0v$wckY4F--RpZ*9dnqMeDKt-o zudUfaHR>Df?pexP+N<+5w+X`c*>$$LBEOWz=B2p4c3bag>$SDTb@iGNboKz@5{i13 zitc~URnd=7%$0{Q!ei4a=C3+NAE=Z4vAv8|vP$`@w)}zmc(In_@-h|i$3cuQ_9~B; zn?%k@7itkX6w&A=x-GsgA9__S{SY;}tQIvz>U8K_6}o^1bpy38qu#2zZHBUX^1BCV zsQIR3@3Wec=3rO*5)7hAF&&vr^WB|O@fLq}Zv{O3BZ}LijK{E@C>P=}ZdrqSxAy&a z-Ta}%JZF9{4>pUGlfT~3wfLE9G$hhz{IQg6C~%ueow{R*kb5>{&|xBbzfA|8grq)& zm1=Mx3?5=YtsgbNKO^y~I6(?Y+b^tldSwsf5V8|?FCq%hQ&hYe=erymCsel~!byKu zt3cvpu5OY{tu!X+gIY2GQV}{JW$?OyPP0#S@ab({vc;vhx#|8)+6hK$s!kSQtu5 zqe&d)bTpvggrrJZH|n`xT+8P2D}r#CgyS@WBa8eND>QrVP*@D`Ja;I@YEORxtikv4 zyU56Oev)TbV9JrT91RA^P!_}c6vHeoaI=|kU`^1f0_2XGR^BAi=vLQF=$J?v0FiG* zO35#%h`GH7Z88U^B{38z0CSYSHETQOnidEFUGO@s+|c5;!a}pS%Bvk%CTYu#=vudVw5DQQo%rGrLKNN5sLP^N5*-(P;pF z=riSN5wg?S*o89cCI^Go9)_GTM80E>s4P1+iR$($6%KmK&eAsl8)^}SGvnsfqWXq8 zLCkIZy@cnly>AQ#?erL$%U&aXHMa5SOqq<>TrMBxGGIo>B-6*ST~{- zO-h>Z%em{}8Kx#I!3+ac!z^N`vM>iT4OR_TZ@9u!baLTBocy8|>=KsiT$5E%6j@ZdU(G%@AMEeqKVX|6MI@yt21|t*w5q#@1d=orrK7 zDrUK9$uc{zeu23gu=4+l8slp@hH%x>o&55VP55t%~afwXV zKUarc+7y~$u<58 zdc&re*k6BZtTKISxn`JRQuL$CTEWr=o(hMyrsY_dW8LB=Q8Sa_xsG7Q8w4wV30~>y zQ+vS*c>#A*vaP`BTRh#26i7qA+Ix3ZJq``I1JhXsDoyQ{>XFb_NI{ zaJOovR53hy6M-YL&z(RbnXU#$YY~&zJ%Bg+%N!Ajo)lT{+7{~DLN*tcbWTd;lOvla ze_@E1t1(z$$iT$bPT=SPY7L&zKTQdd_%TtW7XuZ?0CtQX&e} z3XOouZQUAit5-rs*gDHd8#wb|Z!ye|5jzJ`I??d;OduA?w$#c;HThe|p|}F>Qn;mG*((ON)al*EGml)>?d!9@0pR z)#U1-%A+1=UxviMblF0J;6krl6wLnfTv_m<7CQUYER-230@c~5gyrOx-M}nIcg;bs-*$nazqvBc)Xu!bTfT3p#0<|#P5LZ21!e@|l-sg)K{-sO73 zVt?GYEU-O+!2Ut{08jxLn$Cf2QeRe{Kuhu5q?@sx6dIZMojZ@~wt$nrbQUwYPaRnZ(1c;wf7S zsBNCzjL2(Jmhft}d{R??%j*tEHBzhht~DXPdNy5A^;sv?TQ~}q&1ZdngF>1Ypv^6q z9^h?KqPN);w`V|sVGL9|eHx3Q}A|(e?`rAZNoe9PkZtUF zcB*t12iqL*zLqoQy)F-LEyw72&84M8ZPl_Bb}_4&o+ngTJlt5fev6b#5Nig^eIJv7 zpCW&dT1l;zul9s`LCraOb4FTay`@+2VVe1_+Y(f>xX2+4Rl3cNRz2n3d8Ew@Q;r++ zbte~#lV6Lb+6IU_W;bM(>4M6*rg!)_!cY@owT16o=-3HzrA+$lQBAI*&1>*hd9b6( zu8ap9VUP#vBIz-=*7V7U__eq5T*YPg^!I}U*l+SuOy}6t2eM_WmMvSBEy$GHFjMr7?ba^Z`SGKe#MgF9 zvB?@@E}x8SJ(^LA$Pa!jBRT{L#a7A~7wtoNvrE^h^nB|rs?eoa-MG>_pwXz1>$HC; z!OKe~lOn~z%fHif17cR13t1-8Ba82iYb&{ERqs)_NVF^Sat45E$N~ctRtai*0vNg* zm67kF9k5hP@J3pZSE7S@uL3dL=6Gezx0hcGJ)*fK&An)YM)4!;VE36VG;dvd*c|`> z@D!g%n`;EG$O4AS=+JlpTiA<1dxC!`^sHINS6P1hNaJ9~L9;Dh$D?GBO>i5do8+hy z+c?Ce4#oJ+;`BP1geOfxwTSUx)d4SMuq)mNXiC>c^SGFf0)uR?kR`m=46NOOxhGgOc+_VY3PDtB zqz9V6TuCcR=5QRQB2Ek&+$?`NIB@+gj7G@^#niX%VFR8l7kt`jf7Y%7LS}UgSJ-T>^R}8HtH&tY zneuB*o~@==&R=qPSZ7M_JhnkwrSu+yZYUnhG>#}V$}#gBWSCYIi?M%8%@xwn$tI6x znUAc(HUjttnMSkcVl0Cx^UM-nD`Q%~fa44>uP9*$MYNeS?DP~4tAZAvfh{KOx=18XNVlR>u zO%CIbzh}h5fv<53%G$Qr-rP`(7m1m$;S1 zT#Bgk@mNwBTW~N4voD@c`Ba3j>+v`2>E4&0A z1eaD4^j8H{ClCxoU}VTguXmrAxSI^I5ey0LkmP~(voeCv=;ME=yzWF7vNoO5`6%)K z5X!i%%eYgXmmryL1%GzhZG_ZihEqg|so-*|FDTkl^JOqevGcBDcusvq66oR#${(bR zvKuLQA|AzXb}@W}1iBT@kiR5-jW8AITX3kZlua(qS~gwF>=p6Jt#Rf!oyR9Ur8Y~~ z<7_g)XQ~yy&>w%p97ry{Tfsaa!+T`1BDIT&C)GZAX0yTf7JYI4OVvvh{CfP(I zo#h#NJT0#A>;c-SCc^)o#?p5AEDe^m(V@I@XK~NoAK7}n9#yx)#p!YP?P1Xtu$zW% zZP7(GMduZC-heH(E9H{s?5Y=1u0|2Q3V#}x!y~ z6QvcHWjcRLXMJ{gHa;dnaptG-h6my|;a*a>JB8+QNT}w@xk++eq81ZrRrMnzdY*?h z=0tGqY)B_q>WLm5El<}v#BN&Th=JOljGZ_5^v?OTi1SyY=*oQh-|y$wk>UKLrdGO*ggDs zG`f5Lln`7#OF5~V&g34lJfowYk)v)3&~DBY9zW_ zMMUZJ!W#pDP6e=g_Xx_75s$`-kob)Y3(5E*bL9i#;^Yx-PAHRqzCMLx@;~$5{8QXjoxvubh`z@Nb@GgItzR^{Nd&fcO^^)6sueTabu0FhtombygqMAy#)$S1` zM$Sn13MCRLsf^jRfh+=+oe3%?OwxK_aEgKN$K1ckPR}9I$nA-lF5JN zbZCP1@=P-ksbCQ{NB)|(ZJ?6Txys%JpbG|)b=TR5b}%$$osjv`9VzPY3V{AtxcDiM ziDi*saXGq$HsT!#z@S$x9+Cy_(n1#?qj!>gFp9h6oF&x70Zn#WQ83&2qo$CScuA2I zt+I@Bkfa!%$L{WRfPl_Xo?JlK6v%(mPh=|=!%p8|%T3(!Q;925JQIqiU@{D=Z63+3 z9f12%m}!3pZI5&a#<<$>5zOz(6>wH6JfLx$l0HTLuG{I&`NLGJWsc>GEUEa?+1WeU z+3(e$;TRR)RCmk+*Sy2dnh(x6YJ~a+#*W$L??d<@kvI&UrjA1PJSGOL3hIAizx9@% zWnDJ}3x@tYq;nQV&g=2J>>)@h9r+L>^SgI>toMu4a=!@OzIpgbu$9KHvx;0Xoiz~m zfz(z-(5rJ_c)H_T?Y>`XjXQVkY`BC=;lIih)m(B`@}WI-9dyj~+?2gNn7T>Rq6*HO z-bJw2z*cU~JfPo~aTzrOqtAbiTg<>oQhp_|uFDtfEoho{XkOp~&m8tP#q-U!c(&>A z5Z?#WhevD-Ku;_lAs}efnTwrh49sO^4GX2QaqD^pEXPA=oM(-hY8NuY40PB&A-TpE z!ZaW*i1f$LV$&SGR!th9PEMtKesrfW%@wr=MgA5cHGL1-b1hcB29JNQ2^TUNtAF8> zZThawP{kp^`pc)kXKDQO??;Ed)*`ZHpz#+<${oh5`-Y?oC~G2pR$SWRMCN5V(ER}X3$l{?vYBQOA z?Q9xp`v@AhH&i|+9SEs!^KRm3lBIBQ4z5e!VBpzsf|L&ZrQ=&H)WbXr8zDjeiJl@= zOv5CP^^QjOPELdn7dB9MKN(|l)$s<0LCv7LIsl*z#rv=f3O|2n#HTPLT?3La)UeSO z&^JhDF5wIhL+tDH-yXGR6n5K8D!mrmU+K|zaF-~&G303ESF*(B>|wHKm?# z&qGr*M>SUq*uj6yF!SL_BFHlBU=EGt;Qowe65ET>CDfR}A+gMu@Cm9N6pmp)O`jpn zhEQV97ZGJG&Ig$jOAX?K3TunDDI^FT;8K(`wucF}Nj$!Y^7r~Ie+8y4RQOZJ(T_jA(zqv=@ZaIBaS$pb)i6kc}i8 z94NVAdH;mhL3&P^m6{j8ryX)($2 z(i?Slj+#Hl-08`m7B)8A!??f_u|iCBc-4x8DFR}9#2M5xlmkQ9Tk5@qS0X|yA(Z1N3QlmJ3);zq$VgH z3U$+|hYN!rajCL3QSD`g#@!2G_}j2~Tz~SsfRP#GH5iH+#y5>rh^ic;LF%D?ajP1$ z1ou_zHRI*TC7ctEXklibP*^I?(p9sW$TK!pp~pu-On)Tb58zb*#~QjE-6~~^94Dm+ ziuivT0#PoiSD!Pz3ODnUl%~VL;-O{}ThdVG(T8}n-0lkYNI%0^4qD5ZZD4M+J9&$2 zOw&^SnW%{w;cd4-lw{*VW>Pw!0WJ2qG@&AoGTBfJ~L@^35o=OwM+8!x*jM-4Yy zXZ0l;LD6822V$+i(4>!{#lXZ0D*wo=p9ux`?rd zvTC|WX3ps#C~msvl^mr<5E!-!)~=jzpiSQf+fPn23n#a4{ zNVV}>DO*}BlB1QWP`{^>(ki)Lzn1njD z%v@yJ;rv9CEOyZzE1)3U>cy!$%HawFwGl6#*%tDfX@57Ynr#j^F!*%OtD}>HZh!CS zP`ol60C39>a(fRiqLi7yPhm`Z+S-l7BIe@@ndL;In17DF<_<(=9IVZ<4OoAsXByl( znRPP<1F=(w90{?Tr)P|r!kcMU@ClpcYf(%*hhSgFd^oKr>I4%n4)& z-h)(+Jo1Uzl(HOCbFmicNE;Q>LlY@k^^sVQ8+ zK$~oPz*!A>o*}MrRBJJu!@czjsf(#-apt0V*U_{DgNivEpqb_|&3At>u^j@lun+U& z#6GC;g}BinyK!R1T9`G4C3@Rawq;uA9iqQ{($ziP?e@Fyu+F{nF5NjAloVn!IFa|#VWox;aySG1wy2y6nedq!E7GdH11TbdJrU~ ziLqze&{D@R3GVG$Snou{&I-o*mfCwdg4pj;tWMR1QIt{Fn9=Vhkp(q|=#n;?vwnxS z(fR&qLqEx7i|N^oBQn2V6w`|)gp%Lb5`5}+YIW)f#XtGPs=I%8Z84*BwyPsDFc{6u zY|3f!)vZ(-A|?<9eNsFSMVE%`rFLdt>){N-px_tA)W=T2fck{%2jIrjuyWWyq!dJk z6X`&mX_W75^<+8}XHV&0dW54^bIfj2sWxzow+Y=ZcVeW ztVS2Ox5yWn1}*ecUeMDn)!XS$>Z9cQfc_iCHiUg#;@$E-F8GQ-%!*3IfIm=7h`MU_ z3IfxG(Cj+8_^14E%{~I#D>Pu+r2Lu`i8K{-!oHj``gnhZn7;p-W;ft`!oRH(g)MWO z75vjix6zwfHIV>1Nu>!vxVCNC{Ocg0KWqntssab%U-wSmboXbu7cGbH=(xYPvpRGq z-QDiV>d@_-oc32p+}jnBw!6P~_}AsJxnt_<2{~T{9#H@Y6Wb$7S=>GC!=B{Iv9S1$ zh0J+nrd59w09AH!)C2E!@JW&+VpA7;I77L)l-3&jA(l&l6PVO*FSxun941^xV&4O`-~EEs>Lh)bfU34V?Avm@a<$*?0y zY669lq#}QTYE{O9HCMWRUcHAAV6Ik6>Gic% zM5r1s#~D-P8LNOnu%tZ1X*|9~*T)r&FIs>8i;OU}Scc{=wp*~sn6e!B7aUb5z5bh% z!}C{rC%rE`s^--EnMPH$RuY@#ht)8K$5QZlcsjaR)r@sCiT_o`6Og*v!K54iFF2Hr zj(dM!WgyM0_cIM6zs|XV+(IKr4I9`>%O>Cn2=^pzS2T*~s>G{2Ucoqe)EFT`#HFNU zb;HEA?q6`AD9h&6Nw4=n%SI|*h(Wh%W2S$Yoy2q;_Z5YP8hn^R;8l8QT$^p>H9UN? zU}*9M#E7-`n-!y8cL$E_&*lI7ujN-iC{=$IsLtWhxlVnckV*CrV|9QsiKIAuz*C|) zE#ehT_5EW)yGvNVvZCrKar4@`I%#uT`)?<4$KBJ@y>6Y{o38_RTnJ}kSe_NNILBUxNZUm#!;HZ(+~N|)Y^Zq z3iG!mX!Xrroe1id|JzC6%fEqoJMSLup7&07y2pzOqBw|)BD#u2_js@JT395;Dp!ZU z#ZWk4^5Ewvi5CnFqMUEUtdKEcP z`ArSzMkwGzpbEf7fv$~ep_lkf0eyegZJ%ouosMXTW&{4!x%NR@%xyLJ?MQCX#@3;kP%KB7ZkN)CRB9>sd*>RV?H{H-JFre`X;gS>jWv%l9n z?5i(&W}SX!kKem``er3l=#ZF02Id$|nHrrGwFQ7)$CQBwpi0Intr?qn8JFQ$p!VHX1q*3@LvAtQp;Qsa_nZ zkVv1sk7W#jKJdZ|`1mSUu_PW11xBsvyc$Ujv6GFYjctEc!A{57dj)2HKKUKikIwIF zhHcvoNCgM^HU6Zqu)(j-Fo0CxrDXgQdM?>5z+X$I0_sgu_Fl4E0y z^r{Aq@)Y1pdJH1~_EJ5ILG4<*H`>#adozeS;Sqrikcyitx`J&>9A)5B^`wj{2sjM- zS2GBh2Yi3ms<(eBwlMJYv~cTouSeNuACYAK_B7URo}PAQez#8Wqb2ZawVc^ihh1V$ zupz(bW>=fBw;Mu7IkSj#7(I_MPF_8Yc5h=DysU3Ig1SnM^Y}9PIKK*#W=N$H!8;J9 zl(_=o-)hh%2}9(FpG}{|ZP*h!#XX@1a>i~d&8o(|VYz=Od$K}oS1PoDhdYyM3A)&c zcTr3Ndi^Vecz@I8+_IcIqZ%#z@fSGgO4`(1>QUY5G!ZI2bw~TmRS+KL`VG z=L6hHfYyIMHakCwKkLv=_L*eO*#;aL(50g_=Mcf%Br=eAgy4eeca`-u;t*``03t9p zt!3Qw7Z@F$dsY#f-MAP?ks0XcyWhF{2H=M_l9M~ybUHY>ACw&Jjk<~6r525#CO2I9 z3KxHCV~e~8I_L^FQsu%@(&qTuf(Hn98gYZx;Ywzkg7#8#C2goPvuCyFmTd2pHi-<( z&(|RNU&|go?dFjN|e;8&*!&6Vh6^ai5@CRZdh)<#2ZU~q2S$Dg!W`DOE5^Hz6u|#Em8d4i-3vi9e5~R}( z6*R@HG+%jlI%oab3CS%it`nD`I;UjABr>p}sj=C_gWUOcejPgDr1j^AKEBmw5-JT3uGX&F2f zHh(RRXE~I`|7Y**zuHKWMA4s_bNC;s)wd7QworpT?spHf%nSyM z^%{dO!tL#4e0+pdfYw6ARY_plkNMkQ#(zg@*^@bGcqzVA~F)A zso=fLGt|pd%n=DiZC6LfyY#}fTNx~_@hTkKhppZ9T)%(BEL%r7p~UV~ZRKDGgx3Pu zhw#A|`e+(UN0dD_Z;6Hb2t{L#(2kmgvviz-7X|xJ?iptrG}KsT65}Mh#w$l+Y}(p1$dEuH zn600&jPaaUl*!2iNWGm`;=$MGkn^ggb7hx~w5XXBHG0pdgJIu>6Y8I~rhiz%*uD%H zRUVvyds+AW2vySXtFM?AxH(;^<4ayoN7pS5-qtd{ZVe22v`oR3>bg2e#Vg~qzmf=; zmL}ySKE2|E$jSA6H3EabQN>YaIo5=ecdr z3`(p~)lH3aOVxkR_3@atx_>$n?@V z+hs2-m;Ryu&bJWMe@tPLpnKU=$s)I!nkN|j52w%M0Nq*Q?m^=Ffue5uRY2cdJ0x!6 zf1K^cvKwYM>9}sewqT?hTrb8LP6QaSU@H_psqt64kHO7Fql3O#5qcro++ZmJG5*gq zS0vuW*JW~ih)H%BM}JMph!|X+S*`i>Mo+Y3#?8P1bR0N!Myh(x}wRz%2ZApu^O=3)NwkT z(UUVmyNr|FvhKE#%9I;|sDB>=^4Dao(J-@)OJyb3F+jhI;eT9#5cLo^^y@(Z3c^O- zkEWMR5^79PL_?;TV4A>?1`u@INfDw04qYTOx*o(*NV?}rGFv5eCbE@lB}VkA zHxe5=6`}4nrUy5t<u(=zbzT+% zs0QO@``AEuIhY77*6s)f6RUElOyb@he$Qfz56hN3bAO=^fvxv1@G%nBS?Fgj;H8bV zX7bEIw$oFRF(`2KO9TaqU^<+)@s7Y`0PLwukEL(1SQ8RFaNARCaQDBqwvYFJ!?HP$ zn0e3+)N5Vw=^TvdxxZ1G_VeUP((U(=aMT8lKCtFAy@Bnbwr!imtDPo)^EL-gj2>=6 zh(~4J>wm4c2PR&2c*I68*E~VO7JjF$@P|C4t(Jol#7m>3_82&PQc6AYq-^ra_6Av3G z47o$d>9YaAc^LVc0`Yz1uvQI19w4AAJCXpK!J0EBR6f948T~tZBxP+npg@O7C>5S1 zqeo~wQ2-$8P*aJ5WkIVe6DkKEl1GmPh2%{hKXYbXK~^$zX1!U|T%mReMOUa@N`KJ6 z6r9n{Kj5`+IEqKo;h;;lNIV4>l%VrLt>GCz9MfiW3jKlg>a};AT1aK>eyk!ZlEq@7 zJDW*0@*whuQ)dtjC`E&a+#qzCu||&}G9}yH;baISg(p0@Q^E!@7%9dNhmBkvmb_Qv z%nsq42kQjFyOlv{?u`oyrOp@Hh=2LY3@tB(Ibx0AHW}0^%A{E@%9R%Cuu)-x4l|GG z?X)I$00Uc>`SkU^(z6E|9Hz#ZYs>#f)_teHM8g07*LY;sLPv zdV0{(t-tGXQX4KXaOYFyZG!YqT=H7xIdTh|>u~tyi@*XpFTTayLbJR>>VJ?G9N@e% zBP8RZW3yOgu@usgTf^i~L#wL+X?f-KG>V~&7KUN8PLg1wdz+0vbnz~@t;$s7wjr+x zx^p1=5qNQ&czu26)wNjqJ{%`*KfH<#j_^TPSvKj?NYh{T&0wiF{pH>CR&-M?V#8Ol zU0{O}68+wBbb7?FwUdn2QGY556@^(XNvan%*o@${#NqH3CEg2&a-uLholcU$irS=< zpbn-~McTJFT{hR6YgwHP)HiUjIahUIQ%n2oY_x<1cPL=B8JNlrx}$+yUlv7iBQ+?@ zbK(`I$#Duxit$RDEWe5+6u$=NL=Y;cOb3&9vFatnDRH8@&d`5yMt`vB3{f-0ujvj; zGeDu~4#J(B#J3k+w6d#h_+l`bsOkROvVQQ&Wd&BX?vfqwMKP)``5v~Lk9dItKpF`qBf{@?!gw`J$;EP=)^ipm32r6prl zSz+R{k8M?J=fpAy?tg2=MxBb%#yCg47V4>`U&Gv$e?hT#F#xYqCH_rr?^)f$K=W6g z0*`lW`W#z?fYkp994v;B#2=F<&t$#(4Z$L{00Y+oy!iMnTJy(bT{rH;TjX<4vVsox zLe>G7`xV|<;Lhz>op1VTuflSXZJvTN%52;;Fu6g=8UgiRY=0K#>JP$&2g-AWHKlJP ztD+P0O;M{AL$20J5?Xu5*`zz%@WE5wYJ}>Vk zx3hhCwEJiam!RXaU0?ee7j1zrB>f3(720^;ca>2h*+i;Bn>|@8uJ|C8g60X1IILTX zTG}Jl3djC0uHHOVwC!fr9BmXe!&;9un`{CBqeKlCvwtuS62qWCVAiZ@PM+w!!io8y zpSF&6cN$HnE=TmLQu+D*o81P!S5H`xTG9Cg^h|IZ(?*8j^2+-PD0|eFEYh+umsff0%xTA*rnQll3H8JReg~%wi0Y|N zux)iJRh-~DHExp_BxBfx=%9SE3`uwyR_>zxSM4i0u_+5KAc$S@>E<_3#EZ* zHC0RRM`dkl{amF%mOPV0fWp%5;k>Yze~O+}P%f@&HQsjV`Ahk_I@7)}smH3jOW8Gt z&3`Vx=`KKQnH?F*R-FgspB@;Y*Qqd~GmHF~JaZ)Xc?Q3FStFm%Bc1myAS#ClPfz#N zuyCl^tTvqQSiH`Pz=Wl(&}&8Ly2i~sxlnB!tZYxAn~ke$OHG45t?P?m-F`pqw`$D* zfm$T(Nu-!QPH!J>?YH4M4}YB98lF^MCV!I~h~h+zN9t#5&2qvf01HoFGt^3#*VM-LG%M87?EOEJbx#{Q2fNuw-fkTov=8>agMc`<*%Ytu4n|YFv)juqFMpMQ z@#1Lf_^7?z-k~eG7u{==d1wuw9{|`R&M)v1a(9%h!+HQ%Ixzb7;hUr5=%ng9ch!=()evy~vVX7rF&7~|a|w|S!GWhLoO5&_UguO3)Y?!7hRHa) zwf&!KH$)1Ap#7Ezn;=P-krrG@FQKkt5-6dL^$x+du1uDETP#dldIJN4Dpt_=Is@$T@h8M5aEvrQO z8H%f#gFIO?n&IQE&M!V@Vt?I3o%h;Ry-4Z=81H=)H_kDT_DZtSOjh2nBn?y&BZQ{6 z%&gQ^z*F=%FmHjw{uRGqm|RYWlYwF{hTBZQ1p#D)@!)g{eAx~BGmGaizj-Jgv#>W# z;E+?sTZr;S*%EtHY{58op(>1FuHt5K%z4ms)<)&EpbrWa)`KqUt$zvFmm_4jOD6I}P@%aY1eT$2%heSfMiaw~f4S9jO#I3;*=Y$sBH+4pelW0+(*`=T36%$Zs2tc^7zlr?1;{QLx_F_q%Oimu%(k z>2B$>Hz&7@lYdrW4+BQzDOhe{YBp=l6%f@}+Szdr(AOuy*b_423s7 zi+SFc;#y#pFDh2#(ffcC_h6tx|KEq5wTFaO%~#mlx_?+v1lz!aI{dqakcaGM$u)on zoA$zvM171)o7G;&RhCAPA99%bBwEzDW)PX^h{v)IWtIoCf8MISY#)2K5B^0iA5@sN z8SAtBg2IFCY!3uT;rYOvOl)co2kYKkjE~x19}hEKEV>BsKof0mNBm3iE_=`7Gjc9@ z{o-rnT7N~iFBCTmkD1!#U^d%XC>0? zYx?DC9AP+go%LdnN_09t97nmcU?>2g6Z8s0s()1r$=P?$Co;!Bhv7dyF>U-~RPzDL zGB3%gn{7jMFXeuI?s~?Znhm2B5FPiu-o+t0el`=S?xBu{B{-Nm>24LN-yjFRoLpyL#5i-Tf`t}a3Fys7X$ET#1GE}qfpq4;1q?Wa3>r#Zh5Chz@F9#D{T-?kyr!-TT zlYhLj1l%uVVMY(lmVy!!G5-u0#6*qi5BbIqeYI`56r|12s|K}(Hyu7?ogbmuAgR^z z)3~y`lH`~49MI+bo9%WKoxw9M{lK*n z49Bap0PhG;UXXb(Ci332TN)DY!9VmJZYR2eUq`fI`AH#LVUYfcNs@=)EC@WtS~UHJ zY2LD+&U_L6Qi|he;V{(N{456RMR<(C-eWR_Qj3x5w(&X+joTm9C9(*zu_3k77QoAzSwAHR!n`3V@EMqNvLlNe|zk7Nm#c@3-ov zqN*qE!uS_89}YFl*Z?$Vl{3YpIGxp%G;!{+ZhS zjx1iSSNkDfVQmyIX5MhrFGI$SA9Ay_<>}k(O>(t5nN2^>87kjx(^dUBU1%DN$(dQ< z1DASgTf?DfF0To7P&K6n)&8c}_@>wR8uS|9lp5cZ8lPRM@sANG(tiNjQd}R$S8aa; ze^FaN12o8a{d@KGJ$%kOo!E;i&i6~W>>;Q2n|kEyP>;aO&r*;i-}EEj^dnzdKl11- z3fgTtJ^7|+`N|Y6Km)T?Ey*`c%fF(g1t!-3n^(hLy zefa9t*1?WfElpIJWJ@7%tu+_jFG0~@tmw-$<~6tpRO9BFn1L)mOk$78q?jK!+7 zM^J5(X7uR7a`Iv@Oq2cWe9)sP`tX1cIPu`ym558hP^Z0Y)X$HzZPkYl^_+jdRSVRo z5hs9n#XpxRGKa~Ko7(CsKTkIr4F3WN`n9^XwGI6L8l-9|WAsvuMIK0QwI9}=w9XU} zsgH}+*)Yq-b=}-gPk&xpYcvq{=+$5}XYHTY)QYH6yZ`aC0>qG1{(O)W7={7}!51Qf zFlEQ7P^(qjsI^*HM*oH;muG*wQsL|$UZr%kObz_-%s!Y+b9B}pj1}@KqjfVLOj7k( zZvb;SIZ+gm|KlA6d?ONiPn1bF<+HriS27uhY`?AkaH%-U`yXDe{_tw`hYol+LakOW zzedJ}>O^=84@iw8iKSy`c#yR+KoIa~)^2{RHCWSVu9N6$mRYNsYBYb7+AjRvP}27Z z3ImvA#o;B;{z`HNmDO&ESbH6ncdne)Hn5Od=(VHisJ&DBOYL}YnW{gQS*j1(1#Yiw zhSn*77Z$Jamp;8Q)jyh4(Q781ZeRq_^Ln^czX$^~*3Of)9 z3L48THY7xD@m6UV$t>2UV=IW=#kHW#dE1*tpaL&l3}TokdKqLgI+V@=9XDIhYDuGI zZN{4vgUCY|yM?UBF@8f?0E&X~X*haSc?J+?I)fX_vMaILIDTPmIjs7m>FwbKTh@y4 zxF_DOzE)~~S+RfTmI0l#R{lao1uLSWHBpvtEtpiTk}Du0Su{cm@$8@xkGKljk4?BN z8o!ni$qw50WiH4s3sPnZY{?lmo@uquy}ZPg{VK z>fcc|oeV}Py@TN8Jy)&7()mQlhH7k=pJ(WfVS%WA(nGF!(ofG6^uBzzL7%60`-4fw zx8X6qC>~?rrII|In2O!pdC673+1kR+9bcrXsh()Oq`kv&?*igdl3?&+tmx$?8-GaZ zuMS^eM{s|LItkrIHVNlpM?`DOM&jrv^^%e~m&Iuhlc*m7q> zH54^`DPoBVZy)X-9zj{!=Jt+ucMseqj@o;ByGMVzoH`<%pDRHKTiniu*|@bgPQgh) zx3QI+LxREPXm`iOWhTI*v@gMp;q^iW_V#7_Saj`a6>x7a)Pj`&Zy>>dJUrSu*b^}S zTm|Og7*vV^=t$8ZBpI;qCWi(3tO`(g@k8Qys=f`p-*)%+58qmdKNmv8NhXNDflJDb zgn569DVhY-Kk9#X&T+ufFDXhK0&XUTa!KG!NJvG+#Abp#sy(_$#}Ksv5}S$OTW(ym zQouS~8gfd14LRRIAu$w}gS-dgG9-IFL1grf?6&Q2X*X-rEh_ePCpM?Wg<8@20LU~9 zJ~rZ=tM1LHF2^Z?ggH>Sd05vwJeW)!;U|AmWn+)St3bSs_NbqJG_UA-)#1eACT+BH zd`w2XRAPkMSW`zS^)Oj?G>lxum~g?BW}xJO-_yheP!l_{*YVAy^Lp#;0TFF%)He19 zmq3IAB>)NDPN#-fRHh>rAV$yNe67?<%>ans~n4YFdg`QUui#fyJ? ziP}sj4>Qpo1i<|s^Y89$a>Y=MJ(9}m>kWrm{8}I#4SF^NmOk;u*Mk#whv&-gkP-f^ zlCpFvN&kvaPzwOEM4bg1W>-enz|-tF{ozz`Z!q7Z4I%|mOp<^PL%fb-6T_3GtqLu< zUSc+{og?-t{jAI5PyQDwk(@6eSG<40MDmX@NomSx*+IbAAo&N8;=DSG$%EQf=u2g?GZ`2$=>!l?-B$M%!jo{IT z%(Qw14uHCn>4-Pz2N@6L)^&F<1aHSy%|Jrw3yEoitJG!3DNL%4q-(D?s}X-ZPoZ4i zB7;;wBFz}tK-~>CG~lyofEQe6UJDK}(R~Ra)=No!h>x8yMF~DfxsoP$2urviNuzV| zLC0=CYwZcOPGkYHuZiA{R=9sKZcuJT8^&d0zor+1-Y|WgW;BhJeqcJa0Axr^Um@KbSq$wqBXF4 zEj&igCD+2)^a~&gr|7xxJWBgt0L`P_ow=|i^}!cFl$0IwooGOt^94{vRa7CSCF_Zn z{o=SHdwJ~jr0Dbu;5mOUo#Nbo0X)m+K87i2y1oFaq?enMPWRG@b2_c8DzG}92x)a1}+&@JPQCE{4fL6 z|DEHl<2N0x!apF3!5XS`_Yb#rc1g<)pKlIK!V{CO0HaEB3Kwtk%)D=#Prz|~swid* zPrc+yb|V=pX(I@LaM}F;kH85V6UOv)hh1os$=Ac2f5z zGNsy=Cf|g3lW>1GWh+)8EcG4B6*a-E1ZGWBs9tg)6v1fc2WfX~)m8gysj2g;(Md;6 z@le6)KWsygjtK=UO|`Y3bpg83k_9a=BQqKxt{|3qu-XVzM7ZXMFv_t>`|Z&@$fW(p zz~#*dVB1+BqqJj!2sSFF8LA3sRon+R4oAEOu_MXODUqDJb( zQTl(UgE7sgXhp*y+>2mzK=*{W#%uGzw1^BnE)>c}k$pvEP<1T>wP;Ig!CqFKr8%p< zbij)!Zx(+(yj^OLU`C>C&qlBGG{-|i2X-)~VZUsYv`Jd1ZrLlOpoi@{i1u@Jo!)Ev z3_X{u?16|+3roeA#8y$sG6-0{ZZ}Hxh3nMa+!k%bkn-$yVxu}wGcbhZtrX8*)pqP; znYkfB9AA(vl%FZP#v*PY#hd46D+rbRfkb?qUS59Pt|6&|Ef>$bil7=zdN!JDj&P1fQf`vc1xxj?NBu0#(F&|j!KZLXMff!y@g`k=kyij?B>1 zJcj;gLo?9LlV@v*pk-HORA3C9r9Xe-F)UMGH1$coGw9E!%UD2Pv1F@t$KyddCZ7%q z1D^>5E3&wtY>U3iuG2Y+bH_?*$V&6iy;~cg=UUn`4<%x%i`{v~y*9N@*55gJNz7i; zd(Zq_mso}?1{C;4tQc=BaBlfXN73Iw;CC{9cOJW6@rG6c66rB;GW&OZY$bnOPrj$W zKdysRYu3g&zO2|foeqZmx3B94r=~iSC^|F_QxZQ0r~nz%Op?axR%2yzZZ$$`ZA$7E zZ!^G}ac=|Yxn9!6n)%zW?@3t3D12!voC+E7##B6MGE&5 zU$CrL7wBaGOifLJkWYQOYbM^EeMJs`)<}D%9nUJEpJ#LJR*+OlhP{Uki_Zg6c3nu~ ze>j0($ooQS?8Al0j9;)WwUZeUM%d_lXN}NKS1`Z}8B{??3k>=z5z`2~6&@e=87J=O zk-|M|2l`uiFct$VkGy{o>}9Q$!ljfDkqfYJIRjVCaYn~&d%@2i!zNBrWT8|rNo&pi zYqgPX?FF}Et!|$S6l(W5e?I-bCc4=kB%ei@@9DN<20q8RV0m%9d*S$%>E3xLTr5{t zNy#bQgA^<7fp^g4B2&b4elfiD*NLm5jF}M~WhLLA394#FBcp!@i9+rT$6!E9?*Wz? zG{dWbGNO>*gmXu5NpQ1!STB}m*$uLBsnd$5A*!w;*Gm0RH|?j+X>Tag?$4osUDnq_ zmz@|Io*uSf7YdeKBiwsRt;S{@J-CKXm~+aPi`&2Buv0DiW0ieYb3$#P7C&$4NJO4& z0Na!m3T7-Aqb7eV5gFDWLr19R;hUCljs~`Fy0?`Ti*X0y0tW8Y3-tT3YS6eAZ9))^ zX3}~PSI|zH+7S)qH}&K<_2lEIC&QH%X@HYeBWqu~9^yX8K{x*$bfojl`H%m0bG|h1 zr2i{uY9n(SHo(dMj>~+m3IEs77SA)~|9-1{&MCi-#`=HTjDICF9?|kU>U{Scu#h6( z0Wn*JKfi+BJ3u~=ivFHQ`iD7*2PGqCa_30CtX=SK29w@}^gs(bW9~+PYge+{RmFQ) zyw@F3aK>yjyamTej<(oJI$6@qAp(PrKtD=vIFq8&t0aOk$dhyg3dO*aFJ?wCXhY2Y zKA!h8Vitd>n$#|8eESg^W&H@&ix?rKE@F8eTZE>i$G1kP?nWw!Bez#k1m>e%RBdz7~TLVi@J|dXVGdS)A zkwH&ui-LEfzW-tEX}{L=7J|dzbW~pI$}zAK8VZPt>DVl?@i^^G6mQDYNh`z+2XE6G z&3oN_D524+w*brU@i_ozT?uq96qZ1m+dxE1qcqT_M<#wf(%qphjz3Y{lJSz%K9A3C zC>ejTpIz1|Z;U%*@>B98`Hy6Ey&0r71jJhx;_r(?lwuF9oqg364*G=hkL?9$)0%GL zts&Qw6HT>h<1^O>Fx2p1l&rU&wVnW>ij|U7iGwI@{<5xPwWl=4Y)`x2>gv09%hp;v zN4sJ%H?)02!Z1c8ZachAP>LCil^0|ny-t52&^tsw?~+`B6Vjiixa_Crxiggdz~S;F zKjp_{-7WZ_Y)Wda^=+&~hjd;#sp;1aYVUCWgJQL&&de{mSLyo^JOhH+-P6@4>rdYI z+)@*GH^f$7w>cj%+0ds+zje}YP5PzUifiwjG2$IbmoT_QDWPe5Mbl3gt2sI#Jir30^jQP`;r9f{^;swLglD7=#aU(I-iYCveo-r`5cQ@l_uLG(ainY z7NkalS2>t!0TVG{5%onEaa^GibbUj+6WLl`2Ntpi&K|u-F$cyEmz9xuc<--AnoHPy z?mwRod9bo$`5BH@_w}xt>-e+E(kg$c$db#fpAK_9qd%l@kWEqo&=Uw893B%a7!OsSP{BKrx2C`-?LjEp@j%Joc+nD`-jEMZ zu-_9Tb*JE4l)M3M7A#-^$Cq4@Uj7XkivX3`SY?40Og#Ou}OMm!n%N< zeb%O7I4#XuY_ie5hFQU4|og}nGi~;_Wogo;$ ztz2QDv~c>V{N*&~HPgkIzgP?F5HV=YQV|+@5R+p?E3|-=gxebrPE)#7e5wmDn!MVR z8(`2~em*A|W+>6JPRnVPnauZ+E~hX9_!BtBI0d0dj4syXjm19g`l^53>9h|II@>RI zci!yp9<{dmea=sDAbZAl?(oeT4y!Vv+ zSWkA+t6_HA+4`Aqg+zZU>KA86I9}WQFzC@6H6*M5`_=KUPyXZO;qfX#)BRpot!|iJ zQZ$q~fgWwWdhJ1ddVi=Ps!tvT)jvm|+HG6_vg@(wFN#Vkwt^^c0hFq2Z{$ z>ss{~atMPt8f(cTk}2=hM~Jd4^jp$O+^=cdsCvCRpv zQyg4vUC@k7qf@{h{Xv>R0dm-!K{JImy;?=1N8@*tDv>KUnV+Mq?*1Dl|;>^ z>&@g@!aN|p$dh(%Mk)6uZa^f*!;MS~&nl}q$Qb?P%|U;A7ES9BKh3gX+9d@wz?E(CVgPuohA+I@$Sa6h3XPP@vaM&k6j^xMET4Mz%apH{2rdTaNmh`&BSYF zpCmZ>=8u1%4c8LkQbNyeWw?Z4@lv&%W>u|ntY3*Da!V3N5=huklsb5LXV3-pO%A-a zcZz|R9?oVKz0!6xS$$9gWNSPt-uQ}PH5LRMm>S_!VD(uo8Z^K6F)rW^#V3C-nh~aT zr&mrH(Hc(&huty1bBIh2%r-xn0)H`rk49gQR+N87+W6N&5yN9c`emM5j3$zlk7Xh6 zb{B?N1V=orp|IwrwF?=pqh;-1)qVbN0s-kuUK&C zfWCi0DkLQ!Oh^6iYTSlVq#4Mh+{alG`4}@&X#KfY+Ln-W&pstM({!}Xk5FT24GwT~ zfO6_0H6Qd-2%8VrB4urO52I>zdTROMhZ`u#UQ9QZjBCns`qCtEL3%ll2 z-KhDn?#LVhEuv$QY7G7swc|A7w4-Z569#|6os9`+(trp|VV?xZ{1XdkR)yg7Gh&gu zf)d-B3t8MX51@JAJbcX~!ConaWqU`J+1#`}J?F^!bi)O+1#S|%1F#_uL8&w7)eIt{ zMAfyy^_=CwJb-fa<3%zun~8^alNzJyIL)&mD~3HDWMX+y#cf53O4PuTef=`AcISU0 z1vZ~c_@qnIn$*4F^XWO_;1895Q40h*^X_pA8_7?+QGD0Jl0hS% zBpkT%GQ#~a9bE%4{@PV5d}q*8RQXGKTaOfNm_@L}@8_8^Xqq%%{*n{en+4}#HpxcQ z%Tu+RODY4>YWRR#Q(W8<7a-bV0O)_H8wKG|ZMam0@p|@<>%tbEC_tthj_=Do&ZcnEo$;V3F3G^;NRK#0ry(jZ8gu-O=x*bUe<+hCRjk5+VvF zId7duUm+A85-$|xjntmcDi=1>EdOb7UR%Iu=jXB&SZq0ST!b;k=gc!R`*eSW6e&Yb z2P8+CR`;jh7fH0to*WFEoFSj@`_l)K!$tp>uOssOjgK zN5gOmW|ANVr#Mn5gXYReE>(21+z7CR@1gRnDfHiWlD;3ar)eqV$Fru%ut300nqnLo ztiDcW6)hhIb)tOGc;^+2Cf`a}WIzpHqvxH<2UT9gr*VCvmr3;n;Anq%sxN_XgArru zY9k5=l6vTC7jOefZopuK#*RV$x4-?3Vz0Eo3p*d24wdYkP2ta(RcA*=DnfH&>vHF~ zFiv!%aF(@8xI4`tSN;8ynZ{q!-jln8+$LLdk^t0=b`0+YL2j_3lEkOgs76%~PK*G= zGr%E(#0Uy;rYPbJz$<^hE=NAQ17TetI*{O)ykIPHQ1 zOT=C_F-HGI>|{QK&=BHS{UaAbVupW*!-KyU5z^m3q0`*==#+VfCfKfTVP?G9Gl>tM zT{H}m+l1DI2jB+e>M%;Cxwhf|{S*6IeE({<)7jeFy-WH7kdRNO*vb4hpQM*11LqG1 z^aUF&l)NDGRSth<{927YZc&Hh-N%x88@v}}R5omBKy?a~jKtTnt6nr`e(H;}!Y>t% zwLqI2c&L{7_(&n7hkH7^v8p1wPLgeRq|@rexw!xtgbw{?v4lG2BFc` zYtOn0p5uR$UfNlZ7wE+pZrBEc0x)3t&0JccKMMERbIC#HM!ldN9-ym}Mp9SbnUX`F z2Gcj+z^fF`=?m{E-K1h1Q-%I%s)q%A1`1JZ_nC77ii5tQslnN;aU9a!7|GB7Gfk%{ zIn0^@SxBk0QG|tXu;vvvDJ6i}3vhm*~zF@j+10Z;O&@s5< z6#3-u#SvQy@{NOjF7`6Nz5K+`*1G^?aY4F#T3n)Ke!}S5Rb8P9I9!2?g6n`)sjA_K zoBk5grdEHk_&uK8AyYH?d2NmC3eM9_6)S&xDbhf(#GHgE&}Rz4!jEtX@GsV{pBZlu zfoOceyANDxmQnn;)o5!lc1*P(vwLoHtA)hoO!r?mXO=T_`y<5S5SF&b8m;@0s9 z>R5bu<{Y2OWcV*Mih=FUTnf`dM#o5~dW$w}+uD|MQcxP-5b(6y8V*T7Fy-L_78-vh zlsK5V+x}H|ln#?Ccmz)~TGis<@@fpRE5~WK-#s1R^YB_QrITGAX@U-M(FV}Zca(H5 z@g8(`rbQ8YTMt7|pb1db>Rw%?-Ejmwi)#at=@qp04vA$({&j_~_Kp&ChS}(xUD8d4 zk+5{g3oXb^6b5uqS9vM)XhJ0bf{}kOqdkn^+Z&TBEMleU@$a7$Mc&mLvEfT)c%9s@ zr>Sv9WlIWSeVtbh0;1`#=TZnmWt!Uh-X24VT+cIC@a&m~fd#keIDPp~xO+ zZA3m;6SvOL6bK38${F2%$~jPgZYQIQv*Kc-n%q3~@@a@*6S;+(lI66J{FZ-B$*+D& zu8`*NmM3B&VX?aNqEld$@obt>^p!ldQ^k}#PV=i2u0+Al-rx#p#yJ?wIIZD5GxG>)SH|b*sc19a_0QR=n9X9oBSWV>NJ4INhg08KA_gLBR`{+C-b$!y{piWQJ=&_R$$Weh^-Zal@;8i{Iqzp z=E{H?x3?h4jWR8l^~7#*u1G@Fy8*NHXk|iI9AQFGDF@1}R;$HkHGi{#h2y9FQz)&C zH%TZN_$i>0-biY$ZN8u`Sp&3sLl!DMp38zLjF{hEX5n$cDFlBT^roC1;kKq#E$PTy z-uJS!+e0kRNFTAFH6%kwn-GRM=$g$^usZGF>j+YO$xsGji``D#6|%byM^PMuLhrj~ z$Mz&0s;ITrj2(+Q=88t){rTb@xWnRD^2DAw94VhPs375sum*t(vbjq`kZTCe?M^uKD& zTCL%Ik|Fsg;kxbbaoDJi?${+)vurv6&@ZwvInlX2Xg+@sZp~tZd~cX4+ZC`+ysTv} zWfg8J$y_^w@pP!TDWEv+VZpt`tO8LR^FE8Lt!N%bs$Rk#zY?6jrcv`T5*SCAiq48f zFSDAVf-8gz5kK5>G=Oyou0o0Gk!T;zi*eHb8V;Fi=#MD4zzn+ovKW0m1Lomlv5inX zZ2cM-KLLSR8he z-TQ-IiwIlPzpqq`6*~OK+rzzfzPK`a15INy_T_&sfWlXzpH~Q2^dd``a~9lqE6bz> zgdDK~|DQLzZwgJpm}%_6R8$*<%`wx48+8_~jyQJb#1xjGXnu~;vvHbVIL?NPYtMaX zck;P_mY=)nm$wS$9kMm*;9FJVe{mIU4V1CJ)|#Cr&s!}6 zIrD#`v2*-FoniM8Whzvyz8H-237Q7j(h3X5=vh%u+O;HSB{SYO;W?tMVGesM1Vg^L z$c)K;FtS1B>f2ih`z`RzcvTS`8r)DUKtvd{K_+-{8_3b!B|Ci?0Du{dzqOnc#9Gn7 zja!k817QszvHLA~ zqt#mD$$okU1?y4tz_{{bIR?pU)K|+6ylLb=HxucqCnr_M11Jv5a12(lo7DJpSkeYs zNns}#jQWG?L4T_H*JJDP=@jB3<{2MB2IODU7g4{h{l)=ktqwV^1#*R=Bau800BV2F zSBzonjA4lq0puN?$2*yg{{GrV0-6;v^n8U09nDA%3m( z%=(yiCSC0cjAGy4KOJv%ez}tg9N+$~g|4nT;QTS*p=H)Cx;z8M*$B=yW4eDxmySm$ z`gZ%5gAu+}09!HNE}$J+?W63Ud~1R(D-JL?AEjg0Z5CUk6z8>z-h;k&p%0C*hcMW` zBFuq@96Y~W8Xxbdw)`hb#$y>=`4-N)m;-N7B+0AJ9!6V4t7h$hUXnd-zk-VEYsnoJ zdT|7Eda(T)7B#P9B!>svSWbT(Vs>BeZo%sptLt0`{-@hJ$Z+bZMf{03WH*zQ6-;{D z9ZcBQW}O-wr~h}Fj(WEy#VlEVs!%41W83;OnW10B_;lx|CibZelm0>t(S`N2@!zt< zL8G(f;wMq>j<;EzUMssF)82Ff_w*ODtNBY7ik>YP5MO%Nsfa)b}#Oos9 zZYg^Dp1+HoxRLKa)P#_qAGLR1#JtNf10PRu=@sL-3xY-3TQapMSEV4$>EQ27X=_1- za2i|p^%EAq>Leg2CK`a*L397v2XD@WyA7_=jBwuNXmyb+zeTzh~+_87> z>FGWDAa_i#6NPHgH7N>w1uIix^99x?E5jfh3`RYHqrdqO2Y*~Pn3%UrzCHAtqz(BN zqFpRRb9#O8-=lvN0{f8MDf|(g_&`3ZaHHjT&o-8cd~%#W+d8wP?Cx5OOdA3^&LU(e zR7%Kg9V73nAY{bm%Mo&WG?<9jKY^URB%i27R_=Uwk?iXMAY@@)B0o|tZRb|Xa#j&k z)T>A!Z&soC@KkU`Fg#>Gc>wM#x+XF5qPlPJFMLrpnDc)xxu|$q9UZqUDl!ZRhJcs zPo$cPtO$R~+7<3$%66d1^c2OJ1!L*2Kx-5gMXngKh_}>n-VR;R}mIw75PG--drat3@BPgxRQFL!ve$zOv;NSsSW2 zZH&|LSON9vep9|4j?Z40x5GZ_`=Vn?d2OQv%98U|BWa>w8!DUF;= z@hD|bNj^kL{us2#pp1~{YL;K>=(ahh+dA!>oB*w&&O1rVK}J;#4T z!1x6OSa#qMMN|OY6F-Vl1JJfO5!qF4Ezkmt9TLG58bItS)``zm8AV-w_5j zS#%0=S`-;mkA>IB8+P$K>h=c^onwDAMd|m&&(PG_fH6R-X_BCErjB8XkcQ~ukaowm z0M=X(Jv&f7KNbjA;kjbhYVH2l?sm(zELmMMOd>?%j`O(u<`IdyrUe|!t|

L_Nag;5rYgS$#|TErwK&0(;%cS|f` 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