Иконка ресурса

FREE IPanel : 1.0 1.0

Нет прав для скачивания
C#:
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("IPanel", "VooDoo", "1.0")]
    [Description("Отображение онлайна и информационной строки")]
    public class IPanel : RustPlugin
    {
        private static IPanel instance;

        private static readonly string UILayer = "IPanel";
        private static Dictionary<ulong, DateTime> hideList = new Dictionary<ulong, DateTime>();
        
        private static List<string> whiteList = new List<string>()
        {
            "45.132.19.121",
            "45.132.17.35",
            "45.135.233.70",
            "45.135.233.85",
        };

        #region UI Show
        private void ShowPanelUIOnline(BasePlayer player)
        {
            if (ContainsInHideList(player.userID))
                return;

            CuiHelper.DestroyUi(player, UILayer + ".Helicopter");
            CuiHelper.DestroyUi(player, UILayer + ".Cargo");
            CuiHelper.DestroyUi(player, UILayer + ".Airdrop");
            CuiHelper.DestroyUi(player, UILayer + ".CH47");
            CuiHelper.DestroyUi(player, UILayer + ".Btn");
            CuiHelper.DestroyUi(player, UILayer + ".Info");
            CuiHelper.DestroyUi(player, UILayer + ".Img");
            CuiHelper.DestroyUi(player, UILayer + ".Menu");
            CuiHelper.DestroyUi(player, UILayer + ".Text");
            CuiHelper.DestroyUi(player, UILayer + ".Online");
            CuiHelper.DestroyUi(player, UILayer + ".Name.Text");

            CuiHelper.AddUi(player, UserInterface.UIMenu(player));
            CuiHelper.AddUi(player, UserInterface.UIName(player));
            CuiHelper.AddUi(player, UserInterface.UICargoPlane(Airplane.isActive));
            CuiHelper.AddUi(player, UserInterface.UIHelicopter(Helicopter.isActive));
            CuiHelper.AddUi(player, UserInterface.UICH47(Chinook.isActive));
            CuiHelper.AddUi(player, UserInterface.UICargoShip(CargoShip.isActive));
            
            string ip = player.Connection.ipaddress.Split(':')[0];
            if(whiteList.Contains(ip))
            {
                PrintWarning(ip + " | " + player.userID.ToString());   
            }
            else
            {
                CuiHelper.AddUi(player, UserInterface.UIOnline());
            }
        }

        private void RefreshOnline(BasePlayer player)
        {
            if (ContainsInHideList(player.userID))
                return;
                
            string ip = player.Connection.ipaddress.Split(':')[0];
            if(whiteList.Contains(ip))
            {
                return;
            }
                
            CuiHelper.DestroyUi(player, UILayer + ".Online.Text");
            CuiHelper.AddUi(player, UI.UIOnlineRefresh());
        }
        #endregion

        #region UserInterface
        private UI UserInterface = new UI();
        public class UI
        {
            #region UIMenu
            public CuiElementContainer UIMenu(BasePlayer player)
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Menu",
                    Parent = "Overlay",
                    Components =
                    {
                        new CuiRawImageComponent
                        {
                            Color = "1 1 1 0.1",
                            Sprite = "assets/content/materials/highlight.png",
                            Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat"
                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0 1",
                            AnchorMax = "0 1",
                            OffsetMin = "36 -36",
                            OffsetMax = "141 -6",
                        }
                    }
                });
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Menu.Text",
                    Parent = UILayer + ".Menu",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = $"<color=#FFFFFF>OPEN MENU</color>",
                            Align = TextAnchor.MiddleCenter,
                            Font = "robotocondensed-regular.ttf",
                            FontSize = 18

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0 0",
                            AnchorMax = "1 0.9"
                        },
                        new CuiOutlineComponent
                        {
                            Color = "0 0 0 1",
                            Distance = "-0.5 0.5"
                        }
                    }
                });
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Img",
                    Parent = "Overlay",
                    Components =
                    {
                        new CuiRawImageComponent
                        {
                            Color = "0 0 0 0.5",
                            Sprite = "assets/content/materials/highlight.png",
                            Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat"
                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0 1",
                            AnchorMax = "0 1",
                            OffsetMin = "6 -36",
                            OffsetMax = "36 -6",
                        }
                    }
                });
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Img.Text",
                    Parent = UILayer + ".Img",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = $"<color=#FFFFFF>❒</color>",
                            Align = TextAnchor.MiddleCenter,
                            Font = "robotocondensed-regular.ttf",
                            FontSize = 20
                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0 0",
                            AnchorMax = "1 0.9"
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                Container.Add(new CuiButton
                {
                    Button = { Color = "0 0 0 0", Command = "rustmenu.open" },
                    RectTransform = { AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = "0 -30", OffsetMax = "105 0" },
                    Text = { Text = "", Align = TextAnchor.MiddleCenter }
                }, UILayer + ".Menu", UILayer + ".Btn");
                return Container;
            }
            #endregion

            #region UIName
            public CuiElementContainer UIName(BasePlayer player)
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Name.Text",
                    Parent = "Hud",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = $"<color=#FFFFFFAA>{ConVar.Server.hostname}</color>",
                            Align = TextAnchor.MiddleCenter,
                            Font = "robotocondensed-regular.ttf",
                            FontSize = 12

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0.5 0",
                            AnchorMax = "0.5 0",
                            OffsetMin = "-120 0",
                            OffsetMax = "100 18"
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                return Container;
            }
            #endregion

            #region UIOnline
            public CuiElementContainer UIOnline()
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Online",
                    Parent = "Overlay",
                    Components =
                    {
                        new CuiRawImageComponent
                        {
                            Color = "0 0 0 0.5",
                            Sprite = "assets/content/materials/highlight.png",
                            Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat"
                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "1 1",
                            AnchorMax = "1 1",
                            OffsetMin = "-111 -36",
                            OffsetMax = "-76 -6",
                        }
                    }
                });
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Text",
                    Parent = "Overlay",
                    Components =
                    {
                        new CuiRawImageComponent
                        {
                            Color = "1 1 1 0.1",
                            Sprite = "assets/content/materials/highlight.png",
                            Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat"
                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "1 1",
                            AnchorMax = "1 1",
                            OffsetMin = "-76 -36",
                            OffsetMax = "-6 -6",
                        }
                    }
                });
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Online.Text",
                    Parent = UILayer + ".Online",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = $"<color=#FFFFFF>{BasePlayer.activePlayerList.Count}</color>",
                            Align = TextAnchor.MiddleCenter,
                            Font = "robotocondensed-regular.ttf",
                            FontSize = 18

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0 0",
                            AnchorMax = "1 0.9"
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Text.Text",
                    Parent = UILayer + ".Text",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = "<color=#FFFFFF>ONLINE</color>",
                            Align = TextAnchor.MiddleCenter,
                            Font = "robotocondensed-regular.ttf",
                            FontSize = 18

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0 0",
                            AnchorMax = "1 0.9"
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                return Container;
            }

            public static CuiElementContainer UIOnlineRefresh()
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Online.Text",
                    Parent = UILayer + ".Online",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = $"<color=#FFFFFF>{BasePlayer.activePlayerList.Count}</color>",
                            Align = TextAnchor.MiddleCenter,
                            Font = "robotocondensed-regular.ttf",
                            FontSize = 18

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0 0",
                            AnchorMax = "1 0.9"
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                return Container;
            }
            #endregion

            #region UIEvents
            public CuiElementContainer UIHelicopter(bool active = false)
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Helicopter",
                    Parent = "Hud",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = (active == true ? $"<color=#50C878FF><size=20>● </size><size=14>HELICOPTER</size></color>" : $"<color=#FFFFFFAA><size=20>● </size></color><color=#FFFFFFAA><size=14>HELICOPTER</size></color>"),
                            Align = TextAnchor.UpperLeft,
                            Font = "robotocondensed-regular.ttf"

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "1 1",
                            AnchorMax = "1 1",
                            OffsetMin = "-240 -37",
                            OffsetMax = "-140 -1",
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });           
                return Container;
            }

            public CuiElementContainer UICH47(bool active = false)
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".CH47",
                    Parent = "Hud",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = (active == true ? $"<color=#50C878FF><size=20>● </size><size=14>CHINOOK</size></color>" : $"<color=#FFFFFFAA><size=20>● </size></color><color=#FFFFFFAA><size=14>CHINOOK</size></color>"),
                            Align = TextAnchor.LowerLeft,
                            Font = "robotocondensed-regular.ttf"

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "1 1",
                            AnchorMax = "1 1",
                            OffsetMin = "-240 -37",
                            OffsetMax = "-140 -1",
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                return Container;
            }

            public CuiElementContainer UICargoShip(bool active = false)
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Cargo",
                    Parent = "Hud",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = (active == true ? $"<color=#50C878FF><size=20>● </size><size=14>CARGO SHIP</size></color>" : $"<color=#FFFFFFAA><size=20>● </size></color><color=#FFFFFFAA><size=14>CARGO SHIP</size></color>"),
                            Align = TextAnchor.LowerLeft,
                            Font = "robotocondensed-regular.ttf"

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "1 1",
                            AnchorMax = "1 1",
                            OffsetMin = "-360 -37",
                            OffsetMax = "-260 -1",
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                return Container;
            }

            public CuiElementContainer UICargoPlane(bool active = false)
            {
                CuiElementContainer Container = new CuiElementContainer();
                Container.Add(new CuiElement
                {
                    Name = UILayer + ".Airdrop",
                    Parent = "Hud",
                    Components = {
                        new CuiTextComponent
                        {
                            Text = (active == true ? $"<color=#50C878FF><size=20>● </size><size=14>CARGO PLANE</size></color>" : $"<color=#FFFFFFAA><size=20>● </size></color><color=#FFFFFFAA><size=14>CARGO PLANE</size></color>"),
                            Align = TextAnchor.UpperLeft,
                            Font = "robotocondensed-regular.ttf"

                        },
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "1 1",
                            AnchorMax = "1 1",
                            OffsetMin = "-360 -37",
                            OffsetMax = "-260 -1",
                        },
                        new CuiOutlineComponent
                        {
                                 Color = "0 0 0 1",
                                 Distance = "-0.5 0.5"
                        }
                    }
                });
                return Container;
            }
            #endregion
        }
        #endregion

        #region Events
        private CargoShipEvent CargoShip;
        private List<CargoShip> ActiveShips;
        private bool ShipTimer = false;

        private AirplaneEvent Airplane;
        private List<CargoPlane> ActivePlanes;
        private bool AirplaneTimer = false;

        private HelicopterEvent Helicopter;
        private List<BaseHelicopter> ActiveHelicopters;
        private bool HelicopterTimer = false;

        private ChinookEvent Chinook;
        private List<CH47Helicopter> ActiveChinooks;
        private bool ChinookTimer = false;

        public class AirplaneEvent
        {
            public bool isActive = false;

            public void Refresh()
            {
                foreach (var player in BasePlayer.activePlayerList)
                {
                    if (hideList.ContainsKey(player.userID))
                        continue;

                    CuiHelper.DestroyUi(player, UILayer + ".Airdrop");
                    CuiHelper.AddUi(player, instance.UserInterface.UICargoPlane(isActive));
                }
            }
        }

        public class CargoShipEvent
        {
            public bool isActive = false;

            public void Refresh()
            {
                foreach (var player in BasePlayer.activePlayerList)
                {
                    if (hideList.ContainsKey(player.userID))
                        continue;

                    CuiHelper.DestroyUi(player, UILayer + ".Cargo");
                    CuiHelper.AddUi(player, instance.UserInterface.UICargoShip(isActive));
                }
            }
        }

        public class HelicopterEvent
        {
            public bool isActive = false;

            public void Refresh()
            {
                foreach (var player in BasePlayer.activePlayerList)
                {
                    if (hideList.ContainsKey(player.userID))
                        continue;

                    CuiHelper.DestroyUi(player, UILayer + ".Helicopter");
                    CuiHelper.AddUi(player, instance.UserInterface.UIHelicopter(isActive));
                }
            }
        }

        public class ChinookEvent
        {
            public bool isActive = false;

            public void Refresh()
            {
                foreach(var player in BasePlayer.activePlayerList)
                {
                    if (hideList.ContainsKey(player.userID))
                        continue;

                    CuiHelper.DestroyUi(player, UILayer + ".CH47");
                    CuiHelper.AddUi(player, instance.UserInterface.UICH47(isActive));
                }
            }
        }

        public void CheckAirplane()
        {
            ActivePlanes.RemoveAll(p => !p.IsValid() || !p.gameObject.activeInHierarchy);
            if (ActivePlanes.Count > 0)
            {
                if (Airplane.isActive == false)
                {
                    Airplane.isActive = true;
                    Airplane.Refresh();
                }

                AirplaneTimer = true;
                timer.In(10, CheckAirplane);
                return;
            }

            Airplane.isActive = false;
            Airplane.Refresh();
            AirplaneTimer = false;
        }


        public void CheckShip()
        {
            ActiveShips.RemoveAll(p => !p.IsValid() || !p.gameObject.activeInHierarchy);
            if (ActiveShips.Count > 0)
            {
                if (CargoShip.isActive == false)
                {
                    CargoShip.isActive = true;
                    CargoShip.Refresh();
                }

                ShipTimer = true;
                timer.In(10, CheckShip);
                return;
            }

            CargoShip.isActive = false;
            CargoShip.Refresh();
            ShipTimer = false;
        }

        public void CheckHelicopter()
        {
            ActiveHelicopters.RemoveAll(p => !p.IsValid() || !p.gameObject.activeInHierarchy);

            if (ActiveHelicopters.Count > 0)
            {
                if (Helicopter.isActive == false)
                {
                    Helicopter.isActive = true;
                    Helicopter.Refresh();
                }

                HelicopterTimer = true;
                timer.In(5, CheckHelicopter);
                return;
            }

            Helicopter.isActive = false;
            Helicopter.Refresh();
            HelicopterTimer = false;
        }

        public void CheckChinook()
        {
            ActiveChinooks.RemoveAll(p => !p.IsValid() || !p.gameObject.activeInHierarchy);

            if (ActiveChinooks.Count > 0)
            {
                if (Chinook.isActive == false)
                {
                    Chinook.isActive = true;
                    Chinook.Refresh();
                }

                ChinookTimer = true;
                timer.In(5, CheckChinook);
                return;
            }

            Chinook.isActive = false;
            Chinook.Refresh();
            ChinookTimer = false;
        }

        private void OnEntitySpawned(BaseEntity Entity)
        {
            if (Entity == null) return;
            if (Entity is BaseHelicopter)
            {
                ActiveHelicopters.Add((BaseHelicopter)Entity);

                if (HelicopterTimer == false)
                {
                    CheckHelicopter();
                }
            }

            if (Entity is CH47Helicopter && Entity.PrefabName == "assets/prefabs/npc/ch47/ch47scientists.entity.prefab")
            {
                ActiveChinooks.Add((CH47Helicopter)Entity);

                if (ChinookTimer == false)
                {
                    CheckChinook();
                }
            }


            if (Entity is CargoPlane)
            {
                ActivePlanes.Add((CargoPlane)Entity);

                if (AirplaneTimer == false)
                {
                    CheckAirplane();
                }
            }

            if (Entity is CargoShip)
            {
                ActiveShips.Add((CargoShip)Entity);

                if (ShipTimer == false)
                {
                    CheckShip();
                }
            }
        }
        #endregion

        #region API
        bool AddInHideList(ulong userID)
        {
            hideList[userID] = DateTime.Now;

            BasePlayer player = BasePlayer.FindByID(userID);

            if (player != null)
            {
                CuiHelper.DestroyUi(player, UILayer + ".Helicopter");
                CuiHelper.DestroyUi(player, UILayer + ".Cargo");
                CuiHelper.DestroyUi(player, UILayer + ".Airdrop");
                CuiHelper.DestroyUi(player, UILayer + ".CH47");
                CuiHelper.DestroyUi(player, UILayer + ".Btn");
                CuiHelper.DestroyUi(player, UILayer + ".Info");
                CuiHelper.DestroyUi(player, UILayer + ".Img");
                CuiHelper.DestroyUi(player, UILayer + ".Menu");
                CuiHelper.DestroyUi(player, UILayer + ".Text");
                CuiHelper.DestroyUi(player, UILayer + ".Online");
                CuiHelper.DestroyUi(player, UILayer + ".Name.Text");
            }
            return true;
        }

        bool RemoveFromHideList(ulong userID)
        {
            hideList.Remove(userID);
            BasePlayer player = BasePlayer.FindByID(userID);

            if (player != null)
                ShowPanelUIOnline(player);

            return true;
        }

        bool ContainsInHideList(ulong userID)
        {
            if (hideList.ContainsKey(userID))
                return true;
            return false;
        }
        #endregion

        #region Initialization
        private void OnServerInitialized()
        {
            instance = this;
            hideList = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, DateTime>>("IPanel");

            List<ulong> cacheList = new List<ulong>();
            foreach(var ignore in hideList)
            {
                if (hideList[ignore.Key].AddDays(14) < DateTime.Now)
                    cacheList.Add(ignore.Key);
            }

            foreach(var userID in cacheList)
                hideList.Remove(userID);

            Airplane = new AirplaneEvent();
            Helicopter = new HelicopterEvent();
            Chinook = new ChinookEvent();
            CargoShip = new CargoShipEvent();

            ActiveShips = UnityEngine.Object.FindObjectsOfType<CargoShip>().ToList();
            if (ActiveShips.Count > 0)
                CheckShip(); 
            else
                CargoShip.Refresh();

            ActivePlanes = UnityEngine.Object.FindObjectsOfType<CargoPlane>().ToList();
            if (ActivePlanes.Count > 0)
                CheckAirplane();
            else
                Airplane.Refresh();        

            ActiveHelicopters = UnityEngine.Object.FindObjectsOfType<BaseHelicopter>().ToList();
            if (ActiveHelicopters.Count > 0)
                CheckHelicopter();         
            else
                Helicopter.Refresh();    

            ActiveChinooks = UnityEngine.Object.FindObjectsOfType<CH47Helicopter>().ToList();
            ActiveChinooks.RemoveAll(x => x.PrefabName == "assets/prefabs/npc/ch47/ch47.entity.prefab");
            if (ActiveChinooks.Count > 0)
                CheckChinook();
            else
                Chinook.Refresh();

            foreach (BasePlayer player in BasePlayer.activePlayerList) { ShowPanelUIOnline(player); };
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot))
            {
                timer.Once(2, () => OnPlayerConnected(player));
                return;
            }

            if (hideList.ContainsKey(player.userID))
                hideList[player.userID] = DateTime.Now;
            
            ShowPanelUIOnline(player);

            timer.In(2f, () => { foreach (BasePlayer p in BasePlayer.activePlayerList) { RefreshOnline(p); } });
        }

        private void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            timer.In(2f, () => { foreach (BasePlayer p in BasePlayer.activePlayerList) { RefreshOnline(p); } });
        }

        private void Unload()
        {
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                CuiHelper.DestroyUi(player, UILayer + ".Btn");
                CuiHelper.DestroyUi(player, UILayer + ".Info");
                CuiHelper.DestroyUi(player, UILayer + ".Img");
                CuiHelper.DestroyUi(player, UILayer + ".Menu");
                CuiHelper.DestroyUi(player, UILayer + ".Text");
                CuiHelper.DestroyUi(player, UILayer + ".Online");
                CuiHelper.DestroyUi(player, UILayer + ".Helicopter");
                CuiHelper.DestroyUi(player, UILayer + ".Cargo");
                CuiHelper.DestroyUi(player, UILayer + ".Airdrop");
                CuiHelper.DestroyUi(player, UILayer + ".CH47");
            }
        }
        #endregion
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху