using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AutoLogisticsDroneSetup")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AutoLogisticsDroneSetup")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8dbddacb-9a6f-4c99-944b-06e5e02efe9e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace DSP_Mods;
[BepInPlugin("gimbalhawk.dsp.autoshuttlesetup", "AutoShuttleSetup", "1.8.0")]
public class AutoLogisticsDroneSetup : BaseUnityPlugin
{
public const string pluginGuid = "gimbalhawk.dsp.autoshuttlesetup";
public const string pluginName = "AutoShuttleSetup";
public const string pluginVersion = "1.8.0";
public static Item Drone = new Item
{
Id = 5001,
Name = "Drone"
};
public static Item Vessel = new Item
{
Id = 5002,
Name = "Vessel"
};
public static Item Bot = new Item
{
Id = 5003,
Name = "Bot"
};
private static StorageUtility StorageUtility { get; set; }
private static BuildMenuUIAddOn UI { get; set; }
public void Awake()
{
ModConfig.InitConfig(((BaseUnityPlugin)this).Config);
StorageUtility = new StorageUtility();
Harmony.CreateAndPatchAll(typeof(AutoLogisticsDroneSetup), (string)null);
Harmony.CreateAndPatchAll(typeof(ModConfigWindow), (string)null);
Logger.Init(((BaseUnityPlugin)this).Logger, "AutoLogisticsDroneSetup");
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlanetTransport), "NewStationComponent")]
public static void NewStationComponent_PostFix(PlanetTransport __instance, int _entityId, int _pcId, PrefabDesc _desc)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if (GameMain.mainPlayer == null)
{
Logger.Instance.LogInfo("Couldn't find player");
return;
}
EntityData entityData = __instance.factory.GetEntityData(_entityId);
StationComponent val = __instance.stationPool[entityData.stationId];
if (val == null)
{
Logger.Instance.LogInfo("Couldn't find station? That shouldn't happen");
}
else
{
if (val.isCollector)
{
return;
}
if (val.isStellar)
{
Logger.Instance.LogInfo("Interstellar logistics station built");
if (ModConfig.DepositDronesILS.Value)
{
AddDrones(val, _desc, StorageUtility, ModConfig.DroneAmountILS.Value);
}
if (ModConfig.DepositVesselsILS.Value)
{
AddShips(val, _desc, StorageUtility, ModConfig.VesselAmountILS.Value);
}
}
else
{
Logger.Instance.LogInfo("Planetary logistics station built");
if (ModConfig.DepositDronesPLS.Value)
{
AddDrones(val, _desc, StorageUtility, ModConfig.DroneAmountPLS.Value);
}
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlanetTransport), "NewDispenserComponent")]
public static void NewDispenserComponent_PostFix(PlanetTransport __instance, int _entityId, int _pcId, PrefabDesc _desc)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if (GameMain.mainPlayer == null)
{
Logger.Instance.LogInfo("Couldn't find player");
return;
}
EntityData entityData = __instance.factory.GetEntityData(_entityId);
DispenserComponent val = __instance.dispenserPool[entityData.dispenserId];
if (val == null)
{
Logger.Instance.LogInfo("Couldn't find logistic dispenser? That shouldn't happen");
return;
}
Logger.Instance.LogInfo("Logistics dispenser built");
if (ModConfig.DepositBots.Value)
{
AddBots(val, _desc, StorageUtility, ModConfig.BotAmount.Value);
}
}
private static void AddDrones(StationComponent station, PrefabDesc desc, StorageUtility util, int desiredAmount)
{
if (station == null || desc == null)
{
return;
}
int stationMaxDroneCount = desc.stationMaxDroneCount;
if (stationMaxDroneCount <= 0)
{
return;
}
if (desiredAmount < 0 || desiredAmount > stationMaxDroneCount)
{
desiredAmount = stationMaxDroneCount;
}
if (desiredAmount > 0)
{
int num = util.RemoveItems(Drone, desiredAmount);
if (num > 0)
{
station.idleDroneCount = num;
}
}
}
private static void AddShips(StationComponent station, PrefabDesc desc, StorageUtility util, int desiredAmount)
{
if (station == null || desc == null)
{
return;
}
int stationMaxShipCount = desc.stationMaxShipCount;
if (stationMaxShipCount <= 0)
{
return;
}
if (desiredAmount < 0 || desiredAmount > stationMaxShipCount)
{
desiredAmount = stationMaxShipCount;
}
if (desiredAmount > 0)
{
int num = util.RemoveItems(Vessel, desiredAmount);
if (num > 0)
{
station.idleShipCount = num;
}
}
}
private static void AddBots(DispenserComponent dispenser, PrefabDesc desc, StorageUtility util, int desiredAmount)
{
if (dispenser == null || desc == null)
{
return;
}
int dispenserMaxCourierCount = desc.dispenserMaxCourierCount;
if (dispenserMaxCourierCount <= 0)
{
return;
}
if (desiredAmount < 0 || desiredAmount > dispenserMaxCourierCount)
{
desiredAmount = dispenserMaxCourierCount;
}
if (desiredAmount > 0)
{
int num = util.RemoveItems(Bot, desiredAmount);
if (num > 0)
{
dispenser.idleCourierCount = num;
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIBuildMenu), "OnCategoryButtonClick")]
public static void OnCategoryButtonClick_Postfix(UIBuildMenu __instance)
{
if (__instance.currentCategory != 6)
{
if ((Object)(object)UI != (Object)null)
{
UI.Hide();
}
return;
}
if ((Object)(object)UI == (Object)null)
{
UI = BuildMenuUIAddOn.InitUI(__instance);
}
if ((Object)(object)UI != (Object)null)
{
UI.Show();
}
}
public void OnGUI()
{
if (ModConfigWindow.Visible)
{
ModConfigWindow.OnGUI();
}
}
}
internal class ClickableControl : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerClickHandler
{
private GameObject hoverTextObj;
public string HoverText = "";
public Text TextObject;
public event Action<PointerEventData> OnClick;
public void Start()
{
if ((Object)(object)TextObject != (Object)null)
{
hoverTextObj = ((Component)TextObject).gameObject;
hoverTextObj.SetActive(false);
TextObject.text = HoverText;
}
}
public void OnPointerEnter(PointerEventData eventData)
{
if ((Object)(object)hoverTextObj == (Object)null)
{
Start();
}
else
{
hoverTextObj.SetActive(true);
}
}
public void OnPointerExit(PointerEventData eventData)
{
if ((Object)(object)hoverTextObj == (Object)null)
{
Start();
}
else
{
hoverTextObj.SetActive(false);
}
}
public void OnPointerClick(PointerEventData eventData)
{
this.OnClick?.Invoke(eventData);
}
}
public class Logger
{
public static Logger Instance { get; private set; }
private ManualLogSource LogSource { get; set; }
private string MsgSource { get; set; }
public static void Init(ManualLogSource logger, string source = null)
{
Instance = new Logger
{
LogSource = logger,
MsgSource = source
};
}
public void LogInfo(string msg)
{
string text = ((MsgSource != null) ? (MsgSource + " : ") : "") + msg;
LogSource.LogInfo((object)text);
}
}
public static class ModConfig
{
public static ConfigEntry<int> InventoryPriority;
public static ConfigEntry<int> StoragePriority;
public static ConfigEntry<int> StationsPriority;
public static ConfigEntry<bool> DepositDronesPLS;
public static ConfigEntry<bool> DepositDronesILS;
public static ConfigEntry<bool> DepositVesselsILS;
public static ConfigEntry<bool> DepositBots;
public static ConfigEntry<int> DroneAmountPLS;
public static ConfigEntry<int> DroneAmountILS;
public static ConfigEntry<int> VesselAmountILS;
public static ConfigEntry<int> BotAmount;
public static ConfigFile ConfigFile;
public static void InitConfig(ConfigFile config)
{
ConfigFile = config;
InventoryPriority = config.Bind<int>("Storage", "Inventory Priority", 1, "The priority of selecting from the player inventory. Lower numbers take precendence. Set to a negative number to disable");
StoragePriority = config.Bind<int>("Storage", "Storage Priority", 2, "The priority of selecting from storage chests. Lower numbers take precendence. Set to a negative number to disable");
StationsPriority = config.Bind<int>("Storage", "Stations Priority", 3, "The priority of selecting from stations. Lower numbers take precendence. Set to a negative number to disable");
DepositDronesPLS = config.Bind<bool>("Planetary Logistics", "Deposit Drones", true, "Whether drones should automatically be added to a newly created Planetary Logistics Station");
DroneAmountPLS = config.Bind<int>("Planetary Logistics", "Planetary Drone Amount", -1, "How many drones should be added to a newly created Planetary Logistics Station. Numbers less than 0 or greater than the max are treated as the normal drone maximum");
DepositDronesILS = config.Bind<bool>("Interstellar Logistics", "Deposit Drones", true, "Whether drones should automatically be added to a newly created Interstellar Logistics Station");
DroneAmountILS = config.Bind<int>("Interstellar Logistics", "Interstellar Drone Amount", -1, "How many drones should be added to a newly created Interstellar Logistics Station. Numbers less than 0 or greater than the max are treated as the normal drone maximum");
DepositVesselsILS = config.Bind<bool>("Interstellar Logistics", "Deposit Vessels", true, "Whether vessels should automatically be added to a newly created Interstellar Logistics Station");
VesselAmountILS = config.Bind<int>("Interstellar Logistics", "Interstellar Vessel Amount", -1, "How many vessels should be added to a newly created Interstellar Logistics Station. Numbers less than 0 or greater than the max are treated as the normal drone maximum");
DepositBots = config.Bind<bool>("Logistics Bots", "Deposit Bots", true, "Whether bots should automatically be added to a newly created logistics distrubution ports");
BotAmount = config.Bind<int>("Logistics Bots", "Bots Amount", -1, "How many bots should be added to a newly created distribution port. Numbers less than 0 or greater than the max are treated as the normal bot maximum");
}
public static void ResetAllToDefault()
{
foreach (ConfigDefinition key in ConfigFile.Keys)
{
ConfigEntryBase obj = ConfigFile[key];
obj.BoxedValue = obj.DefaultValue;
}
}
}
public class ModConfigWindow
{
private static Rect WindowRect = new Rect((float)(Screen.width / 3 * 2), 100f, 500f, 420f);
public static bool Visible { get; set; }
public static void Open()
{
Visible = true;
}
public static void Close()
{
Visible = false;
}
public static void OnGUI()
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (Input.GetKeyDown((KeyCode)27))
{
Visible = false;
}
else
{
WindowRect = GUILayout.Window(1786512, WindowRect, new WindowFunction(WindowFunction), "AutoLogisticsDroneSetup config", Array.Empty<GUILayoutOption>());
}
}
private static void WindowFunction(int id)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
GUILayout.BeginArea(new Rect(((Rect)(ref WindowRect)).width - 25f, 0f, 25f, 25f));
if (GUILayout.Button("X", Array.Empty<GUILayoutOption>()))
{
Close();
return;
}
GUILayout.EndArea();
GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
DrawResetButton();
string text = "";
foreach (ConfigDefinition key in ModConfig.ConfigFile.Keys)
{
if (text != key.Section)
{
DrawSectionLabel(key.Section);
}
DrawOption(ModConfig.ConfigFile[key]);
text = key.Section;
}
GUILayout.EndVertical();
GUI.DragWindow();
}
private static void DrawResetButton()
{
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.FlexibleSpace();
if (GUILayout.Button("Restore Defaults", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(125f) }))
{
ModConfig.ResetAllToDefault();
}
GUILayout.EndVertical();
}
private static void DrawSectionLabel(string text)
{
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.FlexibleSpace();
GUILayout.Label(text, Array.Empty<GUILayoutOption>());
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
private static void DrawOption(ConfigEntryBase configEntry)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected O, but got Unknown
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.Label(new GUIContent(configEntry.Definition.Key, configEntry.Description.Description), Array.Empty<GUILayoutOption>());
GUILayout.FlexibleSpace();
if (configEntry.SettingType == typeof(bool))
{
DrawBoolValue(configEntry, 75f);
}
else if (configEntry.SettingType == typeof(int))
{
DrawIntValue(configEntry, 75f);
}
else
{
Logger.Instance.LogInfo($"Attempted to draw invalid option type for setting {configEntry.Definition.Key}. Setting is of type {configEntry.SettingType}");
}
GUILayout.EndHorizontal();
}
private static void DrawBoolValue(ConfigEntryBase configEntry, float width)
{
if (configEntry.SettingType != typeof(bool))
{
Logger.Instance.LogInfo($"Attempted to draw invalid ccnfig type. Expected bool but got {configEntry.SettingType}");
return;
}
bool flag = (bool)configEntry.BoxedValue;
GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(width) });
bool flag2 = GUILayout.Toggle(flag, flag ? "Enabled" : "Disabled", Array.Empty<GUILayoutOption>());
if (flag2 != flag)
{
configEntry.BoxedValue = flag2;
}
GUILayout.EndHorizontal();
}
private static void DrawIntValue(ConfigEntryBase configEntry, float width)
{
if (configEntry.SettingType != typeof(int))
{
Logger.Instance.LogInfo($"Attempted to draw invalid ccnfig type. Expected int but got {configEntry.SettingType}");
return;
}
int num = (int)configEntry.BoxedValue;
GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(width) });
if (int.TryParse(GUILayout.TextField(num.ToString(), Array.Empty<GUILayoutOption>()), out var result) && result != num)
{
configEntry.BoxedValue = result;
}
GUILayout.EndHorizontal();
}
[HarmonyPrefix]
[HarmonyPatch(typeof(UIGame), "On_E_Switch")]
public static bool On_E_Switch_Prefix()
{
if (Visible)
{
Visible = false;
}
return true;
}
}
public class BuildMenuUIAddOn : MonoBehaviour
{
private GameObject ConfigButton;
private Image ConfigIconImage;
public static BuildMenuUIAddOn InitUI(UIBuildMenu buildMenu)
{
GameObject.Find("UI Root/Overlay Canvas/In Game/Function Panel/Build Menu/child-group");
RectTransform component = ((Component)buildMenu).GetComponent<RectTransform>();
if ((Object)(object)component == (Object)null)
{
return null;
}
Text textComponent = null;
GameObject val = GameObject.Find("UI Root/Overlay Canvas/In Game/Function Panel/Build Menu/child-group/button-1");
if ((Object)(object)val != (Object)null)
{
Transform obj = ((Component)val.GetComponent<RectTransform>()).transform.Find("count");
textComponent = ((obj != null) ? ((Component)obj).GetComponentInChildren<Text>() : null);
}
BuildMenuUIAddOn buildMenuUIAddOn = ((Component)component).gameObject.AddComponent<BuildMenuUIAddOn>();
buildMenuUIAddOn.AddModComponents(component, textComponent);
return buildMenuUIAddOn;
}
public void AddModComponents(RectTransform containerRect, Text textComponent)
{
InitConfigButton(containerRect, textComponent);
}
public void Show()
{
((Component)ConfigIconImage).gameObject.SetActive(true);
}
public void Hide()
{
((Component)ConfigIconImage).gameObject.SetActive(false);
}
private void InitConfigButton(RectTransform containerRect, Text textComponent)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
ConfigButton = new GameObject("ALDS_Config");
RectTransform obj = ConfigButton.AddComponent<RectTransform>();
((Transform)obj).SetParent(((Component)containerRect).transform, false);
obj.anchorMax = new Vector2(0f, 0.5f);
obj.anchorMin = new Vector2(0f, 0.5f);
obj.sizeDelta = new Vector2(20f, 20f);
obj.pivot = new Vector2(0f, 1f);
obj.anchoredPosition = new Vector2(210f, 25f);
ClickableControl clickableControl = ((Component)obj).gameObject.AddComponent<ClickableControl>();
clickableControl.HoverText = "Open AutoLogisticsDroneSetup config";
if ((Object)(object)textComponent != (Object)null)
{
Text val = Object.Instantiate<Text>(textComponent, ((Component)containerRect).transform, true);
RectTransform component = ((Component)val).GetComponent<RectTransform>();
((Component)containerRect).GetComponent<RectTransform>();
component.anchorMax = new Vector2(0f, 0.5f);
component.anchorMin = new Vector2(0f, 0.5f);
component.sizeDelta = new Vector2(200f, 25f);
component.pivot = new Vector2(0.5f, 1f);
component.anchoredPosition = new Vector2(225f, 72f);
clickableControl.TextObject = val;
}
ConfigIconImage = ((Component)clickableControl).gameObject.AddComponent<Image>();
((Graphic)ConfigIconImage).color = new Color(0.8f, 0.8f, 0.8f, 1f);
GameObject val2 = GameObject.Find("UI Root/Overlay Canvas/In Game/Game Menu/button-3-bg/button-3/icon");
ConfigIconImage.sprite = val2.GetComponent<Image>().sprite;
clickableControl.OnClick += delegate
{
ModConfigWindow.Visible = !ModConfigWindow.Visible;
};
}
}
public struct Item
{
public int Id { get; set; }
public string Name { get; set; }
}
internal class StorageUtility
{
public enum Source
{
Inventory,
Storage,
Stations
}
private struct StorageSource
{
public Source Source { get; set; }
public int Priority { get; set; }
}
private PlayerPackageUtility PlayerPackageUtility;
private IEnumerable<StorageSource> GetStorageSources()
{
List<StorageSource> list = new List<StorageSource>();
AddSource(list, Source.Inventory, ModConfig.InventoryPriority.Value);
AddSource(list, Source.Storage, ModConfig.StoragePriority.Value);
AddSource(list, Source.Stations, ModConfig.StationsPriority.Value);
return list.OrderBy((StorageSource s) => s.Priority).ToList();
}
private void AddSource(List<StorageSource> sources, Source source, int priority)
{
if (priority >= 0)
{
sources.Add(new StorageSource
{
Source = source,
Priority = priority
});
}
}
public int RemoveItems(Item item, int desiredAmount)
{
Player mainPlayer = GameMain.mainPlayer;
PlanetFactory val = ((mainPlayer != null) ? mainPlayer.factory : null);
if (mainPlayer == null || val == null)
{
return 0;
}
if (desiredAmount <= 0)
{
return 0;
}
int num = 0;
foreach (StorageSource storageSource in GetStorageSources())
{
int num2 = 0;
switch (storageSource.Source)
{
case Source.Inventory:
num2 = RemoveFromPlayer(mainPlayer, item, desiredAmount);
break;
case Source.Storage:
num2 = RemoveFromStorage(val, item, desiredAmount);
break;
case Source.Stations:
num2 = RemoveFromStations(val, item, desiredAmount);
break;
}
num += num2;
desiredAmount -= num2;
if (desiredAmount <= 0)
{
break;
}
}
return num;
}
private int RemoveFromPlayer(Player player, Item item, int desiredAmount)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected O, but got Unknown
if (player == null || player.package == null)
{
return 0;
}
if (PlayerPackageUtility == null || PlayerPackageUtility.player != player)
{
PlayerPackageUtility = new PlayerPackageUtility(player);
}
int id = item.Id;
int num = 0;
int num2 = desiredAmount;
PlayerPackageUtility.TryTakeItemFromAllPackages(ref id, ref num2, ref num, true);
if (num2 > 0)
{
Logger.Instance.LogInfo(string.Format("Removed {0} {1}{2} from player", num2, item.Name, (num2 == 1) ? "" : "s"));
}
return num2;
}
private int RemoveFromStorage(PlanetFactory factory, Item item, int desiredAmount)
{
int num = 0;
for (int i = 0; i < factory.factoryStorage.storageCursor; i++)
{
if (num >= desiredAmount)
{
break;
}
StorageComponent val = factory.factoryStorage.storagePool[i];
if (val != null && val.id == i)
{
int id = item.Id;
int num2 = 0;
int num3 = desiredAmount - num;
val.TakeTailItems(ref id, ref num3, ref num2, false);
num += num3;
if (num3 > 0)
{
Logger.Instance.LogInfo(string.Format("Removed {0} {1}{2} from storage", num3, item.Name, (num3 == 1) ? "" : "s"));
}
}
}
return num;
}
private int RemoveFromStations(PlanetFactory factory, Item item, int desiredAmount)
{
int num = 0;
for (int i = 0; i < factory.transport.stationCursor; i++)
{
if (num >= desiredAmount)
{
break;
}
StationComponent val = factory.transport.stationPool[i];
if (val != null && val.id == i)
{
int id = item.Id;
int num2 = desiredAmount - num;
int num3 = 0;
val.TakeItem(ref id, ref num2, ref num3);
num += num2;
if (num2 > 0)
{
Logger.Instance.LogInfo(string.Format("Removed {0} {1}{2} from station", num2, item.Name, (num2 == 1) ? "" : "s"));
}
}
}
return num;
}
}