]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
make emagged marker component (fixed version of #13867) (#14096)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Sun, 19 Feb 2023 01:03:06 +0000 (01:03 +0000)
committerGitHub <noreply@github.com>
Sun, 19 Feb 2023 01:03:06 +0000 (19:03 -0600)
* The all-in-one hacking solution
The thinking man's lockpick
The iconic EMAG

* emagged medbay's stasis bed

* left med, emagged sec' apc

* went back to chem, emagged the dispenser

* emagged the fax while i was there

* had a donut while waiting for emag to charge

* i broke into the bridge then announced 'mandatory johnson inspection in medical'

* get system instead of dependency

* feedback

* net suggestion

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
* use EnsureComp and import NetworkedComponent

---------

Co-authored-by: deltanedas <user@zenith>
Co-authored-by: deltanedas <deltanedas@laptop>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
19 files changed:
Content.Server/Access/AccessWireAction.cs
Content.Server/Bed/BedSystem.cs
Content.Server/Bed/Components/StasisBedComponent.cs
Content.Server/Chemistry/Components/ReagentDispenserComponent.cs
Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
Content.Server/Communications/CommunicationsConsoleSystem.cs
Content.Server/Fax/FaxMachineComponent.cs
Content.Server/Fax/FaxSystem.cs
Content.Server/Power/Components/ApcComponent.cs
Content.Server/Power/EntitySystems/ApcSystem.cs
Content.Server/Recycling/Components/RecyclerComponent.cs
Content.Server/Recycling/RecyclerSystem.cs
Content.Server/VendingMachines/VendingMachineSystem.cs
Content.Shared/Access/Components/AccessReaderComponent.cs
Content.Shared/Access/Systems/AccessReaderSystem.cs
Content.Shared/Emag/Components/EmaggedComponent.cs [new file with mode: 0644]
Content.Shared/Emag/Systems/EmagSystem.cs
Content.Shared/VendingMachines/SharedVendingMachineSystem.cs
Content.Shared/VendingMachines/VendingMachineComponent.cs

index 35f3efbf0da068e5ae3c6449d4d67255c18f4dcc..8592febf239413ca663d238845f9a8fef77cc600 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Wires;
 using Content.Shared.Access;
 using Content.Shared.Access.Components;
+using Content.Shared.Emag.Components;
 using Content.Shared.Wires;
 
 namespace Content.Server.Access;
@@ -14,26 +15,28 @@ public sealed class AccessWireAction : ComponentWireAction<AccessReaderComponent
     private int _pulseTimeout = 30;
 
     public override StatusLightState? GetLightState(Wire wire, AccessReaderComponent comp)
-        => comp.Enabled ? StatusLightState.On : StatusLightState.Off;
+    {
+        return EntityManager.HasComponent<EmaggedComponent>(comp.Owner) ? StatusLightState.On : StatusLightState.Off;
+    }
 
     public override object StatusKey { get; } = AccessWireActionKey.Status;
 
     public override bool Cut(EntityUid user, Wire wire, AccessReaderComponent comp)
     {
         WiresSystem.TryCancelWireAction(wire.Owner, PulseTimeoutKey.Key);
-        comp.Enabled = false;
+        EntityManager.RemoveComponent<EmaggedComponent>(comp.Owner);
         return true;
     }
 
     public override bool Mend(EntityUid user, Wire wire, AccessReaderComponent comp)
     {
-        comp.Enabled = true;
+        EntityManager.AddComponent<EmaggedComponent>(comp.Owner);
         return true;
     }
 
     public override void Pulse(EntityUid user, Wire wire, AccessReaderComponent comp)
     {
-        comp.Enabled = false;
+        EntityManager.RemoveComponent<EmaggedComponent>(comp.Owner);
         WiresSystem.StartWireAction(wire.Owner, _pulseTimeout, PulseTimeoutKey.Key, new TimedWireEvent(AwaitPulseCancel, wire));
     }
 
@@ -49,9 +52,10 @@ public sealed class AccessWireAction : ComponentWireAction<AccessReaderComponent
     {
         if (!wire.IsCut)
         {
+            // check is still here incase you somehow TOCTOU it into unemagging something it shouldn't
             if (EntityManager.TryGetComponent<AccessReaderComponent>(wire.Owner, out var access))
             {
-                access.Enabled = true;
+                EntityManager.RemoveComponent<EmaggedComponent>(wire.Owner);
             }
         }
     }
index d39f24931cf58dda2a90d65b24f85fd81c3d4f79..01346fd19ac174b9e96bd0b56a563d4a6629af28 100644 (file)
@@ -10,6 +10,7 @@ using Content.Shared.Bed.Sleep;
 using Content.Shared.Body.Components;
 using Content.Shared.Buckle.Components;
 using Content.Shared.Damage;
+using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Server.Construction;
 using Content.Shared.Mobs.Systems;
@@ -114,7 +115,7 @@ namespace Content.Server.Bed
 
         private void OnEmagged(EntityUid uid, StasisBedComponent component, ref GotEmaggedEvent args)
         {
-            // Repeatable
+            args.Repeatable = true;
             // Reset any metabolisms first so they receive the multiplier correctly
             UpdateMetabolisms(uid, component, false);
             component.Multiplier = 1 / component.Multiplier;
@@ -139,7 +140,7 @@ namespace Content.Server.Bed
         {
             var metabolismRating = args.PartRatings[component.MachinePartMetabolismModifier];
             component.Multiplier = component.BaseMultiplier * metabolismRating; //linear scaling so it's not OP
-            if (component.Emagged)
+            if (HasComp<EmaggedComponent>(uid))
                 component.Multiplier = 1f / component.Multiplier;
         }
 
index 4309ba48de4cdb88c020e9ac6a3d5d0a961c7e0f..9a98c793aebef2ae71350d4928733ff4de1320fb 100644 (file)
@@ -6,14 +6,6 @@ namespace Content.Server.Bed.Components
     [RegisterComponent]
     public sealed class StasisBedComponent : Component
     {
-        /// <summary>
-        /// Stores whether or not the stasis bed has been emagged,
-        /// which causes the multiplier to speed up rather than
-        /// slow down. Needs to be stored for machine upgrades.
-        /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)]
-        public bool Emagged = false;
-
         [DataField("baseMultiplier", required: true), ViewVariables(VVAccess.ReadWrite)]
         public float BaseMultiplier = 10f;
 
index 3104a11d3586341f9622181e0f896844529d6eb9..8592eda00e4cad88dcacc2199e944d2a84ff596b 100644 (file)
@@ -22,9 +22,6 @@ namespace Content.Server.Chemistry.Components
         [ViewVariables(VVAccess.ReadWrite)]
         public string? EmagPackPrototypeId = default!;
 
-        [ViewVariables(VVAccess.ReadWrite)]
-        public bool IsEmagged = false;
-
         [DataField("clickSound"), ViewVariables(VVAccess.ReadWrite)]
         public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
 
index 62f4fc0e7dadf4530918fc79616a3195eef991f3..9a1d560f34f5c91683d4d14593229d75e8f28e00 100644 (file)
@@ -5,6 +5,7 @@ using Content.Shared.Chemistry;
 using Content.Shared.Chemistry.Dispenser;
 using Content.Shared.Containers.ItemSlots;
 using Content.Shared.Database;
+using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.FixedPoint;
 using JetBrains.Annotations;
@@ -79,7 +80,7 @@ namespace Content.Server.Chemistry.EntitySystems
                 inventory.AddRange(packPrototype.Inventory);
             }
 
