Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ScalingDailyQuota v1.0.1
ScalingDailyQuota.dll
Decompiled a year agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using ScalingDailyQuota.Modules; using ScalingDailyQuota.NetcodePatcher; using ScalingDailyQuota.Patches; using TMPro; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ScalingDailyQuota")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+8a5c7b77a57da26b670c1bf0f040acc75a532e2d")] [assembly: AssemblyProduct("ScalingDailyQuota")] [assembly: AssemblyTitle("ScalingDailyQuota")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: NetcodePatchedAssembly] internal class <Module> { static <Module>() { } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ScalingDailyQuota { [BepInPlugin("Angst-ScalingDailyQuota", "ScalingDailyQuota", "1.0.1")] public class ScalingDailyQuota : BaseUnityPlugin { public static ConfigEntry<bool>? config_playerScaling; public static ConfigEntry<int>? config_daysPerCycle; public static ConfigEntry<float>? config_commissionPercent; public static ConfigEntry<bool>? config_quotaRollover; public static ConfigEntry<int>? playerQuota_startingAmount; public static ConfigEntry<int>? playerQuota_dailyIncrease; public static ConfigEntry<int>? playerQuota_difficultyIncrease; public static ConfigEntry<int>? fixedQuota_startingAmount; public static ConfigEntry<int>? fixedQuota_dailyIncrease; public static ConfigEntry<int>? fixedQuota_difficultyIncrease; private readonly Harmony harmony = new Harmony("Angst-ScalingDailyQuota"); private static ScalingDailyQuota? Instance; public static ManualLogSource? mls; private void Awake() { if (Object.op_Implicit((Object)(object)(Instance = null))) { Instance = this; } ConfigureConfig(); mls = Logger.CreateLogSource("Angst-ScalingDailyQuota"); mls.LogInfo((object)"Robot is online."); mls.LogInfo((object)"Reviewing primary directives..."); NetcodePatcher(); harmony.PatchAll(typeof(GameNetworkManagerPatch)); harmony.PatchAll(typeof(ScalingDailyQuota)); harmony.PatchAll(typeof(StartOfRoundPatch)); harmony.PatchAll(typeof(TimeOfDayPatch)); harmony.PatchAll(typeof(DepositItemsDeskPatch)); } public void ConfigureConfig() { config_playerScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("Angst", "Player Scaling?", true, "Scale certain config settings depending on player count"); config_daysPerCycle = ((BaseUnityPlugin)this).Config.Bind<int>("Angst", "Days per Quota Cycle", 3, "Sets how many days are in a quota cycle. aka how often the Difficulty Increase happens."); config_commissionPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Angst", "Company Commission Percent", 0.25f, "How much of the fulfilled quota does The Company pay the players and reinvest into future jobs?"); config_quotaRollover = ((BaseUnityPlugin)this).Config.Bind<bool>("Angst", "Quota-Cycle Quota Rollover?", true, "Collecting and selling more than required will be credited towards your next quota. This is how I intended this game mode to work. Disabling this will turn any extra quota into credits."); playerQuota_startingAmount = ((BaseUnityPlugin)this).Config.Bind<int>("Player Scaling", "Quota Starting Amount, Per-Player", 100, "If player scaling is enabled, the quota on the first day will start at this amount, Per-Player"); playerQuota_dailyIncrease = ((BaseUnityPlugin)this).Config.Bind<int>("Player Scaling", "Daily Quota, Per-Player", 100, "If player scaling is enabled, the quota will increase daily by this amount, Per-Player."); playerQuota_difficultyIncrease = ((BaseUnityPlugin)this).Config.Bind<int>("Player Scaling", "Difficulty Increase, Per-Player, Per-Completed-Quota-Cycle", 25, "If player scaling is enabled, the Per-Player Daily Quota will increase this much per-completed quota cycle."); fixedQuota_startingAmount = ((BaseUnityPlugin)this).Config.Bind<int>("Fixed Quota", "Fixed Value Starting Quota", 500, "If player scaling is disabled, the quota will start at this fixed amount."); fixedQuota_dailyIncrease = ((BaseUnityPlugin)this).Config.Bind<int>("Fixed Quota", "Fixed Value Daily Quota Increase", 500, "If player scaling is disabled, the quota will increase daily by this fixed amount."); fixedQuota_difficultyIncrease = ((BaseUnityPlugin)this).Config.Bind<int>("Fixed Quota", "Fixed Difficulty Increase Per-Completed-Quota", 500, "If player scaling is disabled, the Daily Quota will increase this much per-completed quota cycle."); } public static void SetNewQuotaAtEndOfCycle(int otb) { if (NetworkManager.Singleton.IsServer) { Terminal val = Object.FindFirstObjectByType<Terminal>(); TimeOfDay instance = TimeOfDay.Instance; instance.timesFulfilledQuota++; mls.LogWarning((object)"test this part of the code"); mls.LogWarning((object)"credits may be added twice if original code is still running. better check this!"); if (config_quotaRollover.Value) { TimeOfDay instance2 = TimeOfDay.Instance; instance2.quotaFulfilled -= TimeOfDay.Instance.profitQuota; } else { TimeOfDay.Instance.quotaFulfilled = 0; } TimeOfDay.Instance.timeUntilDeadline = TimeOfDay.Instance.totalTime * (float)TimeOfDay.Instance.quotaVariables.deadlineDaysAmount; SetDailyQuota(); Terminal val2 = Object.FindObjectOfType<Terminal>(); val2.RotateShipDecorSelection(); } } public static void SetDailyQuota() { if (NetworkManager.Singleton.IsServer) { int num = (config_playerScaling.Value ? playerQuota_dailyIncrease.Value : fixedQuota_dailyIncrease.Value); int num2 = (config_playerScaling.Value ? playerQuota_difficultyIncrease.Value : fixedQuota_difficultyIncrease.Value); int num3 = RoundManager.Instance.playersManager.connectedPlayersAmount + 1; int timesFulfilledQuota = TimeOfDay.Instance.timesFulfilledQuota; TimeOfDay instance = TimeOfDay.Instance; instance.profitQuota += (num + num2 * timesFulfilledQuota) * num3; mls.LogInfo((object)("New Quota: " + TimeOfDay.Instance.profitQuota)); mls.LogInfo((object)"Sending new quota info to clients."); SDQNetworkHandler.Instance.SyncDailyQuotaClientRPC(TimeOfDay.Instance.profitQuota, TimeOfDay.Instance.quotaFulfilled, TimeOfDay.Instance.timesFulfilledQuota, TimeOfDay.Instance.timeUntilDeadline); } } private static void NetcodePatcher() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { methodInfo.Invoke(null, null); } } } } } public class SDQNetworkHandler : NetworkBehaviour { public static ManualLogSource mls; public static SDQNetworkHandler Instance { get; private set; } public override void OnNetworkSpawn() { if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) { SDQNetworkHandler instance = Instance; if (instance != null) { ((Component)instance).gameObject.GetComponent<NetworkObject>().Despawn(true); } } Instance = this; ((NetworkBehaviour)this).OnNetworkSpawn(); mls = Logger.CreateLogSource("Angst-ScalingDailyQuota"); } [ClientRpc] public void SyncDailyQuotaClientRPC(int pq, int qf, int tfq, float tud) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(3996670526u, val, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val2, pq); BytePacker.WriteValueBitPacked(val2, qf); BytePacker.WriteValueBitPacked(val2, tfq); ((FastBufferWriter)(ref val2)).WriteValueSafe<float>(ref tud, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 3996670526u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost)) { mls.LogInfo((object)"New quota info received from Server."); TimeOfDay.Instance.profitQuota = pq; TimeOfDay.Instance.quotaFulfilled = qf; TimeOfDay.Instance.timesFulfilledQuota = tfq; TimeOfDay.Instance.timeUntilDeadline = tud; ((TMP_Text)StartOfRound.Instance.profitQuotaMonitorText).text = $"PROFIT QUOTA:\n${qf} / ${pq}"; } } } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } [RuntimeInitializeOnLoadMethod] internal static void InitializeRPCS_SDQNetworkHandler() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown NetworkManager.__rpc_func_table.Add(3996670526u, new RpcReceiveHandler(__rpc_handler_3996670526)); } private static void __rpc_handler_3996670526(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int pq = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref pq); int qf = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref qf); int tfq = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref tfq); float tud = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref tud, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)2; ((SDQNetworkHandler)(object)target).SyncDailyQuotaClientRPC(pq, qf, tfq, tud); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "SDQNetworkHandler"; } } } namespace ScalingDailyQuota.Patches { [HarmonyPatch(typeof(DepositItemsDesk))] internal class DepositItemsDeskPatch { [HarmonyPatch("SellItemsOnServer")] [HarmonyPrefix] private static void SellItemsOnServerPrefix(out int __state) { Terminal val = Object.FindObjectOfType<Terminal>(); __state = val.groupCredits; } [HarmonyPatch("SellItemsOnServer")] [HarmonyPostfix] private static void SellItemsOnServerPostfix(int __state) { Terminal val = Object.FindObjectOfType<Terminal>(); int num = val.groupCredits - __state; if (TimeOfDay.Instance.quotaFulfilled + num <= TimeOfDay.Instance.profitQuota || ScalingDailyQuota.config_quotaRollover.Value) { val.groupCredits = __state + (int)((float)num * ScalingDailyQuota.config_commissionPercent.Value); return; } int num2 = TimeOfDay.Instance.quotaFulfilled + num - TimeOfDay.Instance.profitQuota; val.groupCredits = __state + (int)((float)num * ScalingDailyQuota.config_commissionPercent.Value) + num2; } } [HarmonyPatch] public class GameNetworkManagerPatch { private static GameObject networkPrefab; [HarmonyPostfix] [HarmonyPatch(typeof(GameNetworkManager), "Start")] public static void Init() { if (!((Object)(object)networkPrefab != (Object)null)) { networkPrefab = NetworkPrefabs.CreateNetworkPrefab("Angst-ScalingDailyQuota"); networkPrefab.AddComponent<SDQNetworkHandler>(); NetworkManager.Singleton.AddNetworkPrefab(networkPrefab); } } [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "Awake")] private static void SpawnNetworkHandler() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) ManualLogSource val = Logger.CreateLogSource("Angst-ScalingDailyQuota"); if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) { val.LogInfo((object)"spawning network handler."); GameObject val2 = Object.Instantiate<GameObject>(networkPrefab, Vector3.zero, Quaternion.identity); val2.GetComponent<NetworkObject>().Spawn(false); } } } [HarmonyPatch(typeof(HUDManager))] internal class HUDManagerPatch { [HarmonyPatch("DisplayNewDeadline")] [HarmonyPrefix] private static bool DisplayNewDeadlinePrefix(int overtimeBonus) { HUDManager.Instance.reachedProfitQuotaAnimator.SetBool("display", true); ((TMP_Text)HUDManager.Instance.newProfitQuotaText).text = "$" + TimeOfDay.Instance.profitQuota; HUDManager.Instance.UIAudio.PlayOneShot(HUDManager.Instance.reachedQuotaSFX); HUDManager.Instance.displayingNewQuota = true; if (overtimeBonus < 0) { ((TMP_Text)HUDManager.Instance.reachedProfitQuotaBonusText).text = ""; } else { ((TMP_Text)HUDManager.Instance.reachedProfitQuotaBonusText).text = $"Overtime bonus: ${overtimeBonus}"; } ((MonoBehaviour)HUDManager.Instance).StartCoroutine(HUDManager.Instance.rackUpNewQuotaText()); return false; } } internal class RoundManagerPatch { } [HarmonyPatch(typeof(StartOfRound))] internal class StartOfRoundPatch { [HarmonyPatch("PassTimeToNextDay")] [HarmonyPrefix] private static void PassTimeToNextDayPrefix() { if (NetworkManager.Singleton.IsServer && TimeOfDay.Instance.daysUntilDeadline > 1 && StartOfRound.Instance.currentLevel.planetHasTime) { ScalingDailyQuota.SetDailyQuota(); } } [HarmonyPatch("OnClientConnect")] [HarmonyPostfix] private static void OnClientConnectPostfix(ref StartOfRound __instance, ref ulong clientId) { IEnumerator enumerator = DelayedSyncQuota(); int value = ScalingDailyQuota.playerQuota_dailyIncrease.Value; int value2 = ScalingDailyQuota.playerQuota_difficultyIncrease.Value; int timesFulfilledQuota = TimeOfDay.Instance.timesFulfilledQuota; TimeOfDay instance = TimeOfDay.Instance; instance.profitQuota += ScalingDailyQuota.playerQuota_dailyIncrease.Value + value2 * timesFulfilledQuota; ((MonoBehaviour)StartOfRound.Instance.allPlayerScripts[__instance.ClientPlayerList[clientId]]).StartCoroutine(enumerator); } private static IEnumerator DelayedSyncQuota() { yield return (object)new WaitForSeconds(5f); SDQNetworkHandler.Instance.SyncDailyQuotaClientRPC(TimeOfDay.Instance.profitQuota, TimeOfDay.Instance.quotaFulfilled, TimeOfDay.Instance.timesFulfilledQuota, TimeOfDay.Instance.timeUntilDeadline); } [HarmonyPatch("OnClientDisconnect")] [HarmonyPostfix] private static void OnClientDisconnectPostfix() { int value = ScalingDailyQuota.playerQuota_dailyIncrease.Value; int value2 = ScalingDailyQuota.playerQuota_difficultyIncrease.Value; int timesFulfilledQuota = TimeOfDay.Instance.timesFulfilledQuota; TimeOfDay instance = TimeOfDay.Instance; instance.profitQuota -= ScalingDailyQuota.playerQuota_dailyIncrease.Value + value2 * timesFulfilledQuota; SDQNetworkHandler.Instance.SyncDailyQuotaClientRPC(TimeOfDay.Instance.profitQuota, TimeOfDay.Instance.quotaFulfilled, TimeOfDay.Instance.timesFulfilledQuota, TimeOfDay.Instance.timeUntilDeadline); } } [HarmonyPatch(typeof(TimeOfDay))] internal class TimeOfDayPatch { [HarmonyPatch("Awake")] [HarmonyPrefix] public static void AwakePrefix(ref TimeOfDay __instance) { QuotaSettings quotaVariables = __instance.quotaVariables; quotaVariables.startingQuota = (ScalingDailyQuota.config_playerScaling.Value ? ScalingDailyQuota.playerQuota_startingAmount.Value : ScalingDailyQuota.fixedQuota_startingAmount.Value); quotaVariables.deadlineDaysAmount = ScalingDailyQuota.config_daysPerCycle.Value; } [HarmonyPatch("SetNewProfitQuota")] [HarmonyPrefix] private static bool SetNewProfitQuotaPrefix() { if (!NetworkManager.Singleton.IsServer) { return false; } int num = TimeOfDay.Instance.quotaFulfilled - TimeOfDay.Instance.profitQuota; int newQuotaAtEndOfCycle = num / 5 + 15 * TimeOfDay.Instance.daysUntilDeadline; ScalingDailyQuota.SetNewQuotaAtEndOfCycle(newQuotaAtEndOfCycle); return false; } [HarmonyPatch("SetBuyingRateForDay")] [HarmonyPrefix] private static bool SetBuyingRateForDayPrefix() { StartOfRound.Instance.companyBuyingRate = 1f; return false; } } } namespace ScalingDailyQuota.Modules { public class NetworkPrefabs { private static List<GameObject> _networkPrefabs = new List<GameObject>(); public static void RegisterNetworkPrefab(GameObject prefab) { if (prefab == null) { throw new ArgumentNullException("prefab", "The given argument for RegisterNetworkPrefab is null!"); } if (!_networkPrefabs.Contains(prefab)) { _networkPrefabs.Add(prefab); } } public static GameObject CreateNetworkPrefab(string name) { GameObject val = PrefabUtils.CreatePrefab(name); val.AddComponent<NetworkObject>(); byte[] value = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(Assembly.GetCallingAssembly().GetName().Name + name)); val.GetComponent<NetworkObject>().GlobalObjectIdHash = BitConverter.ToUInt32(value, 0); RegisterNetworkPrefab(val); return val; } public static GameObject CloneNetworkPrefab(GameObject prefabToClone, string newName = null) { GameObject val = PrefabUtils.ClonePrefab(prefabToClone, newName); byte[] value = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(Assembly.GetCallingAssembly().GetName().Name + ((Object)val).name)); val.GetComponent<NetworkObject>().GlobalObjectIdHash = BitConverter.ToUInt32(value, 0); RegisterNetworkPrefab(val); return val; } } public class PrefabUtils { internal static Lazy<GameObject> _prefabParent; internal static GameObject prefabParent => _prefabParent.Value; static PrefabUtils() { _prefabParent = new Lazy<GameObject>((Func<GameObject>)delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown GameObject val = new GameObject("LethalLibGeneratedPrefabs"); ((Object)val).hideFlags = (HideFlags)61; val.SetActive(false); return val; }); } public static GameObject ClonePrefab(GameObject prefabToClone, string newName = null) { GameObject val = Object.Instantiate<GameObject>(prefabToClone, prefabParent.transform); ((Object)val).hideFlags = (HideFlags)61; if (newName != null) { ((Object)val).name = newName; } else { ((Object)val).name = ((Object)prefabToClone).name; } return val; } public static GameObject CreatePrefab(string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown GameObject val = new GameObject(name); ((Object)val).hideFlags = (HideFlags)61; val.transform.SetParent(prefabParent.transform); return val; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace ScalingDailyQuota.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }