From 364279e0f73fe6df8b9c1b4d7a5ab8664b62160b Mon Sep 17 00:00:00 2001 From: DamianX Date: Wed, 18 Sep 2019 20:24:55 +0200 Subject: [PATCH] Added medical scanner (#338) * Added medical scanner * RegisterIgnore --- Content.Client/EntryPoint.cs | 1 + .../MedicalScannerBoundUserInterface.cs | 33 ++++ .../MedicalScannerVisualizer2D.cs | 57 ++++++ .../MedicalScanner/MedicalScannerWindow.cs | 38 ++++ .../Medical/MedicalScannerComponent.cs | 182 ++++++++++++++++++ .../Components/Mobs/SpeciesComponent.cs | 2 +- .../EntitySystems/MedicalScannerSystem.cs | 23 +++ .../Medical/SharedMedicalScannerComponent.cs | 54 ++++++ .../Entities/buildings/medical_scanner.yml | 43 +++++ .../Buildings/medical_scanner.rsi/meta.json | 1 + .../medical_scanner.rsi/scanner_death.png | Bin 0 -> 1483 bytes .../medical_scanner.rsi/scanner_green.png | Bin 0 -> 2079 bytes .../medical_scanner.rsi/scanner_off.png | Bin 0 -> 867 bytes .../medical_scanner.rsi/scanner_open.png | Bin 0 -> 1037 bytes .../medical_scanner.rsi/scanner_red.png | Bin 0 -> 2055 bytes .../scanner_terminal_blue.png | Bin 0 -> 1368 bytes .../scanner_terminal_dead.png | Bin 0 -> 1363 bytes .../scanner_terminal_green.png | Bin 0 -> 1481 bytes .../scanner_terminal_off.png | Bin 0 -> 883 bytes .../scanner_terminal_red.png | Bin 0 -> 1473 bytes .../medical_scanner.rsi/scanner_yellow.png | Bin 0 -> 2092 bytes 21 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs create mode 100644 Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerVisualizer2D.cs create mode 100644 Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs create mode 100644 Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs create mode 100644 Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs create mode 100644 Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs create mode 100644 Resources/Prototypes/Entities/buildings/medical_scanner.yml create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/meta.json create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_death.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_green.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_off.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_open.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_red.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_blue.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_dead.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_green.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_off.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_red.png create mode 100644 Resources/Textures/Buildings/medical_scanner.rsi/scanner_yellow.png diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index a21e35dd60..3f1bdee09a 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -108,6 +108,7 @@ namespace Content.Client "AccessReader", "IdCardConsole", "Airlock", + "MedicalScanner", }; foreach (var ignoreName in registerIgnore) diff --git a/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs new file mode 100644 index 0000000000..ff256a4f14 --- /dev/null +++ b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs @@ -0,0 +1,33 @@ +using Robust.Client.GameObjects.Components.UserInterface; +using Robust.Shared.GameObjects.Components.UserInterface; +using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent; + +namespace Content.Client.GameObjects.Components.MedicalScanner +{ + public class MedicalScannerBoundUserInterface : BoundUserInterface + { + public MedicalScannerBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) + { + } + + private MedicalScannerWindow _window; + + protected override void Open() + { + base.Open(); + _window = new MedicalScannerWindow + { + Title = Owner.Owner.Name, + Size = (485, 90), + }; + _window.OnClose += Close; + _window.OpenCentered(); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + _window.Populate((MedicalScannerBoundUserInterfaceState) state); + } + } +} diff --git a/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerVisualizer2D.cs b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerVisualizer2D.cs new file mode 100644 index 0000000000..7865c3d8ed --- /dev/null +++ b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerVisualizer2D.cs @@ -0,0 +1,57 @@ +using System; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent; +using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent.MedicalScannerStatus; + +namespace Content.Client.GameObjects.Components.MedicalScanner +{ + public class MedicalScannerVisualizer2D : AppearanceVisualizer + { + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + var sprite = component.Owner.GetComponent(); + if (!component.TryGetData(MedicalScannerVisuals.Status, out MedicalScannerStatus status)) return; + sprite.LayerSetState(MedicalScannerVisualLayers.Machine, StatusToMachineStateId(status)); + sprite.LayerSetState(MedicalScannerVisualLayers.Terminal, StatusToTerminalStateId(status)); + } + + private string StatusToMachineStateId(MedicalScannerStatus status) + { + switch (status) + { + case Off: return "scanner_off"; + case Open: return "scanner_open"; + case Red: return "scanner_red"; + case Death: return "scanner_death"; + case Green: return "scanner_green"; + case Yellow: return "scanner_yellow"; + default: + throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus"); + } + } + + private string StatusToTerminalStateId(MedicalScannerStatus status) + { + switch (status) + { + case Off: return "scanner_terminal_off"; + case Open: return "scanner_terminal_blue"; + case Red: return "scanner_terminal_red"; + case Death: return "scanner_terminal_dead"; + case Green: return "scanner_terminal_green"; + case Yellow: return "scanner_terminal_blue"; + default: + throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus"); + } + } + + public enum MedicalScannerVisualLayers + { + Machine, + Terminal, + } + } +} diff --git a/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs new file mode 100644 index 0000000000..652280a5f0 --- /dev/null +++ b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Text; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.Utility; +using static Content.Shared.GameObjects.Components.Medical.SharedMedicalScannerComponent; + +namespace Content.Client.GameObjects.Components.MedicalScanner +{ + public class MedicalScannerWindow : SS14Window + { + public MedicalScannerWindow() + { + } + + public void Populate(MedicalScannerBoundUserInterfaceState state) + { + Contents.RemoveAllChildren(); + var text = new StringBuilder(); + if (state.MaxHealth == 0) + { + text.Append("No patient data."); + } else + { + text.Append($"Patient's health: {state.CurrentHealth}/{state.MaxHealth}\n"); + + if (state.DamageDictionary != null) + { + foreach (var (dmgType, amount) in state.DamageDictionary) + { + text.Append($"\n{dmgType}: {amount}"); + } + } + } + Contents.AddChild(new Label(){Text = text.ToString()}); + } + } +} diff --git a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs new file mode 100644 index 0000000000..74e2ca260b --- /dev/null +++ b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.Medical; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.Components.Container; +using Robust.Server.GameObjects.Components.UserInterface; +using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Utility; + +namespace Content.Server.GameObjects.Components.Medical +{ + [RegisterComponent] + [ComponentReference(typeof(IActivate))] + public class MedicalScannerComponent : SharedMedicalScannerComponent, IActivate + { + private AppearanceComponent _appearance; + private BoundUserInterface _userInterface; + private ContainerSlot _bodyContainer; + public bool IsOccupied => _bodyContainer.ContainedEntity != null; + + public override void Initialize() + { + base.Initialize(); + _appearance = Owner.GetComponent(); + _userInterface = Owner.GetComponent() + .GetBoundUserInterface(MedicalScannerUiKey.Key); + _bodyContainer = ContainerManagerComponent.Ensure($"{Name}-bodyContainer", Owner); + UpdateUserInterface(); + } + + private static readonly MedicalScannerBoundUserInterfaceState EmptyUIState = + new MedicalScannerBoundUserInterfaceState( + 0, + 0, + null); + + private MedicalScannerBoundUserInterfaceState GetUserInterfaceState() + { + var body = _bodyContainer.ContainedEntity; + if (body == null) + { + _appearance.SetData(MedicalScannerVisuals.Status, MedicalScannerStatus.Open); + return EmptyUIState; + } + + var damageable = body.GetComponent(); + var species = body.GetComponent(); + var deathThreshold = + species.DamageTemplate.DamageThresholds.FirstOrNull(x => x.ThresholdType == ThresholdType.Death); + if (!deathThreshold.HasValue) + { + return EmptyUIState; + } + + var deathThresholdValue = deathThreshold.Value.Value; + var currentHealth = damageable.CurrentDamage[DamageType.Total]; + + var dmgDict = new Dictionary(); + + foreach (var dmgType in (DamageType[])Enum.GetValues(typeof(DamageType))) + { + if (damageable.CurrentDamage.TryGetValue(dmgType, out var amount)) + { + dmgDict[dmgType.ToString()] = amount; + } + } + + return new MedicalScannerBoundUserInterfaceState( + deathThresholdValue-currentHealth, + deathThresholdValue, + dmgDict); + } + + private void UpdateUserInterface() + { + var newState = GetUserInterfaceState(); + _userInterface.SetState(newState); + } + + private MedicalScannerStatus GetStatusFromDamageState(DamageState damageState) + { + switch (damageState) + { + case NormalState _: return MedicalScannerStatus.Green; + case CriticalState _: return MedicalScannerStatus.Red; + case DeadState _: return MedicalScannerStatus.Death; + default: throw new ArgumentException(nameof(damageState)); + } + } + private MedicalScannerStatus GetStatus() + { + var body = _bodyContainer.ContainedEntity; + return body == null + ? MedicalScannerStatus.Open + : GetStatusFromDamageState(body.GetComponent().CurrentDamageState); + } + + private void UpdateAppearance() + { + _appearance.SetData(MedicalScannerVisuals.Status, GetStatus()); + } + + public void Activate(ActivateEventArgs args) + { + if (!args.User.TryGetComponent(out IActorComponent actor)) + { + return; + } + _userInterface.Open(actor.playerSession); + } + + [Verb] + public sealed class EnterVerb : Verb + { + protected override string GetText(IEntity user, MedicalScannerComponent component) + { + return "Enter"; + } + + protected override VerbVisibility GetVisibility(IEntity user, MedicalScannerComponent component) + { + return component.IsOccupied ? VerbVisibility.Invisible : VerbVisibility.Visible; + } + + protected override void Activate(IEntity user, MedicalScannerComponent component) + { + component.InsertBody(user); + } + } + + [Verb] + public sealed class EjectVerb : Verb + { + protected override string GetText(IEntity user, MedicalScannerComponent component) + { + return "Eject"; + } + + protected override VerbVisibility GetVisibility(IEntity user, MedicalScannerComponent component) + { + return component.IsOccupied ? VerbVisibility.Visible : VerbVisibility.Invisible; + } + + protected override void Activate(IEntity user, MedicalScannerComponent component) + { + component.EjectBody(); + } + } + + public void InsertBody(IEntity user) + { + _bodyContainer.Insert(user); + UpdateUserInterface(); + UpdateAppearance(); + } + + public void EjectBody() + { + _bodyContainer.Remove(_bodyContainer.ContainedEntity); + UpdateUserInterface(); + UpdateAppearance(); + } + + public void Update(float frameTime) + { + if (_bodyContainer.ContainedEntity == null) + { + // There's no need to update if there's no one inside + return; + } + UpdateUserInterface(); + UpdateAppearance(); + } + } +} diff --git a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs index f703d53cea..25743e137f 100644 --- a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs @@ -28,7 +28,7 @@ namespace Content.Server.GameObjects /// /// Holds the damage template which controls the threshold and resistance settings for this species type /// - private DamageTemplates DamageTemplate; + public DamageTemplates DamageTemplate { get; private set; } /// /// Variable for serialization diff --git a/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs new file mode 100644 index 0000000000..54c90381c0 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs @@ -0,0 +1,23 @@ +using Content.Server.GameObjects.Components.Medical; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Server.GameObjects.EntitySystems +{ + public class MedicalScannerSystem : EntitySystem + { + public override void Initialize() + { + EntityQuery = new TypeEntityQuery(typeof(MedicalScannerComponent)); + } + + public override void Update(float frameTime) + { + foreach (var entity in RelevantEntities) + { + var comp = entity.GetComponent(); + comp.Update(frameTime); + } + } + } +} diff --git a/Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs b/Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs new file mode 100644 index 0000000000..ee0a4f029a --- /dev/null +++ b/Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Medical +{ + public class SharedMedicalScannerComponent : Component + { + public override string Name => "MedicalScanner"; + + [Serializable, NetSerializable] + public class MedicalScannerBoundUserInterfaceState : BoundUserInterfaceState + { + public readonly int CurrentHealth; + public readonly int MaxHealth; + public readonly Dictionary DamageDictionary; + + public MedicalScannerBoundUserInterfaceState( + int currentHealth, + int maxHealth, + Dictionary damageDictionary) + { + CurrentHealth = currentHealth; + MaxHealth = maxHealth; + DamageDictionary = damageDictionary; + } + } + + [Serializable, NetSerializable] + public enum MedicalScannerUiKey + { + Key + } + + [Serializable, NetSerializable] + public enum MedicalScannerVisuals + { + Status + } + + [Serializable, NetSerializable] + public enum MedicalScannerStatus + { + Off, + Open, + Red, + Death, + Green, + Yellow, + } + } +} diff --git a/Resources/Prototypes/Entities/buildings/medical_scanner.yml b/Resources/Prototypes/Entities/buildings/medical_scanner.yml new file mode 100644 index 0000000000..af3381a717 --- /dev/null +++ b/Resources/Prototypes/Entities/buildings/medical_scanner.yml @@ -0,0 +1,43 @@ +- type: entity + id: medical_scanner + name: Medical Scanner + description: A bulky medical scanner. + components: + - type: Sprite + netsync: false + sprite: Buildings/medical_scanner.rsi + layers: + - state: scanner_open + map: ["enum.MedicalScannerVisualLayers.Machine"] + - state: scanner_terminal_blue + map: ["enum.MedicalScannerVisualLayers.Terminal"] + + - type: Icon + sprite: Buildings/medical_scanner.rsi + state: scanner_open + + - type: Clickable + - type: Collidable + shapes: + - !type:PhysShapeAabb + bounds: "-0.5,-0.25,0.5,0.25" + mask: 19 + layer: 16 + IsScrapingFloor: true + - type: Physics + mass: 25 + Anchored: true + - type: SnapGrid + offset: Center + - type: MedicalScanner + - type: Damageable + - type: Destructible + thresholdvalue: 100 + - type: Appearance + visuals: + - type: MedicalScannerVisualizer2D + - type: PowerDevice + - type: UserInterface + interfaces: + - key: enum.MedicalScannerUiKey.Key + type: MedicalScannerBoundUserInterface diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/meta.json b/Resources/Textures/Buildings/medical_scanner.rsi/meta.json new file mode 100644 index 0000000000..45f3c3c55d --- /dev/null +++ b/Resources/Textures/Buildings/medical_scanner.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 64, "y": 32}, "states": [{"name": "scanner_death", "directions": 1, "delays": [[0.3, 0.3, 0.3, 0.3]]}, {"name": "scanner_green", "directions": 1, "delays": [[0.3, 0.3, 0.3, 0.3, 0.3, 0.3]]}, {"name": "scanner_off", "directions": 1, "delays": [[1.0]]}, {"name": "scanner_open", "directions": 1, "delays": [[1.0]]}, {"name": "scanner_red", "directions": 1, "delays": [[0.3, 0.3, 0.3, 0.3, 0.3, 0.3]]}, {"name": "scanner_terminal_blue", "directions": 1, "delays": [[0.3, 0.3, 0.3, 0.3]]}, {"name": "scanner_terminal_dead", "directions": 1, "delays": [[0.2, 0.2, 0.2, 0.2]]}, {"name": "scanner_terminal_green", "directions": 1, "delays": [[0.3, 0.3, 0.3, 0.3]]}, {"name": "scanner_terminal_off", "directions": 1, "delays": [[1.0]]}, {"name": "scanner_terminal_red", "directions": 1, "delays": [[0.3, 0.3, 0.3, 0.3]]}, {"name": "scanner_yellow", "directions": 1, "delays": [[0.3, 0.3, 0.3, 0.3, 0.3, 0.3]]}]} \ No newline at end of file diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_death.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_death.png new file mode 100644 index 0000000000000000000000000000000000000000..7abe8dde27202df615c4ad82ddbd6b5d9c088005 GIT binary patch literal 1483 zcmZ9Mdo5wv(;x32&*%F*|2*gW$M<}b9qg^ezzSdh0L0KXC`Z2H`Ex>8 zh|e$Ia5wd@)k0p3Hyp*Hbt2M8pU zqv>=X8aGyZg7Rx_i@ASvE@rMr;-FMAN;Sjgw@4Avl{oe>xNhT^pV?d(x0;NtID}Jv zM8@s|8q98vu~LE&X$E&Yf~=^+BDCIN`FrQp3^jd`iQda*M6Dr>QDPm9G$&g6Zx3!`1^^ei;Er& zD3#w4nQacLEpZNQX^ArWjIR33z{p8%V+w#8GhB(9n7F-d6Vlz@G)s3+!SG>U2Mg5l z0LbwiPQU{ZCs?Mvo+!q-*XVxn)kqU6y2cj)tHn)AQ{VT1Al;E)t-?o?kQd64W?{#- z7t3s*Hr3OtXujy3uOB)o2nK z z%N@PpYhAvnfXr4em?zC7hrwo`tTtAv^iV~u)!sT==1{w{kR4%El5kq9{q{>ITLKlr zVw?BNGs&nKB(A9(kmHh^rRK}>j#4WZOR)I z^60?OL-na3CCpUn0vxR3p>c;7a26QmgiO|Uxb*yZo8KLcPze4NSQ1?wp`AFcvW-Rd z(QhTOHk;$-sb$LpS(N8H8H9Hd>GvC4eS!!XLGfrevIS=7g|Dc*_V=$Ekh8K;t5!Dd zTH_v*fN^1^*LapmCev}zb)(xTi7ARCS@&=T+*m{gG#6k7Z)RCQR|Yl}H`QD6vfnts z$}~sR2mkU7`y2dN-J_ixB)%8|>b_N))3IXWDiQJ1scXq#oXsX-J68t29ML5bc|{^2 z`Z<%`1lG)8;39&vJaD*$eNs8S0WsP+D@YP=xsqmdq3}?%-Uq}bugG_ldft+~+(u=Q zqnYXk0Zv8rOhl>*h){Tob#h$<*SL1`b=F{@uG#q}T3y@lRHSEp3izQV3P;Z`@aE^2 zF?TQ`EZA@H33S{E+v4&o7xRi#zfi%0^@F>gOq9j{j&ac${Je6(VL9Y+6?JWGMOW+A zVWVE%&Z(ZYtf4mrOYSDIN zODFDW1`1XaM;D0A7g+wt6A$n!k-O< zTIS!oB+lz_KzoSOyTqMY2Nbjk_sL!(Ic>;j>3>sKD%z0RL6ywO#A-t*D26K#pO2@R zhKj>!5)o!6J~0NTnP_4K4i!hceo+9?14 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_green.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_green.png new file mode 100644 index 0000000000000000000000000000000000000000..b413cbe1bb9712d1e020d2b7755c1cb233f6d244 GIT binary patch literal 2079 zcmY*adpHwp8z1X6@n)pb0aFSkmNStdLI-?u5z%rSSw#*_n{AFAon9rwln$y(@|siD z*ig!0$Z1Fp<1=EIwRSMuxA*J)uJ`MY=ee)v{{5ckzVF|CUH5a_%foex(rzUH0I`y$+ z986@76jZtmcb%*lG6qq@cp?4;vzPpOxs6dqFj#UemhuM^Lw)RJuuUn$sq7y^qzjd+ z-r+F(dbFf<@rr)$_kqxVNhBOAfJh-5xXPDOrhkBW^+--IJ7@>7szCFu(E-#9pMO0< zl;SJ!i>o}LFJLSNY@rJGFs_boni6Fdhs7m#)34MbIc>@AbHgmdY&4?2*jKnRM`m;< z4&0Jr1NlXxSANIyhCqO@Yn8%jSRyJT^rr951;Pgs_b@`i-veAQjzE_~BHO9ji~zF@ zhbBoDdHAnOD_OOK$c`u1>5A7wb0Cer09Jspc2~E76kbzNEI+@wV6!+55@QD_$jl??i~%A;GNm z2DR+$%VaGUoL;xvaTPiWC?JA#YD$mKr@BozfR$IV0gLiqGhD4|f=iwNm!H1dm6==YeYqz(CM`w7ramQHNwnf9J zbW2r~^aZ5X%o53AzNi`TZ|P1`G>d-16la@KumTpvG&;8O!i$l;2E9GmTFToNd4*D!Rm5G9lbL<)@eh zu{BlV-)aR(bBvStF{ZwS-3ruuUo7qaRBk#?zWo5I3a8@@kNi&T=xX8TRHeT)jmquK z6n2FJ%WS5KwzJ@jI+|e5zd;_vV=Zv5)n54it2^BEwT&>LGgD&pez5Ju+ zde9x0KfC39n`y((Q(95CO8jZv0p|+nuWIz|qo~OPFQsi~Q%ApaY{fAW)STi=a7_QK z3@HI!`cwH=(QyC_U%z+BZUiP?GmT7*aSNTEI3CDw8ThSed>gSddJ!Sp zUH2FZnI9Vdu-gc%p8lZj+47;`u)%qTZOzx(P8eq!#ys3t^HJ%bZ4b_haY^u%I;#|e zjC{*f8OXo81u7W}<5@7aj%G6K++>k1lOz^t%hclNrf5;esc>u*w`n;>=l`T%Q?= zWF)mP@%+E>9wnnmPQC~|3>OIK zgj-7QP=6b{aW=lM_Lxej)qU!?|1%Nx@_P8PNl%ueVRV9+^^pac?R$%d_KO5>JhCn=D?Ir7U SjmtiMfV+!_^Bbp&ss8~H20vH; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_off.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_off.png new file mode 100644 index 0000000000000000000000000000000000000000..1b3c66bfabd662acba209925c3ddf7dbbc550b73 GIT binary patch literal 867 zcmV-p1DyPcP)xCdK zn+siaOWLJE6m3m*5{+YCW@Jt;vYBR@ErOF|LYp7tV#wk7pXYy`d7hbp0RsjM7%<@f z%af$+&GX51(MJO2j&j^p%9xTzU8s`a9m2J{Od1Fo;H zKM%m}?kSZ21{6Xl?=RY0r$;?C~f!Al3@Q=8ynsF1VfDcnMZ3|wXokbFO zSIjq;l}Ir=iK<=|czO7W>Q#Z8iN|dV#!`ZrzjFaXA;AI9=&%JfPUi$&w^mE9vGJ~sVOfAMIB z3m0RY3}NropnJFA)D)E7{`A$PGd*JxUuX8yV6MzRHWFgG6bmu3?PB93rHwHBQZoM%9sJRPFVu#(xGG2 zAp%Mx3F!2q#b0K)orbhqJwgObFHlbf}>N{ek*mJ>?&^QieD?qsvi#Y)0 zpsz1j%0XYz#ajEOv74)_eN*`KINqAQqD) z<0k*=``efG;~(xmK$ai!@*D4=YJPp=V_S`J0r-PY127_t6A3h~9URkEz<0moKI|m< z99lshIrM$Mo@0lVg}@+J+0@@4_GY z*qM_MZqc+2LlG=xHzDwRkoKac=igR>dd#d)YUh@+n~VtKonNuV7z}vr#R-1?y?$Qp zSMwPzUKqQl8}g`%Z#wx~$-8HVL+4sGESo^LxByDUKLJ=+SO6dt3TXqz&R;Z4;5bzC z8SZY}()#&)9)S1Ls|7_sw0fsSi$DQy2}|5sr>2Su^h^xWkCc})HR2KmQ2quLfj00000NkvXX Hu0mjf0#f(X literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_red.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_red.png new file mode 100644 index 0000000000000000000000000000000000000000..e45f895d4666ffc8484e9785299d7a25aa519634 GIT binary patch literal 2055 zcmYjSXsoRFBp`J!J#rl#c*AQD7_Mjx(fzGrsiw(BrKJ-~&a zp#Q3@GUU*X+cQBOc+FQJ=rNL?qoR5p_gEMHqD?v2X8+WUkD-SW$`s;i5Nuf3y!i0K z++p|2&|Dp9QnvmB=(`C-e(n`wtxF6G{8NHHTez07Wkh_*Qqld92-D6)e1~#!l$d>m zZ-tYPg02W=z}H0Jsiv18uO_YogMd`~^BFAe93lmcp+Wl(m(*lM@470D^4ePf*=)jXV>VUpHNVWAGO_P4C_0t`t*fC7l9Guo} ztw`D>`QCx_0nC1{R)*tlM^!Cq#Hh6N$C_t51-iW_yfZiO4&$p zUsa3kCShmZJ-Z&Y@Sc0_B7TH|&O^z3Yl1Qa$2x*Lejb5HdJ*) z5#_>Jb)h9x>axT?ibokku~AxYV@9f?u7NyY?lV@?)xh?$*0;vj z#DU98&Yp;{9C#PM2R%s;&E`AB4qiP~ zN3B*olJ>^TPK^>1vT{_f2qPVCR69+tP>r%6guV$bqtR;S(pD+Hu4$CT<1;zokA29} zyhw)InS5vW-&I|&r(9R-%6C5YWTbgLxZ-oEoaHV{Lraera{H&zUP!c8;qy*Z?3KDp z-q>psn^e!##S--||2Sih5u5@g$!8C4WDf+L`@D4k>@nB7E$2SR!%44_+}4P6X_FER zW(tm5bM*V$8e6%7=CFO7=YUn)N_^$h{=u{L8npW-ha1k1{JwSPz&MgxZKx_gQXMy6 zcV}<#q@%oiS46!}Vl{UOX)&;#YWR}t|7yLS<4%^G%e3}b>A%SLcIC7V4z8pz+OezQnY2+?{ngxT#Oy*D#KAzuQgaoH_(eoP}| zFuu>&mv=n{Qpv~r+AKQ+t}oFQy1ptMD;)}zpkCZ)eI$6!2*fk=xfUY5T zDdI*Bv1uT_a=fRrWo+ ZWxxXUuG~%%67eyc+TMwoe~`f}4hqPD4yX1?bk51Dn3F zpoLdAn`0RpJ4el1dBvTW23V-|B6;3z|_70q$cOhxfJi; z&MU&TuE6;eV1A?um&fJ3A9UE~Rck}!qsL{+v~>j3S}!USUH7JWKk+g$j9!eYL*T;1 zFL&4A;~6}`w7@pE|=&4CC01m8;jO1Uft3II;MQ%pN$GrXY}`?#q; zp7DC;n9{rPzs_A=-wv8JejrVwI;4}jJ_qWl0Rgit$lK|ipb?b0^bl@$(|XxV>4`P# zln)saf8j6RCHH>j|Nx`O8goE=hVo=d^CqO)F-!>!I ze8kr=p9hkTE7>D_;xZk1SnOUhq%6qx?(L{0Cw7+7BD@=mHP+tHF~0~J{vvbpv@Qpf zSC`w9Cew$SAX=|%H?@|ji9r48vJ)@%&)h9J?*W3+gFmqtW9?~9v~oS9>`5%By&}t$ z>x2-_0tjdOHkI%G_|c%^XoHi|zk((dNaN1&G026M$k+C_f32b{RLCvuWWw+dT^`WQXwH-pk;g}A)?zqowx zkW#bT;FN3fHzrEHGto4rR97N<9Y#-7v4f!2{;hf=3xMb@2$p9pZREhQwKD zH4n__e&craGo0S5(hhOj0Beci8zeDEvz&sFG(b8CYbtcq26(%ymx8`nysXI~I3i46 Z0!(DvJaiMXQe_`J$OY~Wt98B<_g|w@D_H;l literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_blue.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..0f4a4b33fe8a0bd805a6e830dd2711864beb993f GIT binary patch literal 1368 zcmZuxdo5|py2A_ zcp7?XP+(-FAsif{QUQ?CadouAlM5FMJ>B;b_P%O)JR!4t|C`*Lv}(IrM5A8$`|F9q z64%25TDP55zVNhSXZAhi!DA>TtWtm+V!kvJ%f+3t%4cQT zP)wPrpoI3`C1T$F(PVxsrMPDd-7?X{ADa|4*PA5-(sX66>B^v0xf3ujx438?5)uMH zczC$xzJ2`*-g>6BFTJ)*jbC&q2*~4eb8{FsH+et|3WAm5y4OBEBH)_^iWby$SaI{J zVIk?0ph4)`>bE5y(Ndz;K{AD-%E;?|D>4?&D%qXn_)2!JR|`WHXW$+Ai`I5DiQ43i zg)xB=fEXGo3yu6bGSW|sKOlA9Iu&ntM?(_SM+8VRv@-_KVxRXjv`3UBbz)rH(7V|U z=dS35&*t4{Wyj|u`MkLD;v@-j%9tHP+wwLh1MYL~+%wyuSnV#f-$>8Te*VKNB+XP? ze=z+79wDrck2_!e=bQS(6l~%KpQKIx8V`i4bE&$cW6R2Q!7(x?%W2Q z2_i!IJm;hfmi!2pOcV7IAL*pV-lG?1Qaz8L{xX{ltLno}zG|*Ydnm5w!tbrKgVk7p z8FD2CS&KClp(8zWYnFGy&9Ob%FxrAce6(PY<}1x{?=xaj59Mf>AvjEODY{-_H>)^F z3P(`C=>jjPur(XfDq|Tw*(H?hR&;DBm%yhNC;)QdV9lmT2lMdI*n^i-AO3h{CeA}2 zo3zfN=ow;at_tJe7d+|F!6iDw=}QGwk?g|=z;*OjC^&!(5jB0JQ}mD+0)ZENg?FOA zj>Y=1%V|Ef;Z5TB-s{h-TWR)IC>B%>1%VMjS z6mHO6z=G6`_9Gd`JKc>d6Hxp#~k~%=yzmY7n7CM7^U`STu!($yBh~1 zFU%GJ4}Dcxp1AqO{ga~>H(ic*)!d5zvikN$9!AIJoKqLm#LpK}8)T8vX<}Z*-Q@dN@4SXf%tAlZG{Fs(&6kS>ux}f5ABnhY&&gk|Y`IqN<`+?o zjX#U{FP?Xr)CpToO}44Fd$lObGK}&$m(n}g2PvJxTUi`o;%m_vMe_V?fW>2nK4<^q zXQOO-);Pk(XTg(lkz#v1sPkJjq6~W~!|jwE*HuUw*l%E339}7RU|o`d#@I2?Py%$R z;0uBw#GAARqW^(M$y*~2#;7)=XlJi*(7<}n4>8|Gl~FH~dTmg1ZdBU1R~uyoLHs7e zi(>LOVbJ*}FDkW$P?rSD_9_(;YT4!@&f04ons!e8_bE`rWx;JU?X5mUvev6p;sOby zk@U71cWD0)svWj9>Q3a8mO*O&>)0;M{HnA(Y}}!`V}h9EvE#*H$JBtf&FU7SDeoO& Uc6GWR`Z0m4lZWFId*Zc!0rHEB1^@s6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_dead.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_dead.png new file mode 100644 index 0000000000000000000000000000000000000000..a79cb10c678785fcaaf63aa47b19fdee919f53b9 GIT binary patch literal 1363 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3HERU8}EWU|^NGEv^&!k2om?sT93kIQ7y3IgO_miZZ5pTeQSwaW2%@RMk=RLbX7_)+JZP zqD6pj>MgIgOOFRAItKq+cId6w8=1x00rhlBDp1tqm zZ1cylXW0c<90gb&y05AzXJBAsW9#|(vy#CfJzf3Sv144nLVbGHe7I77rdz+zSx3xx z*Y4dH@7?2Lh=_}GGmtPb+xJ)M{ocs#c)8riYtQd*3HH$un{3Bf@w)!#Tk$E)875sG zu?)|f*DD8!JD5m4y}Pt4$n&q0n#0DJy@rV({NWwD{+4}R3Vv#XMKQyA0sU%RV* z#k_nzk0I_snLx_%vnm2gjA3D6IsK)v?rGN>=G{HLbyu9gVTqUTSry7v3l{HRy_{e9 z?_Sl{;z|4r47=7%7csW5OI2fJxHE6ZfFM2cJFGQ|j;A3crPLgtxU9)P7m_^Vj6FTeTQ0E=KfkD_DJVUrxos_!BGv zp`yPw+pd^-H)i#!zQTvg81zbH%-J74TAFzKcMjVOV@DyamGgfK9kB3u^8e_c+BMAG z#or4TKDKBO$n(GBxFU)@`mLYIHRj*O3=hL>Dt0_9-EP}Fy-rcPVOgff+x(`W-?J6e z>-K)LOwiws2?HwEWQvuGQIFx>mKQ@ug>V}(q#|91iZ^x|BbcM`|F?wu_6vyNk` z{ZPQ1x%gI2>cUCCT5qyUJM?B!)8^$)+ssxzNt^QN_V>^O?U(LKSaHR@5LaRp>TH?$ zw9|zNh-O>wX4tf|?Ekyzrfr71m(0iwiaY`erZPp9l{!ooKjL+?Y`zxD&zLq%Z1K*W zH^1Hb^{dKpPVgDOueVpM%x7W*9^ zR*#07gE_I*I%(Sfte=I2rUXT&zK>P~CG?wXxVK66F7&wgQRlJoO5M!U`$X^kYF)vQ zv;9^0pLO#UIGPkXPAMPJoArnBgnR>tc);+9U7@~VkwQI?!Qk+Z;R(OO%asWY`|I9u zJ`gKY^LwUJz-%q{Ji4Bt%qZfS*8{izXTB_{G`leUAH&b(O@E*9ANV79<6*%4pUgac z{y%TYH=Oso|VYw&Jk`FWO9Xde{Tj~U| z5o|3sBB34RMu%O}&hCwW7-1?HfI_FBfd%%&fp2rbehC13D$c6nRXyLYyVoX~oa}Q3 P7M2X2u6{1-oD!M<$QyqQ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_green.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_green.png new file mode 100644 index 0000000000000000000000000000000000000000..13befd59340034f87004921afe8498eedabdd306 GIT binary patch literal 1481 zcmV;)1vdJLP)4F52(1UpBMLlQ_ zLWM+7qlZFUXrc6|MToVDCKk6{a7NN>*NL0#xU-X;9^#C%*@YA07s4-v2NeK4ZzNwJ2`jmTv@*=i3uwr^{=VNm(;@0 z(2%u%|9-Y_-wwdNd-sUNV%DWgm)Npp3yPx9-`|f{%+SzK=#yYM{l7l?hIc<~Vf>dl zK6v{p-}Jv$>lgSzB9R~(jndxUPBa=Nkw}Q{(yEe3B-q>)p?mL}Z0?Hqsy~nkP$?%) zk60&8k65DnA&PqF7rq1lOifJ@i^WPFo2E%VpT{&!GMP+S48Vo+CxOL*`1;GwL%SS! z={M#r<}(Wz^Omprg;#*_@$s5IH!wWPh4Uu~YbB^ve@|~;P5Ol=Ks~5+5W-F^lOPZY zFgZC{@>tU}Ow+_L3{2BR)3mY}n==Ow0O76#UiuB)BBvEGbnAusdwTmgbMQdb`U9~C z0MIn8s+fV{Q6~uiE{iI}O?0hTk^ZF>uu}cP zD}bUX#N%;PRefo!J4R6yjt?FK76;;(s{*W#by@)bWi%fA^*6+~Ew(h*x%ahGH~mLH zbKYBt{yi0w{`tVHo6c zISj)v+ z)6K-#4fb`f13I`ka+!{14STiQ*cydrGl2Lu?%aP=?{3!(QThW}0aR5jsQ}BZkH1~} zmabiU_~FlaXC}A_YXwkM6@B*ECUCastNuVFfcpZ+au-CrV#cPFvO#bYmOX$-{lXK# zE^Df)zH}$-j!_ha){ZVxPopJ+;3fyCPCsa}FN9=L6TtKT z#X-eO|C8wjnkevOdVxv&(=U8rwr<^OwYRsIy!Pxbw{ld%U`dFvc z+R;^Uyq)p->`Z9Oz8lf{15p9&-D;!K==voRi9{litUiI*MN5AG=?@_N0i-{`bEH3j z^arR2=?@_N0RZU_ApHSCdMX&i>ldB?wPK%%3v&|Gf_*HmVf_K@lfhxG1hx1B+`N9p zIUCrJ{s2o)1vi>MfbEZ99}aCee}IAE(T4U1uxJ0$S0i-{G^alW>KR_sdd=Rfc5KDmc2ax^%CC{Zlfb<7g j7U>Tl{Q+J%MC$(^KE>8sP>{lf00000NkvXXu0mjf1j^3y literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_off.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_off.png new file mode 100644 index 0000000000000000000000000000000000000000..46f8d61efdd8add19037dd736c81785ed11734ab GIT binary patch literal 883 zcmV-(1C0EMP)F|9LGOaOG-+kkqf!Flz1?a3_5h}5>(Qqn_Yq~d5BI6A|XqM=qetpLy(6RM7jhO zbm|x(Xyv~(+!}Bu%xN20-EscFbkH4loUv@jn34Qk-pugb_vU@)`+M_d;eZ1U_@Ai? z`vw4ddV1{1$w>e@J3AQ~8uHxNZZwr}WG^}iLOPwcySln)Yik2wc6OF{JZ_JSjL_87 zgd|CHcX#8bNvG3+O*j;^gMUFPl|m2%5{U$YAdpI>{@GZOG+?*%4`l5Afs7rbkI+j1 zAe+q+kH=ldmSv&qI+kUT&*wcFfTxci0vkp=xOcOnatJ*EQ&UrcfA{q9Ln=)|=mzW+ zm6{L<1Lo%DT*s=aVp$f3VPIJns;YW4epF&YB-Q``RaN&yGn^Uyt8pWdfG~+n0`{64 zx9-~Q=P$ahO;5bz`LjXS+aeMP5Jk~-EXy*cX;Lf}F-;R$mOUDPM}uSBzSHO1=lG0B zQ&NdU;Qj4aE))s|}{N#cHAFTTn;k#RL{{>cP|m(s1A@E-8j|gZ>w?RK za`sIEwv)@{&~=?cp@6RI&z$q!0)L$U#+qI2w0=Zp5v+vq8IcQTldd)| zZX`;4|Dp=6|M9~p5(X%W;yh(VQBV{GP169-G|lWx3+mmlKHulve97_yy&c>8^1_l{NqX002ov JPDHLkV1j**pP~Q& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_red.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_terminal_red.png new file mode 100644 index 0000000000000000000000000000000000000000..8f02d3cdd377a43109b9d62125a259eca73b2d35 GIT binary patch literal 1473 zcmZ`(c{JNu6n>J}YmzA?j7luEtED}v2(e@kt=eW#WejE1QdCQ7ODK+|S_ZMD6jfA* zv}&1Js_hUe9BQYh)|M0d5+o(&r)U11bKd>l{o}rSzxUnuZmPYVm6(W(2mnCL#@f;m z+9{CXg#;k{I7%i1z@K7cY359#taHZOPStJlibnRolmxf3IeETAM`Bd0U;^@r<|If76!x zw+dd3ZYX5O_@G25z%;eAq~+4fgxsiEJ=d|ldX^5%R0rvmRoKi5(d(&cLnS_Ew|+Hz zrztYRhu&1 zuOcJ1*OC=qT;^A$zWsdmuM;fJe*H3W>45M)aQocD&7~H32G3o`;t?mH#<42S-I?O5 z=||EOf+^XU>lGv_*`N^eDgxjp68BGT4g9L~@VPdW#bIC(>CPg(LBo$rxPf_BOA8hq zAisi1J}Zgl_qs2SK4FeZliOQxt>qiRsM>3%bz1BCL9ns`q6=+#7o*vb7u;I~HSh7CR~ELt zc_t%ioB~Gkrzjcxv1nL(HFJ;E{^7gv_oOLa;>E@u8h4s(1+)(vpMwM}S{>ic-W;=< z#@^;B#O?c76$wYtu0rp$_ZhjZfTYL&-L1;NsPkCIOoU4$j;|Jd7KH6AkU0x%cX zx(32jlj7W!@WyguFOB6MDncul$Ojy&b0YR^G39z~sG&*AAUXGCjZ>_oOvvk)J@Rhx zeoBswL{f6T>(g;wUtc}$&Gg13ixpr;b7S88GF7!T3a2Qy$KbS(t?Y0NUFNs?xvb*S z*RN#&y{%2G$EisC4@oC>mz(q5<fpBRH0 zi)&?1mBFf7ercMEIQ%{yXvU4>gltp5foC3rtT_)XAnj2LNIVaKZVcssPc}*&JyTZ_ z4Ra;n#1|Ko=m}Ap{S7?8>hV%>fobr7Q}+Di1m1-Um&Ki0(IG} zgICobEp2X?AO97}*xlu@Y*R|qdCw9=?Y5vnTG0U?Q<;wg@9^aT0;`Dt#cT;;$>4uM z@jJ5zExNa5yD<<|h~@$k9Mk0dC)oGXI>su;NxDUk@6}-|c;)a2el~M-1g)wt42@=B ML$I@~HTO#R7dG3g?f?J) literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/medical_scanner.rsi/scanner_yellow.png b/Resources/Textures/Buildings/medical_scanner.rsi/scanner_yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..fe31a166e44351a6e4d9fa116a2dd4b73898be02 GIT binary patch literal 2092 zcmZWrc{tST7yn8(rDal7E4WQ3?js3#WPy6A!bRe8-tCpj=j=8f5@QA@I6 zCK1S6&fcbue{&T)M7V#(T0cB{(hAX)CCa9cTvXvfDlod?i*x&!>Y=gk7CeBOyuqf8 z`PK*NKXLTy+Zj(m{$M}b5VI)`E#L-K)uDHmF{wzV3#R^I#$l7UR?^SCX3Fxd(ukNF zjT8En%KK#~A8Y19b#)`CJ{^cTR(sKCi$xnfT74SDs8hK%uWcZuHnibtm~IN`u(Q!= zq+5$LOGF!#ri8r&b@FhTxRLe{DX*Jlr2faB*mM>yG=$g^2R(a{4?4=e-7!CKmzo!1 z>HjHCysoW!`CAO-Ly(Bfm7jCvf{88E$&DZvp$PUrCD4z0Cbgf8hR~8M!ZeWzZuZDu z?BrPv^70m@NGU&f!}H-VBlsAtPwl|jngYYx_6lu7n~@74G2!XN+}7q9`JHrTYAOgr zP}+HW6+OI9=-=zM(d?MTDLuT?d8Ks>8T?@Kjbix;`Dn5CJ=X%YuAnuC+o6u*<7RiW zq8@WV!Y&nYMw;oUfE~4;G}RdFuW0nBPa&muK>hKvhLms4S8afYCJTxI6!3 z#o<&#zfXCx7yC#Ri3k6|Z2+8~m|s7Tqltr;JUISa(~6$@FJU}*EeFJutEj{@MM3X83M~-pF&&Hxk4G4Z{_3nmD*&#hQLo^hQw5B~ zvT`$Xr##!r@hE6Msn{-38AvEBJ}6s$sZn#X8BXMm>ub%}C^88sfoG*Y;(U$?f&qG; zaLYxLX^6S#Nb*pS$aN+_5$gI9Dn1706aZA=g!-#RjwP@wWkuQGBZE77nli1^K9}<5h)EZOG0Gva~+lOR%@hjqvD~wEjyF-P6mwnc8FW8 zwP07QrG1N+mi?csGJ~tmrVGPDZY6iQHXLW>U^UNKy;|if5R`1ERiVcC9V4$Y2sJP6 z1v0`1w8Xp+Y~Y7V7JedbFi3P!ah`*umovH(x_xQEmJCyxJ0{_b z{Yfs0v20tj;Iuj0KH#&E8&-AJPN)z&GH&m`I`Df^^I5H|OCPH1VKds~m@ZCp+mj}q zciOSYg%`Ij`$bLd-Y=@P3!ZAYDFfaYaaNrQ0AN^12<=RCq4d5r#1A-6wML+RkTslK zTjs_^Z-`w|>Y`rf^-Kgu&a>E@9hal$kynX;hR|a18R%C0RnKDm!qCJqV*HZQ5b8h2 z^WVeTQf5!Iag)SJCF5h!3uE0|T#VsKg=vuMD|_F)hxGbEaR#Pu5|xZ#s3m-Sz7VLQ z6SNN;Y&owHZfu-1oMu-GE8e|0hS_u7_!UfUUG4^7I`lde_p>>@b7k*!gc$=L>p0bt zvpW+Pxzi8^qkTJ9Rsky>frG)V>5#c|G#n10$^V`yJp^7)|CQ#xCiP#AS(!+@jn`7j zQEy^bM%Pr7KFllJxE_Nr$z2#1Cgr9{uK0`A0A%axJmS`w>7KdinL7sNn%~Gm;M$u+ znd(KJ=`22;vL-c{3PtalFl*l!*REA-;T(VOf92dj45F2?c(J49d25 z@n6h0vLPD61pYHNq}S$qEaUH32`*_Y8^xCf(