-            if (reagentDispenser.IsEmagged
+            if (HasComp<EmaggedComponent>(reagentDispenser.Owner)
                 && reagentDispenser.EmagPackPrototypeId is not null
                 && _prototypeManager.TryIndex(reagentDispenser.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype))
             {
@@ -91,12 +92,10 @@ namespace Content.Server.Chemistry.EntitySystems
 
         private void OnEmagged(EntityUid uid, ReagentDispenserComponent reagentDispenser, ref GotEmaggedEvent args)
         {
-            if (!reagentDispenser.IsEmagged)
-            {
-                reagentDispenser.IsEmagged = true;
-                args.Handled = true;
-                UpdateUiState(reagentDispenser);
-            }
+            // adding component manually to have correct state
+            EntityManager.AddComponent<EmaggedComponent>(uid);
+            UpdateUiState(reagentDispenser);
+            args.Handled = true;
         }
 
         private void OnSetDispenseAmountMessage(EntityUid uid, ReagentDispenserComponent reagentDispenser, ReagentDispenserSetDispenseAmountMessage message)
index 23dc79b648b83da2e23e127ee2041019252d16e5..6e2844e2713ecb9ed693e7cc942ca02a42442c02 100644 (file)
@@ -15,6 +15,7 @@ using Content.Shared.Access.Systems;
 using Content.Shared.CCVar;
 using Content.Shared.Communications;
 using Content.Shared.Database;
+using Content.Shared.Emag.Components;
 using Content.Shared.Examine;
 using Content.Shared.Popups;
 using Robust.Server.GameObjects;
@@ -175,7 +176,7 @@ namespace Content.Server.Communications
             if (!_interaction.InRangeUnobstructed(console, user))
                 return false;
 
-            if (TryComp<AccessReaderComponent>(console, out var accessReaderComponent) && accessReaderComponent.Enabled)
+            if (TryComp<AccessReaderComponent>(console, out var accessReaderComponent) && !HasComp<EmaggedComponent>(console))
             {
                 return _accessReaderSystem.IsAllowed(user, accessReaderComponent);
             }
index 07402aefc8f6a4cd0cf4e3e5d6ebeebea5bd658a..25ceaf179c22413221c895de3a2843928d24cc45 100644 (file)
@@ -50,13 +50,6 @@ public sealed class FaxMachineComponent : Component
     [DataField("receiveNukeCodes")]
     public bool ReceiveNukeCodes { get; set; } = false;
 
-    /// <summary>
-    /// Is fax was emaaged
-    /// </summary>
-    [ViewVariables(VVAccess.ReadWrite)]
-    [DataField("emagged")]
-    public bool Emagged { get; set; } = false;
-
     /// <summary>
     /// Sound to play when fax has been emagged
     /// </summary>
index b7126a192caf58ab41cdc1413498f9d4b4eb5689..2881dae02224e93a55a5bdb86ee8f4cdb5c9fb9d 100644 (file)
@@ -13,6 +13,7 @@ using Content.Server.UserInterface;
 using Content.Shared.Administration.Logs;
 using Content.Shared.Containers.ItemSlots;
 using Content.Shared.Database;
+using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Fax;
 using Content.Shared.Interaction;
@@ -210,7 +211,7 @@ public sealed class FaxSystem : EntitySystem
                 return;
             }
 
-            if (component.KnownFaxes.ContainsValue(newName) && !component.Emagged) // Allow exist names if emagged for fun
+            if (component.KnownFaxes.ContainsValue(newName) && !HasComp<EmaggedComponent>(uid)) // Allow existing names if emagged for fun
             {
                 _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-name-exist"), uid);
                 return;
@@ -228,11 +229,7 @@ public sealed class FaxSystem : EntitySystem
 
     private void OnEmagged(EntityUid uid, FaxMachineComponent component, ref GotEmaggedEvent args)
     {
-        if (component.Emagged)
-            return;
-
         _audioSystem.PlayPvs(component.EmagSound, uid);
-        component.Emagged = true;
         args.Handled = true;
     }
 
@@ -246,7 +243,7 @@ public sealed class FaxSystem : EntitySystem
             switch (command)
             {
                 case FaxConstants.FaxPingCommand:
-                    var isForSyndie = component.Emagged &&
+                    var isForSyndie = HasComp<EmaggedComponent>(uid) &&
                                       args.Data.ContainsKey(FaxConstants.FaxSyndicateData);
                     if (!isForSyndie && !component.ResponsePings)
                         return;
@@ -362,7 +359,7 @@ public sealed class FaxSystem : EntitySystem
             { DeviceNetworkConstants.Command, FaxConstants.FaxPingCommand }
         };
 
-        if (component.Emagged)
+        if (HasComp<EmaggedComponent>(uid))
             payload.Add(FaxConstants.FaxSyndicateData, true);
 
         _deviceNetworkSystem.QueuePacket(uid, null, payload);
index 3047d7a7111656b74f1b36faf3a915f710f660e6..12a7f619211b88ae2555bb96b807a060c90f17af 100644 (file)
@@ -27,8 +27,6 @@ public sealed class ApcComponent : BaseApcNetComponent
     [ViewVariables]
     public bool MainBreakerEnabled = true;
 
-    public bool Emagged = false;
-
     public const float HighPowerThreshold = 0.9f;
     public static TimeSpan VisualsChangeDelay = TimeSpan.FromSeconds(1);
 
index c602ee3ab6e67e87f19820ac193aa0b78319cb29..d442a77c0644c1ddb84495d157926b2dfec3a986 100644 (file)
@@ -5,6 +5,7 @@ using Content.Server.Wires;
 using Content.Shared.Access.Components;
 using Content.Shared.Access.Systems;
 using Content.Shared.APC;
+using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Interaction;
@@ -88,11 +89,8 @@ namespace Content.Server.Power.EntitySystems
 
         private void OnEmagged(EntityUid uid, ApcComponent comp, ref GotEmaggedEvent args)
         {
-            if(!comp.Emagged)
-            {
-                comp.Emagged = true;
-                args.Handled = true;
-            }
+            // no fancy conditions
+            args.Handled = true;
         }
 
         public void UpdateApcState(EntityUid uid,
@@ -147,7 +145,7 @@ namespace Content.Server.Power.EntitySystems
             ApcComponent? apc=null,
             BatteryComponent? battery=null)
         {
-            if (apc != null && apc.Emagged)
+            if (apc != null && HasComp<EmaggedComponent>(uid))
                 return ApcChargeState.Emag;
 
             if (!Resolve(uid, ref apc, ref battery))
index 37225b5721435af72e9caea6c6b90cf9e1be2297..017c9881c1a4f7ed33c1d86f31aa3d6ea7391a61 100644 (file)
@@ -13,13 +13,6 @@ namespace Content.Server.Recycling.Components
         [DataField("enabled")]
         public bool Enabled;
 
-        /// <summary>
-        ///     Whether or not sentient beings will be recycled
-        /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("safe")]
-        internal bool Safe = true;
-
         /// <summary>
         ///     The percentage of material that will be recovered
         /// </summary>
index 43d274bcf4961ca21a7c69a0b92458ad5e41c350..de7c558b4c4179cd5b2cae33df279adf3b518552 100644 (file)
@@ -8,6 +8,7 @@ using Content.Server.Power.EntitySystems;
 using Content.Server.Recycling.Components;
 using Content.Shared.Audio;
 using Content.Shared.Body.Components;
+using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Examine;
 using Content.Shared.IdentityManagement;
@@ -131,7 +132,7 @@ namespace Content.Server.Recycling
 
             // Can only recycle things that are tagged trash or recyclable... And also check the safety of the thing to recycle.
             if (!_tags.HasAnyTag(entity, "Trash", "Recyclable") &&
-                (!TryComp(entity, out recyclable) || !recyclable.Safe && component.Safe))
+                (!TryComp(entity, out recyclable) || !recyclable.Safe && !HasComp<EmaggedComponent>(component.Owner)))
             {
                 return;
             }
@@ -162,7 +163,7 @@ namespace Content.Server.Recycling
 
         private bool CanGib(RecyclerComponent component, EntityUid entity)
         {
-            return HasComp<BodyComponent>(entity) && !component.Safe &&
+            return HasComp<BodyComponent>(entity) && HasComp<EmaggedComponent>(component.Owner) &&
                    this.IsPowered(component.Owner, EntityManager);
         }
 
@@ -191,8 +192,7 @@ namespace Content.Server.Recycling
 
         private void OnEmagged(EntityUid uid, RecyclerComponent component, ref GotEmaggedEvent args)
         {
-            if (!component.Safe) return;
-            component.Safe = false;
+            // no fancy conditions
             args.Handled = true;
         }
     }
index 7949b56ec45bb47ccca11bcb1a285c28ceb746bc..ccef2b1b4c62cb3491f01b387c640c74c31526fa 100644 (file)
@@ -10,6 +10,7 @@ using Content.Shared.Actions;
 using Content.Shared.Actions.ActionTypes;
 using Content.Shared.Damage;
 using Content.Shared.Destructible;
+using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Popups;
 using Content.Shared.Throwing;
@@ -133,11 +134,8 @@ namespace Content.Server.VendingMachines
 
         private void OnEmagged(EntityUid uid, VendingMachineComponent component, ref GotEmaggedEvent args)
         {
-            if (component.Emagged || component.EmaggedInventory.Count == 0 )
-                return;
-
-            component.Emagged = true;
-            args.Handled = true;
+            // only emag if there are emag-only items
+            args.Handled = component.EmaggedInventory.Count > 0;
         }
 
         private void OnDamage(EntityUid uid, VendingMachineComponent component, DamageChangedEvent args)
@@ -224,7 +222,7 @@ namespace Content.Server.VendingMachines
 
             if (TryComp<AccessReaderComponent?>(vendComponent.Owner, out var accessReader))
             {
-                if (!_accessReader.IsAllowed(sender.Value, accessReader) && !vendComponent.Emagged)
+                if (!_accessReader.IsAllowed(sender.Value, accessReader) && !HasComp<EmaggedComponent>(uid))
                 {
                     _popupSystem.PopupEntity(Loc.GetString("vending-machine-component-try-eject-access-denied"), uid);
                     Deny(uid, vendComponent);
@@ -391,7 +389,7 @@ namespace Content.Server.VendingMachines
 
         private VendingMachineInventoryEntry? GetEntry(string entryId, InventoryType type, VendingMachineComponent component)
         {
-            if (type == InventoryType.Emagged && component.Emagged)
+            if (type == InventoryType.Emagged && HasComp<EmaggedComponent>(component.Owner))
                 return component.EmaggedInventory.GetValueOrDefault(entryId);
 
             if (type == InventoryType.Contraband && component.Contraband)
index db5f9218e890ccd9dd02ee1df98a2fd0ed6a386a..97fe78f7e69861401301072383868fe4f7f4e780 100644 (file)
@@ -7,13 +7,6 @@ namespace Content.Shared.Access.Components
     [RegisterComponent]
     public sealed class AccessReaderComponent : Component
     {
-        /// <summary>
-        ///     Whether this reader is enabled or not. If disabled, all access
-        ///     checks will pass.
-        /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)]
-        public bool Enabled = true;
-
         /// <summary>
         ///     The set of tags that will automatically deny an allowed check, if any of them are present.
         /// </summary>
index e19db766ab935aace9fa518f02708560a20ae867..4562d05858fca23c648754386f82b477105cef0b 100644 (file)
@@ -1,6 +1,7 @@
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Content.Shared.Inventory;
+using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
 using Content.Shared.PDA;
 using Content.Shared.Access.Components;
@@ -28,7 +29,7 @@ namespace Content.Shared.Access.Systems
         {
             if (args.User == null) // AutoLink (and presumably future external linkers) have no user.
                 return;
-            if (component.Enabled && !IsAllowed(args.User.Value, component))
+            if (!HasComp<EmaggedComponent>(uid) && !IsAllowed(args.User.Value, component))
                 args.Cancel();
         }
 
@@ -46,12 +47,10 @@ namespace Content.Shared.Access.Systems
 
         private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
         {
-            if (reader.Enabled)
-            {
-                reader.Enabled = false;
-                args.Handled = true;
-            }
+            // no fancy conditions
+            args.Handled = true;
         }
+
         /// <summary>
         /// Searches the source for access tags
         /// then compares it with the targets readers access list to see if it is allowed.
@@ -86,7 +85,7 @@ namespace Content.Shared.Access.Systems
         /// <param name="reader">An access reader to check against</param>
         public bool IsAllowed(ICollection<string> accessTags, AccessReaderComponent reader)
         {
-            if (!reader.Enabled)
+            if (HasComp<EmaggedComponent>(reader.Owner))
             {
                 // Access reader is totally disabled, so access is always allowed.
                 return true;
diff --git a/Content.Shared/Emag/Components/EmaggedComponent.cs b/Content.Shared/Emag/Components/EmaggedComponent.cs
new file mode 100644 (file)
index 0000000..1b66357
--- /dev/null
@@ -0,0 +1,11 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Emag.Components;
+
+/// <summary>
+/// Marker component for emagged entities
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed class EmaggedComponent : Component
+{
+}
index 8d68131e42e08b444115c1fc780730383c759d4e..d5db09e1e242b5d5212e3de7a1eba9d43af129fa 100644 (file)
@@ -156,12 +156,19 @@ namespace Content.Shared.Emag.Systems
         /// </summary>
         public bool DoEmagEffect(EntityUid user, EntityUid target)
         {
+            // prevent emagging twice
+            if (HasComp<EmaggedComponent>(target))
+                return false;
+
             var emaggedEvent = new GotEmaggedEvent(user);
             RaiseLocalEvent(target, ref emaggedEvent);
+
+            if (!emaggedEvent.Repeatable)
+                EnsureComp<EmaggedComponent>(target);
             return emaggedEvent.Handled;
         }
     }
 
     [ByRefEvent]
-    public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false);
+    public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false, bool Repeatable = false);
 }
