using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using ComputerysModdingUtilities; using FishNet.Managing.Scened; using FishNet.Transporting; using HarmonyLib; using Microsoft.CodeAnalysis; using MyceliumNetworking; using Steamworks; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: StraftatMod(false)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Koki")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+09cc5fb7580c83d65182e8e5a7a2c7a9b3693307")] [assembly: AssemblyProduct("CustomLevelsReborn")] [assembly: AssemblyTitle("CustomLevelsReborn")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } [DefaultExecutionOrder(-500)] public class ImportGameObjects : MonoBehaviour { private void Awake() { foreach (GameObject sceneGO in StealSceneGOs.SceneGOs) { GameObject obj = Object.Instantiate(sceneGO); obj.transform.SetParent(((Component)this).transform); obj.SetActive(true); ((Object)obj).name = ((Object)obj).name.Replace("(Clone)", ""); } } } internal enum WeaponType { AAA12, AKK, APMine, AR15, BaseballBat, Bayshore, BeamLoad, Bender, BigFattyBro, BlankState, Bublee, Bukanee, Claymore, Couperet, Crisis, CurvedKnife, DF_Blister, DF_Cyst, DF_GodSword, DF_Torrent, Dispenser, DualLauncher, Elephant, FG42, Flamberge, FlashLight, Gamma, GammaGen2, GlaiveGun, GlandGrenade, Glock, Gun, Gust, HandCanon, HandGrenade, Havoc, Hill_H15, HK_Caws, HK_G11, Impetus, JahvalMahmaerd, Kanye, Katana, Keso, Kusma, M2000, Mac10, Minigun, Mortini, Nizeh, Nugget, Phoenix, Propeller, Prophet, ProximityMine, QCW05, Repulsar, Revolver, RocketLauncher, SawedOff, Shotgun, Silenzzio, SMG, SmithCarbine, StunGrenade, StunMine, Stylus, Taser, Tromblonj, Warden, Webley, Yangtse } public class CustomSpawner : MonoBehaviour { [SerializeField] private WeaponType _weapon; [Range(0f, 60f)] [SerializeField] private float _weaponRespawnTimeInSeconds = 3f; private void Awake() { string text = _weapon.ToString(); if (text == "AKK") { text = "AK-K"; } if (SpawnerManager.NameToWeaponDict.Count == 0) { SpawnerManager.PopulateAllWeapons(); } ItemSpawner component = ((Component)this).gameObject.GetComponent(); component.itemToSpawn = SpawnerManager.NameToWeaponDict[text]; ((Spawner)component).weaponRespawnTimeInSeconds = _weaponRespawnTimeInSeconds; ((Component)component).gameObject.SetActive(true); } } internal class SyncMaps : MonoBehaviour { [HarmonyPatch(typeof(SteamLobby), "OnLobbyEntered")] private static class HandleLobbyEnter { private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Transport), "SetClientAddress", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(SyncMaps), "DetermineMidMatchJoin", (Type[])null, (Type[])null); return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(true, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo, (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null) }).Insert((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Call, (object)methodInfo2), new CodeInstruction(OpCodes.Ret, (object)null) }).InstructionEnumeration(); } } [HarmonyPatch(typeof(MapSelection), "UpdateScenes")] private static class BlockDisabledMapsFromQueue { private static void Prefix(MapSelection __instance) { SelectSceneInstance[] sceneInstances = __instance.sceneInstances; foreach (SelectSceneInstance val in sceneInstances) { if (Enumerable.Contains(mapsToDisable.Keys, val.sceneName)) { val.selected = false; } } } } [HarmonyPatch(typeof(SceneMotor), "ServerStartGameScene")] private static class SetMapsInRotation { private static void Postfix(SceneMotor __instance) { CollectionExtensions.Do(__instance.PlayListMapsQueue.Where(((IEnumerable)CLRPlugin.SceneToBundleDir.Keys).Contains), (Action)delegate(string map) { foreach (string mapVersion in CLRPlugin.MapVersions) { if (mapVersion.Substring(0, mapVersion.LastIndexOf("-")) == map) { customMapsInRotation.Add(mapVersion); } } }); MyceliumNetwork.SetLobbyData("MapsInRotation", (object)string.Join(";", customMapsInRotation)); MyceliumNetwork.SetLobbyData("GameStarted", (object)true); customMapsInRotation.Clear(); } } [HarmonyPatch(typeof(SteamLobby), "EnterExplorationMap")] private static class BlockExploringDisabledMap { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(SyncMaps), "IsMapDisabled", (Type[])null, (Type[])null); Label label = default(Label); return new CodeMatcher(instructions, generator).End().CreateLabel(ref label).Start() .Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)methodInfo), new CodeInstruction(OpCodes.Brtrue, (object)label) }) .InstructionEnumeration(); } } private static readonly uint ID = 568324179u; private static Dictionary> mapsToDisable = new Dictionary>(); private static List customMapsInRotation = new List(); private void Awake() { MyceliumNetwork.RegisterNetworkObject((object)this, ID, 0); MyceliumNetwork.RegisterLobbyDataKey("MapsInRotation"); MyceliumNetwork.RegisterLobbyDataKey("GameStarted"); MyceliumNetwork.LobbyCreated += ResetMapLists; MyceliumNetwork.PlayerLeft += OnLobbyLeave; SceneManager.sceneLoaded += ResetLobbyKey; } private void ResetLobbyKey(Scene scene, LoadSceneMode _) { if (MyceliumNetwork.IsHost && MyceliumNetwork.InLobby && ((Scene)(ref scene)).name == "MainMenu") { MyceliumNetwork.SetLobbyData("GameStarted", (object)false); } } private void ResetMapLists() { mapsToDisable.Clear(); customMapsInRotation.Clear(); MyceliumNetwork.SetLobbyData("GameStarted", (object)false); } private static void Connect() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (((Transport)SteamLobby.Instance._fishySteamworks).StartConnection(false)) { SteamLobby.Instance.inSteamLobby = true; TargetedRPC(MyceliumNetwork.LobbyHost, "DisableNonSharedMaps", new object[1] { string.Join(";;", CLRPlugin.MapVersions) }); } else { Debug.LogError((object)"Failed to start FishySteamworks connection"); SteamLobby.Instance.LeaveLobby(); } } private static void DetermineMidMatchJoin() { if (MyceliumNetwork.IsHost || !MyceliumNetwork.GetLobbyData("GameStarted")) { Connect(); } else if (MyceliumNetwork.GetLobbyData("MapsInRotation").Split(";").Except(CLRPlugin.MapVersions) .Any()) { PauseManager.Instance.WriteOfflineLog("You are missing maps currently being used in this lobby!"); SteamLobby.Instance.LeaveLobby(); } else { Connect(); } } private string[] GetNonSharedMaps(string input) { return (from map in CLRPlugin.MapVersions.Except(input.Split(";;")) select map.Substring(0, map.LastIndexOf("-"))).ToArray(); } [CustomRPC] private void DisableNonSharedMaps(string clientMapString, RPCInfo sender) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) string[] nonSharedMaps = GetNonSharedMaps(clientMapString); string[] array = nonSharedMaps; foreach (string key in array) { if (!mapsToDisable.TryGetValue(key, out var value)) { value = new List(); mapsToDisable.Add(key, value); } value.Add(sender.SenderSteamID); } foreach (KeyValuePair mapDisabledSprite in CLRPlugin.MapDisabledSprites) { if (nonSharedMaps.Contains(mapDisabledSprite.Key)) { mapDisabledSprite.Value.SetActive(true); } } if (nonSharedMaps.Length != 0 && SceneMotor.Instance.currentSceneName == null && !SceneMotor.Instance.testMap) { PauseManager.Instance.ShowInfoPopup(SteamFriends.GetFriendPersonaName(sender.SenderSteamID) + " is missing " + string.Join(", ", nonSharedMaps) + "!"); } } private static bool IsMapDisabled(string mapname) { bool num = Enumerable.Contains(mapsToDisable.Keys, mapname); if (num) { PauseManager.Instance.WriteOfflineLog("Someone in the lobby doesn't have this map"); } return num; } private void OnLobbyLeave(CSteamID id) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!MyceliumNetwork.IsHost || MyceliumNetwork.Players.Length == 0) { return; } List list = new List(); foreach (KeyValuePair> item in mapsToDisable) { if (item.Value.Contains(id)) { item.Value.Remove(id); if (item.Value.Count == 0) { list.Add(item.Key); CLRPlugin.MapDisabledSprites[item.Key].SetActive(false); } } } CollectionExtensions.Do((IEnumerable)list, (Action)delegate(string m) { mapsToDisable.Remove(m); }); if (list.Count > 0 && (SceneMotor.Instance.currentSceneName == null || !SceneMotor.Instance.testMap)) { PauseManager.Instance.WriteOfflineLog(string.Join(", ", list) + " have been re-enabled."); } } private static void TargetedRPC(CSteamID target, string methodname, object[] parameters) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) MyceliumNetwork.RPCTarget(ID, methodname, target, (ReliableType)1, parameters); } } internal static class BundleLoad { private static AssetBundle bundleRef; internal static void UnloadBundle(Scene scene) { if (Object.op_Implicit((Object)(object)bundleRef) && CLRPlugin.SceneToBundleDir.ContainsKey(((Scene)(ref scene)).name)) { bundleRef.Unload(true); bundleRef = null; } } internal static void Start(string sceneName) { if (!Object.op_Implicit((Object)(object)bundleRef) && CLRPlugin.SceneToBundleDir.ContainsKey(sceneName)) { bundleRef = AssetBundle.LoadFromFile(CLRPlugin.SceneToBundleDir[sceneName]); } } } internal static class MultiplayerBundleLoad { [HarmonyPatch(typeof(SceneMotor), "GetNextMap")] private static class LoadHost { private static void Prepare() { SceneManager.sceneUnloaded += BundleLoad.UnloadBundle; } private static void Postfix(string __result) { BundleLoad.Start(__result); } } [HarmonyPatch(typeof(DefaultSceneProcessor), "BeginLoadAsync")] private static class LoadClient { private static void Prefix(string sceneName) { BundleLoad.Start(sceneName); } } } [HarmonyPatch(typeof(SceneMotor), "RpcLogic___EnterScene_3615296227")] internal static class SingleplayerBundleLoad { private static void Prefix(string sceneName) { BundleLoad.Start(sceneName); } } internal static class FixKillCamNRE { [HarmonyPatch(typeof(KillCam), "OnDisable")] private static class PreventDeathExplosion { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(KillCam), "switchCamText"); MethodInfo methodInfo = AccessTools.Method(typeof(FixKillCamNRE), "AreFieldsUninitialized", (Type[])null, (Type[])null); Label label = default(Label); return new CodeMatcher(instructions, generator).End().CreateLabel(ref label).MatchBack(false, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)fieldInfo, (string)null) }) .Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)methodInfo), new CodeInstruction(OpCodes.Brtrue, (object)label) }) .InstructionEnumeration(); } } private static bool AreFieldsUninitialized(KillCam __instance) { if (!Object.op_Implicit((Object)(object)__instance.switchCamText) && !Object.op_Implicit((Object)(object)__instance.playerHpText)) { return !Object.op_Implicit((Object)(object)__instance.playerNameText); } return false; } } [HarmonyPatch(typeof(MapsManager), "InitMaps")] internal static class RegisterScenes { private static void Postfix(MapsManager __instance) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) List list = new List(); int num = __instance.allMaps.Length; foreach (string key in CLRPlugin.SceneToBundleDir.Keys) { Map val = new Map { index = num++, mapName = key, isDlcExclusive = false, isAltMap = key.EndsWith("_alt"), isSelected = false, isUnlocked = true, mapInstance = null }; list.Add(val); __instance.allMapsDict.Add(val.mapName, val); GameObject val2 = Object.Instantiate(__instance.mapInstance, __instance.standardMapParent.position, Quaternion.identity, __instance.standardMapParent); val.mapInstance = val2.GetComponent(); val.mapInstance.name = val.mapName; val.mapInstance.selected = val.isSelected; } __instance.SortMapsFromMapInstanceName(); Map[] allMaps = __instance.allMaps; List list2 = list; int num2 = 0; Map[] array = (Map[])(object)new Map[allMaps.Length + list2.Count]; ReadOnlySpan readOnlySpan = new ReadOnlySpan(allMaps); readOnlySpan.CopyTo(new Span(array).Slice(num2, readOnlySpan.Length)); num2 += readOnlySpan.Length; foreach (Map item in list2) { array[num2] = item; num2++; } __instance.allMaps = array; List list3 = new List(); list3.AddRange(__instance.unlockedMaps); list3.AddRange(list.Select((Map map) => map.index)); __instance.unlockedMaps = list3.ToArray(); } } [HarmonyPatch(typeof(MapInstance), "Start")] internal static class SetThumbnail { public static void Postfix(MapInstance __instance) { if (!Object.op_Implicit((Object)(object)__instance.sprite) && CLRPlugin.MapThumbnails.ContainsKey(__instance.name)) { __instance.sprite = CLRPlugin.MapThumbnails[__instance.name]; __instance.img.texture = (Texture)(object)__instance.sprite; __instance.UpdateUI(); } } } [HarmonyPatch(typeof(SelectSceneInstance), "Start")] internal static class SetThumbnailAgain { public static void Postfix(SelectSceneInstance __instance) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)__instance.sprite)) { if (CLRPlugin.MapThumbnails.ContainsKey(__instance.sceneName)) { __instance.sprite = CLRPlugin.MapThumbnails[__instance.sceneName]; __instance.mapImg.texture = (Texture)(object)__instance.sprite; __instance.UpdateUI(); } if (!CLRPlugin.MapDisabledSprites.ContainsKey(__instance.sceneName)) { GameObject val = new GameObject(); val.AddComponent().sprite = CLRPlugin.MapDisabledSprite; ((Object)val).name = "MapDisabled"; val.SetActive(false); val.transform.SetParent(((Component)__instance).gameObject.transform); val.transform.localPosition = new Vector3(-77.4f, 0f, 0f); val.transform.localScale = new Vector3(1.1f, 0.6f, 0f); CLRPlugin.MapDisabledSprites.TryAdd(__instance.sceneName, val); } } } } internal static class StealSceneGOs { private static readonly string MapToStealFrom = "TheSamePlace_08"; private static readonly List RequiredGOs = new List(5) { "GameManager", "NetworkManager", "---USER INTERFACE---", "Main Camera", "EventSystem" }; internal static List SceneGOs = new List(); internal static void OnSceneLoad(Scene s, LoadSceneMode mode) { if (((Scene)(ref s)).name == "MainMenu") { SceneManager.LoadSceneAsync(MapToStealFrom, (LoadSceneMode)1); } else { if (!(((Scene)(ref s)).name == MapToStealFrom)) { return; } GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { if (RequiredGOs.Contains(((Object)val).name)) { val.SetActive(false); GameObject val2 = Object.Instantiate(val); Object.DontDestroyOnLoad((Object)(object)val2); SceneGOs.Add(val2); val.SetActive(true); } } SceneManager.sceneLoaded -= OnSceneLoad; SceneManager.UnloadSceneAsync(MapToStealFrom); } } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.koki.lvlreborn", "Custom Levels Reborn", "1.1.7")] public class CLRPlugin : BaseUnityPlugin { [Serializable] public class ThunderstoreManifest { public string name; public string version_number; public string website_url; public string description; } internal static ManualLogSource Log; internal static List MapVersions = new List(); internal static Sprite MapDisabledSprite; internal static Dictionary SceneToBundleDir = new Dictionary(); internal static Dictionary MapThumbnails = new Dictionary(); internal static Dictionary MapDisabledSprites = new Dictionary(); private Harmony _harmony = new Harmony("com.koki.lvlreborn"); private static string PluginDir; private HashSet seenBundles = new HashSet(); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; _harmony.PatchAll(); PluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); if (PluginDir == null) { PluginDir = Path.Combine(Paths.PluginPath, "DEVELOPMENT-BUILD-Custom Levels Reborn"); } FindBundles(); ((Component)this).gameObject.AddComponent(); SceneManager.sceneLoaded += StealSceneGOs.OnSceneLoad; } private void FindBundles() { MapDisabledSprite = AssetBundle.LoadFromFile(Path.Combine(PluginDir, "clr_shared")).LoadAsset("MapDisableOverlay"); foreach (string item in Directory.EnumerateDirectories(Paths.PluginPath)) { string packageVersion = GetPackageVersion(item); string text = Directory.GetDirectories(item, "CustomMaps", SearchOption.AllDirectories).FirstOrDefault(); if (!Utility.IsNullOrWhiteSpace(text)) { LoadBundles(text, packageVersion); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded maps: " + string.Join(", ", MapVersions))); } private void LoadBundles(string dir, string packageVer) { foreach (string item in Directory.EnumerateFiles(dir, "*", SearchOption.AllDirectories)) { string fileName = Path.GetFileName(item); if (seenBundles.Contains(fileName)) { continue; } seenBundles.Add(fileName); AssetBundle val = AssetBundle.LoadFromFile(item); if (val.isStreamedSceneAssetBundle) { foreach (string item2 in val.GetAllScenePaths().Select(Path.GetFileNameWithoutExtension)) { if (!SceneToBundleDir.ContainsKey(item2)) { SceneToBundleDir.Add(item2, item); MapVersions.Add(item2 + "-v" + packageVer); } } val.Unload(true); } else if (item.EndsWith("_resources")) { Texture2D[] array = val.LoadAllAssets(); foreach (Texture2D val2 in array) { MapThumbnails.Add(((Object)val2).name, val2); } } } } private string GetPackageVersion(string folder) { string path = Path.Combine(folder, "manifest.json"); try { ThunderstoreManifest thunderstoreManifest = JsonUtility.FromJson(File.ReadAllText(path)); if (thunderstoreManifest != null && !string.IsNullOrEmpty(thunderstoreManifest.version_number)) { return thunderstoreManifest.version_number; } } catch (Exception) { } return "{NO_VERSION_FOUND}"; } } namespace CustomLevelsReborn { public static class MyPluginInfo { public const string PLUGIN_GUID = "com.koki.lvlreborn"; public const string PLUGIN_NAME = "Custom Levels Reborn"; public const string PLUGIN_VERSION = "1.1.7"; } }