Decompiled source of SODStockMarket v2.0.8
SOD.StockMarket.dll
Decompiled 4 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; using AssetBundleLoader; using BepInEx; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using Bogus; using HarmonyLib; using Il2CppInterop.Runtime.Injection; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using SOD.Common; using SOD.Common.BepInEx; using SOD.Common.BepInEx.Configuration; using SOD.Common.Custom; using SOD.Common.Extensions; using SOD.Common.Helpers; using SOD.Common.Helpers.GameplayObjects; using SOD.StockMarket.Implementation; using SOD.StockMarket.Implementation.Cruncher; using SOD.StockMarket.Implementation.Cruncher.Content; using SOD.StockMarket.Implementation.Cruncher.News; using SOD.StockMarket.Implementation.DataConversion; using SOD.StockMarket.Implementation.DataConversion.Converters; using SOD.StockMarket.Implementation.Stocks; using SOD.StockMarket.Implementation.Trade; using SOD.StockMarket.Patches; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using UniverseLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("SOD.StockMarket")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+4d12de394cca59f54d683ec13e921db597f69b1f")] [assembly: AssemblyProduct("SOD.StockMarket")] [assembly: AssemblyTitle("SOD.StockMarket")] [assembly: AssemblyVersion("1.0.0.0")] 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; } } } namespace SOD.StockMarket { internal class Constants { internal const bool IsDebugEnabled = false; internal const string StockDataSaveFormat = "bin"; internal const int OpeningHour = 9; internal const int ClosingHour = 16; internal const string DaysClosed = "Saturday,Sunday"; internal const double StockTrendChancePercentage = 2.0; internal const int MaxTrends = 6; internal const int MaxHoursTrendsCanPersist = 16; internal const int MinHoursTrendsMustPersist = 3; internal const double PriceFluctuationPercentage = 0.35; internal const int DaysToKeepStockHistoricalData = 31; internal const double PastHistoricalDataVolatility = 15.0; internal const bool RunSimulation = false; internal const int SimulationDays = 365; internal const int MinimumStocksInMarket = 30; internal const int MinimumMurderTrendPercentage = -5; internal const int MaximumMurderTrendPercentage = -15; } public interface IPluginBindings : IDebugBindings, IMarketBindings, IEconomyBindings, IntegrationBindings { } public interface IDebugBindings { [Binding(false, "Enables debug mode which prints several useful information into the console.", "Debugging.EnableDebugMode")] bool IsDebugEnabled { get; set; } [Binding("bin", "The save format for the stock data. Options: \"csv\", \"bin\")", "Debugging.StockDataSaveFormat")] string StockDataSaveFormat { get; set; } [Binding(false, "If this option is enabled, it will run a simulation after initial economy load and export it as a csv.", "Debugging.RunSimulation")] bool RunSimulation { get; set; } [Binding(365, "The total amount of days to simulate for (only if RunSimulation is enabled).", "Debugging.SimulationDays")] int SimulationDays { get; set; } } public interface IntegrationBindings { [Binding(true, "Should murder's impact the stock market?", "Integrations.EnableMurderIntegration")] bool EnableMurderIntegration { get; set; } } public interface IMarketBindings { [Binding(9, "The hour the stock market opens everyday. (24h clock)", "StockMarket.OpeningHour")] int OpeningHour { get; set; } [Binding(16, "The hour the stock market closes everyday. (24h clock)", "StockMarket.ClosingHour")] int ClosingHour { get; set; } [Binding("Saturday,Sunday", "The days the stock market is closed.", "StockMarket.DaysClosed")] string DaysClosed { get; set; } } public interface IEconomyBindings { [Binding(2.0, "The percentage change a stock has to start a trend. (0-100)", "StockMarket.Economy.StockTrendChancePercentage")] double StockTrendChancePercentage { get; set; } [Binding(6, "The maximum amount of trends that can be ongoing at once. (-1 for unlimited)", "StockMarket.Economy.MaxTrends")] int MaxTrends { get; set; } [Binding(16, "The maximum amount of hours a trend can persist until its completed. (MIN 1)", "StockMarket.Economy.MaxHoursTrendsCanPersist")] int MaxHoursTrendsCanPersist { get; set; } [Binding(3, "The minimum amount of hours a trend must persist until its completed. (MIN 1)", "StockMarket.Economy.MinHoursTrendsMustPersist")] int MinHoursTrendsMustPersist { get; set; } [Binding(0.35, "The base price fluctuation percentage of stocks. (based on stock volatility)", "StockMarket.Economy.PriceFluctuationPercentage")] double PriceFluctuationPercentage { get; set; } [Binding(31, "The amount of days the historical data should be kept per stock.", "StockMarket.Economy.DaysToKeepStockHistoricalData")] int DaysToKeepStockHistoricalData { get; set; } [Binding(15.0, "The base percentage of volatility the market has been for the past [DaysToKeepStockHistoricalData] on market initialization. (MIN 1.0)", "StockMarket.Economy.PastHistoricalDataVolatility")] double PastHistoricalDataVolatility { get; set; } [Binding(30, "The minimum amount of stocks that should be in the market on generation.", "StockMarket.Economy.MinimumStocksInMarket")] int MinimumStocksInMarket { get; set; } [Binding(-5, "The minimum percentage effect on the stock on a company employee murder.", "StockMarket.Economy.MinimumMurderTrendPercentage")] int MinimumMurderTrendPercentage { get; set; } [Binding(-15, "The maximum percentage effect on the stock on a company employee murder.", "StockMarket.Economy.MaximumMurderTrendPercentage")] int MaximumMurderTrendPercentage { get; set; } } [BepInPlugin("Venomaus.SOD.StockMarket", "StockMarket", "2.0.8")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : PluginController<Plugin, IPluginBindings> { public const string PLUGIN_GUID = "Venomaus.SOD.StockMarket"; public const string PLUGIN_NAME = "StockMarket"; public const string PLUGIN_VERSION = "2.0.8"; internal Market Market { get; private set; } public override void Load() { ClassInjector.RegisterTypeInIl2Cpp<StockMarketAppContent>(); PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Plugin registered custom types into IL2CPP domain."); Market = new Market(); PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Plugin initialized stock market hooks."); base.Harmony.PatchAll(Assembly.GetExecutingAssembly()); PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Plugin is patched."); } public override void OnConfigureBindings() { base.OnConfigureBindings(); ValidateBindingValues(); } private void ValidateBindingValues() { if (base.Config.MaxHoursTrendsCanPersist < 1) { base.Config.MaxHoursTrendsCanPersist = 16; } if (base.Config.MinHoursTrendsMustPersist < 1) { base.Config.MinHoursTrendsMustPersist = 3; } double stockTrendChancePercentage = base.Config.StockTrendChancePercentage; if (stockTrendChancePercentage < 0.0 || stockTrendChancePercentage > 100.0) { base.Config.StockTrendChancePercentage = 2.0; } if (base.Config.MaxTrends < -1) { base.Config.MaxTrends = 6; } if (base.Config.PastHistoricalDataVolatility < 1.0) { base.Config.PastHistoricalDataVolatility = 15.0; } if (!Enum.TryParse<DataSaveFormat>(base.Config.StockDataSaveFormat.Trim(), ignoreCase: true, out var _)) { base.Config.StockDataSaveFormat = "bin"; } } } } namespace SOD.StockMarket.Patches { internal class CitizenCreatorPatches { [HarmonyPatch(typeof(CitizenCreator), "Populate")] internal class CitizenCreator_Populate { internal static bool Init; [HarmonyPostfix] internal static void Postfix() { if (!Init) { Init = true; PluginController<Plugin, IPluginBindings>.Instance.Market.PostStocksInitialization(typeof(CitizenCreator)); } } } } internal class CityConstructorPatches { [HarmonyPatch(typeof(CityConstructor), "Finalized")] internal class CityConstructor_Finalized { internal static bool Init; [HarmonyPostfix] internal static void Postfix() { if (!Init) { Init = true; PluginController<Plugin, IPluginBindings>.Instance.Market.PostStocksInitialization(typeof(CityConstructor)); } } } } internal class CompanyPatches { [HarmonyPatch(typeof(Company), "Setup")] internal class Company_Setup { internal static bool ShownInitializingMessage; [HarmonyPostfix] internal static void Postfix(Company __instance) { if (!PluginController<Plugin, IPluginBindings>.Instance.Market.Initialized && (!((SoCustomComparison)(object)__instance.preset != (SoCustomComparison)null) || !__instance.preset.isSelfEmployed) && !__instance.preset.isIllegal) { if (!ShownInitializingMessage) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Initializing stock market data."); ShownInitializingMessage = true; } PluginController<Plugin, IPluginBindings>.Instance.Market.InitStock(new Stock(__instance)); } } } } internal class InteriorCreatorPatches { [HarmonyPatch(typeof(InteriorCreator), "GenChunk")] internal class InteriorCreator_GenChunk { internal static bool Init; [HarmonyPostfix] internal static void Postfix() { if (!Init) { Init = true; PluginController<Plugin, IPluginBindings>.Instance.Market.PostStocksInitialization(typeof(InteriorCreator)); } } } } internal class MainMenuControllerPatches { [HarmonyPatch(typeof(MainMenuController), "Start")] internal class MainMenuController_Start { private static bool _init; [HarmonyPostfix] internal static void Postfix() { if (!_init) { _init = true; LoadStockMarketBundle(); } } private static void LoadStockMarketBundle() { string path = "stockmarketbundle"; CruncherAppPreset obj = BundleLoader.LoadBundle(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), path), false, true).LoadAsset<CruncherAppPreset>("StockMarketPreset"); obj.appContent[0].AddComponent<StockMarketAppContent>(); InsertAppToCrunchers(obj); } private static void InsertAppToCrunchers(CruncherAppPreset preset) { foreach (InteractablePreset item in ((IEnumerable<InteractablePreset>)Resources.FindObjectsOfTypeAll<InteractablePreset>()).Where((InteractablePreset preset) => ((Object)preset).name.Contains("Cruncher"))) { item.additionalApps.Insert(item.additionalApps.Count - 2, preset); } } } } internal class MurderIntegration { internal static void Initialize() { if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.EnableMurderIntegration) { Lib.Gameplay.OnVictimReported += Detective_OnVictimReported; } } private static void Detective_OnVictimReported(object sender, VictimReportedArgs e) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0081: 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_016f: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Expected O, but got Unknown Human victim = ((VictimKilledArgs)e).Victim; Human reporter = e.Reporter; ReportType reportType = e.ReportType; bool flag = default(bool); if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(47, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Victim \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(victim.GetCitizenName()); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" was reported by \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reporter.GetCitizenName()); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" | Report Type: \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ReportType>(reportType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\"."); } log.LogInfo(val); } if (!PluginController<Plugin, IPluginBindings>.Instance.Market.Initialized) { return; } Occupation job = victim.job; if (job == null || job.employer == null) { return; } Company company = job.employer; Stock stock = PluginController<Plugin, IPluginBindings>.Instance.Market.Stocks.FirstOrDefault((Stock a) => a.CompanyId == company.companyID); if (stock == null) { if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { ManualLogSource log2 = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(108, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Victim was part of company \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(company.name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\", but no stock was found. Self employed or illegal companies don't have stocks."); } log2.LogInfo(val); } return; } if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { ManualLogSource log3 = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(66, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Victim was part of company \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(company.name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\", created a negative \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(stock.Symbol); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" stock impact."); } log3.LogInfo(val); } if (stock.Trend.HasValue) { stock.RemoveTrend(); } int minimumMurderTrendPercentage = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.MinimumMurderTrendPercentage; int maximumMurderTrendPercentage = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.MaximumMurderTrendPercentage; StockTrend stockTrend = new StockTrend(MathHelper.Random.Next(minimumMurderTrendPercentage, maximumMurderTrendPercentage), stock.Price, Market.CalculateRandomSteps()); stock.SetTrend(stockTrend); if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { ManualLogSource log4 = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(61, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Created trend: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(stockTrend.Percentage); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("% | Source Price: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(stockTrend.StartPrice); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Target Price: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(stockTrend.EndPrice); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Steps: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(stockTrend.Steps); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } log4.LogInfo(val); } if (!PluginController<Plugin, IPluginBindings>.Instance.Market.Simulation) { NewsGenerator.GenerateArticle(stock, stockTrend, murder: true); } } } } namespace SOD.StockMarket.Implementation { internal class Market : IStocksContainer { private readonly List<Stock> _stocks; private bool _interiorCreatorFinished; private bool _citizenCreatorFinished; private bool _cityConstructorFinalized; internal readonly bool Simulation; internal TimeData? SimulationTime; private bool _isLoading; private string _afterPreModPath; public IReadOnlyList<Stock> Stocks => _stocks; internal bool Initialized { get; private set; } private static int OpeningHour => ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.OpeningHour; private static int ClosingHour => ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ClosingHour; internal TradeController TradeController { get; private set; } internal event EventHandler<EventArgs> OnCalculate; internal event EventHandler<EventArgs> OnInitialized; internal Market() { _stocks = new List<Stock>(); TradeController = new TradeController(this); Lib.SaveGame.OnBeforeNewGame += OnBeforeNewGame; Lib.SaveGame.OnBeforeLoad += OnFileLoad; Lib.SaveGame.OnBeforeSave += OnFileSave; Lib.SaveGame.OnBeforeDelete += OnFileDelete; Lib.Time.OnTimeInitialized += InitDdsRecords; Lib.Time.OnMinuteChanged += OnMinuteChanged; Lib.Time.OnHourChanged += OnHourChanged; MurderIntegration.Initialize(); if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.RunSimulation) { return; } OnInitialized += delegate { if (!Lib.Time.IsInitialized) { Lib.Time.OnTimeInitialized += OnTimeInit; } else { Simulate(((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.SimulationDays); } }; } private void InitDdsRecords(object sender, TimeChangedArgs e) { Lib.DdsStrings["computer", "stockmarketpreset"] = "Stock Market"; Lib.Time.OnTimeInitialized -= InitDdsRecords; } private void OnTimeInit(object sender, TimeChangedArgs args) { if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.RunSimulation) { Simulate(((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.SimulationDays); } Lib.Time.OnTimeInitialized -= OnTimeInit; } private Market(Market market) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) _stocks = new List<Stock>(); foreach (Stock stock in market.Stocks) { _stocks.Add(new Stock(stock)); } TradeController = new TradeController(this); Simulation = true; SimulationTime = new TimeData(1979, 1, 1, ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.OpeningHour, 0); Initialized = true; } internal void Simulate(int days) { //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) Market market = new Market(this); TradeController tradeController = market.TradeController; int num = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ClosingHour - ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.OpeningHour; int openingHour = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.OpeningHour; for (int i = 0; i < days; i++) { TimeData value; for (int j = 0; j < num; j++) { for (int k = 0; k < 59; k++) { value = market.SimulationTime.Value; int year = ((TimeData)(ref value)).Year; value = market.SimulationTime.Value; int month = ((TimeData)(ref value)).Month; value = market.SimulationTime.Value; int day = ((TimeData)(ref value)).Day; value = market.SimulationTime.Value; market.SimulationTime = new TimeData(year, month, day, ((TimeData)(ref value)).Hour, k); market.OnMinuteChanged(this, null); } value = market.SimulationTime.Value; int year2 = ((TimeData)(ref value)).Year; value = market.SimulationTime.Value; int month2 = ((TimeData)(ref value)).Month; value = market.SimulationTime.Value; int day2 = ((TimeData)(ref value)).Day; value = market.SimulationTime.Value; market.SimulationTime = new TimeData(year2, month2, day2, ((TimeData)(ref value)).Hour + 1, 0); market.OnHourChanged(this, null); } value = market.SimulationTime.Value; int year3 = ((TimeData)(ref value)).Year; value = market.SimulationTime.Value; int month3 = ((TimeData)(ref value)).Month; value = market.SimulationTime.Value; market.SimulationTime = new TimeData(year3, month3, ((TimeData)(ref value)).Day, openingHour, 0); value = market.SimulationTime.Value; market.SimulationTime = ((TimeData)(ref value)).AddDays(1); } StockDataIO.Export(market, tradeController, Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), "Simulation.csv"), this); } private void OnBeforeNewGame(object sender, EventArgs e) { _stocks.Clear(); TradeController.Reset(); NewsGenerator.Clear(); CitizenCreatorPatches.CitizenCreator_Populate.Init = false; CityConstructorPatches.CityConstructor_Finalized.Init = false; CompanyPatches.Company_Setup.ShownInitializingMessage = false; InteriorCreatorPatches.InteriorCreator_GenChunk.Init = false; _interiorCreatorFinished = false; _cityConstructorFinalized = false; _citizenCreatorFinished = false; Initialized = false; Lib.Time.OnTimeInitialized -= InitializeMarket; Lib.Time.OnTimeInitialized += InitializeMarket; } internal void PostStocksInitialization(Type type) { if (type == typeof(CitizenCreator)) { _citizenCreatorFinished = true; } else if (type == typeof(InteriorCreator)) { _interiorCreatorFinished = true; } else if (type == typeof(CityConstructor)) { _cityConstructorFinalized = true; } else if (type == typeof(StockDataIO)) { _citizenCreatorFinished = true; _interiorCreatorFinished = true; _cityConstructorFinalized = true; Initialized = true; _isLoading = false; this.OnInitialized?.Invoke(this, EventArgs.Empty); return; } if (_isLoading || Initialized || !_citizenCreatorFinished || !_interiorCreatorFinished || !_cityConstructorFinalized) { return; } MathHelper.Init(TypeExtensions.GetFnvHashCode(CityData.Instance.seed)); (CompanyStockData, decimal?)[] stocks = CustomStocks.Stocks; for (int i = 0; i < stocks.Length; i++) { var (companyData, basePrice) = stocks[i]; InitStock(new Stock(companyData, basePrice)); } if (_stocks.Count < ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.MinimumStocksInMarket) { int num = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.MinimumStocksInMarket - _stocks.Count; for (int j = 0; j < num; j++) { Stock stock = new Stock(new CompanyStockData(StockNameGenerator.GenerateStockName(), Math.Round(MathHelper.Random.NextDouble(0.15, 0.85), 2))); InitStock(stock); } } foreach (Stock stock2 in _stocks) { stock2.Initialize(); } StockSymbolGenerator.Clear(); if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)("Stocks created: " + _stocks.Count)); } PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Stock market initialized."); Initialized = true; } internal void InitStock(Stock stock) { if (!Initialized) { _stocks.Add(stock); } } private void InitializeMarket(object sender, TimeChangedArgs e) { //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) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) //IL_04ba: Unknown result type (might be due to invalid IL or missing references) //IL_04c1: Expected O, but got Unknown //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Expected O, but got Unknown Lib.Time.OnTimeInitialized -= InitializeMarket; if (!Simulation) { TradeController.CreatePortfolioHistoricalDataEntry(); } int num = 0; TimeData currentDate = Lib.Time.CurrentDate; int daysToKeepStockHistoricalData = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.DaysToKeepStockHistoricalData; float num2 = (float)((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.PastHistoricalDataVolatility; bool flag = default(bool); foreach (Stock stock in _stocks) { StockData stockData = null; for (int num3 = daysToKeepStockHistoricalData + 1; num3 > 0; num3--) { TimeData date = ((TimeData)(ref currentDate)).AddDays(-num3); StockData stockData2 = new StockData { Date = date, Open = (stockData?.Close ?? stock.Price) }; float num4 = (0f - num2) * (float)stock.Volatility; float num5 = num2 * (float)stock.Volatility; _ = stock.Volatility; stockData2.Close = Math.Round(stockData2.Open + stockData2.Open / 100m * (decimal)MathHelper.Random.NextDouble((double)num4, (double)num5), 2); decimal? close = stockData2.Close; if ((close.GetValueOrDefault() <= default(decimal)) & close.HasValue) { stockData2.Close = 0.01m; } stockData2.Low = Math.Round(stockData2.Close.Value + stockData2.Close.Value / 100m * (decimal)MathHelper.Random.NextDouble((double)num4, 0.0), 2); if (stockData2.Low <= 0m) { stockData2.Low = 0.01m; } stockData2.High = Math.Round(stockData2.Close.Value + stockData2.Close.Value / 100m * (decimal)MathHelper.Random.NextDouble(0.0, (double)num5), 2); if (stockData2.High <= 0m) { stockData2.High = 0.01m; } stock.CreateHistoricalData(stockData2); stockData = stockData2; num++; } if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { continue; } ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(65, 7, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Stock("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(stock.Symbol); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(stock.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Volatility ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(stock.Volatility); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") | "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Close ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(Math.Round(stock.HistoricalData.Average((StockData a) => a.Close.Value), 2)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") | "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Open ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(Math.Round(stock.HistoricalData.Average((StockData a) => a.Open), 2)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") | "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("High ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(Math.Round(stock.HistoricalData.Average((StockData a) => a.High), 2)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") | "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Low ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(Math.Round(stock.HistoricalData.Average((StockData a) => a.Low), 2)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")."); } log.LogInfo(val); } if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { ManualLogSource log2 = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(37, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Initialized "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" historical data entries."); } log2.LogInfo(val); } GenerateTrends(); this.OnInitialized?.Invoke(this, EventArgs.Empty); } private void OnMinuteChanged(object sender, TimeChangedArgs args) { NewsGenerator.TickToBeReleased(); if (IsOpen() && (args == null || !args.IsHourChanged)) { Calculate(); } } private void OnHourChanged(object sender, TimeChangedArgs args) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown TimeData val = (TimeData)(((??)SimulationTime) ?? Lib.Time.CurrentDateTime); if (((TimeData)(ref val)).Hour == OpeningHour) { OnOpen(); } else if (((TimeData)(ref val)).Hour == ClosingHour) { OnClose(); } if (!IsOpen()) { return; } Calculate(); GenerateTrends(); NewsGenerator.RemoveOutdatedArticles(); if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled || Simulation) { return; } ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(21, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("- New stock updates -"); } log.LogInfo(val2); foreach (Stock item in _stocks.OrderBy((Stock a) => a.Id)) { ManualLogSource log2 = PluginController<Plugin, IPluginBindings>.Log; val2 = new BepInExInfoLogInterpolatedStringHandler(23, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Stock: \"("); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(item.Symbol); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(") "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(item.Name); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\" | Price: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<decimal>(item.Price); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("."); } log2.LogInfo(val2); } ManualLogSource log3 = PluginController<Plugin, IPluginBindings>.Log; val2 = new BepInExInfoLogInterpolatedStringHandler(17, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("- End of Stocks -"); } log3.LogInfo(val2); } internal bool IsOpen() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) if (!Simulation && !Lib.Time.IsInitialized) { return false; } TimeData val = (TimeData)(((??)SimulationTime) ?? Lib.Time.CurrentDateTime); int hour = ((TimeData)(ref val)).Hour; if (hour < OpeningHour || hour >= ClosingHour) { return false; } HashSet<WeekDay> hashSet = (from a in ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.DaysClosed.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) select Enum.Parse<WeekDay>(a.ToLower())).ToHashSet(); ref TimeData? simulationTime = ref SimulationTime; WeekDay val2; if (!simulationTime.HasValue) { val2 = Lib.Time.CurrentDayEnum; } else { TimeData valueOrDefault = simulationTime.GetValueOrDefault(); val2 = ((TimeData)(ref valueOrDefault)).DayEnum; } WeekDay item = val2; if (hashSet.Contains(item)) { return false; } return true; } private void OnClose() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown int historicalDataDeleted = 0; _stocks.ForEach(delegate(Stock a) { a.ClosingPrice = a.Price; a.CreateHistoricalData(null, SimulationTime); historicalDataDeleted += a.CleanUpHistoricalData(SimulationTime); }); if (historicalDataDeleted > 0 && ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled && !Simulation) { ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(29, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Deleted "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(historicalDataDeleted); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" old historical data."); } log.LogInfo(val); } if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled && !Simulation) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Stock market is closing."); } } private void OnOpen() { _stocks.ForEach(delegate(Stock a) { a.OpeningPrice = a.ClosingPrice ?? a.Price; a.ClosingPrice = null; }); if (!Simulation) { TradeController.CreatePortfolioHistoricalDataEntry(); } if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled && !Simulation) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Stock market is opening."); } } private void Calculate() { foreach (Stock stock in _stocks) { stock.DeterminePrice(); } this.OnCalculate?.Invoke(this, EventArgs.Empty); } private void GenerateTrends() { //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0233: Unknown result type (might be due to invalid IL or missing references) int num = 0; double stockTrendChancePercentage = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.StockTrendChancePercentage; int maxTrends = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.MaxTrends; bool isDebugEnabled = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled; if (maxTrends > -1 && Stocks.Count((Stock a) => a.Trend.HasValue) >= maxTrends) { return; } List<double> historicalPercentageChanges = new List<double>(); bool flag = default(bool); foreach (Stock item in Stocks.Where((Stock a) => !a.Trend.HasValue)) { if (!(MathHelper.Random.NextDouble() * 100.0 < stockTrendChancePercentage) || !CalculateStockTrend(historicalPercentageChanges, item, out var stockTrend)) { continue; } StockTrend value = stockTrend.Value; item.SetTrend(value); if (!Simulation) { NewsGenerator.GenerateArticle(item, value); } if (isDebugEnabled && !Simulation) { ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(69, 6, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NEW TREND]: \"("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item.Symbol); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" | Price: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(value.StartPrice); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Target "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(value.EndPrice); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Percentage: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Math.Round(value.Percentage, 2)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | MinutesLeft: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(value.Steps); } log.LogInfo(val); } num++; } if (num > 0 && isDebugEnabled && !Simulation && Lib.Time.IsInitialized) { ManualLogSource log2 = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GameTime("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<TimeData>(Lib.Time.CurrentDateTime); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")] Created "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" new trends."); } log2.LogInfo(val); } } private static bool CalculateStockTrend(List<double> historicalPercentageChanges, Stock stock, out StockTrend? stockTrend) { stockTrend = null; double mean; double stdDev; if (stock.HistoricalData.Count >= 2) { for (int i = 1; i < stock.HistoricalData.Count; i++) { decimal value = stock.HistoricalData[i - 1].Close.Value; double item = (double)((stock.HistoricalData[i].Close.Value - value) / value * 100m); historicalPercentageChanges.Add(item); } mean = historicalPercentageChanges.Average(); stdDev = MathHelper.CalculateStandardDeviation(historicalPercentageChanges); historicalPercentageChanges.Clear(); } else { mean = 0.0; stdDev = 0.3; } double num = Math.Round(MathHelper.NextGaussian(mean, stdDev)); int num2 = (int)num; if (num2 == 0) { return false; } if (Math.Abs(num2) < 2) { num = ((num < 0.0) ? (num - 3.0) : (num + 3.0)); } if (MathHelper.Random.NextDouble() * 100.0 < 7.0) { num *= (double)MathHelper.Random.Next(2, 5); } stockTrend = new StockTrend(num, stock.Price, CalculateRandomSteps()); return true; } internal static int CalculateRandomSteps() { int maxHoursTrendsCanPersist = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.MaxHoursTrendsCanPersist; int minHoursTrendsMustPersist = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.MinHoursTrendsMustPersist; return MathHelper.Random.Next(60 * minHoursTrendsMustPersist, 60 * maxHoursTrendsCanPersist); } private void OnFileSave(object sender, SaveGameArgs e) { string saveFilePath = GetSaveFilePath(e.FilePath); StockDataIO.Export(this, TradeController, saveFilePath); } private void OnFileLoad(object sender, SaveGameArgs e) { string saveFilePath = GetSaveFilePath(e.FilePath); if (!File.Exists(saveFilePath)) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Attempting to load a premod install savegame, a new market economy will be generated for this savegame."); InitPreModInstallEconomyExistingSavegame(saveFilePath, saveImmediately: true); } else if (!_isLoading) { _isLoading = true; _stocks.Clear(); TradeController.Reset(); NewsGenerator.Clear(); _interiorCreatorFinished = true; _cityConstructorFinalized = true; _citizenCreatorFinished = true; Initialized = false; if (!StockDataIO.Import(this, TradeController, saveFilePath)) { _isLoading = false; InitPreModInstallEconomyExistingSavegame(saveFilePath, saveImmediately: false); } } } private void OnFileDelete(object sender, SaveGameArgs e) { string saveFilePath = GetSaveFilePath(e.FilePath); if (File.Exists(saveFilePath)) { File.Delete(saveFilePath); } } private void InitPreModInstallEconomyExistingSavegame(string filePath, bool saveImmediately) { _stocks.Clear(); TradeController.Reset(); NewsGenerator.Clear(); CitizenCreatorPatches.CitizenCreator_Populate.Init = false; CityConstructorPatches.CityConstructor_Finalized.Init = false; CompanyPatches.Company_Setup.ShownInitializingMessage = false; InteriorCreatorPatches.InteriorCreator_GenChunk.Init = false; _interiorCreatorFinished = false; _cityConstructorFinalized = false; _citizenCreatorFinished = false; Initialized = false; PostStocksInitialization(typeof(CitizenCreator)); PostStocksInitialization(typeof(InteriorCreator)); PostStocksInitialization(typeof(CityConstructor)); _afterPreModPath = filePath; if (!Lib.Time.IsInitialized) { Lib.Time.OnTimeInitialized += InitializeMarket; if (saveImmediately) { Lib.Time.OnTimeInitialized += AfterPreModInit; } else { _afterPreModPath = null; } } else { InitializeMarket(this, null); if (saveImmediately) { AfterPreModInit(this, null); } else { _afterPreModPath = null; } } } private void AfterPreModInit(object sender, TimeChangedArgs e) { Lib.Time.OnTimeInitialized -= AfterPreModInit; StockDataIO.Export(this, TradeController, _afterPreModPath); _afterPreModPath = null; } private static string GetSaveFilePath(string filePath) { string uniqueString = Lib.SaveGame.GetUniqueString(filePath); if (!Enum.TryParse<DataSaveFormat>(((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.StockDataSaveFormat.Trim(), ignoreCase: true, out var result)) { throw new Exception("Invalid save format \"" + ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.StockDataSaveFormat + "\"."); } string text = "." + result.ToString().ToLower(); string text2 = "stocks_" + uniqueString + text; return Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), text2); } } internal interface IStocksContainer { IReadOnlyList<Stock> Stocks { get; } } internal static class MathHelper { internal static MersenneTwister Random { get; private set; } internal static void Init(int seed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Random = new MersenneTwister(seed); } internal static void Init(MersenneTwister random) { Random = random; } private static double NextGaussian() { double num; double num3; do { num = 2.0 * Random.NextDouble() - 1.0; double num2 = 2.0 * Random.NextDouble() - 1.0; num3 = num * num + num2 * num2; } while (num3 >= 1.0 || num3 == 0.0); num3 = Math.Sqrt(-2.0 * Math.Log(num3) / num3); return num * num3; } public static double NextGaussian(double mean, double stdDev) { return mean + stdDev * NextGaussian(); } public static double CalculateStandardDeviation(List<double> values) { double mean = values.Average(); return Math.Sqrt(values.Sum((double value) => Math.Pow(value - mean, 2.0)) / (double)values.Count); } } } namespace SOD.StockMarket.Implementation.Trade { internal static class Extensions { internal static string ToLimitedString(this decimal value, int max, CultureInfo culture = null) { return value.ToString(culture ?? CultureInfo.InvariantCulture).Substring(0, Math.Min(max, value.ToString(culture ?? CultureInfo.InvariantCulture).Length)); } } internal class HistoricalPortfolio { [JsonIgnore] private TimeData? _timeData; [JsonIgnore] internal TimeData Date { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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) //IL_0040: Unknown result type (might be due to invalid IL or missing references) TimeData valueOrDefault = _timeData.GetValueOrDefault(); if (!_timeData.HasValue) { ((TimeData)(ref valueOrDefault))..ctor(Year, Month, Day, 0, 0); _timeData = valueOrDefault; return valueOrDefault; } return valueOrDefault; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) _timeData = value; } } public decimal Worth { get; set; } public int Year { get; set; } public int Month { get; set; } public int Day { get; set; } public HistoricalPortfolio() { } internal HistoricalPortfolio(TimeData date, decimal worth) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Date = date; Worth = worth; Year = ((TimeData)(ref date)).Year; Month = ((TimeData)(ref date)).Month; Day = ((TimeData)(ref date)).Day; } } internal class TradeController : IStocksContainer { internal readonly Market Market; private Dictionary<int, decimal> _playerStocks; private List<TradeOrder> _playerTradeOrders; private List<HistoricalPortfolio> _historicalPortfolio; private List<TradeHistory> _tradeHistory; internal bool NotificationsEnabled { get; set; } = true; internal decimal AvailableFunds { get; private set; } internal static int Money { get { return GameplayController.Instance.money; } set { GameplayController.Instance.money = value; FirstPersonItemController.Instance.PlayerMoneyCheck(); if ((Object)(object)InterfaceControls.Instance.cashText != (Object)null) { ((TMP_Text)InterfaceControls.Instance.cashText).text = CityControls.Instance.cityCurrency + Money; if ((Object)(object)BioScreenController.Instance.cashText != (Object)null) { ((TMP_Text)BioScreenController.Instance.cashText).text = ((TMP_Text)InterfaceControls.Instance.cashText).text; } } } } public IReadOnlyList<Stock> Stocks => (from playerStock in _playerStocks join marketStock in Market.Stocks on playerStock.Key equals marketStock.Id select marketStock).ToList(); public IReadOnlyList<TradeOrder> TradeOrders => _playerTradeOrders; public IReadOnlyList<HistoricalPortfolio> HistoricalPortfolioData => _historicalPortfolio; public IReadOnlyList<TradeHistory> TradeHistory => _tradeHistory; internal decimal TotalInvestedInStocks { get { decimal d = default(decimal); foreach (Stock stock in Stocks) { decimal num = _playerStocks[stock.Id]; d += num * stock.Price; } Dictionary<int, Stock> stocks = Market.Stocks.ToDictionary((Stock a) => a.Id, (Stock a) => a); d += (from a in TradeOrders where a.OrderType == OrderType.Sell select stocks[a.StockId].Price * a.Amount).Sum(); return Math.Round(d, 2); } } internal decimal PortfolioWorth { get { decimal num = (from a in TradeOrders where a.OrderType == OrderType.Buy select a.Price * a.Amount).Sum(); return Math.Round(TotalInvestedInStocks + AvailableFunds + num, 2); } } internal decimal GetInvestedVolume(Stock stock) { if (!_playerStocks.TryGetValue(stock.Id, out var value)) { return 0m; } return value; } internal TradeController(Market market) { Market = market; Market.OnCalculate += Market_OnCalculate; Import(null); } internal void CreatePortfolioHistoricalDataEntry() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) TimeData currentDate = Lib.Time.CurrentDate; if (!_historicalPortfolio.Any((HistoricalPortfolio a) => a.Date == currentDate)) { _historicalPortfolio.Add(new HistoricalPortfolio(currentDate, PortfolioWorth)); } } internal decimal? GetPortfolioPercentageChange(int days) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) TimeData currentDate = Lib.Time.CurrentDate; decimal? num = HistoricalPortfolioData.OrderByDescending((HistoricalPortfolio a) => a.Date).ToArray().FirstOrDefault((HistoricalPortfolio a) => (currentDate - a.Date).TotalDays >= (double)days)?.Worth; if (num.HasValue) { decimal? num2 = num; if (!((num2.GetValueOrDefault() == default(decimal)) & num2.HasValue)) { decimal portfolioWorth = PortfolioWorth; decimal? num3 = num; return ((decimal?)portfolioWorth - num3) / num * (decimal?)100; } } return null; } internal void Reset() { _playerStocks.Clear(); _playerTradeOrders.Clear(); _historicalPortfolio.Clear(); _tradeHistory.Clear(); AvailableFunds = 0m; } internal void DepositFunds(int money) { if (money > 0 && Money >= money) { AvailableFunds += (decimal)money; Money -= money; } } internal void WithdrawFunds(int money) { if (money > 0 && AvailableFunds >= (decimal)money) { AvailableFunds -= (decimal)money; Money += money; } } internal void Import(TradeSaveData saveData) { _playerStocks = saveData?.PlayerStocks ?? new Dictionary<int, decimal>(); _playerTradeOrders = saveData?.PlayerTradeOrders ?? new List<TradeOrder>(); _historicalPortfolio = saveData?.HistoricalPortfolio ?? new List<HistoricalPortfolio>(); _tradeHistory = saveData?.TradeHistory ?? new List<TradeHistory>(); AvailableFunds = saveData?.AvailableFunds ?? 0m; } internal TradeSaveData Export() { return new TradeSaveData { PlayerStocks = _playerStocks.ToDictionary((KeyValuePair<int, decimal> a) => a.Key, (KeyValuePair<int, decimal> a) => a.Value), PlayerTradeOrders = _playerTradeOrders.ToList(), HistoricalPortfolio = _historicalPortfolio.ToList(), TradeHistory = _tradeHistory.ToList(), AvailableFunds = AvailableFunds }; } internal bool InstantBuy(Stock stock, decimal amount, bool deductMoney = true) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (deductMoney && !IsValidOrder(OrderType.Buy, stock, amount)) { return false; } if (deductMoney) { decimal num = Math.Round(stock.Price * amount, 2); AvailableFunds -= num; } if (_playerStocks.TryGetValue(stock.Id, out var value)) { _playerStocks[stock.Id] = value + amount; } else { _playerStocks[stock.Id] = amount; } _tradeHistory.Add(new TradeHistory(Lib.Time.CurrentDateTime, stock.Symbol, OrderType.Buy, amount, stock.Price)); return true; } internal bool InstantSell(Stock stock, decimal amount, bool removeStock = true) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) if (removeStock && !IsValidOrder(OrderType.Sell, stock, amount)) { return false; } if (removeStock) { _playerStocks[stock.Id] -= amount; if (_playerStocks[stock.Id] <= 0m) { _playerStocks.Remove(stock.Id); } } decimal num = Math.Round(stock.Price * amount, 2); AvailableFunds += num; _tradeHistory.Add(new TradeHistory(Lib.Time.CurrentDateTime, stock.Symbol, OrderType.Sell, amount, stock.Price)); return true; } internal bool BuyLimitOrder(Stock stock, decimal price, decimal amount) { if (!IsValidOrder(OrderType.Buy, stock, amount)) { return false; } decimal num = Math.Round(stock.Price * amount, 2); AvailableFunds -= num; _playerTradeOrders.Add(new TradeOrder(OrderType.Buy, stock.Id, price, amount)); return true; } internal bool SellLimitOrder(Stock stock, decimal price, decimal amount) { if (!IsValidOrder(OrderType.Sell, stock, amount)) { return false; } _playerTradeOrders.Add(new TradeOrder(OrderType.Sell, stock.Id, price, amount)); _playerStocks[stock.Id] -= amount; if (_playerStocks[stock.Id] <= 0m) { _playerStocks.Remove(stock.Id); } return true; } internal void CancelOrder(TradeOrder order) { if (order.Completed) { return; } if (order.OrderType == OrderType.Buy) { AvailableFunds += Math.Round(order.Price * order.Amount, 2); } else if (order.OrderType == OrderType.Sell) { if (_playerStocks.TryGetValue(order.StockId, out var value)) { _playerStocks[order.StockId] = value + order.Amount; } else { _playerStocks[order.StockId] = order.Amount; } } order.Completed = true; _playerTradeOrders.Remove(order); } private void Market_OnCalculate(object sender, EventArgs e) { //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Expected O, but got Unknown foreach (TradeOrder order in _playerTradeOrders) { if (order.Completed) { continue; } Stock stock = Market.Stocks.FirstOrDefault((Stock a) => a.Id == order.StockId); if (stock == null) { order.Completed = true; continue; } decimal price = stock.Price; if ((order.OrderType == OrderType.Buy && price <= order.Price) || (order.OrderType == OrderType.Sell && price >= order.Price)) { bool flag = false; flag = order.OrderType switch { OrderType.Buy => InstantBuy(stock, order.Amount, deductMoney: false), OrderType.Sell => InstantSell(stock, order.Amount, removeStock: false), _ => throw new NotImplementedException($"OrderType \"{order.OrderType}\" doesn't have an implementation."), }; order.Completed = flag; if (order.Completed && NotificationsEnabled) { Lib.GameMessage.Broadcast($"{order.OrderType} order \"({stock.Symbol}) '{order.Amount}' for target price € {order.Price}\" completed.", (GameMessageType)0, (Icon)17, (Color?)null, 0f); } } } _playerTradeOrders.RemoveAll((TradeOrder a) => a.Completed); TimeData currentDateTime = Lib.Time.CurrentDateTime; int num = 0; num += _tradeHistory.RemoveAll((TradeHistory a) => (currentDateTime - a.DateTime).TotalDays >= 7.0); num += _historicalPortfolio.RemoveAll((HistoricalPortfolio a) => (currentDateTime - a.Date).TotalDays >= 32.0); if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled && num > 0) { ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; bool flag2 = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(31, 1, ref flag2); if (flag2) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Deleted "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" trade history entries."); } log.LogInfo(val); } } private bool IsValidOrder(OrderType orderType, Stock stock, decimal amount) { decimal value; return orderType switch { OrderType.Buy => AvailableFunds >= Math.Round(stock.Price * amount, 2), OrderType.Sell => _playerStocks.TryGetValue(stock.Id, out value) && value >= amount, _ => false, }; } } internal class TradeHistory { [JsonIgnore] private TimeData? _dateTime; [JsonIgnore] public TimeData DateTime { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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) TimeData valueOrDefault = _dateTime.GetValueOrDefault(); if (!_dateTime.HasValue) { ((TimeData)(ref valueOrDefault))..ctor(Year, Month, Day, Hour, Minute); _dateTime = valueOrDefault; return valueOrDefault; } return valueOrDefault; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) _dateTime = value; } } public int Year { get; set; } public int Month { get; set; } public int Day { get; set; } public int Hour { get; set; } public int Minute { get; set; } public string StockSymbol { get; set; } public OrderType OrderType { get; set; } public decimal Amount { get; set; } public decimal Price { get; set; } [JsonIgnore] public decimal Total => Math.Round(Price * Amount, 2); public TradeHistory() { } internal TradeHistory(TimeData dateTime, string symbol, OrderType orderType, decimal amount, decimal price) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) DateTime = dateTime; StockSymbol = symbol; OrderType = orderType; Amount = amount; Price = price; Year = ((TimeData)(ref dateTime)).Year; Month = ((TimeData)(ref dateTime)).Month; Day = ((TimeData)(ref dateTime)).Day; Hour = ((TimeData)(ref dateTime)).Hour; Minute = ((TimeData)(ref dateTime)).Minute; } } internal sealed class TradeHistoryPagination { private readonly int _maxTradeHistoryPerPage; private readonly TradeController _tradeController; private Func<TradeHistory, object> _currentSortingProperty; private bool _sortAscending = true; internal int CurrentPage { get; private set; } internal TradeHistory[] Current { get { TradeHistory[] array = new TradeHistory[_maxTradeHistoryPerPage]; SetHistories(array); return array; } } internal TradeHistoryPagination(TradeController tradeController, int maxTradeHistoryPerPage) { _tradeController = tradeController; _maxTradeHistoryPerPage = maxTradeHistoryPerPage; } internal TradeHistory[] Next() { TradeHistory[] array = new TradeHistory[_maxTradeHistoryPerPage]; int num = (int)Math.Ceiling((double)_tradeController.TradeHistory.Count / (double)_maxTradeHistoryPerPage); if (CurrentPage < num - 1) { CurrentPage++; SetHistories(array); } else if (CurrentPage == num - 1) { CurrentPage = 0; SetHistories(array); } return array; } internal TradeHistory[] Previous() { TradeHistory[] array = new TradeHistory[_maxTradeHistoryPerPage]; if (CurrentPage > 0) { CurrentPage--; SetHistories(array); } else if (CurrentPage == 0) { int num = (int)Math.Ceiling((double)_tradeController.TradeHistory.Count / (double)_maxTradeHistoryPerPage); CurrentPage = Math.Max(0, num - 1); SetHistories(array); } return array; } internal TradeHistory[] Reset() { TradeHistory[] array = new TradeHistory[_maxTradeHistoryPerPage]; CurrentPage = 0; SetHistories(array); return array; } internal void SortBy(Func<TradeHistory, object> selector, bool? ascending = null) { if (_currentSortingProperty == selector) { _sortAscending = !_sortAscending; } else { _sortAscending = true; } _currentSortingProperty = selector; if (ascending.HasValue) { _sortAscending = ascending.Value; } } private void SetHistories(TradeHistory[] slots) { if (_tradeController.TradeHistory.Count != 0) { IReadOnlyList<TradeHistory> readOnlyList = _tradeController.TradeHistory; if (_currentSortingProperty != null) { readOnlyList = (_sortAscending ? readOnlyList.OrderBy(_currentSortingProperty).ToList() : readOnlyList.OrderByDescending(_currentSortingProperty).ToList()); } int num = CurrentPage * _maxTradeHistoryPerPage; for (int i = 0; i < _maxTradeHistoryPerPage; i++) { slots[i] = ((readOnlyList.Count > num + i) ? readOnlyList[num + i] : null); } } } } internal class TradeOrder { public int StockId { get; set; } public decimal Price { get; set; } public decimal Amount { get; set; } public OrderType OrderType { get; set; } public bool Completed { get; set; } public TradeOrder() { } internal TradeOrder(OrderType orderType, int stockId, decimal price, decimal amount) { StockId = stockId; Price = price; Amount = amount; OrderType = orderType; Completed = false; } } internal enum OrderType { Buy, Sell } internal sealed class TradeOrderPagination { private readonly int _maxTradeOrdersPerPage; private readonly TradeController _tradeController; private Stock _forStockOnly; internal int CurrentPage { get; private set; } internal StockOrder[] Current { get { StockOrder[] array = new StockOrder[_maxTradeOrdersPerPage]; SetStocks(array); return array; } } internal TradeOrderPagination(TradeController tradeController, int maxTradeOrdersPerPage) { _tradeController = tradeController; _maxTradeOrdersPerPage = maxTradeOrdersPerPage; } internal void SetForStockOnly(Stock stock) { _forStockOnly = stock; } internal StockOrder[] Next() { StockOrder[] array = new StockOrder[_maxTradeOrdersPerPage]; int num = (int)Math.Ceiling((double)_tradeController.TradeOrders.Count / (double)_maxTradeOrdersPerPage); if (CurrentPage < num - 1) { CurrentPage++; SetStocks(array); } else if (CurrentPage == num - 1) { CurrentPage = 0; SetStocks(array); } return array; } internal StockOrder[] Previous() { StockOrder[] array = new StockOrder[_maxTradeOrdersPerPage]; if (CurrentPage > 0) { CurrentPage--; SetStocks(array); } else if (CurrentPage == 0) { int num = (int)Math.Ceiling((double)_tradeController.TradeOrders.Count / (double)_maxTradeOrdersPerPage); CurrentPage = num - 1; SetStocks(array); } return array; } internal StockOrder[] Reset() { StockOrder[] array = new StockOrder[_maxTradeOrdersPerPage]; CurrentPage = 0; SetStocks(array); return array; } private void SetStocks(StockOrder[] stocks) { IReadOnlyList<TradeOrder> readOnlyList = _tradeController.TradeOrders; if (_forStockOnly != null) { readOnlyList = readOnlyList.Where((TradeOrder a) => a.StockId == _forStockOnly.Id).ToList(); } if (readOnlyList.Count == 0) { return; } int num = CurrentPage * _maxTradeOrdersPerPage; for (int i = 0; i < _maxTradeOrdersPerPage; i++) { TradeOrder order = ((readOnlyList.Count > num + i) ? readOnlyList[num + i] : null); if (order == null) { stocks[i] = null; continue; } Stock stock = _tradeController.Market.Stocks.FirstOrDefault((Stock a) => a.Id == order.StockId); if (stock == null) { stocks[i] = null; } else { stocks[i] = new StockOrder(stock, order); } } } } internal sealed class StockOrder { internal Stock Stock { get; } internal TradeOrder TradeOrder { get; } internal StockOrder(Stock stock, TradeOrder tradeOrder) { Stock = stock; TradeOrder = tradeOrder; } } internal sealed class TradeSaveData { public Dictionary<int, decimal> PlayerStocks { get; set; } public List<TradeOrder> PlayerTradeOrders { get; set; } public List<HistoricalPortfolio> HistoricalPortfolio { get; set; } public List<TradeHistory> TradeHistory { get; set; } public decimal AvailableFunds { get; set; } internal string ToJson() { return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = false }); } internal static TradeSaveData FromJson(string json) { return JsonSerializer.Deserialize<TradeSaveData>(json); } } } namespace SOD.StockMarket.Implementation.Stocks { internal class CompanyStockData { private Company _company; private decimal? _averageSales; private decimal? _minSalary; private decimal? _topSalary; internal string Name { get; private set; } internal string Symbol { get; private set; } internal decimal AverageSales => GetAverageSales(); internal decimal MinSalary => GetMinSalary(); internal decimal TopSalary => GetTopSalary(); internal double Volatility { get; private set; } internal CompanyStockData(string name, double volatility, string symbol = null) { Name = name; Symbol = symbol ?? StockSymbolGenerator.Generate(Name); Volatility = volatility; } internal CompanyStockData(Company company) { _company = company; } internal void Initialize() { if (_company != null) { Name = _company.name; Symbol = StockSymbolGenerator.Generate(Name); Volatility = Math.Round(MathHelper.Random.NextDouble(0.15, 0.85), 2); } _company = null; } private decimal GetAverageSales() { decimal valueOrDefault = _averageSales.GetValueOrDefault(); if (!_averageSales.HasValue) { valueOrDefault = MathHelper.Random.Next(5, 1000); _averageSales = valueOrDefault; return valueOrDefault; } return valueOrDefault; } private decimal GetMinSalary() { if (_company != null && _company.minimumSalary > 0f) { return (decimal)_company.minimumSalary; } decimal valueOrDefault = _minSalary.GetValueOrDefault(); if (!_minSalary.HasValue) { valueOrDefault = MathHelper.Random.Next(550, 1350); _minSalary = valueOrDefault; return valueOrDefault; } return valueOrDefault; } private decimal GetTopSalary() { if (_company != null && _company.topSalary > 0f) { return (decimal)_company.topSalary; } decimal valueOrDefault = _topSalary.GetValueOrDefault(); if (!_topSalary.HasValue) { valueOrDefault = MathHelper.Random.Next((int)GetMinSalary() + 1, 2250); _topSalary = valueOrDefault; return valueOrDefault; } return valueOrDefault; } } internal static class CustomStocks { internal static readonly (CompanyStockData data, decimal? basePrice)[] Stocks = new(CompanyStockData, decimal?)[3] { (new CompanyStockData("Starch Kola", 0.5), (decimal)MathHelper.Random.NextDouble(5000.0, 10000.0)), (new CompanyStockData("Kaizen-7", 0.4), (decimal)MathHelper.Random.NextDouble(3500.0, 7500.0)), (new CompanyStockData("Crow Coin", 0.15), (decimal)MathHelper.Random.NextDouble(0.9750000238418579, 1.024999976158142)) }; } internal class Stock { private static int _id; private readonly List<StockData> _historicalData; private readonly CompanyStockData _companyData; private readonly decimal? _basePrice; private readonly bool _imported; private int _currentStep; internal int Id { get; } internal string Name => _companyData.Name; internal string Symbol => _companyData.Symbol; internal double Volatility => _companyData.Volatility; internal decimal Price { get; private set; } internal decimal OpeningPrice { get; set; } internal decimal? ClosingPrice { get; set; } internal decimal HighPrice { get; private set; } internal decimal LowPrice { get; private set; } internal StockTrend? Trend { get; private set; } [JsonIgnore] internal decimal TodayDiff => Math.Round(Price - OpeningPrice, 2); [JsonIgnore] internal decimal DailyPercentage => GetPercentage(Price, OpeningPrice); [JsonIgnore] internal decimal? WeeklyPercentage { get { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) TimeData currentDate = Lib.Time.CurrentDate; StockData stockData = HistoricalData.OrderByDescending((StockData a) => a.Date).FirstOrDefault((StockData a) => (currentDate - a.Date).TotalDays >= 7.0); if (stockData == null) { return null; } return GetPercentage(Price, stockData.Open); } } [JsonIgnore] internal decimal? MonthlyPercentage { get { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) TimeData currentDate = Lib.Time.CurrentDate; StockData stockData = HistoricalData.OrderByDescending((StockData a) => a.Date).FirstOrDefault((StockData a) => (currentDate - a.Date).TotalDays >= 30.0); if (stockData == null) { return null; } return GetPercentage(Price, stockData.Open); } } internal IReadOnlyList<StockData> HistoricalData => _historicalData; internal int CompanyId { get; } internal Stock(Company company) : this() { CompanyId = company.companyID; _companyData = new CompanyStockData(company); } internal Stock(CompanyStockData companyData, decimal? basePrice = null) : this((int?)null, basePrice) { CompanyId = -1; _companyData = companyData; } internal Stock(StockDataIO.StockDataDTO dto, IEnumerable<StockData> historicalData) : this(dto.Id, dto.Price) { _companyData = new CompanyStockData(dto.Name, dto.Volatility.Value, dto.Symbol); Price = dto.Price.Value; OpeningPrice = dto.Open; ClosingPrice = dto.Close; LowPrice = dto.Low; HighPrice = dto.High; if (dto.TrendPercentage.HasValue && dto.TrendStartPrice.HasValue && dto.TrendEndPrice.HasValue && dto.TrendSteps.HasValue) { StockTrend value = new StockTrend { Percentage = dto.TrendPercentage.Value, StartPrice = dto.TrendStartPrice.Value, EndPrice = dto.TrendEndPrice.Value, Steps = dto.TrendSteps.Value }; Trend = value; } foreach (StockData item in historicalData.OrderBy((StockData a) => a.Date)) { CreateHistoricalData(item); } _imported = true; } internal Stock(Stock stock) { Id = stock.Id; _companyData = stock._companyData; Price = stock.Price; OpeningPrice = stock.OpeningPrice; ClosingPrice = stock.ClosingPrice; LowPrice = stock.LowPrice; HighPrice = stock.HighPrice; Trend = stock.Trend; _historicalData = new List<StockData>(); foreach (StockData historicalDatum in stock._historicalData) { _historicalData.Add(new StockData(historicalDatum)); } _basePrice = stock._basePrice; _imported = stock._imported; } private Stock(int? id = null, decimal? basePrice = null) { Id = id ?? _id++; _historicalData = new List<StockData>(); _basePrice = basePrice; _imported = false; } private static decimal GetPercentage(decimal currentPrice, decimal openingPrice) { double num = ((openingPrice != 0m) ? ((double)((currentPrice - openingPrice) / openingPrice * 100m)) : ((currentPrice > 0m) ? double.PositiveInfinity : ((!(currentPrice < 0m)) ? 0.0 : double.NegativeInfinity))); return Math.Round((decimal)num, 2); } internal void DeterminePrice() { if ((!Trend.HasValue || _currentStep >= Trend.Value.Steps) && MathHelper.Random.Next(0, 99) < 10) { if (Trend.HasValue && _currentStep >= Trend.Value.Steps) { RemoveTrend(); } return; } decimal? num = null; if (Trend.HasValue) { StockTrend value = Trend.Value; if (_currentStep >= value.Steps) { RemoveTrend(); } else { decimal num2 = (decimal)_currentStep / (decimal)value.Steps; num = value.StartPrice + (value.EndPrice - value.StartPrice) * num2; _currentStep++; if (_currentStep >= value.Steps) { RemoveTrend(); } } } if (!num.HasValue) { decimal num3 = (decimal)((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.PriceFluctuationPercentage * (decimal)Volatility; decimal num4 = Price * (num3 / 100m); num = Price + (decimal)(MathHelper.Random.NextDouble() * (double)num4 * 2.0) - num4; } if (num.HasValue) { decimal? num5 = num; if (!((num5.GetValueOrDefault() <= default(decimal)) & num5.HasValue)) { goto IL_0222; } } num = 0.01m; if (Trend.HasValue && Trend.Value.EndPrice <= 0.01m) { RemoveTrend(); } goto IL_0222; IL_0222: Price = Math.Round(num.Value, 2); UpdateHighestLowestPrices(); } internal void SetTrend(StockTrend stockTrend) { if (!Trend.HasValue) { Trend = stockTrend; } } internal void RemoveTrend() { _currentStep = 0; Trend = null; } internal void CreateHistoricalData(StockData stockData = null, TimeData? date = null) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (stockData != null) { _historicalData.Add(stockData); return; } TimeData date2 = (TimeData)(((??)date) ?? Lib.Time.CurrentDate); _historicalData.Add(new StockData { Date = date2, Close = ClosingPrice, Open = OpeningPrice, Low = LowPrice, High = HighPrice, Trend = Trend }); LowPrice = ClosingPrice.Value; HighPrice = ClosingPrice.Value; } internal int CleanUpHistoricalData(TimeData? date) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) TimeData currentDate = (TimeData)(((??)date) ?? Lib.Time.CurrentDate); int maxDays = ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.DaysToKeepStockHistoricalData; return _historicalData.RemoveAll((StockData stockData) => ((currentDate - stockData.Date).Days > maxDays) ? true : false); } internal void Initialize() { if (_imported) { throw new Exception("An imported stock is already initialized, no need to call Initialize();"); } _companyData.Initialize(); Price = Math.Round(_basePrice ?? (_companyData.AverageSales / (_companyData.MinSalary + _companyData.TopSalary) * 1000m), 2); OpeningPrice = Price; LowPrice = Price; HighPrice = Price; } private void UpdateHighestLowestPrices() { if (LowPrice > Price) { LowPrice = Price; } else if (HighPrice < Price) { HighPrice = Price; } } } internal class StockData : IEquatable<StockData> { public TimeData Date { get; set; } public decimal Open { get; set; } public decimal? Close { get; set; } public decimal High { get; set; } public decimal Low { get; set; } public StockTrend? Trend { get; set; } internal StockData() { } internal StockData(StockData data) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) Date = data.Date; Open = data.Open; Close = data.Close; High = data.High; Low = data.Low; Trend = data.Trend; } public bool Equals(StockData other) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (other != null) { TimeData date = other.Date; return ((TimeData)(ref date)).Equals(Date); } return false; } public override bool Equals(object obj) { return Equals(obj as StockData); } public override int GetHashCode() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) TimeData date = Date; return ((object)(TimeData)(ref date)).GetHashCode(); } } internal static class StockDataIO { internal sealed class StockDataDTO { public int Id { get; set; } public string Name { get; set; } public string Symbol { get; set; } public TimeData? Date { get; set; } public decimal Open { get; set; } public decimal? Close { get; set; } public decimal High { get; set; } public decimal Low { get; set; } public decimal Average { get; set; } public decimal? Price { get; set; } public double? Volatility { get; set; } public double? TrendPercentage { get; set; } public decimal? TrendStartPrice { get; set; } public decimal? TrendEndPrice { get; set; } public int? TrendSteps { get; set; } public TradeSaveData TradeSaveData { get; set; } public List<Article> Articles { get; set; } public decimal? OriginalPrice { get; set; } public decimal SimulationChange => Math.Round(Price.Value - OriginalPrice.Value, 2); } internal static void Export(Market market, TradeController tradeController, string path, Market simulation = null) { //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Expected O, but got Unknown //IL_033a: Unknown result type (might be due to invalid IL or missing references) if (!market.Initialized) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Cannot export stock market data, market not yet initialized."); return; } List<StockDataDTO> list = new List<StockDataDTO> { new StockDataDTO { TradeSaveData = tradeController.Export() }, new StockDataDTO { Articles = NewsGenerator.AllArticles.ToList() } }; foreach (Stock stock in market.Stocks.OrderBy((Stock a) => a.Id)) { StockDataDTO stockDataDTO = new StockDataDTO { Id = stock.Id, Name = stock.Name, Symbol = stock.Symbol, Date = null, Price = stock.Price, Open = stock.OpeningPrice, Close = stock.ClosingPrice, High = stock.HighPrice, Low = stock.LowPrice, Volatility = stock.Volatility, TrendPercentage = stock.Trend?.Percentage, TrendStartPrice = stock.Trend?.StartPrice, TrendEndPrice = stock.Trend?.EndPrice, TrendSteps = stock.Trend?.Steps, Average = Math.Round((stock.HighPrice + stock.LowPrice + stock.Price) / 3m, 2) }; if (simulation != null) { Stock stock2 = simulation.Stocks.First((Stock a) => a.Id == stock.Id); stockDataDTO.OriginalPrice = stock2.Price; } list.Add(stockDataDTO); foreach (StockData item2 in stock.HistoricalData.OrderBy((StockData a) => a.Date)) { StockDataDTO item = new StockDataDTO { Id = stock.Id, Name = stock.Name, Symbol = stock.Symbol, Date = item2.Date, Open = item2.Open, Close = item2.Close, High = item2.High, Low = item2.Low, Average = Math.Round((item2.Open + item2.Close.Value + item2.High + item2.Low) / 4m), Price = null, Volatility = null, TrendPercentage = item2.Trend?.Percentage, TrendStartPrice = item2.Trend?.StartPrice, TrendEndPrice = item2.Trend?.EndPrice, TrendSteps = item2.Trend?.Steps, OriginalPrice = null }; list.Add(item); } } ConverterFactory.Get(path).Save(list, MathHelper.Random, path, simulation != null); ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Exported "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" stock market data rows."); } log.LogInfo(val); } internal static bool Import(Market market, TradeController tradeController, string path) { //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Expected O, but got Unknown //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Expected O, but got Unknown //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Expected O, but got Unknown if (market.Initialized) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Cannot import stock market data, market is already initialized."); return true; } bool flag = default(bool); try { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Loading stock data.."); List<StockDataDTO> list = ConverterFactory.Get(path).Load(path); Dictionary<int, StockData[]> dictionary = (from a in list where a.TradeSaveData == null && a.Articles == null && !a.Price.HasValue group a by a.Id).Select(delegate(IGrouping<int, StockDataDTO> a) { IEnumerable<StockData> source = a.OrderBy((StockDataDTO a) => a.Date).Select(delegate(StockDataDTO a) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) StockData stockData = new StockData { Close = a.Close, High = a.High, Low = a.Low, Date = a.Date.Value, Open = a.Open }; if (a.TrendPercentage.HasValue && a.TrendStartPrice.HasValue && a.TrendEndPrice.HasValue && a.TrendSteps.HasValue) { StockTrend stockTrend = default(StockTrend); stockTrend.Percentage = a.TrendPercentage.Value; stockTrend.StartPrice = a.TrendStartPrice.Value; stockTrend.EndPrice = a.TrendEndPrice.Value; stockTrend.Steps = a.TrendSteps.Value; StockTrend value = stockTrend; stockData.Trend = value; } return stockData; }); return new { Key = a.Key, Data = source.ToArray() }; }).ToDictionary(a => a.Key, a => a.Data); foreach (StockDataDTO item in from a in list where a.TradeSaveData == null && a.Articles == null && a.Price.HasValue orderby a.Id select a) { Stock stock = new Stock(item, dictionary[item.Id]); market.InitStock(stock); } TradeSaveData tradeSaveData = list[0].TradeSaveData; if (tradeSaveData != null) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Loading trade data.."); tradeController.Import(tradeSaveData); } PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Loading news data.."); NewsGenerator.Import(list[1].Articles); if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.IsDebugEnabled) { PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)("Stocks data loaded: " + market.Stocks.Count)); ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(17, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("- Loaded stocks -"); } log.LogInfo(val); foreach (Stock item2 in market.Stocks.OrderBy((Stock a) => a.Id)) { ManualLogSource log2 = PluginController<Plugin, IPluginBindings>.Log; val = new BepInExInfoLogInterpolatedStringHandler(23, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Stock: \"("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item2.Symbol); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item2.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" | Price: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<decimal>(item2.Price); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } log2.LogInfo(val); } ManualLogSource log3 = PluginController<Plugin, IPluginBindings>.Log; val = new BepInExInfoLogInterpolatedStringHandler(17, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("- End of Stocks -"); } log3.LogInfo(val); } PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Stock market loaded."); } catch (Exception) { ManualLogSource log4 = PluginController<Plugin, IPluginBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(86, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The savefile is not compatible with \"Stockmarket v"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("2.0.8"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\", skipped loading stockmarket data."); } log4.LogInfo(val); return false; } market.PostStocksInitialization(typeof(StockDataIO)); return true; } } internal static class StockNameGenerator { private static readonly Faker faker = new Faker("en"); internal static string GenerateStockName() { return faker.Company.CompanyName((int?)null); } } internal sealed class StockPagination { private readonly IStocksContainer _stockContainer; private readonly Func<int> _maxStocksPerPageFunc; private Func<Stock, object> _currentSortingProperty; private bool _sortAscending = true; internal int CurrentPage { get; private set; } internal Stock[] Current { get { Stock[] array = new Stock[_maxStocksPerPageFunc()]; SetStocks(array); return array; } } internal StockPagination(IStocksContainer stockContainer, int maxStocksPerPage) { _stockContainer = stockContainer; _maxStocksPerPageFunc = () => maxStocksPerPage; } internal StockPagination(IStocksContainer stockContainer, Func<int> maxStocksPerPage) { _stockContainer = stockContainer; _maxStocksPerPageFunc = maxStocksPerPage; } internal Stock[] Next() { int num = _maxStocksPerPageFunc(); Stock[] array = new Stock[num]; int num2 = (int)Math.Ceiling((double)_stockContainer.Stocks.Count / (double)num); if (CurrentPage < num2 - 1) { CurrentPage++; SetStocks(array); } else if (CurrentPage == num2 - 1) { CurrentPage = 0; SetStocks(array); } return array; } internal Stock[] Previous() { int num = _maxStocksPerPageFunc(); Stock[] array = new Stock[num]; if (CurrentPage > 0) { CurrentPage--; SetStocks(array); } else if (CurrentPage == 0) { int num2 = (int)Math.Ceiling((double)_stockContainer.Stocks.Count / (double)num); CurrentPage = num2 - 1; SetStocks(array); } return array; } internal Stock[] Reset() { Stock[] array = new Stock[_maxStocksPerPageFunc()]; CurrentPage = 0; SetStocks(array); return array; } internal void SortBy(Func<Stock, object> selector, bool? ascending = null) { if (_currentSortingProperty == selector) { _sortAscending = !_sortAscending; } else { _sortAscending = true; } _currentSortingProperty = selector; if (ascending.HasValue) { _sortAscending = ascending.Value; } } private void SetStocks(Stock[] stocks) { if (_stockContainer.Stocks.Count != 0) { IReadOnlyList<Stock> readOnlyList = _stockContainer.Stocks; if (_currentSortingProperty != null) { readOnlyList = (_sortAscending ? readOnlyList.OrderBy(_currentSortingProperty).ToList() : readOnlyList.OrderByDescending(_currentSortingProperty).ToList()); } int num = _maxStocksPerPageFunc(); int num2 = CurrentPage * num; for (int i = 0; i < num; i++) { Stock stock = ((readOnlyList.Count > num2 + i) ? readOnlyList[num2 + i] : null); stocks[i] = stock; } } } } internal static class StockSymbolGenerator { private static Dictionary<string, int> _companySymbolCount; internal static string Generate(string companyName) { string text = GetSymbol(companyName); if (_companySymbolCount == null) { _companySymbolCount = new Dictionary<string, int>(); } if (_companySymbolCount.TryGetValue(text, out var value)) { value++; _companySymbolCount[text] = value; } else { _companySymbolCount[text] = 0; } if (text.Length == 4 && value > 0) { text = new string(text.Take(3).ToArray()); if (_companySymbolCount.TryGetValue(text, out value)) { value++; _companySymbolCount[text] = value; } else { _companySymbolCount[text] = 0; } } string text2 = text + value; if (text2.Length == 1) { text2 = text + value.ToString("D3"); } else if (text2.Length == 2) { text2 = text + value.ToString("D2"); } text2 = text2.Substring(0, Math.Min(text2.Length, 4)); return text2.ToUpper(); } internal static void Clear() { _companySymbolCount = null; } private static string GetSymbol(string companyName) { char[] blockedChars = new char[3] { '-', '_', '&' }; string[] array = (from a in companyName.Split(' ', StringSplitOptions.RemoveEmptyEntries) where a.Length > 1 select a).ToArray(); if (array.Length == 0) { throw new Exception("Missing company name."); } if (array.Length == 1) { return new string(array[0].Where((char a) => !blockedChars.Contains(a)).Take(4).ToArray()); } return new string(array[0].Where((char a) => !blockedChars.Contains(a)).Take(2).Concat(array[1].Where((char a) => !blockedChars.Contains(a)).Take(2)) .ToArray()); } } internal readonly struct StockTrend { internal double Percentage { get; init; } internal decimal StartPrice { get; init; } internal decimal EndPrice { get; init; } internal int Steps { get; init; } internal StockTrend(double percentage, decimal currentPrice, int steps) { Percentage = percentage; StartPrice = currentPrice; Steps = steps; EndPrice = Math.Round(StartPrice + StartPrice / 100m * (decimal)Percentage, 2); } } } namespace SOD.StockMarket.Implementation.DataConversion { internal static class ConverterFactory { private static readonly Dictionary<string, Func<IDataConverter>> _converters = new Dictionary<string, Func<IDataConverter>>(StringComparer.OrdinalIgnoreCase) { { ".csv", () => CsvConverter.Create() }, { ".bin", () => BinaryConverter.Create() } }; public static IDataConverter Get(string filePath) { string extension = Path.GetExtension(filePath); if (_converters.TryGetValue(extension, out var value)) { return value(); } throw new NotSupportedException("Data type \"" + extension + "\" is not supported."); } } public enum DataSaveFormat { Csv, Bin } internal interface IDataConverter { void Save(List<StockDataIO.StockDataDTO> data, MersenneTwister random, string path, bool simulation = false); List<StockDataIO.StockDataDTO> Load(string path); } } namespace SOD.StockMarket.Implementation.DataConversion.Converters { internal sealed class BinaryConverter : IDataConverter { private BinaryConverter() { } internal static BinaryConverter Create() { return new BinaryConverter(); } public void Save(List<StockDataIO.StockDataDTO> data, MersenneTwister random, string path, bool simulation = false) { using BinaryWriter binaryWriter = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write)); binaryWriter.Write("BinaryStockData"); var (value, array) = random.SaveState(); binaryWriter.Write(value); uint[] array2 = array; foreach (uint value2 in array2) { binaryWriter.Write(value2); } string value3 = data[0].TradeSaveData.ToJson(); binaryWriter.Write(value3); string value4 = JsonSerializer.Serialize(data[1].Articles, new JsonSerializerOptions { WriteIndented = false }); binaryWriter.Write(value4); for (int j = 2; j < data.Count; j++) { StockDataIO.StockDataDTO stockDataDTO = data[j]; binaryWriter.Write(stockDataDTO.Id); binaryWriter.Write(stockDataDTO.Name); binaryWriter.Write(stockDataDTO.Symbol); WriteNullableTimeData(binaryWriter, stockDataDTO.Date); WriteNullableDecimal(binaryWriter, stockDataDTO.Price); binaryWriter.Write(stockDataDTO.Open); WriteNullableDecimal(binaryWriter, stockDataDTO.Close); binaryWriter.Write(stockDataDTO.High); binaryWriter.Write(stockDataDTO.Low); WriteNullableDouble(binaryWriter, stockDataDTO.Volatility); WriteNullableDouble(binaryWriter, stockDataDTO.TrendPercentage); WriteNullableDecimal(binaryWriter, stockDataDTO.TrendStartPrice); WriteNullableDecimal(binaryWriter, stockDataDTO.TrendEndPrice); WriteNullableInt(binaryWriter, stockDataDTO.TrendSteps); binaryWriter.Write(stockDataDTO.Average); } } public List<StockDataIO.StockDataDTO> Load(string path) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown List<StockDataIO.StockDataDTO> list = new List<StockDataIO.StockDataDTO>(); using BinaryReader binaryReader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read)); if (binaryReader.ReadString() != "BinaryStockData") { throw new InvalidDataException("Invalid binary file format."); } int item = binaryReader.ReadInt32(); uint[] array = new uint[624]; for (int i = 0; i < array.Length; i++) { array[i] = binaryReader.ReadUInt32(); } MathHelper.Init(new MersenneTwister((item, array))); TradeSaveData tradeSaveData = TradeSaveData.FromJson(binaryReader.ReadString()); list.Add(new StockDataIO.StockDataDTO { TradeSaveData = tradeSaveData }); List<Article> articles = JsonSerializer.Deserialize<List<Article>>(binaryReader.ReadString()); list.Add(new StockDataIO.StockDataDTO { Articles = articles }); while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length) { StockDataIO.StockDataDTO item2 = new StockDataIO.StockDataDTO { Id = binaryReader.ReadInt32(), Name = binaryReader.ReadString(), Symbol = binaryReader.ReadString(), Date = ReadNullableTimeData(binaryReader), Price = ReadNullableDecimal(binaryReader), Open = binaryReader.ReadDecimal(), Close = ReadNullableDecimal(binaryReader), High = binaryReader.ReadDecimal(), Low = binaryReader.ReadDecimal(), Volatility = ReadNullableDouble(binaryReader), TrendPercentage = ReadNullableDouble(binaryReader), TrendStartPrice = ReadNullableDecimal(binaryReader), TrendEndPrice = ReadNullableDecimal(binaryReader), TrendSteps = ReadNullableInt(binaryReader), Average = binaryReader.ReadDecimal() }; list.Add(item2); } return list; } private static void WriteNullableTimeData(BinaryWriter writer, TimeData? value) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) writer.Write(value.HasValue);
Bogus.dll
Decompiled 4 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using Bogus.Bson; using Bogus.DataSets; using Bogus.Extensions; using Bogus.Extensions.Extras; using Bogus.Platform; using Bogus.Vendor; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyProduct("Bogus")] [assembly: AssemblyTitle("Bogus Fake Data Generator for .NET")] [assembly: AssemblyCompany("Brian Chavez")] [assembly: AssemblyCopyright("Brian Chavez © 2023")] [assembly: AssemblyFileVersion("35.2.0")] [assembly: AssemblyInformationalVersion("35.2.0 built on 2023-12-26 20:42:03Z")] [assembly: AssemblyTrademark("MIT License")] [assembly: AssemblyDescription("https://github.com/bchavez/Bogus")] [assembly: InternalsVisibleTo("Bogus.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d981a0be5616f450cc0528f88cf96e7bb782edb8ea9a06517cc42b340cdd644a931aab0c7c4902c129eff3d09a3f8c331026286d55c36f225f33f4709be9352fdf16c7b6781652528c2b77063f19a6ab21ee79368f552f60da8f503832e2d6ab6aafce934cc8736c24fd391ac286aa14dd5b5959fa546eb25841e41cfb625aa2")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyVersion("35.2.0.0")] 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 System { internal static class AssemblyVersionInformation { internal const string AssemblyProduct = "Bogus"; internal const string AssemblyTitle = "Bogus Fake Data Generator for .NET"; internal const string AssemblyCompany = "Brian Chavez"; internal const string AssemblyCopyright = "Brian Chavez © 2023"; internal const string AssemblyVersion = "35.2.0"; internal const string AssemblyFileVersion = "35.2.0"; internal const string AssemblyInformationalVersion = "35.2.0 built on 2023-12-26 20:42:03Z"; internal const string AssemblyTrademark = "MIT License"; internal const string AssemblyDescription = "https://github.com/bchavez/Bogus"; internal const string InternalsVisibleTo = "Bogus.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d981a0be5616f450cc0528f88cf96e7bb782edb8ea9a06517cc42b340cdd644a931aab0c7c4902c129eff3d09a3f8c331026286d55c36f225f33f4709be9352fdf16c7b6781652528c2b77063f19a6ab21ee79368f552f60da8f503832e2d6ab6aafce934cc8736c24fd391ac286aa14dd5b5959fa546eb25841e41cfb625aa2"; } } namespace Bogus { public interface IBinder { Dictionary<string, MemberInfo> GetMembers(Type t); } public class Binder : IBinder { protected internal BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public Binder() { } public Binder(BindingFlags bindingFlags) { BindingFlags = bindingFlags; } public virtual Dictionary<string, MemberInfo> GetMembers(Type t) { return (from mi in (from m in t.GetAllMembers(BindingFlags) select UseBaseTypeDeclaredPropertyInfo(t, m)).Where(delegate(MemberInfo m) { if (m.GetCustomAttributes(typeof(CompilerGeneratedAttribute), inherit: true).Any()) { return false; } if (m is PropertyInfo propertyInfo) { return propertyInfo.CanWrite; } return m is FieldInfo fieldInfo && !fieldInfo.IsPrivate; }) group mi by mi.Name).ToDictionary((IGrouping<string, MemberInfo> k) => k.Key, (IGrouping<string, MemberInfo> g) => g.First()); } protected virtual MemberInfo UseBaseTypeDeclaredPropertyInfo(Type t, MemberInfo m) { if (m is PropertyInfo propertyInfo && !propertyInfo.CanWrite && (object)m.DeclaringType != null && m.DeclaringType != t) { PropertyInfo property = m.DeclaringType.GetProperty(m.Name, BindingFlags); if ((object)property != null) { return property; } } return m; } } public class BogusException : Exception { public BogusException() { } public BogusException(string message) : base(message) { } public BogusException(string message, Exception innerException) : base(message, innerException) { } } public static class Chars { public const string LowerCase = "abcdefghijklmnopqrstuvwxyz"; public const string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; public const string Numbers = "0123456789"; public const string HexLowerCase = "0123456789abcdef"; public const string HexUpperCase = "0123456789ABCDEF"; public const string AlphaNumericUpperCase = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; public const string AlphaNumericLowerCase = "0123456789abcdefghijklmnopqrstuvwxyz"; } [EditorBrowsable(EditorBrowsableState.Never)] public static class SafeUnicodeRanges { public static string[] Basic = new string[262] { "0-9", "A-Z", "a-z", "À-Ö", "Ø-ö", "ø-ˁ", "ˆ-ˑ", "ˠ-ˤ", "ͺ-ͽ", "Έ-Ί", "Ύ-Ρ", "Σ-ώ", "ϐ-ϵ", "Ϸ-ҁ", "Ҋ-ԓ", "Ա-Ֆ", "ա-և", "א-ת", "װ-ײ", "ء-غ", "ـ-ي", "٠-٩", "ٮ-ٯ", "ٱ-ۓ", "ۥ-ۦ", "ۮ-ۼ", "ܒ-ܯ", "ݍ-ݭ", "ހ-ޥ", "߀-ߪ", "ߴ-ߵ", "ऄ-ह", "क़-ॡ", "०-९", "ॻ-ॿ", "অ-ঌ", "এ-ঐ", "ও-ন", "প-র", "শ-হ", "ড়-ঢ়", "য়-ৡ", "০-ৱ", "ਅ-ਊ", "ਏ-ਐ", "ਓ-ਨ", "ਪ-ਰ", "ਲ-ਲ਼", "ਵ-ਸ਼", "ਸ-ਹ", "ਖ਼-ੜ", "੦-੯", "ੲ-ੴ", "અ-ઍ", "એ-ઑ", "ઓ-ન", "પ-ર", "લ-ળ", "વ-હ", "ૠ-ૡ", "૦-૯", "ଅ-ଌ", "ଏ-ଐ", "ଓ-ନ", "ପ-ର", "ଲ-ଳ", "ଵ-ହ", "ଡ଼-ଢ଼", "ୟ-ୡ", "୦-୯", "அ-ஊ", "எ-ஐ", "ஒ-க", "ங-ச", "ஞ-ட", "ண-த", "ந-ப", "ம-ஹ", "௦-௯", "అ-ఌ", "ఎ-ఐ", "ఒ-న", "ప-ళ", "వ-హ", "ౠ-ౡ", "౦-౯", "ಅ-ಌ", "ಎ-ಐ", "ಒ-ನ", "ಪ-ಳ", "ವ-ಹ", "ೠ-ೡ", "೦-೯", "ೱ-ೲ", "അ-ഌ", "എ-ഐ", "ഒ-ന", "പ-ഹ", "ൠ-ൡ", "൦-൯", "අ-ඖ", "ක-න", "ඳ-ර", "ව-ෆ", "ก-ะ", "า-ำ", "เ-ๆ", "๐-๙", "ກ-ຂ", "ງ-ຈ", "ດ-ທ", "ນ-ຟ", "ມ-ຣ", "ສ-ຫ", "ອ-ະ", "າ-ຳ", "ເ-ໄ", "໐-໙", "ໜ-ໝ", "༠-༩", "ཀ-ཇ", "ཉ-ཪ", "ྈ-ྋ", "က-အ", "ဣ-ဧ", "ဩ-ဪ", "၀-၉", "ၐ-ၕ", "Ⴀ-Ⴥ", "ა-ჺ", "ᄀ-ᅙ", "ᅟ-ᆢ", "ᆨ-ᇹ", "ሀ-ቈ", "ቊ-ቍ", "ቐ-ቖ", "ቚ-ቝ", "በ-ኈ", "ኊ-ኍ", "ነ-ኰ", "ኲ-ኵ", "ኸ-ኾ", "ዂ-ዅ", "ወ-ዖ", "ዘ-ጐ", "ጒ-ጕ", "ጘ-ፚ", "ᎀ-ᎏ", "Ꭰ-Ᏼ", "ᐁ-ᙬ", "ᙯ-ᙶ", "ᚁ-ᚚ", "ᚠ-ᛪ", "ᜀ-ᜌ", "ᜎ-ᜑ", "ᜠ-ᜱ", "ᝀ-ᝑ", "ᝠ-ᝬ", "ᝮ-ᝰ", "ក-ឳ", "០-៩", "᠐-᠙", "ᠠ-ᡷ", "ᢀ-ᢨ", "ᤀ-ᤜ", "᥆-ᥭ", "ᥰ-ᥴ", "ᦀ-ᦩ", "ᦰ-ᧉ", "᧐-᧙", "ᨀ-ᨖ", "ᬅ-ᬳ", "ᭅ-ᭋ", "᭐-᭙", "ᴀ-ᶿ", "Ḁ-ẛ", "Ạ-ỹ", "ἀ-ἕ", "Ἐ-Ἕ", "ἠ-ὅ", "Ὀ-Ὅ", "ὐ-ὗ", "Ὗ-ώ", "ᾀ-ᾴ", "ᾶ-ᾼ", "ῂ-ῄ", "ῆ-ῌ", "ῐ-ΐ", "ῖ-Ί", "ῠ-Ῥ", "ῲ-ῴ", "ῶ-ῼ", "ₐ-ₔ", "ℊ-ℓ", "ℙ-ℝ", "K-ℭ", "ℯ-ℹ", "ℼ-ℿ", "ⅅ-ⅉ", "Ↄ-ↄ", "Ⰰ-Ⱞ", "ⰰ-ⱞ", "Ⱡ-ⱬ", "ⱴ-ⱷ", "Ⲁ-ⳤ", "ⴀ-ⴥ", "ⴰ-ⵥ", "ⶀ-ⶖ", "ⶠ-ⶦ", "ⶨ-ⶮ", "ⶰ-ⶶ", "ⶸ-ⶾ", "ⷀ-ⷆ", "ⷈ-ⷎ", "ⷐ-ⷖ", "ⷘ-ⷞ", "々-〆", "〱-〵", "〻-〼", "ぁ-ゖ", "ゝ-ゟ", "ァ-ヺ", "ー-ヿ", "ㄅ-ㄬ", "ㄱ-ㆎ", "ㆠ-ㆷ", "ㇰ-ㇿ", "㐀-䶵", "一-龻", "ꀀ-ꒌ", "ꜗ-ꜚ", "ꠀ-ꠁ", "ꠃ-ꠅ", "ꠇ-ꠊ", "ꠌ-ꠢ", "ꡀ-ꡳ", "가-힣", "豈-鶴", "侮-頻", "並-龎", "ff-st", "ﬓ-ﬗ", "ײַ-ﬨ", "שׁ-זּ", "טּ-לּ", "נּ-סּ", "ףּ-פּ", "צּ-ﮱ", "ﯓ-ﴽ", "ﵐ-ﶏ", "ﶒ-ﷇ", "ﷰ-ﷻ", "ﹰ-ﹴ", "ﹶ-ﻼ", "0-9", "A-Z", "a-z", "ヲ-ᄒ", "ᅡ-ᅦ", "ᅧ-ᅬ", "ᅭ-ᅲ", "ᅳ-ᅵ" }; public static string[] SurrogatePairs = new string[93] { "\ud800\udc00-\ud800\udc0b", "\ud800\udc0d-\ud800\udc26", "\ud800\udc28-\ud800\udc3a", "\ud800\udc3c-\ud800\udc3d", "\ud800\udc3f-\ud800\udc4d", "\ud800\udc50-\ud800\udc5d", "\ud800\udc80-\ud800\udcfa", "\ud800\udf00-\ud800\udf1e", "\ud800\udf30-\ud800\udf40", "\ud800\udf42-\ud800\udf49", "\ud800\udf80-\ud800\udf9d", "\ud800\udfa0-\ud800\udfc3", "\ud800\udfc8-\ud800\udfcf", "\ud801\udc00-\ud801\udc9d", "\ud801\udca0-\ud801\udca9", "\ud802\udc00-\ud802\udc05", "\ud802\udc0a-\ud802\udc35", "\ud802\udc37-\ud802\udc38", "\ud802\udd00-\ud802\udd15", "\ud802\ude10-\ud802\ude13", "\ud802\ude15-\ud802\ude17", "\ud802\ude19-\ud802\ude33", "\ud808\udc00-\ud808\udf6e", "\ud835\udc00-\ud835\udc54", "\ud835\udc56-\ud835\udc9c", "\ud835\udc9e-\ud835\udc9f", "\ud835\udca5-\ud835\udca6", "\ud835\udca9-\ud835\udcac", "\ud835\udcae-\ud835\udcb9", "\ud835\udcbd-\ud835\udcc3", "\ud835\udcc5-\ud835\udd05", "\ud835\udd07-\ud835\udd0a", "\ud835\udd0d-\ud835\udd14", "\ud835\udd16-\ud835\udd1c", "\ud835\udd1e-\ud835\udd39", "\ud835\udd3b-\ud835\udd3e", "\ud835\udd40-\ud835\udd44", "\ud835\udd4a-\ud835\udd50", "\ud835\udd52-\ud835\udea5", "\ud835\udea8-\ud835\udec0", "\ud835\udec2-\ud835\udeda", "\ud835\udedc-\ud835\udefa", "\ud835\udefc-\ud835\udf14", "\ud835\udf16-\ud835\udf34", "\ud835\udf36-\ud835\udf4e", "\ud835\udf50-\ud835\udf6e", "\ud835\udf70-\ud835\udf88", "\ud835\udf8a-\ud835\udfa8", "\ud835\udfaa-\ud835\udfc2", "\ud835\udfc4-\ud835\udfcb", "\ud835\udfce-\ud835\udfff", "\ud840\udc00-\ud840\udfff", "\ud841\udc00-\ud841\udfff", "\ud842\udc00-\ud842\udfff", "\ud843\udc00-\ud843\udfff", "\ud844\udc00-\ud844\udfff", "\ud845\udc00-\ud845\udfff", "\ud846\udc00-\ud846\udfff", "\ud847\udc00-\ud847\udfff", "\ud848\udc00-\ud848\udfff", "\ud849\udc00-\ud849\udfff", "\ud84a\udc00-\ud84a\udfff", "\ud84b\udc00-\ud84b\udfff", "\ud84c\udc00-\ud84c\udfff", "\ud84d\udc00-\ud84d\udfff", "\ud84e\udc00-\ud84e\udfff", "\ud84f\udc00-\ud84f\udfff", "\ud850\udc00-\ud850\udfff", "\ud851\udc00-\ud851\udfff", "\ud852\udc00-\ud852\udfff", "\ud853\udc00-\ud853\udfff", "\ud854\udc00-\ud854\udfff", "\ud855\udc00-\ud855\udfff", "\ud856\udc00-\ud856\udfff", "\ud857\udc00-\ud857\udfff", "\ud858\udc00-\ud858\udfff", "\ud859\udc00-\ud859\udfff", "\ud85a\udc00-\ud85a\udfff", "\ud85b\udc00-\ud85b\udfff", "\ud85c\udc00-\ud85c\udfff", "\ud85d\udc00-\ud85d\udfff", "\ud85e\udc00-\ud85e\udfff", "\ud85f\udc00-\ud85f\udfff", "\ud860\udc00-\ud860\udfff", "\ud861\udc00-\ud861\udfff", "\ud862\udc00-\ud862\udfff", "\ud863\udc00-\ud863\udfff", "\ud864\udc00-\ud864\udfff", "\ud865\udc00-\ud865\udfff", "\ud866\udc00-\ud866\udfff", "\ud867\udc00-\ud867\udfff", "\ud868\udc00-\ud868\udfff", "\ud869\udc00-\ud869\uded6" }; } public static class Database { public static Lazy<ConcurrentDictionary<string, BObject>> Data = new Lazy<ConcurrentDictionary<string, BObject>>(Initialize, LazyThreadSafetyMode.ExecutionAndPublication); public const string ResourceNameFormat = "Bogus.data.{0}.locale.bson"; public static string[] GetAllLocales() { Assembly assembly = typeof(Database).GetAssembly(); string[] array = "Bogus.data.{0}.locale.bson".Split(new string[1] { "{0}" }, StringSplitOptions.None); string prefix = array[0]; string suffix = array[1]; return (from name in assembly.GetManifestResourceNames() where name.EndsWith(suffix) select name.Replace(prefix, "").Replace(suffix, "")).ToArray(); } public static bool LocaleResourceExists(string locale) { Assembly assembly = typeof(Database).GetAssembly(); string localeResourceName = GetLocaleResourceName(locale); return ResourceHelper.ResourceExists(assembly, localeResourceName); } private static string GetLocaleResourceName(string locale) { return $"Bogus.data.{locale}.locale.bson"; } private static ConcurrentDictionary<string, BObject> Initialize() { ConcurrentDictionary<string, BObject> concurrentDictionary = new ConcurrentDictionary<string, BObject>(); concurrentDictionary.TryAdd("en", DeserializeLocale("en")); return concurrentDictionary; } internal static BObject DeserializeLocale(string locale) { Assembly assembly = typeof(Database).GetAssembly(); string localeResourceName = GetLocaleResourceName(locale); return ResourceHelper.ReadBObjectResource(assembly, localeResourceName); } public static BObject GetLocale(string locale) { if (!Data.Value.TryGetValue(locale, out var value)) { value = DeserializeLocale(locale); Data.Value.TryAdd(locale, value); } return value; } public static void ResetLocale(string locale) { Data.Value[locale] = DeserializeLocale(locale); } public static bool HasKey(string category, string path, string locale, string fallbackLocale = "en") { BObject locale2 = GetLocale(locale); if (Select(category, path, locale2) != null) { return true; } if (fallbackLocale == null) { return false; } locale2 = GetLocale(fallbackLocale); if (Select(category, path, locale2) != null) { return true; } return false; } public static BValue Get(string category, string path, string locale = "en", string localeFallback = "en") { BObject locale2 = GetLocale(locale); BValue bValue = Select(category, path, locale2); if (bValue != null) { return bValue; } BObject locale3 = GetLocale(localeFallback); return Select(category, path, locale3); } private static BValue Select(string category, string path, BValue localeRoot) { BValue bValue = localeRoot[category]; if ((object)bValue == null) { return null; } int startIndex = 0; while (true) { int num = path.IndexOf('.', startIndex); string key; if (num < 0) { key = path.Substring(startIndex); return bValue[key]; } key = path.Substring(startIndex, num); bValue = bValue[key]; if ((object)bValue == null) { break; } startIndex = num + 1; } return null; } } [AttributeUsage(AttributeTargets.Class)] public class DataCategoryAttribute : Attribute { public string Name { get; set; } public DataCategoryAttribute(string name) { Name = name; } } public class DataSet : ILocaleAware, IHasRandomizer { protected SeedNotifier Notifier = new SeedNotifier(); private Randomizer randomizer; private static readonly Regex parseTokensRegex = new Regex("\\#{(.*?)\\}", RegexOptions.Compiled); protected string Category { get; set; } public string Locale { get; set; } public Randomizer Random { get { return this.randomizer ?? (Random = new Randomizer()); } set { randomizer = value; Notifier.Notify(value); } } public DataSet(string locale = "en") { if (!Database.LocaleResourceExists(locale)) { throw new BogusException($"The locale '{locale}' does not exist. To see all available locales visit {"https://github.com/bchavez/Bogus"}."); } Locale = locale; Category = ResolveCategory(GetType()); } SeedNotifier IHasRandomizer.GetNotifier() { return Notifier; } public static string ResolveCategory(Type type) { DataCategoryAttribute customAttributeX = type.GetCustomAttributeX<DataCategoryAttribute>(); if (customAttributeX == null) { return type.Name.ToLowerInvariant(); } return customAttributeX.Name; } protected internal virtual BValue Get(string path) { return Database.Get(Category, path, Locale); } protected internal virtual BValue Get(string category, string path) { return Database.Get(category, path, Locale); } protected internal virtual bool HasKey(string path, bool includeFallback = true) { if (includeFallback) { return Database.HasKey(Category, path, Locale); } return Database.HasKey(Category, path, Locale, null); } protected internal virtual BArray GetArray(string path) { return (BArray)Get(path); } protected internal virtual BArray GetArray(string category, string path) { return (BArray)Get(category, path); } protected internal virtual BObject GetObject(string path) { return (BObject)Get(path); } protected internal virtual string GetRandomArrayItem(string path, int? min = null, int? max = null) { return GetRandomArrayItem(Category, path, min, max); } protected internal virtual string GetRandomArrayItem(string category, string path, int? min = null, int? max = null) { BArray array = GetArray(category, path); if (!array.HasValues) { return string.Empty; } return Random.ArrayElement(array, min, max); } protected internal virtual BObject GetRandomBObject(string path) { BArray array = GetArray(path); if (!array.HasValues) { return null; } return Random.ArrayElement(array) as BObject; } protected internal virtual string GetFormattedValue(string path) { string randomArrayItem = GetRandomArrayItem(path); string format = ParseTokens(randomArrayItem); return Random.Replace(format); } private string ParseTokens(string value) { return parseTokensRegex.Replace(value, delegate(Match x) { string[] array = x.Groups[1].Value.ToLowerInvariant().Split('.'); BArray props = ((array.Length != 1) ? ((BArray)Database.Get(array[0], array[1], Locale)) : ((BArray)Database.Get(Category, array[0], Locale))); BValue bValue = Random.ArrayElement(props); return ParseTokens(bValue); }); } } public class Faker : ILocaleAware, IHasRandomizer, IHasContext { public static bool DefaultStrictMode = false; protected SeedNotifier Notifier = new SeedNotifier(); private Randomizer randomizer; private Person person; public static int GlobalUniqueIndex = -1; private int capturedGlobalIndex; public int IndexFaker = -1; public int IndexVariable; Dictionary<string, object> IHasContext.Context { get; } = new Dictionary<string, object>(); [RegisterMustasheMethods] public Randomizer Random { get { return this.randomizer ?? (Random = new Randomizer()); } set { randomizer = value; Notifier.Notify(value); } } public Person Person => person ?? (person = new Person(Random, Locale)); [RegisterMustasheMethods] public Hacker Hacker { get; set; } [RegisterMustasheMethods] public PhoneNumbers Phone { get; set; } [RegisterMustasheMethods] public Name Name { get; set; } [RegisterMustasheMethods] public Lorem Lorem { get; set; } [RegisterMustasheMethods] public Images Image { get; set; } [RegisterMustasheMethods] public Finance Finance { get; set; } [RegisterMustasheMethods] public Address Address { get; set; } [RegisterMustasheMethods] public Date Date { get; set; } [RegisterMustasheMethods] public Company Company { get; set; } [RegisterMustasheMethods] public Internet Internet { get; set; } [RegisterMustasheMethods] public Commerce Commerce { get; set; } [RegisterMustasheMethods] public Bogus.DataSets.System System { get; set; } [RegisterMustasheMethods] public Bogus.DataSets.Database Database { get; set; } [RegisterMustasheMethods] public Rant Rant { get; set; } [RegisterMustasheMethods] public Vehicle Vehicle { get; set; } [RegisterMustasheMethods] public Music Music { get; set; } public string Locale { get; set; } internal bool HasContext => IndexFaker != -1; public int UniqueIndex => capturedGlobalIndex; public int IndexGlobal => capturedGlobalIndex; public Hashids Hashids { get; set; } public Faker(string locale = "en") { Locale = locale; Address = Notifier.Flow(new Address(locale)); Company = Notifier.Flow(new Company(locale)); Date = Notifier.Flow(new Date(locale)); Finance = Notifier.Flow(new Finance { Locale = locale }); Hacker = Notifier.Flow(new Hacker(locale)); Image = Notifier.Flow(new Images(locale)); Internet = Notifier.Flow(new Internet(locale)); Lorem = Notifier.Flow(new Lorem(locale)); Name = Notifier.Flow(new Name(locale)); Phone = Notifier.Flow(new PhoneNumbers(locale)); System = Notifier.Flow(new Bogus.DataSets.System(locale)); Commerce = Notifier.Flow(new Commerce(locale)); Database = Notifier.Flow(new Bogus.DataSets.Database()); Rant = Notifier.Flow(new Rant()); Vehicle = Notifier.Flow(new Vehicle()); Music = Notifier.Flow(new Music()); Hashids = new Hashids(); } SeedNotifier IHasRandomizer.GetNotifier() { return Notifier; } public string Parse(string str) { return Tokenizer.Parse(str, Address, Company, Date, Finance, Hacker, Image, Internet, Lorem, Name, Phone, System, Commerce, Database, Random); } public T PickRandom<T>(IEnumerable<T> items) { return Random.ArrayElement(items.ToArray()); } public T PickRandom<T>(IList<T> items) { return Random.ListItem(items); } public T PickRandom<T>(ICollection<T> items) { return Random.CollectionItem(items); } public T PickRandom<T>(List<T> items) { return Random.ListItem(items); } public T PickRandom<T>(params T[] items) { return Random.ArrayElement(items); } public T PickRandomParam<T>(params T[] items) { return Random.ArrayElement(items); } public IEnumerable<T> PickRandom<T>(IEnumerable<T> items, int amountToPick) { if (amountToPick < 0) { throw new ArgumentOutOfRangeException("amountToPick needs to be a positive integer."); } int num = items.Count(); if (amountToPick > num) { throw new ArgumentOutOfRangeException("amountToPick is greater than the number of items."); } return Random.Shuffle(items).Take(amountToPick); } public IList<T> Make<T>(int count, Func<T> action) { return (from n in Enumerable.Range(1, count) select action()).ToList(); } public IList<T> Make<T>(int count, Func<int, T> action) { return Enumerable.Range(1, count).Select(action).ToList(); } public IEnumerable<T> MakeLazy<T>(int count, Func<T> action) { return from n in Enumerable.Range(1, count) select action(); } public IEnumerable<T> MakeLazy<T>(int count, Func<int, T> action) { return Enumerable.Range(1, count).Select(action); } public T PickRandom<T>() where T : struct, Enum { return Random.Enum(Array.Empty<T>()); } public T PickRandomWithout<T>(params T[] exclude) where T : struct, Enum { return Random.Enum(exclude); } internal void NewContext() { person = null; capturedGlobalIndex = Interlocked.Increment(ref GlobalUniqueIndex); Interlocked.Increment(ref IndexFaker); } } public interface IFakerTInternal { Faker FakerHub { get; } IBinder Binder { get; } int? LocalSeed { get; } Type TypeOfT { get; } } public class Faker<T> : IFakerTInternal, ILocaleAware, IRuleSet<T> where T : class { protected const string Default = "default"; private static readonly string[] DefaultRuleSet = new string[1] { "default" }; protected internal Faker FakerHub; protected internal IBinder binder; protected internal readonly MultiDictionary<string, string, PopulateAction<T>> Actions = new MultiDictionary<string, string, PopulateAction<T>>(StringComparer.OrdinalIgnoreCase); protected internal readonly Dictionary<string, FinalizeAction<T>> FinalizeActions = new Dictionary<string, FinalizeAction<T>>(StringComparer.OrdinalIgnoreCase); protected internal Dictionary<string, Func<Faker, T>> CreateActions = new Dictionary<string, Func<Faker, T>>(StringComparer.OrdinalIgnoreCase); protected internal readonly Dictionary<string, MemberInfo> TypeProperties; protected internal readonly Dictionary<string, Action<T, object>> SetterCache = new Dictionary<string, Action<T, object>>(StringComparer.OrdinalIgnoreCase); protected internal Dictionary<string, bool> StrictModes = new Dictionary<string, bool>(); protected internal bool? IsValid; protected internal string currentRuleSet = "default"; protected internal int? localSeed; private readonly object _setterCreateLock = new object(); Faker IFakerTInternal.FakerHub => FakerHub; IBinder IFakerTInternal.Binder => binder; int? IFakerTInternal.LocalSeed => localSeed; Type IFakerTInternal.TypeOfT => typeof(T); public string Locale { get; set; } public Faker<T> Clone() { Faker<T> faker = new Faker<T>(Locale, binder); foreach (KeyValuePair<string, bool> strictMode in StrictModes) { faker.StrictModes.Add(strictMode.Key, strictMode.Value); } foreach (KeyValuePair<string, Func<Faker, T>> createAction in CreateActions) { faker.CreateActions[createAction.Key] = createAction.Value; } foreach (KeyValuePair<string, FinalizeAction<T>> finalizeAction in FinalizeActions) { faker.FinalizeActions.Add(finalizeAction.Key, finalizeAction.Value); } foreach (KeyValuePair<string, Dictionary<string, PopulateAction<T>>> action in Actions) { foreach (KeyValuePair<string, PopulateAction<T>> item in action.Value) { faker.Actions.Add(action.Key, item.Key, item.Value); } } if (localSeed.HasValue) { faker.UseSeed(localSeed.Value); } return faker; } public Faker() : this("en", (IBinder)null) { } public Faker(string locale) : this(locale, (IBinder)null) { } public Faker(string locale = "en", IBinder binder = null) { this.binder = binder ?? new Binder(); Locale = locale; FakerHub = new Faker(locale); TypeProperties = this.binder.GetMembers(typeof(T)); CreateActions["default"] = (Faker faker) => Activator.CreateInstance<T>(); } public virtual Faker<T> UseSeed(int seed) { localSeed = seed; FakerHub.Random = new Randomizer(seed); return this; } public virtual Faker<T> CustomInstantiator(Func<Faker, T> factoryMethod) { CreateActions[currentRuleSet] = factoryMethod; return this; } public virtual Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, Func<Faker, T, TProperty> setter) { string propertyOrField = PropertyName.For(property); return AddRule(propertyOrField, (Faker f, T t) => setter(f, t)); } public virtual Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, TProperty value) { string propertyOrField = PropertyName.For(property); return AddRule(propertyOrField, (Faker f, T t) => value); } public virtual Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, Func<TProperty> valueFunction) { string propertyOrField = PropertyName.For(property); return AddRule(propertyOrField, (Faker f, T t) => valueFunction()); } public virtual Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, Func<Faker, TProperty> setter) { string propertyOrField = PropertyName.For(property); return AddRule(propertyOrField, (Faker f, T t) => setter(f)); } public virtual Faker<T> RuleFor<TProperty>(string propertyOrFieldName, Func<Faker, TProperty> setter) { EnsureMemberExists(propertyOrFieldName, $"The property or field {propertyOrFieldName} was not found on {typeof(T)}. Can't create a rule for {typeof(T)}.{propertyOrFieldName} when {propertyOrFieldName} cannot be found. Try creating a custom IBinder for Faker<T> with the appropriate System.Reflection.BindingFlags that allows deeper reflection into {typeof(T)}."); return AddRule(propertyOrFieldName, (Faker f, T t) => setter(f)); } public virtual Faker<T> RuleFor<TProperty>(string propertyOrFieldName, Func<Faker, T, TProperty> setter) { EnsureMemberExists(propertyOrFieldName, $"The property or field {propertyOrFieldName} was not found on {typeof(T)}. Can't create a rule for {typeof(T)}.{propertyOrFieldName} when {propertyOrFieldName} cannot be found. Try creating a custom IBinder for Faker<T> with the appropriate System.Reflection.BindingFlags that allows deeper reflection into {typeof(T)}."); return AddRule(propertyOrFieldName, (Faker f, T t) => setter(f, t)); } protected virtual Faker<T> AddRule(string propertyOrField, Func<Faker, T, object> invoker) { PopulateAction<T> value = new PopulateAction<T> { Action = invoker, RuleSet = currentRuleSet, PropertyName = propertyOrField }; Actions.Add(currentRuleSet, propertyOrField, value); return this; } public virtual Faker<T> Rules(Action<Faker, T> setActions) { Func<Faker, T, object> action = delegate(Faker f, T t) { setActions(f, t); return null; }; string text = Guid.NewGuid().ToString(); PopulateAction<T> value = new PopulateAction<T> { Action = action, RuleSet = currentRuleSet, PropertyName = text, ProhibitInStrictMode = true }; Actions.Add(currentRuleSet, text, value); return this; } public virtual Faker<T> RuleForType<TType>(Type type, Func<Faker, TType> setterForType) { if (typeof(TType) != type) { throw new ArgumentException("TType must be the same type as parameter named 'type'"); } foreach (KeyValuePair<string, MemberInfo> typeProperty in TypeProperties) { Type fieldOrPropertyType = GetFieldOrPropertyType(typeProperty.Value); string key = typeProperty.Key; if (fieldOrPropertyType == type) { RuleFor(key, setterForType); } } return this; } protected virtual Type GetFieldOrPropertyType(MemberInfo mi) { if (mi is PropertyInfo propertyInfo) { return propertyInfo.PropertyType; } if (mi is FieldInfo fieldInfo) { return fieldInfo.FieldType; } return null; } public virtual Faker<T> RuleSet(string ruleSetName, Action<IRuleSet<T>> action) { if (currentRuleSet != "default") { throw new ArgumentException("Cannot create a rule set within a rule set."); } currentRuleSet = ruleSetName; action(this); currentRuleSet = "default"; return this; } protected virtual void EnsureMemberExists(string propNameOrField, string exceptionMessage) { if (!TypeProperties.TryGetValue(propNameOrField, out var _)) { throw new ArgumentException(exceptionMessage); } } public virtual Faker<T> Ignore(string propertyOrFieldName) { EnsureMemberExists(propertyOrFieldName, $"The property or field {propertyOrFieldName} was not found on {typeof(T)}. Can't ignore member {typeof(T)}.{propertyOrFieldName} when {propertyOrFieldName} cannot be found. Try creating a custom IBinder for Faker<T> with the appropriate System.Reflection.BindingFlags that allows deeper reflection into {typeof(T)}."); PopulateAction<T> value = new PopulateAction<T> { Action = null, RuleSet = currentRuleSet, PropertyName = propertyOrFieldName }; Actions.Add(currentRuleSet, propertyOrFieldName, value); return this; } public virtual Faker<T> Ignore<TPropertyOrField>(Expression<Func<T, TPropertyOrField>> propertyOrField) { string propertyOrFieldName = PropertyName.For(propertyOrField); return Ignore(propertyOrFieldName); } public virtual Faker<T> StrictMode(bool ensureRulesForAllProperties) { StrictModes[currentRuleSet] = ensureRulesForAllProperties; return this; } public virtual Faker<T> FinishWith(Action<Faker, T> action) { FinalizeAction<T> value = new FinalizeAction<T> { Action = action, RuleSet = currentRuleSet }; FinalizeActions[currentRuleSet] = value; return this; } protected virtual string[] ParseDirtyRulesSets(string dirtyRules) { dirtyRules = dirtyRules?.Trim(',').Trim(); if (string.IsNullOrWhiteSpace(dirtyRules)) { return DefaultRuleSet; } return (from s in dirtyRules.Split(',') where !string.IsNullOrWhiteSpace(s) select s.Trim()).ToArray(); } public virtual T Generate(string ruleSets = null) { Func<Faker, T> value = null; string[] array = ParseDirtyRulesSets(ruleSets); if (string.IsNullOrWhiteSpace(ruleSets)) { value = CreateActions["default"]; } else { string key = array[0]; value = (CreateActions.TryGetValue(key, out value) ? value : CreateActions["default"]); } FakerHub.NewContext(); T val = value(FakerHub); PopulateInternal(val, array); return val; } public virtual List<T> Generate(int count, string ruleSets = null) { return (from i in Enumerable.Range(1, count) select Generate(ruleSets)).ToList(); } public virtual IEnumerable<T> GenerateLazy(int count, string ruleSets = null) { return from i in Enumerable.Range(1, count) select Generate(ruleSets); } public virtual IEnumerable<T> GenerateForever(string ruleSets = null) { while (true) { yield return Generate(ruleSets); } } public virtual void Populate(T instance, string ruleSets = null) { string[] ruleSets2 = ParseDirtyRulesSets(ruleSets); PopulateInternal(instance, ruleSets2); } protected virtual void PopulateInternal(T instance, string[] ruleSets) { ValidationResult validationResult = null; if (!IsValid.HasValue) { validationResult = ValidateInternal(ruleSets); IsValid = validationResult.IsValid; } if (!IsValid.GetValueOrDefault()) { throw MakeValidationException(validationResult ?? ValidateInternal(ruleSets)); } lock (Randomizer.Locker.Value) { if (!FakerHub.HasContext) { FakerHub.NewContext(); } string[] array = ruleSets; foreach (string key in array) { if (!Actions.TryGetValue(key, out var value)) { continue; } foreach (PopulateAction<T> value3 in value.Values) { PopulateProperty(instance, value3); } } array = ruleSets; foreach (string key2 in array) { if (FinalizeActions.TryGetValue(key2, out var value2)) { value2.Action(FakerHub, instance); } } } } private void PopulateProperty(T instance, PopulateAction<T> action) { Func<Faker, T, object> action2 = action.Action; if (action2 == null) { return; } object arg = action2(FakerHub, instance); if (SetterCache.TryGetValue(action.PropertyName, out var value)) { value(instance, arg); } else { if (!TypeProperties.TryGetValue(action.PropertyName, out var value2) || value2 == null) { return; } lock (_setterCreateLock) { if (SetterCache.TryGetValue(action.PropertyName, out value)) { value(instance, arg); return; } if (value2 is PropertyInfo property) { value = property.CreateSetter<T>(); } else { FieldInfo field = value2 as FieldInfo; if ((object)field != null) { value = delegate(T i, object v) { field?.SetValue(i, v); }; } } if (value != null) { SetterCache.Add(action.PropertyName, value); value(instance, arg); } } } } public virtual bool Validate(string ruleSets = null) { string[] ruleSets2 = ((ruleSets == null) ? Actions.Keys.ToArray() : ParseDirtyRulesSets(ruleSets)); return ValidateInternal(ruleSets2).IsValid; } public virtual void AssertConfigurationIsValid(string ruleSets = null) { string[] ruleSets2 = ((ruleSets != null) ? ParseDirtyRulesSets(ruleSets) : Actions.Keys.ToArray()); ValidationResult validationResult = ValidateInternal(ruleSets2); if (!validationResult.IsValid) { throw MakeValidationException(validationResult); } } protected virtual ValidationException MakeValidationException(ValidationResult result) { StringBuilder builder = new StringBuilder(); result.ExtraMessages.ForEach(delegate(string m) { builder.AppendLine(m); builder.AppendLine(); }); StringBuilder stringBuilder = builder.AppendLine("Validation was called to ensure all properties / fields have rules."); StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(40, 1, stringBuilder); handler.AppendLiteral("There are missing rules for Faker<T> '"); handler.AppendFormatted(typeof(T).Name); handler.AppendLiteral("'."); stringBuilder.AppendLine(ref handler).AppendLine("=========== Missing Rules ==========="); foreach (string missingRule in result.MissingRules) { builder.AppendLine(missingRule); } return new ValidationException(builder.ToString().Trim()); } private ValidationResult ValidateInternal(string[] ruleSets) { ValidationResult validationResult = new ValidationResult { IsValid = true }; Dictionary<string, MemberInfo>.KeyCollection keys = TypeProperties.Keys; foreach (string key in ruleSets) { if (!StrictModes.TryGetValue(key, out var value)) { value = Faker.DefaultStrictMode; } if (!value) { continue; } Actions.TryGetValue(key, out var value2); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (value2 != null) { hashSet.UnionWith(value2.Keys); } hashSet.SymmetricExceptWith(keys); if (hashSet.Count <= 0) { continue; } foreach (string item in hashSet) { if (value2 != null && value2.TryGetValue(item, out var value3)) { if (value3.ProhibitInStrictMode) { validationResult.ExtraMessages.Add($"When StrictMode is set to True the Faker<{typeof(T).Name}>.Rules(...) method cannot verify that all properties have rules. You need to use Faker<{typeof(T).Name}>.RuleFor( x => x.Prop, ...) for each property to ensure each property has an associated rule when StrictMode is true; otherwise, set StrictMode to False in order to use Faker<{typeof(T).Name}>.Rules() method."); validationResult.IsValid = false; } } else { validationResult.MissingRules.Add(item); validationResult.IsValid = false; } } } return validationResult; } public static implicit operator T(Faker<T> faker) { return faker.Generate(); } [Obsolete("This exists here only as a Visual Studio IntelliSense work around. See: https://github.com/bchavez/Bogus/issues/54", true)] public void RuleFor<TProperty>(Expression<Func<T, TProperty>> property) { throw new NotImplementedException(); } } public static class ExtensionsForFakerT { public static List<T> GenerateBetween<T>(this Faker<T> faker, int min, int max, string ruleSets = null) where T : class { int count = ((IFakerTInternal)faker).FakerHub.Random.Number(min, max); return faker.Generate(count, ruleSets); } public static T OrNull<T>(this T value, in Faker f, float nullWeight = 0.5f) where T : class { if (nullWeight > 1f || nullWeight < 0f) { throw new ArgumentOutOfRangeException("nullWeight", $".{"OrNull"}() {"nullWeight"} of '{nullWeight}' must be between 1.0f and 0.0f."); } if (!(f.Random.Float() > nullWeight)) { return null; } return value; } public static T? OrNull<T>(this T value, Faker f, float nullWeight = 0.5f) where T : struct { if (nullWeight > 1f || nullWeight < 0f) { throw new ArgumentOutOfRangeException("nullWeight", $".{"OrNull"}() {"nullWeight"} of '{nullWeight}' must be between 1.0f and 0.0f."); } if (!(f.Random.Float() > nullWeight)) { return null; } return value; } public static T OrDefault<T>(this T value, Faker f, float defaultWeight = 0.5f, T defaultValue = default(T)) { if (defaultWeight > 1f || defaultWeight < 0f) { throw new ArgumentOutOfRangeException("defaultWeight", $".{"OrDefault"}() {"defaultWeight"} of '{defaultWeight}' must be between 1.0f and 0.0f. "); } if (!(f.Random.Float() > defaultWeight)) { return defaultValue; } return value; } } public class Hashids : IHashids { public const string DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; public const string DEFAULT_SEPS = "cfhistuCFHISTU"; private const int MIN_ALPHABET_LENGTH = 16; private const double SEP_DIV = 3.5; private const double GUARD_DIV = 12.0; private string alphabet; private string salt; private string seps; private string guards; private int minHashLength; private Regex guardsRegex; private Regex sepsRegex; private static Regex hexValidator = new Regex("^[0-9a-fA-F]+$", RegexOptions.Compiled); private static Regex hexSplitter = new Regex("[\\w\\W]{1,12}", RegexOptions.Compiled); public Hashids() : this(string.Empty) { } public Hashids(string salt = "", int minHashLength = 0, string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", string seps = "cfhistuCFHISTU") { if (string.IsNullOrWhiteSpace(alphabet)) { throw new ArgumentNullException("alphabet"); } this.salt = salt; this.alphabet = string.Join(string.Empty, alphabet.Distinct()); this.seps = seps; this.minHashLength = minHashLength; if (this.alphabet.Length < 16) { throw new ArgumentException("alphabet must contain at least 4 unique characters.", "alphabet"); } SetupSeps(); SetupGuards(); } public virtual string Encode(params int[] numbers) { return GenerateHashFrom(((IEnumerable<int>)numbers).Select((Func<int, long>)((int n) => n)).ToArray()); } public virtual string Encode(IEnumerable<int> numbers) { return Encode(numbers.ToArray()); } public virtual int[] Decode(string hash) { return (from n in GetNumbersFrom(hash) select (int)n).ToArray(); } public virtual string EncodeHex(string hex) { if (!hexValidator.IsMatch(hex)) { return string.Empty; } List<long> list = new List<long>(); foreach (Match item2 in hexSplitter.Matches(hex)) { long item = Convert.ToInt64("1" + item2.Value, 16); list.Add(item); } return EncodeLong(list.ToArray()); } public virtual string DecodeHex(string hash) { StringBuilder stringBuilder = new StringBuilder(); long[] array = DecodeLong(hash); foreach (long num in array) { stringBuilder.Append($"{num:X}".Substring(1)); } return stringBuilder.ToString(); } public long[] DecodeLong(string hash) { return GetNumbersFrom(hash); } public string EncodeLong(params long[] numbers) { return GenerateHashFrom(numbers); } public string EncodeLong(IEnumerable<long> numbers) { return EncodeLong(numbers.ToArray()); } [Obsolete("Use 'Encode' instead. The method was renamed to better explain what it actually does.")] public virtual string Encrypt(params int[] numbers) { return Encode(numbers); } [Obsolete("Use 'EncodeHex' instead. The method was renamed to better explain what it actually does.")] public virtual string EncryptHex(string hex) { return EncodeHex(hex); } [Obsolete("Use 'Decode' instead. Method was renamed to better explain what it actually does.")] public virtual int[] Decrypt(string hash) { return Decode(hash); } [Obsolete("Use 'DecodeHex' instead. The method was renamed to better explain what it actually does.")] public virtual string DecryptHex(string hash) { return DecodeHex(hash); } private void SetupSeps() { seps = new string(seps.Intersect(alphabet.ToArray()).ToArray()); alphabet = new string(alphabet.Except(seps.ToArray()).ToArray()); seps = ConsistentShuffle(seps, salt); if (seps.Length == 0 || (double)(alphabet.Length / seps.Length) > 3.5) { int num = (int)Math.Ceiling((double)alphabet.Length / 3.5); if (num == 1) { num = 2; } if (num > seps.Length) { int num2 = num - seps.Length; seps += alphabet.Substring(0, num2); alphabet = alphabet.Substring(num2); } else { seps = seps.Substring(0, num); } } sepsRegex = new Regex("[" + seps + "]", RegexOptions.Compiled); alphabet = ConsistentShuffle(alphabet, salt); } private void SetupGuards() { int num = (int)Math.Ceiling((double)alphabet.Length / 12.0); if (alphabet.Length < 3) { guards = seps.Substring(0, num); seps = seps.Substring(num); } else { guards = alphabet.Substring(0, num); alphabet = alphabet.Substring(num); } guardsRegex = new Regex("[" + guards + "]", RegexOptions.Compiled); } private string GenerateHashFrom(long[] numbers) { if (numbers == null || numbers.Length == 0) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(); string text = alphabet; long num = 0L; for (int i = 0; i < numbers.Length; i++) { num += (int)(numbers[i] % (i + 100)); } char c = text[(int)(num % text.Length)]; stringBuilder.Append(c.ToString()); for (int j = 0; j < numbers.Length; j++) { long num2 = numbers[j]; string text2 = c + salt + text; text = ConsistentShuffle(text, text2.Substring(0, text.Length)); string text3 = Hash(num2, text); stringBuilder.Append(text3); if (j + 1 < numbers.Length) { num2 %= text3[0] + j; int index = (int)num2 % seps.Length; stringBuilder.Append(seps[index]); } } if (stringBuilder.Length < minHashLength) { int index2 = (int)(num + (int)stringBuilder[0]) % guards.Length; char value = guards[index2]; stringBuilder.Insert(0, value); if (stringBuilder.Length < minHashLength) { index2 = (int)(num + (int)stringBuilder[2]) % guards.Length; value = guards[index2]; stringBuilder.Append(value); } } int num3 = text.Length / 2; while (stringBuilder.Length < minHashLength) { text = ConsistentShuffle(text, text); stringBuilder.Insert(0, text.Substring(num3)); stringBuilder.Append(text.Substring(0, num3)); int num4 = stringBuilder.Length - minHashLength; if (num4 > 0) { stringBuilder.Remove(0, num4 / 2); stringBuilder.Remove(minHashLength, stringBuilder.Length - minHashLength); } } return stringBuilder.ToString(); } private string Hash(long input, string alphabet) { StringBuilder stringBuilder = new StringBuilder(); do { stringBuilder.Insert(0, alphabet[(int)(input % alphabet.Length)]); input /= alphabet.Length; } while (input > 0); return stringBuilder.ToString(); } private long Unhash(string input, string alphabet) { long num = 0L; for (int i = 0; i < input.Length; i++) { int num2 = alphabet.IndexOf(input[i]); num += (long)((double)num2 * Math.Pow(alphabet.Length, input.Length - i - 1)); } return num; } private long[] GetNumbersFrom(string hash) { if (string.IsNullOrWhiteSpace(hash)) { return new long[0]; } string text = new string(alphabet.ToCharArray()); List<long> list = new List<long>(); int num = 0; string text2 = guardsRegex.Replace(hash, " "); string[] array = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 3 || array.Length == 2) { num = 1; } text2 = array[num]; if (text2[0] != 0) { char c = text2[0]; text2 = text2.Substring(1); text2 = sepsRegex.Replace(text2, " "); array = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (string input in array) { string text3 = c + salt + text; text = ConsistentShuffle(text, text3.Substring(0, text.Length)); list.Add(Unhash(input, text)); } if (EncodeLong(list.ToArray()) != hash) { list.Clear(); } } return list.ToArray(); } private string ConsistentShuffle(string alphabet, string salt) { if (string.IsNullOrWhiteSpace(salt)) { return alphabet; } int num3; int num2; int num; int num4 = (num3 = (num2 = (num = 0))); int num5 = alphabet.Length - 1; while (num5 > 0) { num4 %= salt.Length; num3 += (num2 = salt[num4]); num = (num2 + num4 + num3) % num5; char c = alphabet[num]; alphabet = alphabet.Substring(0, num) + alphabet[num5] + alphabet.Substring(num + 1); alphabet = alphabet.Substring(0, num5) + c + alphabet.Substring(num5 + 1); num5--; num4++; } return alphabet; } } public interface IHashids { int[] Decode(string hash); long[] DecodeLong(string hash); string DecodeHex(string hash); string Encode(params int[] numbers); string Encode(IEnumerable<int> numbers); string EncodeLong(params long[] numbers); string EncodeLong(IEnumerable<long> numbers); string EncodeHex(string hex); } public interface ILocaleAware { string Locale { get; set; } } public interface IHasContext { Dictionary<string, object> Context { get; } } public interface IRuleSet<T> where T : class { Faker<T> CustomInstantiator(Func<Faker, T> factoryMethod); Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, Func<Faker, T, TProperty> setter); Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, Func<Faker, TProperty> setter); Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, Func<TProperty> valueFunction); Faker<T> Ignore<TPropertyOrField>(Expression<Func<T, TPropertyOrField>> propertyOrField); Faker<T> StrictMode(bool ensureRulesForAllProperties); Faker<T> FinishWith(Action<Faker, T> action); Faker<T> RuleFor<TProperty>(Expression<Func<T, TProperty>> property, TProperty value); Faker<T> Rules(Action<Faker, T> setActions); } public class Person : IHasRandomizer, IHasContext { public class CardAddress { public class CardGeo { public double Lat; public double Lng; } public string Street; public string Suite; public string City; public string State; public string ZipCode; public CardGeo Geo; } public class CardCompany { public string Name; public string CatchPhrase; public string Bs; } internal Dictionary<string, object> context = new Dictionary<string, object>(); protected SeedNotifier Notifier = new SeedNotifier(); private Randomizer randomizer; public Name.Gender Gender; public string FirstName; public string LastName; public string FullName; public string UserName; public string Avatar; public string Email; public DateTime DateOfBirth; public CardAddress Address; public string Phone; public string Website; public CardCompany Company; Dictionary<string, object> IHasContext.Context => context; protected Name DsName { get; set; } protected Internet DsInternet { get; set; } protected Date DsDate { get; set; } protected PhoneNumbers DsPhoneNumbers { get; set; } protected Address DsAddress { get; set; } protected Company DsCompany { get; set; } public Randomizer Random { get { return this.randomizer ?? (Random = new Randomizer()); } set { randomizer = value; Notifier.Notify(value); } } public Person(string locale = "en", int? seed = null) { GetDataSources(locale); if (seed.HasValue) { Random = new Randomizer(seed.Value); } Populate(); } internal Person(Randomizer randomizer, string locale = "en") { GetDataSources(locale); Random = randomizer; Populate(); } private void GetDataSources(string locale) { DsName = Notifier.Flow(new Name(locale)); DsInternet = Notifier.Flow(new Internet(locale)); DsDate = Notifier.Flow(new Date { Locale = locale }); DsPhoneNumbers = Notifier.Flow(new PhoneNumbers(locale)); DsAddress = Notifier.Flow(new Address(locale)); DsCompany = Notifier.Flow(new Company(locale)); } protected internal virtual void Populate() { Gender = Random.Enum(Array.Empty<Name.Gender>()); FirstName = DsName.FirstName(Gender); LastName = DsName.LastName(Gender); FullName = FirstName + " " + LastName; UserName = DsInternet.UserName(FirstName, LastName); Email = DsInternet.Email(FirstName, LastName); Website = DsInternet.DomainName(); Avatar = DsInternet.Avatar(); DateOfBirth = DsDate.Past(50, Date.SystemClock().AddYears(-20)); Phone = DsPhoneNumbers.PhoneNumber(); Address = new CardAddress { Street = DsAddress.StreetAddress(), Suite = DsAddress.SecondaryAddress(), City = DsAddress.City(), State = DsAddress.State(), ZipCode = DsAddress.ZipCode(), Geo = new CardAddress.CardGeo { Lat = DsAddress.Latitude(), Lng = DsAddress.Longitude() } }; Company = new CardCompany { Name = DsCompany.CompanyName(), CatchPhrase = DsCompany.CatchPhrase(), Bs = DsCompany.Bs() }; } SeedNotifier IHasRandomizer.GetNotifier() { return Notifier; } } [EditorBrowsable(EditorBrowsableState.Never)] public static class PropertyName { public static string For<T, TProp>(Expression<Func<T, TProp>> expression) { return GetMemberName(expression.Body); } public static string For<T>(Expression<Func<T, object>> expression) { return GetMemberName(expression.Body); } public static string For(Expression<Func<object>> expression) { return GetMemberName(expression.Body); } public static string GetMemberName(Expression expression) { string text = expression.ToString(); if (text.IndexOf('.') != text.LastIndexOf('.')) { throw new ArgumentException($"Your expression '{text}' cant be used. Nested accessors like 'o => o.NestedObject.Foo' at a parent level are not allowed. You should create a dedicated faker for NestedObject like new Faker<NestedObject>().RuleFor(o => o.Foo, ...) with its own rules that define how 'Foo' is generated. " + "See this GitHub issue for more info: https://github.com/bchavez/Bogus/issues/115"); } MemberExpression memberExpression = ((!(expression is UnaryExpression unaryExpression)) ? (expression as MemberExpression) : (unaryExpression.Operand as MemberExpression)); if (memberExpression == null) { throw new ArgumentException("Expression was not of the form 'x => x.Property or x => x.Field'."); } return memberExpression.Member.Name; } } public class Randomizer { public static Random Seed = new Random(); internal static Lazy<object> Locker = new Lazy<object>(() => new object(), LazyThreadSafetyMode.ExecutionAndPublication); protected Random localSeed; private WordFunctions wordFunctions; private static char[] AlphaChars = new char[36] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; private static char[] HexChars = new char[16] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; public Randomizer() { localSeed = Seed; } public Randomizer(int localSeed) { this.localSeed = new Random(localSeed); } public int Number(int max) { return Number(0, max); } public int[] Digits(int count, int minDigit = 0, int maxDigit = 9) { if (maxDigit > 9 || maxDigit < 0) { throw new ArgumentException("max digit can't be lager than 9 or smaller than 0", "maxDigit"); } if (minDigit > 9 || minDigit < 0) { throw new ArgumentException("min digit can't be lager than 9 or smaller than 0", "minDigit"); } int[] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = Number(minDigit, maxDigit); } return array; } public int Number(int min = 0, int max = 1) { lock (Locker.Value) { if (max < int.MaxValue) { return localSeed.Next(min, max + 1); } if (min > int.MinValue) { return 1 + localSeed.Next(min - 1, max); } int num = localSeed.Next(); int num2 = localSeed.Next(); int num3 = (num >> 8) & 0xFFFF; int num4 = (num2 >> 8) & 0xFFFF; return (num3 << 16) | num4; } } public int Even(int min = 0, int max = 1) { if (min > max) { throw new ArgumentException($"The min/max range is invalid. The minimum value '{min}' is greater than the maximum value '{max}'.", "max"); } if ((min & 1) == 1 && max - 1 < min) { throw new ArgumentException("The specified range does not contain any even numbers.", "max"); } min = (min + 1) & -2; max |= 1; if (min > max) { return min; } return Number(min, max) & -2; } public int Odd(int min = 0, int max = 1) { if (min > max) { throw new ArgumentException($"The min/max range is invalid. The minimum value '{min}' is greater than the maximum value '{max}'.", "max"); } if ((max & 1) == 0 && min + 1 > max) { throw new ArgumentException("The specified range does not contain any odd numbers.", "max"); } if (max == int.MinValue) { return -2147483647; } min &= -2; max = (max - 1) | 1; if (min > max) { return min | 1; } return Number(min, max) | 1; } public double Double(double min = 0.0, double max = 1.0) { lock (Locker.Value) { if (min == 0.0 && max == 1.0) { return localSeed.NextDouble(); } return localSeed.NextDouble() * (max - min) + min; } } public decimal Decimal(decimal min = 0.0m, decimal max = 1.0m) { return Convert.ToDecimal(Double()) * (max - min) + min; } public float Float(float min = 0f, float max = 1f) { return Convert.ToSingle(Double() * (double)(max - min) + (double)min); } public byte Byte(byte min = 0, byte max = byte.MaxValue) { return Convert.ToByte(Number(min, max)); } public byte[] Bytes(int count) { byte[] array = new byte[count]; lock (Locker.Value) { localSeed.NextBytes(array); return array; } } public sbyte SByte(sbyte min = sbyte.MinValue, sbyte max = sbyte.MaxValue) { return Convert.ToSByte(Number(min, max)); } public int Int(int min = int.MinValue, int max = int.MaxValue) { return Number(min, max); } public uint UInt(uint min = 0u, uint max = uint.MaxValue) { return Convert.ToUInt32(Double() * (double)(max - min) + (double)min); } public ulong ULong(ulong min = 0uL, ulong max = ulong.MaxValue) { return Convert.ToUInt64(Double() * (double)(max - min) + (double)min); } public long Long(long min = long.MinValue, long max = long.MaxValue) { decimal num = (decimal)max - (decimal)min; return Convert.ToInt64((decimal)Double() * num + (decimal)min); } public short Short(short min = short.MinValue, short max = short.MaxValue) { return Convert.ToInt16(Double() * (double)(max - min) + (double)min); } public ushort UShort(ushort min = 0, ushort max = ushort.MaxValue) { return Convert.ToUInt16(Double() * (double)(max - min) + (double)(int)min); } public char Char(char min = '\0', char max = '\uffff') { return Convert.ToChar(Number(min, max)); } public char[] Chars(char min = '\0', char max = '\uffff', int count = 5) { char[] array = new char[count]; for (int i = 0; i < count; i++) { array[i] = Char(min, max); } return array; } public string String(int? length = null, char minChar = '\0', char maxChar = '\uffff') { int count = length ?? Number(40, 80); return new string(Chars(minChar, maxChar, count)); } public string String(int minLength, int maxLength, char minChar = '\0', char maxChar = '\uffff') { int value = Number(minLength, maxLength); return String((int?)value, minChar, maxChar); } public string String2(int length, string chars = "abcdefghijklmnopqrstuvwxyz") { char[] array = new char[length]; for (int i = 0; i < length; i++) { int index = Number(0, chars.Length - 1); array[i] = chars[index]; } return new string(array); } public string String2(int minLength, int maxLength, string chars = "abcdefghijklmnopqrstuvwxyz") { int length = Number(minLength, maxLength); return String2(length, chars); } public string Utf16String(int minLength = 40, int maxLength = 80, bool excludeSurrogates = false) { int num = ((minLength == maxLength) ? minLength : Number(minLength, maxLength)); StringBuilder stringBuilder = new StringBuilder(); while (stringBuilder.Length < num) { int num2 = num - stringBuilder.Length; string text = null; int num3 = 0; if (!excludeSurrogates && num2 >= 2 && Bool()) { text = ArrayElement(SafeUnicodeRanges.SurrogatePairs); num3 = 1; } else { text = ArrayElement(SafeUnicodeRanges.Basic); num3 = 0; } char min = text[num3]; char max = text[2 + num3 * 2]; char value = (char)UShort(min, max); if (num3 == 1) { stringBuilder.Append(text[0]); stringBuilder.Append(value); } else { stringBuilder.Append(value); } } return stringBuilder.ToString(); } public string Hash(int length = 40, bool upperCase = false) { return String2(length, upperCase ? "0123456789ABCDEF" : "0123456789abcdef"); } public bool Bool() { return Number() == 0; } public bool Bool(float weight) { return Float() < weight; } public T ArrayElement<T>(T[] array) { if (array.Length == 0) { throw new ArgumentException("The array is empty. There are no items to select.", "array"); } int num = Number(array.Length - 1); return array[num]; } public BValue ArrayElement(BArray props, int? min = null, int? max = null) { int index = Number(min.GetValueOrDefault(), (max - 1) ?? (props.Count - 1)); return props[index]; } public string ArrayElement(Array array) { if (array == null) { array = new string[3] { "a", "b", "c" }; } int index = Number(array.Length - 1); return array.GetValue(index).ToString(); } public T[] ArrayElements<T>(T[] array, int? count = null) { if (count > array.Length) { throw new ArgumentOutOfRangeException("count"); } if (!count.HasValue) { count = Number(0, array.Length - 1); } return Shuffle(array).Take(count.Value).ToArray(); } public T ListItem<T>(List<T> list) { return ListItem((IList<T>)list); } public T ListItem<T>(IList<T> list) { if (list.Count <= 0) { throw new ArgumentException("The list is empty. There are no items to select.", "list"); } int index = Number(list.Count - 1); return list[index]; } public List<T> ListItems<T>(IList<T> items, int? count = null) { if (count > items.Count) { throw new ArgumentOutOfRangeException("count"); } if (!count.HasValue) { count = Number(0, items.Count - 1); } return Shuffle(items).Take(count.Value).ToList(); } public IList<T> ListItems<T>(List<T> items, int? count = null) { return ListItems((IList<T>)items, count); } public T CollectionItem<T>(ICollection<T> collection) { if (collection.Count <= 0) { throw new ArgumentException("The collection is empty. There are no items to select.", "collection"); } int count = Number(collection.Count - 1); return collection.Skip(count).First(); } public string ReplaceNumbers(string format, char symbol = '#') { return ReplaceSymbols(format, symbol, () => Convert.ToChar(48 + Number(9))); } public string ReplaceSymbols(string format, char symbol, Func<char> func) { return new string(format.Select((char c) => (c != symbol) ? c : func()).ToArray()); } public string Replace(string format) { return new string(format.Select(delegate(char c) { if (c == '*') { c = (Bool() ? '#' : '?'); } return c switch { '#' => Convert.ToChar(48 + Number(9)), '?' => Convert.ToChar(65 + Number(25)), _ => c, }; }).ToArray()); } public string ClampString(string str, int? min = null, int? max = null) { if (max.HasValue && str.Length > max) { str = str.Substring(0, max.Value).Trim(); } if (min.HasValue && min > str.Length) { string text = Replace("".PadRight((min - str.Length).Value, '?')); return str + text; } return str; } public T Enum<T>(params T[] exclude) where T : struct, Enum { Type e = typeof(T); if (!e.IsEnum()) { throw new ArgumentException("When calling Enum<T>() with no parameters T must be an enum."); } string[] array = System.Enum.GetNames(e); if (exclude.Any()) { IEnumerable<string> second = exclude.Select((T ex) => System.Enum.GetName(e, ex)); array = array.Except(second).ToArray(); } if (!array.Any()) { throw new ArgumentException("There are no values after exclusion to choose from."); } System.Enum.TryParse<T>(ArrayElement(array), out var result); return result; } public T[] EnumValues<T>(int? count = null, params T[] exclude) where T : Enum { T[] array = ((exclude.Length == 0) ? System.Enum.GetValues(typeof(T)).OfType<T>().Except(exclude) .ToArray() : System.Enum.GetValues(typeof(T)).OfType<T>().Except(exclude) .ToArray()); if (count > array.Length || count < 0) { throw new ArgumentOutOfRangeException("count", count, $"The {"count"} parameter is {count} and the calculated set of enums has a length of {array.Length}. It is impossible to pick {count} enums from a list of {array.Length}."); } return ArrayElements(array, count); } public IEnumerable<T> Shuffle<T>(IEnumerable<T> source) { List<T> buffer = source.ToList(); for (int i = 0; i < buffer.Count; i++) { int j; lock (Locker.Value) { j = localSeed.Next(i, buffer.Count); } yield return buffer[j]; buffer[j] = buffer[i]; } } public string Word() { if (wordFunctions == null) { wordFunctions = new WordFunctions(this); } return ListItem(wordFunctions.Functions)(); } public string Words(int? count = null) { if (!count.HasValue) { count = Number(1, 3); } string[] value = WordsArray(count.Value); return string.Join(" ", value); } public string[] WordsArray(int min, int max) { int count = Number(min, max); return WordsArray(count); } public string[] WordsArray(int count) { return (from f in Enumerable.Range(1, count) select Word()).ToArray(); } public Guid Guid() { return new Guid(Bytes(16)); } public Guid Uuid() { return new Guid(Bytes(16)); } public string RandomLocale() { return ArrayElement(Database.GetAllLocales()); } public string AlphaNumeric(int length) { StringBuilder seed = new StringBuilder(); return Enumerable.Range(1, length).Aggregate(seed, (StringBuilder b, int i) => b.Append(ArrayElement(AlphaChars)), (StringBuilder b) => b.ToString()); } public string Hexadecimal(int length = 1, string prefix = "0x") { StringBuilder seed = new StringBuilder(); return Enumerable.Range(1, length).Aggregate(seed, (StringBuilder b, int i) => b.Append(ArrayElement(HexChars)), (StringBuilder b) => $"{prefix}{b}"); } public T WeightedRandom<T>(T[] items, float[] weights) { if (weights.Length != items.Length) { throw new ArgumentOutOfRangeException("items.Length and weights.Length must be the same."); } float num = Float(); float num2 = 0f; T result = default(T); for (int i = 0; i < weights.Length; i++) { float num3 = num2 + weights[i]; result = items[i]; if (num >= num2 && num <= num3) { break; } num2 += weights[i]; } return result; } } public class WordFunctions { public List<Func<string>> Functions { get; } = new List<Func<string>>(); private Commerce Commerce { get; } private Company Company { get; } private Address Address { get; } private Finance Finance { get; } private Hacker Hacker { get; } private Name Name { get; } public WordFunctions(Randomizer r) { Commerce = new Commerce { Random = r }; Company = new Company { Random = r }; Address = new Address { Random = r }; Finance = new Finance { Random = r }; Hacker = new Hacker { Random = r }; Name = new Name { Random = r }; Init(); } private void Init() { Functions.Add(() => Commerce.Department()); Functions.Add(() => Commerce.ProductName()); Functions.Add(() => Commerce.ProductAdjective()); Functions.Add(() => Commerce.ProductMaterial()); Functions.Add(() => Commerce.ProductName()); Functions.Add(() => Commerce.Color()); Functions.Add(() => Company.CatchPhraseAdjective()); Functions.Add(() => Company.CatchPhraseDescriptor()); Functions.Add(() => Company.CatchPhraseNoun()); Functions.Add(() => Company.BsAdjective()); Functions.Add(() => Company.BsBuzz()); Functions.Add(() => Company.BsNoun()); Functions.Add(() => Address.StreetSuffix()); Functions.Add(() => Address.County()); Functions.Add(() => Address.Country()); Functions.Add(() => Address.State()); Functions.Add(() => Address.StreetSuffix()); Functions.Add(() => Finance.AccountName()); Functions.Add(() => Finance.TransactionType()); Functions.Add(() => Finance.Currency().Description); Functions.Add(() => Hacker.Noun()); Functions.Add(() => Hacker.Verb()); Functions.Add(() => Hacker.Adjective()); Functions.Add(() => Hacker.IngVerb()); Functions.Add(() => Hacker.Abbreviation()); Functions.Add(() => Name.JobDescriptor()); Functions.Add(() => Name.JobArea()); Functions.Add(() => Name.JobType()); } } public static class ResourceHelper { public static bool ResourceExists(Assembly assembly, string resourceName) { return assembly.GetManifestResourceInfo(resourceName) != null; } public static byte[] ReadResource(Assembly assembly, string resourceName) { using Stream stream = assembly.GetManifestResourceStream(resourceName); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } public static BValue ReadBValueResource(Assembly assembly, string resourceName) { using Stream stream = assembly.GetManifestResourceStream(resourceName); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return Bogus.Bson.Bson.Load(memoryStream.ToArray()); } public static BObject ReadBObjectResource(Assembly assembly, string resourceName) { using Stream stream = assembly.GetManifestResourceStream(resourceName); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return Bogus.Bson.Bson.Load(memoryStream.ToArray()); } } public class Rule<T> { public T Action { get; set; } public string PropertyName { get; set; } public string RuleSet { get; set; } = string.Empty; public bool ProhibitInStrictMode { get; set; } } public class PopulateAction<T> : Rule<Func<Faker, T, object>> { } public class FinalizeAction<T> : Rule<Action<Faker, T>> { } public class MultiDictionary<Key, Key2, Value> : Dictionary<Key, Dictionary<Key2, Value>> { public MultiDictionary(IEqualityComparer<Key> comparer) : base(comparer) { } public void Add(Key key, Key2 key2, Value value) { if (!TryGetValue(key, out var value2)) { value2 = new Dictionary<Key2, Value>(); Add(key, value2); } value2[key2] = value; } } public class MultiSetDictionary<Key, Value> : Dictionary<Key, HashSet<Value>> { public MultiSetDictionary(IEqualityComparer<Key> comparer) : base(comparer) { } public void Add(Key key, Value value) { if (!TryGetValue(key, out var value2)) { value2 = new HashSet<Value>(); Add(key, value2); } if (value2.Contains(value)) { throw new ArgumentException("An item with the same key has already been added."); } value2.Add(value); } } public interface IHasRandomizer { Randomizer Random { set; } SeedNotifier GetNotifier(); } public class SeedNotifier { private List<IHasRandomizer> registry = new List<IHasRandomizer>(); public U Flow<U>(U item) where U : IHasRandomizer { registry.Add(item); return item; } public void Notify(Randomizer r) { foreach (IHasRandomizer item in registry) { item.Random = r; } } } public class MustashMethod { public string Name { get; set; } public MethodInfo Method { get; set; } public object[] OptionalArgs { get; set; } } public class Tokenizer { public static ILookup<string, MustashMethod> MustashMethods; static Tokenizer() { RegisterMustashMethods(typeof(Faker)); } public static void RegisterMustashMethods(Type type) { MustashMethods = (from p in type.GetProperties() where p.IsDefined(typeof(RegisterMustasheMethodsAttribute), inherit: true) select p).SelectMany((PropertyInfo p) => (from mi in p.PropertyType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public) where mi.GetGenericArguments().Length == 0 select mi).Select(delegate(MethodInfo mi) { string text = DataSet.ResolveCategory(p.PropertyType); string name = mi.Name; return new MustashMethod { Name = (text + "." + name).ToUpperInvariant(), Method = mi, OptionalArgs = (from pi in mi.GetParameters() where pi.IsOptional select pi into _ select Type.Missing).ToArray() }; })).ToLookup((MustashMethod mm) => mm.Name); } public static string Parse(string str, params object[] dataSets) { int num = str.IndexOf("{{", StringComparison.Ordinal); int num2 = str.IndexOf("}}", StringComparison.Ordinal); if (num == -1 && num2 == -1) { return str; } ParseMustashText(str, num, num2, out var methodName, out var arguments); if (!MustashMethods.Contains(methodName)) { throw new ArgumentException("Unknown method " + methodName + " can't be found."); } object obj = FindDataSetWithMethod(dataSets, methodName); MustashMethod mustashMethod = FindMustashMethod(methodName, arguments); object[] array = ConvertStringArgumentsToObjects(arguments, mustashMethod); IEnumerable<object> second = mustashMethod.OptionalArgs.Take(mustashMethod.Method.GetParameters().Length - array.Length); object[] parameters = array.Concat(second).ToArray(); string value = mustashMethod.Method.Invoke(obj, parameters).ToString(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(str, 0, num); stringBuilder.Append(value); stringBuilder.Append(str.Substring(num2 + 2)); return Parse(stringBuilder.ToString(), dataSets); } private static object FindDataSetWithMethod(object[] dataSets, string methodName) { Type dataSetType = MustashMethods[methodName].First().Method.DeclaringType; return dataSets.FirstOrDefault((object o) => o.GetType() == dataSetType) ?? throw new ArgumentException($"Can't parse {methodName} because the dataset was not provided in the {"dataSets"} parameter.", "dataSets"); } private static void ParseMustashText(string str, int start, int end, out string methodName, out string[] arguments) { string text = str.Substring(start + 2, end - start - 2).Replace("}}", "").Replace("{{", ""); int num = text.IndexOf("(", StringComparison.Ordinal); if (num != -1) { string argumentsString = GetArgumentsString(text, num); methodName = text.Substring(0, num).Trim(); arguments = (from s in argumentsString.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim()).ToArray(); } else { methodName = text; arguments = new string[0]; } methodName = methodName.ToUpperInvariant(); } private static MustashMethod FindMustashMethod(string methodName, string[] arguments) { return (from mm in MustashMethods[methodName] orderby mm.Method.GetParameters().Count((ParameterInfo pi) => pi.IsOptional) - arguments.Length where mm.Method.GetParameters().Length >= arguments.Length where mm.OptionalArgs.Length + arguments.Length >= mm.Method.GetParameters().Length select mm).FirstOrDefault() ?? throw new ArgumentException($"Cannot find a method '{methodName}' that could accept {arguments.Length} arguments"); } private static object[] ConvertStringArgumentsToObjects(string[] parameters, MustashMethod mm) { try { return mm.Method.GetParameters().Zip(parameters, GetValueForParameter).ToArray(); } catch (OverflowException innerException) { throw new ArgumentOutOfRangeException("One of the arguments for " + mm.Name + " is out of supported range. Argument list: " + string.Join(",", parameters), innerException); } catch (Exception ex) when (ex is InvalidCastException || ex is FormatException) { throw new ArgumentException("One of the arguments for " + mm.Name + " cannot be converted to target type. Argument list: " + string.Join(",", parameters), ex); } catch (Exception innerException2) { throw new ArgumentException("Cannot parse arguments for " + mm.Name + ". Argument list: " + string.Join(",", parameters), innerException2); } } private static object GetValueForParameter(ParameterInfo parameterInfo, string parameterValue) { Type type = Nullable.GetUnderlyingType(parameterInfo.ParameterType) ?? parameterInfo.ParameterType; if (typeof(Enum).IsAssignableFrom(type)) { return Enum.Parse(type, parameterValue); } if (typeof(TimeSpan) == type) { return TimeSpan.Parse(parameterValue); } return Convert.ChangeType(parameterValue, type); } private static string GetArgumentsString(string methodCall, int parametersStart) { int num = methodCall.IndexOf(')'); if (num == -1) { throw new ArgumentException("The method call '" + methodCall + "' is missing a terminating ')' character."); } return methodCall.Substring(parametersStart + 1, num - parametersStart - 1); } } [AttributeUsage(AttributeTargets.Property)] internal class RegisterMustasheMethodsAttribute : Attribute { } public static class Transliterater { public static Trie CharMap = BuildCharMap(new Trie()); public static Trie DiatricMap = BuildDiatricMap(new Trie()); public static MultiDictionary<string, string, string> LangCharMap = BuildLangCharMap(new MultiDictionary<string, string, string>(StringComparer.Ordinal)); public static MultiDictionary<string, string, string> SymbolMap = BuildSymbolMap(new MultiDictionary<string, string, string>(StringComparer.Ordinal)); public static readonly Dictionary<string, string> EmptyDictionary = new Dictionary<string, string>(); public static string Translate(string input, string lang = "en") { if (!LangCharMap.TryGetValue(lang, out var value)) { value = EmptyDictionary; } if (!SymbolMap.TryGetValue(lang, out var value2)) { value2 = SymbolMap["en"]; } StringBuilder stringBuilder = new StringBuilder(input.Length); for (int i = 0; i < input.Length; i++) { string text = input.Substring(i, 1); if (value.TryGetValue(text, out var value3)) { stringBuilder.Append(value3); continue; } int used = 0; string text2 = WalkTrie(i, input, CharMap, ref used); if (text2 != null) { stringBuilder.Append(text2); i += used - 1; continue; } used = 0; string text3 = WalkTrie(i, input, DiatricMap, ref used); string value4; if (text3 != null) { stringBuilder.Append(text3); i += used - 1; } else if (value2.TryGetValue(text, out value4)) { stringBuilder.Append(value4); } else { stringBuilder.Append(text); } } return stringBuilder.ToString(); } [EditorBrowsable(EditorBrowsableState.Never)] public static string WalkTrie(int i, string input, Trie trie, ref int used) { if (i >= input.Length) { return trie.Value; } string key = input.Substring(i, 1); if (trie.Map.TryGetValue(key, out var value)) { used++; return WalkTrie(i + 1, input, value, ref used); } string value2 = trie.Value; if (value2 != null && value2.Length > 0) { return trie.Value; } return null; } [EditorBrowsable(EditorBrowsableState.Never)] public static Trie BuildCharMap(Trie trie) { Trie.Insert(trie, "À", "A"); Trie.Insert(trie, "Á", "A"); Trie.Insert(trie, "Â", "A"); Trie.Insert(trie, "Ã", "A"); Trie.Insert(trie, "Ä", "Ae"); Trie.Insert(trie, "Å", "A"); Trie.Insert(trie, "Æ", "AE"); Trie.Insert(trie, "Ç", "C"); Trie.Insert(trie, "È", "E"); Trie.Insert(trie, "É", "E"); Trie.Insert(trie, "Ê", "E"); Trie.Insert(trie, "Ë", "E"); Trie.Insert(trie, "Ì", "I"); Trie.Insert(trie, "Í", "I"); Trie.Insert(trie, "Î", "I"); Trie.Insert(trie, "Ï", "I"); Trie.Insert(trie, "Ð", "D"); Trie.Insert(trie, "Ñ", "N"); Trie.Insert(trie, "Ò", "O"); Trie.Insert(trie, "Ó", "O"); Trie.Insert(trie, "Ô", "O"); Trie.Insert(trie, "Õ", "O"); Trie.Insert(trie, "Ö", "Oe"); Trie.Insert(trie, "Ő", "O"); Trie.Insert(trie, "Ø", "O"); Trie.Insert(trie, "Ù", "U"); Trie.Insert(trie, "Ú", "U"); Trie.Insert(trie, "Û", "U"); Trie.Insert(trie, "Ü", "Ue"); Trie.Insert(trie, "Ű", "U"); Trie.Insert(trie, "Ý", "Y"); Trie.Insert(trie, "Þ", "TH"); Trie.Insert(trie, "ß", "ss"); Trie.Insert(trie, "à", "a"); Trie.Insert(trie, "á", "a"); Trie.Insert(trie, "â", "a"); Trie.Insert(trie, "ã", "a"); Trie.Insert(trie, "ä", "ae"); Trie.Insert(trie, "å", "a"); Trie.Insert(trie, "æ", "ae"); Trie.Insert(trie, "ç", "c"); Trie.Insert(trie, "è", "e"); Trie.Insert(trie, "é", "e"); Trie.Insert(trie, "ê", "e"); Trie.Insert(trie, "ë", "e"); Trie.Insert(trie, "ì", "i"); Trie.Insert(trie, "í", "i"); Trie.Insert(trie, "î", "i"); Trie.Insert(trie, "ï", "i"); Trie.Insert(trie, "ð", "d"); Trie.Insert(trie, "ñ", "n"); Trie.Insert(trie, "ò", "o"); Trie.Insert(trie, "ó", "o"); Trie.Insert(trie, "ô", "o"); Trie.Insert(trie, "õ", "o"); Trie.Insert(trie, "ö", "oe"); Trie.Insert(trie, "ő", "o"); Trie.Insert(trie, "ø", "o"); Trie.Insert(trie, "ù", "u"); Trie.Insert(trie, "ú", "u"); Trie.Insert(trie, "û", "u"); Trie.Insert(trie, "ü", "ue"); Trie.Insert(trie, "ű", "u"); Trie.Insert(trie, "ý", "y"); Trie.Insert(trie, "þ", "th"); Trie.Insert(trie, "ÿ", "y"); Trie.Insert(trie, "ẞ", "SS"); Trie.Insert(trie, "ا", "a"); Trie.Insert(trie, "أ", "a"); Trie.Insert(trie, "إ", "i"); Trie.Insert(trie, "آ", "aa"); Trie.Insert(trie, "ؤ", "u"); Trie.Insert(trie, "ئ", "e"); Trie.Insert(trie, "ء", "a"); Trie.Insert(trie, "ب", "b"); Trie.Insert(trie, "ت", "t"); Trie.Insert(trie, "ث", "th"); Trie.Insert(trie, "ج", "j"); Trie.Insert(trie, "ح", "h"); Trie.Insert(trie, "خ", "kh"); Trie.Insert(trie, "د", "d"); Trie.Insert(trie, "ذ", "th"); Trie.Insert(trie, "ر", "r"); Trie.Insert(trie, "ز", "z"); Trie.Insert(trie, "س", "s"); Trie.Insert(trie, "ش", "sh"); Trie.Insert(trie, "ص", "s"); Trie.Insert(trie, "ض", "dh"); Trie.Insert(trie, "ط", "t"); Trie.Insert(trie, "ظ", "z"); Trie.Insert(trie, "ع", "a"); Trie.Insert(trie, "غ", "gh"); Trie.Insert(trie, "ف", "f"); Trie.Insert(trie, "ق", "q"); Trie.Insert(trie, "ك", "k"); Trie.Insert(trie, "ل", "l"); Trie.Insert(trie, "م", "m"); Trie.Insert(trie, "ن", "n"); Trie.Insert(trie, "ه", "h"); Trie.Insert(trie, "و", "w"); Trie.Insert(trie, "ي", "y"); Trie.Insert(trie, "ى", "a"); Trie.Insert(trie, "ة", "h"); Trie.Insert(trie, "ﻻ", "la"); Trie.Insert(trie, "ﻷ", "laa"); Trie.Insert(trie, "ﻹ", "lai"); Trie.Insert(trie, "ﻵ", "laa"); Trie.Insert(trie, "گ", "g"); Trie.Insert(trie, "چ", "ch"); Trie.Insert(trie, "پ", "p"); Trie.Insert(trie, "ژ", "zh"); Trie.Insert(trie, "ک", "k"); Trie.Insert(trie, "ی", "y"); Trie.Insert(trie, "\u064e", "a"); Trie.Insert(trie, "\u064b", "an"); Trie.Insert(trie, "\u0650", "e"); Trie.Insert(trie, "\u064d", "en"); Trie.Insert(trie, "\u064f", "u"); Trie.Insert(trie, "\u064c", "on"); Trie.Insert(trie, "\u0652", ""); Trie.Insert(trie, "٠", "0"); Trie.Insert(trie, "١", "1"); Trie.Insert(trie, "٢", "2"); Trie.Insert(trie, "٣", "3"); Trie.Insert(trie, "٤", "4"); Trie.Insert(trie, "٥", "5"); Trie.Insert(trie, "٦", "6"); Trie.Insert(trie, "٧", "7"); Trie.Insert(trie, "٨", "8"); Trie.Insert(trie, "٩", "9"); Trie.Insert(trie, "۰", "0"); Trie.Insert(trie, "۱", "1"); Trie.Insert(trie, "۲", "2"); Trie.Insert(trie, "۳", "3"); Trie.Insert(trie, "۴", "4"); Trie.Insert(trie, "۵", "5"); Trie.Insert(trie, "۶", "6"); Trie.Insert(trie, "۷", "7"); Trie.Insert(trie, "۸", "8"); Trie.Insert(trie, "۹", "9"); Trie.Insert(trie, "က", "k"); Trie.Insert(trie, "ခ", "kh"); Trie.Insert(trie, "ဂ", "g"); Trie.Insert(trie, "ဃ", "ga"); Trie.Insert(trie, "င", "ng"); Trie.Insert(trie, "စ", "s"); Trie.Insert(trie, "ဆ", "sa"); Trie.Insert(trie, "ဇ", "z"); Trie.Insert(trie, "စ\u103b", "za"); Trie.Insert(trie, "ည", "ny"); Trie.Insert(trie, "ဋ", "t"); Trie.Insert(trie, "ဌ", "ta"); Trie.Insert(trie, "ဍ", "d"); Trie.Insert(trie, "ဎ", "da"); Trie.Insert(trie, "ဏ", "na"); Trie.Insert(trie, "တ", "t"); Trie.Insert(trie, "ထ", "ta"); Trie.Insert(trie, "ဒ", "d"); Trie.Insert(trie, "ဓ", "da"); Trie.Insert(trie, "န", "n"); Trie.Insert(trie, "ပ", "p"); Trie.Insert(trie, "ဖ", "pa"); Trie.Insert(trie, "ဗ", "b"); Trie.Insert(trie, "ဘ", "ba"); Trie.Insert(trie, "မ", "m"); Trie.Insert(trie, "ယ", "y"); Trie.Insert(trie, "ရ", "ya"); Trie.Insert(trie, "လ", "l"); Trie.Insert(trie, "ဝ", "w"); Trie.Insert(trie, "သ", "th"); Trie.Insert(trie, "ဟ", "h"); Trie.Insert(trie, "ဠ", "la"); Trie.Insert(trie, "အ", "a"); Trie.Insert(trie, "\u103c", "y"); Trie.Insert(trie, "\u103b", "ya"); Trie.Insert(trie, "\u103d", "w"); Trie.Insert(trie, "\u103c\u103d", "yw"); Trie.Insert(trie, "\u103b\u103d", "ywa"); Trie.Insert(trie, "\u103e", "h"); Trie.Insert(trie, "ဧ", "e"); Trie.Insert(trie, "၏", "-e"); Trie.Insert(trie, "ဣ", "i"); Trie.Insert(trie, "ဤ", "-i"); Trie.Insert(trie, "ဉ", "u"); Trie.Insert(trie, "ဦ", "-u"); Trie.Insert(trie, "ဩ", "aw"); Trie.Insert(trie, "သ\u103c\u1031\u102c", "aw"); Trie.Insert(trie, "ဪ", "aw"); Trie.Insert(trie, "၀", "0"); Trie.Insert(trie, "၁", "1"); Trie.Insert(trie, "၂", "2"); Trie.Insert(trie, "၃", "3"); Trie.Insert(trie, "၄", "4"); Trie.Insert(trie, "၅", "5"); Trie.Insert(trie, "၆", "6"); Trie.Insert(trie, "၇", "7"); Trie.Insert(trie, "၈", "8"); Trie.Insert(trie, "၉", "9"); Trie.Insert(trie, "\u1039", ""); Trie.Insert(trie, "\u1037", ""); Trie.Insert(trie, "\u1038", ""); Trie.Insert(trie, "č", "c"); Trie.Insert(trie, "ď", "d"); Trie.Insert(trie, "ě", "e"); Trie.Insert(trie, "ň", "n"); Trie.Insert(trie, "ř", "r"); Trie.Insert(trie, "š", "s"); Trie.Insert(trie, "ť", "t"); Trie.Insert(trie, "ů", "u"); Trie.Insert(trie, "ž", "z"); Trie.Insert(trie, "Č", "C"); Trie.Insert(trie, "Ď", "D"); Trie.Insert(trie, "Ě", "E"); Trie.Insert(trie, "Ň", "N"); Trie.Insert(trie, "Ř", "R"); Trie.Insert(trie, "Š", "S"); Trie.Insert(trie, "Ť", "T"); Trie.Insert(trie, "Ů", "U"); Trie.Insert(trie, "Ž", "Z"); Trie.Insert(trie, "ހ", "h"); Trie.Insert(trie, "ށ", "sh"); Trie.Insert(trie, "ނ", "n"); Trie.Insert(trie, "ރ", "r"); Trie.Insert(trie, "ބ", "b"); Trie.Insert(trie, "ޅ", "lh"); Trie.Insert(trie, "ކ", "k"); Trie.Insert(trie, "އ", "a"); Trie.Insert(trie, "ވ", "v"); Trie.Insert(trie, "މ", "m"); Trie.Insert(trie, "ފ", "f"); Trie.Insert(trie, "ދ", "dh"); Trie.Insert(trie, "ތ", "th"); Trie.Insert(trie, "ލ", "l"); Trie.Insert(trie, "ގ", "g"); Trie.Insert(trie, "ޏ", "gn"); Trie.Insert(trie, "ސ", "s"); Trie.Insert(trie, "ޑ", "d"); Trie.Insert(trie, "ޒ", "z"); Trie.Insert(trie, "ޓ", "t"); Trie.Insert(trie, "ޔ", "y"); Trie.Insert(trie, "ޕ", "p"); Trie.Insert(trie, "ޖ", "j"); Trie.Insert(trie, "ޗ", "ch"); Trie.Insert(trie, "ޘ", "tt"); Trie.Insert(trie, "ޙ", "hh"); Trie.Insert(trie, "ޚ", "kh"); Trie.Insert(trie, "ޛ", "th"); Trie.Insert(trie, "ޜ", "z"); Trie.Insert(trie, "ޝ", "sh"); Trie.Insert(trie, "ޞ", "s"); Trie.Insert(trie, "ޟ", "d"); Trie.Insert(trie, "ޠ", "t"); Trie.Insert(trie, "ޡ", "z"); Trie.Insert(trie, "ޢ", "a"); Trie.Insert(trie, "ޣ", "gh"); Trie.Insert(trie, "ޤ", "q"); Trie.Insert(trie, "ޥ", "w"); Trie.Insert(trie, "\u07a6", "a"); Trie.Insert(trie, "\u07a7", "aa"); Trie.Insert(trie, "\u07a8", "i"); Trie.Insert(trie, "\u07a9", "ee"); Trie.Insert(trie, "\u07aa", "u"); Trie.Insert(trie, "\u07ab", "oo"); Trie.Insert(trie, "\u07ac", "e"); Trie.Insert(trie, "\u07ad", "ey"); Trie.Insert(trie, "\u07ae", "o"); Trie.Insert(trie, "\u07af", "oa"); Trie.Insert(trie, "\u07b0", ""); Trie.Insert(trie, "ა", "a"); Trie.Insert(trie, "ბ", "b"); Trie.Insert(trie, "გ", "g"); Trie.Insert(trie, "დ", "d"); Trie.Insert(trie, "ე", "e"); Trie.Insert(trie, "ვ", "v"); Trie.Insert(trie, "ზ", "z"); Trie.Insert(trie, "თ", "t"); Trie.Insert(trie, "ი", "i"); Trie.Insert(trie, "კ", "k"); Trie.Insert(trie, "ლ", "l"); Trie.Insert(trie, "მ", "m"); Trie.Insert(trie, "ნ", "n"); Trie.Insert(trie, "ო", "o"); Trie.Insert(trie, "პ", "p"); Trie.Insert(trie, "ჟ", "zh"); Trie.Insert(trie, "რ", "r"); Trie.Insert(trie, "ს", "s"); Trie.Insert(trie, "ტ", "t"); Trie.Insert(trie, "უ", "u"); Trie.Insert(trie, "ფ", "p"); Trie.Insert(trie, "ქ", "k"); Trie.Insert(trie, "ღ", "gh"); Trie.Insert(trie, "ყ", "q"); Trie.Insert(trie, "შ", "sh"); Trie.Insert(trie, "ჩ", "ch"); Trie.Insert(trie, "ც", "ts"); Trie.Insert(trie, "ძ", "dz"); Trie.Insert(trie, "წ", "ts"); Trie.Insert(trie, "ჭ", "ch"); Trie.Insert(trie, "ხ", "kh"); Trie.Insert(trie, "ჯ", "j"); Trie.Insert(trie, "ჰ", "h"); Trie.Insert(trie, "α", "a"); Trie.Insert(trie, "β", "v"); Trie.Insert(trie, "γ", "g"); Trie.Insert(trie, "δ", "d"); Trie.Insert(trie, "ε", "e"); Trie.Insert(trie, "ζ", "z"); Trie.Insert(trie, "η", "i"); Trie.Insert(trie, "θ", "th"); Trie.Insert(trie, "ι", "i"); Trie.Insert(trie, "κ", "k"); Trie.Insert(trie, "λ", "l"); Trie.Insert(trie, "μ", "m"); Trie.Insert(trie, "ν", "n"); Trie.Insert(trie, "ξ", "ks"); Trie.Insert(trie, "ο", "o"); Trie.Insert(trie, "π", "p"); Trie.Insert(trie, "ρ", "r"); Trie.Insert(trie, "σ", "s"); Trie.Insert(trie, "τ", "t"); Trie.Insert(trie, "υ", "y"); Trie.Insert(trie, "φ", "f"); Trie.Insert(trie, "χ", "x"); Trie.Insert(trie, "ψ", "ps"); Trie.Insert(trie, "ω", "o"); Trie.Insert(trie, "ά", "a"); Trie.Insert(trie, "έ", "e"); Trie.Insert(trie, "ί", "i"); Trie.Insert(trie, "ό", "o"); Trie.Insert(trie, "ύ", "y"); Trie.Insert(trie, "ή", "i"); Trie.Insert(trie, "ώ", "o"); Trie.Insert(trie, "ς", "s"); Trie.Insert(trie, "ϊ", "i"); Trie.Insert(trie, "ΰ", "y"); Trie.Insert(trie, "ϋ", "y"); Trie.Insert(trie, "ΐ", "i"); Trie.Insert(trie, "Α", "A"); Trie.Insert(trie, "Β", "B"); Trie.Insert(trie, "Γ", "G"); Trie.Insert(trie, "Δ", "D"); Trie.Insert(trie, "Ε", "E"); Trie.Insert(trie, "Ζ", "Z"); Trie.Insert(trie, "Η", "I"); Trie.Insert(trie, "Θ", "TH"); Trie.Insert(trie, "Ι", "I"); Trie.Insert(trie, "Κ", "K"); Trie.Insert(trie, "Λ", "L"); Trie.Insert(trie, "Μ", "M"); Trie.Insert(trie, "Ν", "N"); Trie.Insert(trie, "Ξ", "KS"); Trie.Insert(trie, "Ο", "O"); Trie.Insert(trie, "Π", "P"); Trie.Insert(trie, "Ρ", "R"); Trie.Insert(trie, "Σ", "S"); Trie.Insert(trie, "Τ", "T"); Trie.Insert(trie, "Υ", "Y"); Trie.Insert(trie, "Φ", "F"); Trie.Insert(trie, "Χ", "X"); Trie.Insert(trie, "Ψ", "PS"); Trie.Insert(trie, "Ω", "O"); Trie.Insert(trie, "Ά", "A"); Trie.Insert(trie, "Έ", "E"); Trie.Insert(trie, "Ί", "I"); Trie.Insert(trie, "Ό", "O"); Trie.Insert(trie, "Ύ", "Y"); Trie.Insert(trie, "Ή", "I"); Trie.Insert(trie, "Ώ", "O"); Trie.Insert(trie, "Ϊ", "I"); Trie.Insert(trie, "Ϋ", "Y"); Trie.Insert(trie, "ā", "a"); Trie.Insert(trie, "ē", "e"); Trie.Insert(trie, "ģ", "g"); Trie.Insert(trie, "ī", "i"); Trie.Insert(trie, "ķ", "k"); Trie.Insert(trie, "ļ", "l"); Trie.Insert(trie, "ņ", "n"); Trie.Insert(trie, "ū", "u"); Trie.Insert(trie, "Ā", "A"); Trie.Insert(trie, "Ē", "E"); Trie.Insert(trie, "Ģ", "G"); Trie.Insert(trie, "Ī", "I"); Trie.Insert(trie, "Ķ", "k"); Trie.Insert(trie, "Ļ", "L"); Trie.Insert(trie, "Ņ", "N"); Trie.Insert(trie, "Ū", "U"); Trie.Insert(trie, "Ќ", "Kj"); Trie.Insert(trie, "ќ", "kj"); Trie.Insert(trie, "Љ", "Lj"); Trie.Insert(trie, "љ", "lj"); Trie.Insert(trie, "Њ", "Nj"); Trie.Insert(trie, "њ", "nj"); Trie.Insert(trie, "Тс", "Ts"); Trie.Insert(trie, "тс", "ts"); Trie.Insert(trie, "ą", "a"); Trie.Insert(trie, "ć", "c"); Trie.Insert(trie, "ę", "e"); Trie.Insert(trie, "ł", "l"); Trie.Insert(trie, "ń", "n"); Trie.Insert(trie, "ś", "s"); Trie.Insert(trie, "ź", "z"); Trie.Insert(trie, "ż", "z"); Trie.Insert(trie, "Ą", "A"); Trie.Insert(trie, "Ć", "C"); Trie.Insert(trie, "Ę", "E"); Trie.Insert(trie, "Ł", "L"); Trie.Insert(trie, "Ń", "N"); Trie.Insert(trie, "Ś", "S"); Trie.Insert(trie, "Ź", "Z"); Trie.Insert(trie, "Ż", "Z"); Trie.Insert(trie, "Є", "Ye"); Trie.Insert(trie, "І", "I"); Trie.Insert(trie, "Ї", "Yi"); Trie.Insert(trie, "Ґ", "G"); Trie.Insert(trie, "є", "ye"); Trie.Insert(trie, "і", "i"); Trie.Insert(trie, "ї", "yi"); Trie.Insert(trie, "ґ", "g"); Trie.Insert(trie, "ă", "a"); Trie.Insert(trie, "Ă", "A"); Trie.Insert(trie, "ș", "s"); Trie.Insert(trie, "Ș", "S"); Trie.Insert(trie, "ț", "t"); Trie.Insert(trie, "Ț", "T"); Trie.Insert(trie, "ţ", "t"); Trie.Insert(trie, "Ţ", "T"); Trie.Insert(trie, "а", "a"); Trie.Insert(trie, "б", "b"); Trie.Insert(trie, "в", "v"); Trie.Insert(trie, "г", "g"); Trie.Insert(trie, "д", "d"); Trie.Insert(trie, "е", "e"); Trie.Insert(trie, "ё", "yo"); Trie.Insert(trie, "ж", "zh"); Trie.Insert(trie, "з", "z"); Trie.Insert(trie, "и", "i"); Trie.Insert(trie, "й", "i"); Trie.Insert(trie, "к", "k"); Trie.Insert(trie, "л", "l"); Trie.Insert(trie, "м", "m"); Trie.Insert(trie, "н", "n"); Trie.Insert(trie, "о", "o"); Trie.Insert(trie, "п", "p"); Trie.Insert(trie, "р", "r"); Trie.Insert(trie, "с", "s"); Trie.Insert(trie, "т", "t"); Trie.Insert(trie, "у", "u"); Trie.Insert(trie, "ф", "f"); Trie.Insert(trie, "х", "kh"); Trie.Insert(trie, "ц", "c"); Trie.Insert(trie, "ч", "ch"); Trie.Insert(trie, "ш", "sh"); Trie.Insert(trie, "щ", "sh"); Trie.Insert(trie, "ъ", ""); Trie.Insert(trie, "ы", "y"); Trie.Insert(trie, "ь", ""); Trie.Insert(trie, "э", "e"); Trie.Insert(trie, "ю", "yu"); Trie.Insert(trie, "я", "ya"); Trie.Insert(trie, "А", "A"); Trie.Insert(trie, "Б", "B"); Trie.Insert(trie, "В", "V"); Trie.Insert(trie, "Г", "G"); Trie.Insert(trie, "Д", "D"); Trie.Insert(trie, "Е", "E"); Trie.Insert(trie, "Ё", "Yo"); Trie.Insert(trie, "Ж", "Zh"); Trie.Insert(trie, "З", "Z"); Trie.Insert(trie, "И", "I"); Trie.Insert(trie, "Й", "I"); Trie.Insert(trie, "К", "K"); Trie.Insert(trie, "Л", "L"); Trie.Insert(trie, "М", "M"); Trie.Insert(trie, "Н", "N"); Trie.Insert(trie, "О", "O"); Trie.Insert(trie, "П", "P"); Trie.Insert(trie, "Р", "R"); Trie.Insert(trie, "С", "S"); Trie.Insert(trie, "Т", "T"); Trie.Insert(trie, "У", "U"); Trie.Insert(trie, "Ф", "F"); Trie.Insert(trie, "Х", "Kh"); Trie.Insert(trie, "Ц", "C"); Trie.Insert(trie, "Ч", "Ch"); Trie.Insert(trie, "Ш", "Sh"); Trie.Insert(trie, "Щ", "Sh"); Trie.Insert(trie, "Ъ", ""); Trie.Insert(trie, "Ы", "Y"); Trie.Insert(trie, "Ь", ""); Trie.Insert(trie, "Э", "E"); Trie.Insert(trie, "Ю", "Yu"); Trie.Insert(trie, "Я", "Ya"); Trie.Insert(trie, "ђ", "dj"); Trie.Insert(trie, "ј", "j"); Trie.Insert(trie, "ћ", "c"); Trie.Insert(trie, "џ", "dz"); Trie.Insert(trie, "Ђ", "Dj"); Trie.Insert(trie, "Ј", "j"); Trie.Insert(trie, "Ћ", "C"); Trie.Insert(trie, "Џ", "Dz"); Trie.Insert(trie, "ľ", "l"); Trie.Insert(trie, "ĺ", "l"); Trie.Insert(trie, "ŕ", "r"); Trie.Insert(trie, "Ľ", "L"); Trie.Insert(trie, "Ĺ", "L"); Trie.Insert(trie, "Ŕ", "R"); Trie.Insert(trie, "ş", "s"); Trie.Insert(trie, "Ş", "S"); Trie.Insert(trie, "ı", "i"); Trie.Insert(trie, "İ", "I"); Trie.Insert(trie, "ğ", "g"); Trie.Insert(trie, "Ğ", "G"); Trie.Insert(trie, "ả", "a"); Trie.Insert(trie, "Ả", "A"); Trie.Insert(trie, "ẳ", "a"); Trie.Insert(trie, "Ẳ", "A"); Trie.Insert(trie, "ẩ", "a"); Trie.Insert(trie, "Ẩ", "A"); Trie.Insert(trie, "đ", "d"); Trie.Insert(trie, "Đ", "D"); Trie.Insert(trie, "ẹ", "e"); Trie.Insert(trie, "Ẹ", "E"); Trie.Insert(trie, "ẽ", "e"); Trie.Insert(trie, "Ẽ", "E"); Trie.Insert(trie, "ẻ", "e"); Trie.Insert(trie, "Ẻ", "E"); Trie.Insert(trie, "ế", "e"); Trie.Insert(trie, "Ế", "E"); Trie.Insert(trie, "ề", "e"); Trie.Insert(trie, "Ề", "E"); Trie.Insert(trie, "ệ", "e"); Trie.Insert(trie, "Ệ", "E"); Trie.Insert(trie, "ễ", "e"); Trie.Insert(trie, "Ễ", "E"); Trie.Insert(trie, "ể", "e"); Trie.Insert(trie, "Ể", "E"); Trie.Insert(trie, "ỏ", "o"); Trie.Insert(trie, "ọ", "o"); Trie.Insert(trie, "Ọ", "o"); Trie.Insert(trie, "ố", "o"); Trie.Insert(trie, "Ố", "O"); Trie.Insert(trie, "ồ", "o"); Trie.Insert(trie, "Ồ", "O"); Trie.Insert(trie, "ổ", "o"); Trie.Insert(trie, "Ổ", "O"); Trie.Insert(trie, "ộ", "o"); Trie.Insert(trie, "Ộ", "O"); Trie.Insert(trie, "ỗ", "o"); Trie.Insert(trie, "Ỗ", "O"); Trie.Insert(trie, "ơ", "o"); Trie.Insert(trie, "Ơ", "O"); Trie.Insert(trie, "ớ", "o"); Trie.Insert(trie, "Ớ", "O"); Trie.Insert(trie, "ờ", "o"); Trie.Insert(trie, "Ờ", "O"); Trie.Insert(trie, "ợ", "o"); Trie.Insert(trie, "Ợ", "O"); Trie.Insert(trie, "ỡ", "o"); Trie.Insert(trie, "Ỡ", "O"); Trie.Insert(trie, "Ở", "o"); Trie.Insert(trie, "ở", "o"); Trie.Insert(trie, "ị", "i"); Trie.Insert(trie, "Ị", "I"); Trie.Insert(trie, "ĩ", "i"); Trie.Insert(trie, "Ĩ", "I"); Trie.Insert(trie, "ỉ", "i"); Trie.Insert(trie, "Ỉ", "i"); Trie.Insert(trie, "ủ", "u"); Trie.Insert(trie, "Ủ", "U"); Trie.Insert(trie, "ụ", "u"); Trie.Insert(trie, "Ụ", "U"); Trie.Insert(trie, "ũ", "u"); Trie.Insert(trie, "Ũ", "U"); Trie.Insert(trie, "ư", "u"); Trie.Insert(trie, "Ư", "U"); Trie.Insert(trie, "ứ", "u"); Trie.Insert(trie, "Ứ", "U"); Trie.Insert(trie, "ừ", "u"); Trie.Insert(trie, "Ừ", "U"); Trie.Insert(trie, "ự", "u"); Trie.Insert(trie, "Ự", "U"); Trie.Insert(trie, "ữ", "u"); Trie.Insert(trie, "Ữ", "U"); Trie.Insert(trie, "ử", "u"); Trie.Insert(trie, "Ử", "ư"); Trie.Insert(trie, "ỷ", "y"); Trie.Insert(trie, "Ỷ", "y"); Trie.Insert(trie, "ỳ", "y"); Trie.Insert(trie, "Ỳ", "Y"); Trie.Insert(trie, "ỵ", "y"); Trie.Insert(trie, "Ỵ", "Y"); Trie.Insert(trie, "ỹ", "y"); Trie.Insert(trie, "Ỹ", "Y"); Trie.Insert(trie, "ạ", "a"); Trie.Insert(trie, "Ạ", "A"); Trie.Insert(trie, "ấ", "a"); Trie.Insert(trie, "Ấ", "A"); Trie.Insert(trie, "ầ", "a"); Trie.Insert(trie, "Ầ", "A"); Trie.Insert(trie, "ậ", "a"); Trie.Insert(trie, "Ậ", "A"); Trie.Insert(trie, "ẫ", "a"); Trie.Insert(trie, "Ẫ", "A"); Trie.Insert(trie, "ắ", "a"); Trie.Insert(trie, "Ắ", "A"); Trie.Insert(trie, "ằ", "a"); Trie.Insert(trie, "Ằ", "A"); Trie.Insert(trie, "ặ", "a"); Trie.Insert(trie, "Ặ", "A"); Trie.Insert(trie, "ẵ", "a"); Trie.Insert(trie, "Ẵ", "A"); Trie.Insert(trie, "⓪", "0"); Trie.Insert(trie, "①", "1"); Trie.Insert(trie, "②", "2"); Trie.Insert(trie, "③", "3"); Trie.Insert(trie, "④", "4"); Trie.Insert(trie, "⑤", "5"); Trie.Insert(trie, "⑥", "6"); Trie.Insert(trie, "⑦", "7"); Trie.Insert(trie, "⑧", "8"); Trie.Insert(trie, "⑨", "9"); Trie.Insert(trie, "⑩", "10"); Trie.Insert(trie, "⑪", "11"); Trie.Insert(trie, "⑫", "12"); Trie.Insert(trie, "⑬", "13"); Trie.Insert(trie, "⑭", "14"); Trie.Insert(trie, "⑮", "15"); Trie.Insert(trie, "⑯", "16"); Trie.Insert(trie, "⑰", "17"); Trie.Insert