index 96b1f0a1d151fb3c256cd6560b7dc307cdfd2fbe..dfd129a9da2857f8a5b5ca10022bb92ca593e784 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Emag.Components;
 using Robust.Shared.Prototypes;
 using System.Linq;
 
@@ -36,7 +37,7 @@ public abstract class SharedVendingMachineSystem : EntitySystem
 
     /// <summary>
     /// Returns all of the vending machine's inventory. Only includes emagged and contraband inventories if
-    /// <see cref="VendingMachineComponent.Emagged"/> and <see cref="VendingMachineComponent.Contraband"/>
+    /// <see cref="EmaggedComponent"/> exists and <see cref="VendingMachineComponent.Contraband"/> is true
     /// are <c>true</c> respectively.
     /// </summary>
     /// <param name="uid"></param>
@@ -49,7 +50,7 @@ public abstract class SharedVendingMachineSystem : EntitySystem
 
         var inventory = new List<VendingMachineInventoryEntry>(component.Inventory.Values);
 
-        if (component.Emagged)
+        if (HasComp<EmaggedComponent>(uid))
             inventory.AddRange(component.EmaggedInventory.Values);
 
         if (component.Contraband)
index 1ae9562f7b908a97d44a24b9737394968de62281..52264aa4f3f0dcb06b76ca894f7c5ef3358ca1cb 100644 (file)
@@ -40,7 +40,6 @@ namespace Content.Shared.VendingMachines
         [ViewVariables]
         public Dictionary<string, VendingMachineInventoryEntry> ContrabandInventory = new();
 
-        public bool Emagged;
         public bool Contraband;
 
         public bool Ejecting;