Decompiled source of DiscordConnector v2.1.17

plugins/DiscordConnector.dll

Decompiled 4 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
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;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Timers;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DiscordConnector.Config;
using DiscordConnector.LeaderBoards;
using DiscordConnector.Records;
using HarmonyLib;
using LiteDB;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Valheim Discord Connector (games.nwest.valheim.discordconnector)")]
[assembly: AssemblyProduct("Valheim Discord Connector")]
[assembly: AssemblyCopyright("© 2024 Nicholas Westerhausen Repository at github: nwesterhausen/valheim-discordconnector")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.17.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DiscordConnector
{
	internal class ConfigWatcher
	{
		private static Regex watchedConfigFilesRegex = new Regex("discordconnector?[\\w\\-]*\\.cfg$");

		private static Regex configExtensionMatcherRegex = new Regex("discordconnector-(\\w+)\\.cfg$");

		private static DateTime lastChangeDetected;

		private static int DEBOUNCE_SECONDS = 10;

		private static Dictionary<string, string> _fileHashDictionary;

		public ConfigWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
			fileSystemWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite;
			fileSystemWatcher.Changed += OnChanged;
			fileSystemWatcher.Error += OnError;
			fileSystemWatcher.Path = Plugin.StaticConfig.configPath;
			fileSystemWatcher.Filter = "discordconnector*.cfg";
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.EnableRaisingEvents = true;
			Plugin.StaticLogger.LogInfo("File watcher loaded and watching for changes to configs.");
			_fileHashDictionary = new Dictionary<string, string>();
			PopulateHashDictionary();
			lastChangeDetected = DateTime.Now;
		}

		private void PopulateHashDictionary()
		{
			Task.Run(delegate
			{
				foreach (string item in from file in Directory.EnumerateFiles(Plugin.StaticConfig.configPath)
					where watchedConfigFilesRegex.IsMatch(file)
					select file)
				{
					string key = ConfigExtensionFromFilename(item);
					_fileHashDictionary.Add(key, Hashing.GetMD5Checksum(item));
				}
				Plugin.StaticLogger.LogDebug("Initialization of file hash dictionary completed.");
				Plugin.StaticLogger.LogDebug(string.Join(Environment.NewLine, _fileHashDictionary));
			});
		}

		private static string ConfigExtensionFromFilename(string filename)
		{
			string result = "main";
			Match match = configExtensionMatcherRegex.Match(filename);
			if (match.Success && match.Groups.Count > 1)
			{
				result = match.Groups[1].Value;
			}
			return result;
		}

		private static void OnChanged(object sender, FileSystemEventArgs e)
		{
			if (e.ChangeType == WatcherChangeTypes.Changed)
			{
				string text = ConfigExtensionFromFilename(e.FullPath);
				Plugin.StaticLogger.LogDebug("Detected change of " + text + " config file");
				string mD5Checksum = Hashing.GetMD5Checksum(e.FullPath);
				if (!_fileHashDictionary.ContainsKey(text))
				{
					Plugin.StaticLogger.LogWarning("Unexpectedly encountered unhashed config file!");
					Plugin.StaticLogger.LogDebug("Added " + text + " config to config hash dictionary.");
					_fileHashDictionary.Add(text, mD5Checksum);
				}
				else if (string.Equals(_fileHashDictionary[text], mD5Checksum))
				{
					Plugin.StaticLogger.LogDebug("Changes to file were determined to be inconsequential.");
				}
				else if (lastChangeDetected.AddSeconds(DEBOUNCE_SECONDS) > DateTime.Now)
				{
					Plugin.StaticLogger.LogDebug("Skipping config reload, within DEBOUNCE timing.");
				}
				else
				{
					Plugin.StaticConfig.ReloadConfig(text);
					lastChangeDetected = DateTime.Now;
				}
			}
		}

		private static void OnError(object sender, ErrorEventArgs e)
		{
			Plugin.StaticLogger.LogError(e.GetException().ToString());
		}
	}
	internal class PluginConfig
	{
		private MainConfig mainConfig;

		private MessagesConfig messagesConfig;

		private TogglesConfig togglesConfig;

		private VariableConfig variableConfig;

		private LeaderBoardConfig leaderBoardConfig;

		public readonly string configPath;

		private const string ConfigJsonFilename = "config-dump.json";

		internal static string[] ConfigExtensions = new string[5] { "messages", "variables", "leaderBoard", "toggles", "main" };

		public bool LaunchMessageEnabled => togglesConfig.LaunchMessageEnabled;

		public bool LoadedMessageEnabled => togglesConfig.LoadedMessageEnabled;

		public bool StopMessageEnabled => togglesConfig.StopMessageEnabled;

		public bool ShutdownMessageEnabled => togglesConfig.ShutdownMessageEnabled;

		public bool WorldSaveMessageEnabled => togglesConfig.WorldSaveMessageEnabled;

		public bool ChatShoutEnabled => togglesConfig.ChatShoutEnabled;

		public bool ChatPingEnabled => togglesConfig.ChatPingEnabled;

		public bool PlayerJoinMessageEnabled => togglesConfig.PlayerJoinMessageEnabled;

		public bool PlayerDeathMessageEnabled => togglesConfig.PlayerDeathMessageEnabled;

		public bool PlayerLeaveMessageEnabled => togglesConfig.PlayerLeaveMessageEnabled;

		public bool EventStartMessageEnabled => togglesConfig.EventStartMessageEnabled;

		public bool EventStopMessageEnabled => togglesConfig.EventStopMessageEnabled;

		public bool EventPausedMessageEnabled => togglesConfig.EventPausedMessageEnabled;

		public bool EventResumedMessageEnabled => togglesConfig.EventResumedMessageEnabled;

		public bool ChatShoutAllCaps => togglesConfig.ChatShoutAllCaps;

		public bool StatsDeathEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsDeathEnabled;
				}
				return false;
			}
		}

		public bool StatsJoinEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsJoinEnabled;
				}
				return false;
			}
		}

		public bool StatsLeaveEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsLeaveEnabled;
				}
				return false;
			}
		}

		public bool StatsPingEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsPingEnabled;
				}
				return false;
			}
		}

		public bool StatsShoutEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsShoutEnabled;
				}
				return false;
			}
		}

		public bool ChatPingPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.ChatPingPosEnabled;
				}
				return false;
			}
		}

		public bool ChatShoutPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.ChatShoutPosEnabled;
				}
				return false;
			}
		}

		public bool PlayerJoinPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.PlayerJoinPosEnabled;
				}
				return false;
			}
		}

		public bool PlayerDeathPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.PlayerDeathPosEnabled;
				}
				return false;
			}
		}

		public bool PlayerLeavePosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.PlayerLeavePosEnabled;
				}
				return false;
			}
		}

		public bool EventStartPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventStartPosEnabled;
				}
				return false;
			}
		}

		public bool EventStopPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventStopPosEnabled;
				}
				return false;
			}
		}

		public bool EventPausedPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventPausedPosEnabled;
				}
				return false;
			}
		}

		public bool EventResumedPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventResumedPosEnabled;
				}
				return false;
			}
		}

		public WebhookEntry PrimaryWebhook => mainConfig.PrimaryWebhook;

		public WebhookEntry SecondaryWebhook => mainConfig.SecondaryWebhook;

		public bool CollectStatsEnabled => mainConfig.CollectStatsEnabled;

		public bool DiscordEmbedsEnabled => mainConfig.DiscordEmbedsEnabled;

		public bool SendPositionsEnabled => mainConfig.SendPositionsEnabled;

		public bool AnnouncePlayerFirsts => mainConfig.AnnouncePlayerFirsts;

		public MainConfig.RetrievalDiscernmentMethods RecordRetrievalDiscernmentMethod => mainConfig.RecordRetrievalDiscernmentMethod;

		public List<string> MutedPlayers => mainConfig.MutedPlayers;

		public Regex MutedPlayersRegex => mainConfig.MutedPlayersRegex;

		public bool AllowNonPlayerShoutLogging => mainConfig.AllowNonPlayerShoutLogging;

		public string LaunchMessage => messagesConfig.LaunchMessage;

		public string LoadedMessage => messagesConfig.LoadedMessage;

		public string StopMessage => messagesConfig.StopMessage;

		public string ShutdownMessage => messagesConfig.ShutdownMessage;

		public string SaveMessage => messagesConfig.SaveMessage;

		public string JoinMessage => messagesConfig.JoinMessage;

		public string LeaveMessage => messagesConfig.LeaveMessage;

		public string DeathMessage => messagesConfig.DeathMessage;

		public string PingMessage => messagesConfig.PingMessage;

		public string ShoutMessage => messagesConfig.ShoutMessage;

		public string PlayerFirstDeathMessage => messagesConfig.PlayerFirstDeathMessage;

		public string PlayerFirstJoinMessage => messagesConfig.PlayerFirstJoinMessage;

		public string PlayerFirstLeaveMessage => messagesConfig.PlayerFirstLeaveMessage;

		public string PlayerFirstPingMessage => messagesConfig.PlayerFirstPingMessage;

		public string PlayerFirstShoutMessage => messagesConfig.PlayerFirstShoutMessage;

		public bool AnnouncePlayerFirstDeathEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstDeathEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstJoinEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstJoinEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstLeaveEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstLeaveEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstPingEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstPingEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstShoutEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstShoutEnabled;
				}
				return false;
			}
		}

		public string EventStartMessage => messagesConfig.EventStartMessage;

		public string EventStopMessage => messagesConfig.EventStopMessage;

		public string EventPausedMessage => messagesConfig.EventPausedMessage;

		public string EventResumedMessage => messagesConfig.EventResumedMessage;

		public string UserVariable => variableConfig.UserVariable;

		public string UserVariable1 => variableConfig.UserVariable1;

		public string UserVariable2 => variableConfig.UserVariable2;

		public string UserVariable3 => variableConfig.UserVariable3;

		public string UserVariable4 => variableConfig.UserVariable4;

		public string UserVariable5 => variableConfig.UserVariable5;

		public string UserVariable6 => variableConfig.UserVariable6;

		public string UserVariable7 => variableConfig.UserVariable7;

		public string UserVariable8 => variableConfig.UserVariable8;

		public string UserVariable9 => variableConfig.UserVariable9;

		public string PosVarFormat => variableConfig.PosVarFormat;

		public string AppendedPosFormat => variableConfig.AppendedPosFormat;

		public bool DebugEveryPlayerPosCheck => togglesConfig.DebugEveryPlayerPosCheck;

		public bool DebugEveryEventCheck => togglesConfig.DebugEveryEventCheck;

		public bool DebugEveryEventChange => togglesConfig.DebugEveryEventChange;

		public bool DebugHttpRequestResponse => togglesConfig.DebugHttpRequestResponse;

		public bool DebugDatabaseMethods => togglesConfig.DebugDatabaseMethods;

		public string LeaderBoardTopPlayerHeading => messagesConfig.LeaderBoardTopPlayerHeading;

		public string LeaderBoardBottomPlayersHeading => messagesConfig.LeaderBoardBottomPlayersHeading;

		public string LeaderBoardHighestHeading => messagesConfig.LeaderBoardHighestHeading;

		public string LeaderBoardLowestHeading => messagesConfig.LeaderBoardLowestHeading;

		public LeaderBoardConfigReference[] LeaderBoards => leaderBoardConfig.LeaderBoards;

		public ActivePlayersAnnouncementConfigValues ActivePlayersAnnouncement => leaderBoardConfig.ActivePlayersAnnouncement;

		internal void migrateConfigIfNeeded()
		{
			if (!Directory.Exists(configPath))
			{
				Directory.CreateDirectory(configPath);
			}
			string[] configExtensions = ConfigExtensions;
			foreach (string text in configExtensions)
			{
				string text2 = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector-" + text + ".cfg");
				string text3 = Path.Combine(configPath, "discordconnector-" + text + ".cfg");
				if (text.Equals("main"))
				{
					text2 = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector.cfg");
					text3 = Path.Combine(configPath, "discordconnector.cfg");
				}
				if (File.Exists(text2))
				{
					if (File.Exists(text3))
					{
						Plugin.StaticLogger.LogWarning("Expected to be moving " + text + " config from pre-2.1.0 location to new config location, but already exists!");
					}
					else
					{
						File.Move(text2, text3);
					}
				}
			}
		}

		public PluginConfig(ConfigFile config)
		{
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Expected O, but got Unknown
			configPath = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector");
			migrateConfigIfNeeded();
			string path = "discordconnector.cfg";
			string path2 = "discordconnector-" + MessagesConfig.ConfigExtension + ".cfg";
			string path3 = "discordconnector-" + TogglesConfig.ConfigExtension + ".cfg";
			string path4 = "discordconnector-" + VariableConfig.ConfigExtension + ".cfg";
			string text = "discordconnector-" + LeaderBoardConfig.ConfigExtension + ".cfg";
			string text2 = Path.Combine(configPath, path);
			string text3 = Path.Combine(configPath, path2);
			string text4 = Path.Combine(configPath, path3);
			string text5 = Path.Combine(configPath, path4);
			string text6 = Path.Combine(configPath, text);
			Plugin.StaticLogger.LogDebug("Main config: " + text2);
			Plugin.StaticLogger.LogDebug("Messages config: " + text3);
			Plugin.StaticLogger.LogDebug("Toggles config: " + text4);
			Plugin.StaticLogger.LogDebug("Variable config: " + text5);
			Plugin.StaticLogger.LogDebug("Leader board config: " + text);
			mainConfig = new MainConfig(new ConfigFile(text2, true));
			messagesConfig = new MessagesConfig(new ConfigFile(text3, true));
			togglesConfig = new TogglesConfig(new ConfigFile(text4, true));
			variableConfig = new VariableConfig(new ConfigFile(text5, true));
			leaderBoardConfig = new LeaderBoardConfig(new ConfigFile(text6, true));
			Plugin.StaticLogger.LogDebug("Configuration Loaded");
			Plugin.StaticLogger.LogDebug("Muted Players Regex pattern ('a^' is default for no matches): " + mainConfig.MutedPlayersRegex.ToString());
			DumpConfigAsJson();
		}

		public void ReloadConfig()
		{
			mainConfig.ReloadConfig();
			messagesConfig.ReloadConfig();
			togglesConfig.ReloadConfig();
			variableConfig.ReloadConfig();
			leaderBoardConfig.ReloadConfig();
		}

		public void ReloadConfig(string configExt)
		{
			switch (configExt)
			{
			case "main":
				mainConfig.ReloadConfig();
				break;
			case "messages":
				messagesConfig.ReloadConfig();
				break;
			case "toggles":
				togglesConfig.ReloadConfig();
				break;
			case "variables":
				variableConfig.ReloadConfig();
				break;
			case "leaderBoard":
				leaderBoardConfig.ReloadConfig();
				break;
			}
		}

		public void DumpConfigAsJson()
		{
			string jsonString = "{";
			jsonString = jsonString + "\"Config.Main\":" + mainConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.Messages\":" + messagesConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.Toggles\":" + togglesConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.Variables\":" + variableConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.LeaderBoard\":" + leaderBoardConfig.ConfigAsJson();
			jsonString += "}";
			Task.Run(delegate
			{
				File.WriteAllText(Path.Combine(configPath, "config-dump.json"), jsonString);
				Plugin.StaticLogger.LogDebug("Dumped configuration files to config-dump.json");
			});
		}
	}
	internal class DiscordApi
	{
		public static void SendMessage(Webhook.Event ev, string message, Vector3 pos)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.StaticConfig.DiscordEmbedsEnabled)
			{
				SendMessageWithFields(ev, message, new List<Tuple<string, string>> { Tuple.Create("Coordinates", MessageTransformer.FormatVector3AsPos(pos)) });
			}
			else
			{
				SendMessage(ev, message + " " + MessageTransformer.FormatAppendedPos(pos));
			}
		}

		public static void SendMessage(Webhook.Event ev, string message)
		{
			DiscordSimpleWebhook discordSimpleWebhook = new DiscordSimpleWebhook
			{
				content = message
			};
			try
			{
				string serializedJson = JsonConvert.SerializeObject((object)discordSimpleWebhook);
				SendSerializedJson(ev, serializedJson);
			}
			catch (Exception arg)
			{
				Plugin.StaticLogger.LogWarning($"Error serializing payload: {arg}");
			}
		}

		public static void SendMessageWithFields(Webhook.Event ev, string content = null, List<Tuple<string, string>> fields = null)
		{
			if (string.IsNullOrEmpty(content) && fields == null)
			{
				content = "Uh-oh! An unexpectedly empty message was sent!";
			}
			string text = "{";
			if (fields != null)
			{
				List<string> list = new List<string>();
				foreach (Tuple<string, string> field in fields)
				{
					try
					{
						list.Add(JsonConvert.SerializeObject((object)new DiscordField
						{
							name = field.Item1,
							value = field.Item2
						}));
					}
					catch (Exception arg)
					{
						Plugin.StaticLogger.LogWarning($"Error serializing field: {arg}");
					}
				}
				if (list.Count > 0)
				{
					text += "\"embeds\":[{\"fields\":[";
					text += string.Join(",", list.ToArray());
					text += "]}]";
					if (content != null)
					{
						text += ",";
					}
				}
			}
			if (content != null)
			{
				text = text + "\"content\":\"" + content + "\"";
			}
			text += "}";
			SendSerializedJson(ev, text);
		}

		private static void SendSerializedJson(Webhook.Event ev, string serializedJson)
		{
			Plugin.StaticLogger.LogDebug($"Trying webhook with payload: {serializedJson} (event: {ev})");
			if (ev == Webhook.Event.Other)
			{
				Plugin.StaticLogger.LogInfo("Dispatching webhook for 3rd party plugin (configured as 'Other' in WebHook config)");
			}
			if ((!string.IsNullOrEmpty(Plugin.StaticConfig.PrimaryWebhook.Url) || !string.IsNullOrEmpty(Plugin.StaticConfig.SecondaryWebhook.Url)) && !string.IsNullOrEmpty(serializedJson))
			{
				byte[] bytes = Encoding.UTF8.GetBytes(serializedJson);
				if (Plugin.StaticConfig.PrimaryWebhook.HasEvent(ev))
				{
					Plugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook");
					DispatchRequest(Plugin.StaticConfig.PrimaryWebhook, bytes);
				}
				if (Plugin.StaticConfig.SecondaryWebhook.HasEvent(ev))
				{
					Plugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook");
					DispatchRequest(Plugin.StaticConfig.SecondaryWebhook, bytes);
				}
			}
		}

		private static void DispatchRequest(WebhookEntry webhook, byte[] byteArray)
		{
			if (string.IsNullOrEmpty(webhook.Url))
			{
				Plugin.StaticLogger.LogDebug("Dispatch attempted with empty webhook - ignoring");
				return;
			}
			WebRequest request = WebRequest.Create(webhook.Url);
			request.Method = "POST";
			request.ContentType = "application/json";
			request.ContentLength = byteArray.Length;
			Task.Run(delegate
			{
				Stream requestStream = request.GetRequestStream();
				requestStream.Write(byteArray, 0, byteArray.Length);
				requestStream.Close();
				WebResponse response = request.GetResponse();
				if (Plugin.StaticConfig.DebugHttpRequestResponse)
				{
					Plugin.StaticLogger.LogDebug("Request Response Short Code: " + ((HttpWebResponse)response).StatusDescription);
				}
				using (requestStream = response.GetResponseStream())
				{
					string text = new StreamReader(requestStream).ReadToEnd();
					if (Plugin.StaticConfig.DebugHttpRequestResponse)
					{
						Plugin.StaticLogger.LogDebug("Full response: " + text);
					}
				}
				response.Close();
			}).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static void SendMessage(string message, Vector3 pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			SendMessage(Webhook.Event.Other, message, pos);
		}

		public static void SendMessage(string message)
		{
			SendMessage(Webhook.Event.Other, message);
		}

		public static void SendMessageWithFields(string content = null, List<Tuple<string, string>> fields = null)
		{
			SendMessageWithFields(Webhook.Event.Other, content, fields);
		}

		private static void SendSerializedJson(string serializedJson)
		{
			SendSerializedJson(Webhook.Event.Other, serializedJson);
		}
	}
	internal class DiscordSimpleWebhook
	{
		public string content { get; set; }
	}
	internal class DiscordComplexWebhook
	{
		public DiscordEmbed embeds { get; set; }
	}
	internal class DiscordEmbed
	{
		public string? title { get; set; }

		public string? description { get; set; }

		public List<DiscordField>? fields { get; set; }
	}
	internal class DiscordField
	{
		public string name { get; set; }

		public string value { get; set; }
	}
	internal class EventWatcher
	{
		private static class Status
		{
			public static bool HaveActiveEvent => RandEventSystem.HaveActiveEvent();

			public static RandomEvent Event
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return null;
					}
					return RandEventSystem.instance.GetCurrentRandomEvent();
				}
			}

			public static string Name
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return "";
					}
					return Event.m_name;
				}
			}

			public static float Duration
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return 0f;
					}
					return Event.m_duration;
				}
			}

			public static float Elapsed
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return 0f;
					}
					return Event.m_time;
				}
			}

			public static bool IsRunning
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return false;
					}
					return RandEventSystem.instance.IsAnyPlayerInEventArea(Event);
				}
			}

			public static Vector3 Pos
			{
				get
				{
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					//IL_0016: Unknown result type (might be due to invalid IL or missing references)
					if (!HaveActiveEvent)
					{
						return new Vector3(0f, 0f, 0f);
					}
					return Event.m_pos;
				}
			}

			public static string EndMessage
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return "";
					}
					return Localization.instance.Localize(Event.m_endMessage);
				}
			}

			public static string StartMessage
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return "";
					}
					return Localization.instance.Localize(Event.m_startMessage);
				}
			}

			public static string[] InvolvedPlayersList()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: 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)
				List<string> list = new List<string>();
				if (!HaveActiveEvent)
				{
					return list.ToArray();
				}
				foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
				{
					if (!player.m_publicPosition)
					{
						if (Plugin.StaticConfig.DebugEveryPlayerPosCheck)
						{
							Plugin.StaticLogger.LogDebug("Unable to check location for " + player.m_name + " because their location is not public.");
						}
					}
					else if (RandEventSystem.instance.IsInsideRandomEventArea(Event, player.m_position))
					{
						list.Add(player.m_name);
						if (Plugin.StaticConfig.DebugEveryPlayerPosCheck)
						{
							Plugin.StaticLogger.LogDebug($"{player.m_name} is at {player.m_position}");
						}
					}
				}
				return list.ToArray();
			}
		}

		private bool WasRunning;

		private bool HadActiveEvent;

		private float PreviousElapsed;

		private string PreviousEventStartMessage;

		private string PreviousEventEndMessage;

		private Vector3 PreviousEventPos;

		private Timer randEventTimer;

		public EventWatcher()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			WasRunning = false;
			HadActiveEvent = false;
			PreviousElapsed = 0f;
			PreviousEventStartMessage = "";
			PreviousEventEndMessage = "";
			PreviousEventPos = default(Vector3);
			randEventTimer = new Timer();
			randEventTimer.Elapsed += CheckRandomEvent;
			randEventTimer.Interval = 1000.0;
		}

		public void Activate()
		{
			randEventTimer.Start();
		}

		public void Dispose()
		{
			randEventTimer.Stop();
		}

		public void CheckRandomEvent(object sender, ElapsedEventArgs elapsedEventArgs)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			if (Status.HaveActiveEvent)
			{
				string message = $"Currently an event: {Status.HaveActiveEvent}. {Status.StartMessage} | {Status.EndMessage}" + Environment.NewLine + $"Event: {Status.Name} at {Status.Pos}. Status.IsRunning: {Status.IsRunning}. {Status.Elapsed} of {Status.Duration} seconds completed." + Environment.NewLine + $"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Involved Players: " + string.Join(",", Status.InvolvedPlayersList());
				if (Plugin.StaticConfig.DebugEveryEventCheck)
				{
					Plugin.StaticLogger.LogDebug(message);
				}
				if (Status.IsRunning)
				{
					if (!HadActiveEvent)
					{
						TriggerEventStart();
						if (Plugin.StaticConfig.DebugEveryEventChange)
						{
							Plugin.StaticLogger.LogDebug(message);
						}
					}
					if (HadActiveEvent && !WasRunning)
					{
						TriggerEventResumed();
						if (Plugin.StaticConfig.DebugEveryEventChange)
						{
							Plugin.StaticLogger.LogDebug(message);
						}
					}
				}
				else if (!HadActiveEvent || (HadActiveEvent && WasRunning))
				{
					TriggerEventPaused();
					if (Plugin.StaticConfig.DebugEveryEventChange)
					{
						Plugin.StaticLogger.LogDebug(message);
					}
				}
				if (Status.Pos != Vector3.zero)
				{
					PreviousEventStartMessage = Status.StartMessage;
					PreviousEventEndMessage = Status.EndMessage;
					PreviousEventPos = Status.Pos;
				}
			}
			else
			{
				if (Plugin.StaticConfig.DebugEveryEventCheck)
				{
					Plugin.StaticLogger.LogDebug($"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Event check ran, no current events (or world isn't loaded yet).");
				}
				if (HadActiveEvent)
				{
					TriggerEventStop();
					if (Plugin.StaticConfig.DebugEveryEventChange)
					{
						Plugin.StaticLogger.LogDebug("Event stopped!");
					}
				}
			}
			HadActiveEvent = Status.HaveActiveEvent;
			WasRunning = Status.IsRunning;
			PreviousElapsed = Status.Elapsed;
		}

		internal void TriggerEventStart()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.StaticConfig.EventStartMessageEnabled)
			{
				string text = MessageTransformer.FormatEventStartMessage(Plugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage);
				if (!Plugin.StaticConfig.EventStartPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventStart, text);
					return;
				}
				if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventStart, text, Status.Pos);
					return;
				}
				text = MessageTransformer.FormatEventStartMessage(Plugin.StaticConfig.EventResumedMessage, Status.EndMessage, Status.StartMessage, Status.Pos);
				DiscordApi.SendMessage(Webhook.Event.EventStart, text);
			}
		}

		internal void TriggerEventPaused()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.StaticConfig.EventPausedMessageEnabled)
			{
				string text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage);
				if (!Plugin.StaticConfig.EventPausedPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventPaused, text);
					return;
				}
				if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventPaused, text, Status.Pos);
					return;
				}
				text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage, Status.Pos);
				DiscordApi.SendMessage(Webhook.Event.EventPaused, text);
			}
		}

		internal void TriggerEventResumed()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.StaticConfig.EventResumedMessageEnabled)
			{
				string text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage);
				if (!Plugin.StaticConfig.EventResumedPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventResumed, text);
					return;
				}
				if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventResumed, text, Status.Pos);
					return;
				}
				text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage, Status.Pos);
				DiscordApi.SendMessage(Webhook.Event.EventResumed, text);
			}
		}

		internal void TriggerEventStop()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.StaticConfig.EventStopMessageEnabled)
			{
				string text = MessageTransformer.FormatEventEndMessage(Plugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage);
				if (!Plugin.StaticConfig.EventStopPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventStop, text);
					return;
				}
				if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventStop, text, PreviousEventPos);
					return;
				}
				text = MessageTransformer.FormatEventEndMessage(Plugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage, PreviousEventPos);
				DiscordApi.SendMessage(Webhook.Event.EventStop, text);
			}
		}
	}
	internal static class Handlers
	{
		public static HashSet<string> joinedPlayers = new HashSet<string>();

		public static void Join(ZNetPeer peer)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				Plugin.StaticLogger.LogDebug("Handler:Join - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerJoin;
			string text = peer.m_socket.GetHostName() ?? "";
			if (!joinedPlayers.Add(text))
			{
				Plugin.StaticLogger.LogDebug(text + " already exists in list of joined players.");
				if (((ZDOID)(ref peer.m_characterID)).ID != 0)
				{
					Death(peer);
				}
				return;
			}
			Plugin.StaticLogger.LogDebug($"Added player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) to joined player list.");
			string text2 = "";
			if (Plugin.StaticConfig.AnnouncePlayerFirstJoinEnabled && Plugin.StaticDatabase.CountOfRecordsByName("join", peer.m_playerName) == 0)
			{
				text2 = Plugin.StaticConfig.PlayerFirstJoinMessage;
				ev = Webhook.Event.PlayerFirstJoin;
			}
			else if (Plugin.StaticConfig.PlayerJoinMessageEnabled)
			{
				text2 = Plugin.StaticConfig.JoinMessage;
			}
			if (Plugin.StaticConfig.StatsJoinEnabled)
			{
				Plugin.StaticDatabase.InsertSimpleStatRecord("join", peer.m_playerName, text, peer.m_refPos);
			}
			if (!string.IsNullOrEmpty(text2))
			{
				FinalizeFormattingAndSend(peer, text, text2, Plugin.StaticConfig.PlayerJoinPosEnabled, ev);
			}
		}

		public static void Leave(ZNetPeer peer)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				Plugin.StaticLogger.LogDebug("Handler:Leave - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerLeave;
			string text = peer.m_socket.GetHostName() ?? "";
			if (!joinedPlayers.Remove(text))
			{
				Plugin.StaticLogger.LogDebug(text + " did not exist in the list of joined players!");
				return;
			}
			Plugin.StaticLogger.LogDebug($"Removed player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) from joined player list.");
			string text2 = "";
			if (Plugin.StaticConfig.AnnouncePlayerFirstLeaveEnabled && Plugin.StaticDatabase.CountOfRecordsByName("leave", peer.m_playerName) == 0)
			{
				text2 = Plugin.StaticConfig.PlayerFirstLeaveMessage;
				ev = Webhook.Event.PlayerFirstLeave;
			}
			else if (Plugin.StaticConfig.PlayerLeaveMessageEnabled)
			{
				text2 = Plugin.StaticConfig.LeaveMessage;
			}
			if (Plugin.StaticConfig.StatsLeaveEnabled)
			{
				Plugin.StaticDatabase.InsertSimpleStatRecord("leave", peer.m_playerName, text, peer.m_refPos);
			}
			if (!string.IsNullOrEmpty(text2))
			{
				FinalizeFormattingAndSend(peer, text, text2, Plugin.StaticConfig.PlayerLeavePosEnabled, ev);
			}
		}

		public static void Death(ZNetPeer peer)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				Plugin.StaticLogger.LogDebug("Handler:Death - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerDeath;
			string playerHostName = peer.m_socket.GetHostName() ?? "";
			string text = "";
			if (Plugin.StaticConfig.AnnouncePlayerFirstDeathEnabled && Plugin.StaticDatabase.CountOfRecordsByName("death", peer.m_playerName) == 0)
			{
				text = Plugin.StaticConfig.PlayerFirstDeathMessage;
				ev = Webhook.Event.PlayerFirstDeath;
			}
			else if (Plugin.StaticConfig.PlayerDeathMessageEnabled)
			{
				text = Plugin.StaticConfig.DeathMessage;
			}
			if (Plugin.StaticConfig.StatsDeathEnabled)
			{
				Plugin.StaticDatabase.InsertSimpleStatRecord("death", peer.m_playerName, playerHostName, peer.m_refPos);
			}
			if (!string.IsNullOrEmpty(text))
			{
				FinalizeFormattingAndSend(peer, playerHostName, text, Plugin.StaticConfig.PlayerDeathPosEnabled, ev);
			}
		}

		public static void Ping(ZNetPeer peer, Vector3 pos)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				Plugin.StaticLogger.LogDebug("Handler:Ping - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerPing;
			string playerHostName = peer.m_socket.GetHostName() ?? "";
			string text = "";
			if (Plugin.StaticConfig.AnnouncePlayerFirstPingEnabled && Plugin.StaticDatabase.CountOfRecordsByName("ping", peer.m_playerName) == 0)
			{
				text = Plugin.StaticConfig.PlayerFirstPingMessage;
				ev = Webhook.Event.PlayerFirstPing;
			}
			else if (Plugin.StaticConfig.ChatPingEnabled)
			{
				text = Plugin.StaticConfig.PingMessage;
			}
			if (Plugin.StaticConfig.StatsPingEnabled)
			{
				Plugin.StaticDatabase.InsertSimpleStatRecord("ping", peer.m_playerName, playerHostName, pos);
			}
			if (!string.IsNullOrEmpty(text))
			{
				FinalizeFormattingAndSend(peer, playerHostName, text, Plugin.StaticConfig.ChatPingPosEnabled, ev);
			}
		}

		public static void Shout(ZNetPeer peer, Vector3 pos, string text)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				Plugin.StaticLogger.LogDebug("Handler:Shout - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerShout;
			string playerHostName = peer.m_socket.GetHostName() ?? "";
			string text2 = "";
			if (Plugin.StaticConfig.AnnouncePlayerFirstShoutEnabled && Plugin.StaticDatabase.CountOfRecordsByName("shout", peer.m_playerName) == 0)
			{
				text2 = Plugin.StaticConfig.PlayerFirstShoutMessage;
				ev = Webhook.Event.PlayerFirstShout;
			}
			else if (Plugin.StaticConfig.ChatShoutEnabled)
			{
				text2 = Plugin.StaticConfig.ShoutMessage;
			}
			if (Plugin.StaticConfig.StatsShoutEnabled)
			{
				Plugin.StaticDatabase.InsertSimpleStatRecord("shout", peer.m_playerName, playerHostName, pos);
			}
			if (!string.IsNullOrEmpty(text2))
			{
				if (Plugin.StaticConfig.ChatShoutAllCaps)
				{
					text = text.ToUpper();
				}
				FinalizeFormattingAndSend(peer, playerHostName, text2, Plugin.StaticConfig.ChatShoutPosEnabled, pos, text, ev);
			}
		}

		private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Webhook.Event ev)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			FinalizeFormattingAndSend(peer, playerHostName, preFormattedMessage, posEnabled, peer.m_refPos, ev);
		}

		private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, Webhook.Event ev)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			string text;
			if (preFormattedMessage.Contains("%POS%"))
			{
				if (!posEnabled)
				{
					preFormattedMessage.Replace("%POS%", "");
				}
				text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, pos);
			}
			else
			{
				text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName);
			}
			if (posEnabled && (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")))
			{
				DiscordApi.SendMessage(ev, text, pos);
			}
			else
			{
				DiscordApi.SendMessage(ev, text);
			}
		}

		private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, string text, Webhook.Event ev)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			string text2;
			if (preFormattedMessage.Contains("%POS%"))
			{
				if (!posEnabled)
				{
					preFormattedMessage.Replace("%POS%", "");
				}
				text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text, pos);
			}
			else
			{
				text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text);
			}
			if (posEnabled && (Plugin.StaticConfig.DiscordEmbedsEnabled || !text2.Contains("%POS%")))
			{
				DiscordApi.SendMessage(ev, text2, pos);
			}
			else
			{
				DiscordApi.SendMessage(ev, text2);
			}
		}

		internal static void NonPlayerChat(Type type, string user, string text)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if (Plugin.StaticConfig.AllowNonPlayerShoutLogging)
			{
				if ((int)type != 2)
				{
					Plugin.StaticLogger.LogDebug("Ignored ping/join/leave from non-player " + user);
					return;
				}
				string playerId = "";
				Plugin.StaticLogger.LogDebug("Sending shout from '" + user + "' to discord: '" + text + "'");
				if (Plugin.StaticConfig.ChatShoutEnabled)
				{
					string playerName = MessageTransformer.CleanCaretFormatting(user);
					string text2 = MessageTransformer.FormatPlayerMessage(Plugin.StaticConfig.ShoutMessage, playerName, playerId, text);
					if (text2.Contains("%POS%"))
					{
						text2.Replace("%POS%", "");
					}
					DiscordApi.SendMessage(Webhook.Event.PlayerShout, text2);
				}
			}
			else
			{
				Plugin.StaticLogger.LogInfo("Ignored shout from " + user + " because they aren't a real player");
			}
		}
	}
	internal class LeaderBoard
	{
		private Base leaderBoard1;

		private Base leaderBoard2;

		private Base leaderBoard3;

		private Base leaderBoard4;

		private Base leaderBoard5;

		public static readonly int MAX_LEADER_BOARD_SIZE = 16;

		public Base LeaderBoard1 => leaderBoard1;

		public Base LeaderBoard2 => leaderBoard2;

		public Base LeaderBoard3 => leaderBoard3;

		public Base LeaderBoard4 => leaderBoard4;

		public Base LeaderBoard5 => leaderBoard5;

		public LeaderBoard()
		{
			leaderBoard1 = new Composer(0);
			leaderBoard2 = new Composer(1);
			leaderBoard3 = new Composer(2);
			leaderBoard4 = new Composer(3);
			leaderBoard5 = new Composer(4);
		}

		public static string RankedCountResultToString(List<CountResult> rankings)
		{
			string text = "";
			for (int i = 0; i < rankings.Count; i++)
			{
				text += $"{i + 1}: {rankings[i].Name}: {rankings[i].Count}{Environment.NewLine}";
			}
			return text;
		}
	}
	internal class VDCLogger
	{
		private static ManualLogSource _logger;

		private bool _logDebugMessages;

		public VDCLogger(ManualLogSource logger)
		{
			_logger = logger;
			_logger.LogInfo((object)"Logger initialized.");
		}

		internal void SetLogLevel(bool logDebugMessages)
		{
			_logDebugMessages = logDebugMessages;
		}

		public void LogDebug(string message)
		{
			_logger.LogDebug((object)message);
			if (_logDebugMessages)
			{
				_logger.LogInfo((object)message);
			}
		}

		public void LogInfo(string message)
		{
			_logger.LogInfo((object)message);
		}

		public void LogWarning(string message)
		{
			_logger.LogWarning((object)message);
		}

		public void LogError(string message)
		{
			_logger.LogError((object)message);
		}

		public void LogFatal(string message)
		{
			_logger.LogFatal((object)message);
		}
	}
	internal static class MessageTransformer
	{
		private const string PUBLIC_IP = "%PUBLICIP%";

		private const string VAR = "%VAR1%";

		private const string VAR_1 = "%VAR2%";

		private const string VAR_2 = "%VAR3%";

		private const string VAR_3 = "%VAR4%";

		private const string VAR_4 = "%VAR5%";

		private const string VAR_5 = "%VAR6%";

		private const string VAR_6 = "%VAR7%";

		private const string VAR_7 = "%VAR8%";

		private const string VAR_8 = "%VAR9%";

		private const string VAR_9 = "%VAR10%";

		private const string PLAYER_NAME = "%PLAYER_NAME%";

		private const string PLAYER_STEAMID = "%PLAYER_STEAMID%";

		private const string PLAYER_ID = "%PLAYER_ID%";

		private const string SHOUT = "%SHOUT%";

		private const string POS = "%POS%";

		private const string EVENT_START_MSG = "%EVENT_START_MSG%";

		private const string EVENT_END_MSG = "%EVENT_END_MSG%";

		private const string EVENT_MSG = "%EVENT_MSG%";

		private const string EVENT_PLAYERS = "%PLAYERS%";

		private const string N = "%N%";

		private const string WORLD_NAME = "%WORLD_NAME%";

		private static Regex OpenCaretRegex = new Regex("<[\\w=]+>");

		private static Regex CloseCaretRegex = new Regex("</[\\w]+>");

		private static string ReplaceVariables(string rawMessage)
		{
			return ReplaceDynamicVariables(rawMessage).Replace("%VAR1%", Plugin.StaticConfig.UserVariable).Replace("%VAR2%", Plugin.StaticConfig.UserVariable1).Replace("%VAR3%", Plugin.StaticConfig.UserVariable2)
				.Replace("%VAR4%", Plugin.StaticConfig.UserVariable3)
				.Replace("%VAR5%", Plugin.StaticConfig.UserVariable4)
				.Replace("%VAR6%", Plugin.StaticConfig.UserVariable5)
				.Replace("%VAR7%", Plugin.StaticConfig.UserVariable6)
				.Replace("%VAR8%", Plugin.StaticConfig.UserVariable7)
				.Replace("%VAR9%", Plugin.StaticConfig.UserVariable8)
				.Replace("%VAR10%", Plugin.StaticConfig.UserVariable9)
				.Replace("%PUBLICIP%", Plugin.PublicIpAddress);
		}

		private static string ReplaceDynamicVariables(string rawMessage)
		{
			string newValue = "";
			try
			{
				newValue = ZNet.instance.GetWorldName();
			}
			catch (Exception ex)
			{
				Plugin.StaticLogger.LogDebug("Unable to get World Name from ZNet. " + ex.Message);
			}
			return rawMessage.Replace("%WORLD_NAME%", newValue);
		}

		public static string FormatServerMessage(string rawMessage)
		{
			return ReplaceVariables(rawMessage);
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId)
		{
			return ReplaceVariables(rawMessage).Replace("%PLAYER_STEAMID%", playerId).Replace("%PLAYER_ID%", playerId).Replace("%PLAYER_NAME%", playerName);
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, Vector3 pos)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return FormatPlayerMessage(rawMessage, playerName, playerId).Replace("%POS%", $"{pos}");
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, string shout)
		{
			return FormatPlayerMessage(rawMessage, playerName, playerId).Replace("%SHOUT%", shout);
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerSteamId, string shout, Vector3 pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return FormatPlayerMessage(rawMessage, playerName, playerSteamId, pos).Replace("%SHOUT%", shout);
		}

		public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg)
		{
			return ReplaceVariables(rawMessage).Replace("%EVENT_START_MSG%", eventStartMsg).Replace("%EVENT_END_MSG%", eventEndMsg);
		}

		public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%POS%", $"{pos}");
		}

		public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg)
		{
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventStartMsg);
		}

		public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg)
		{
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventEndMsg);
		}

		public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventStartMsg);
		}

		public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventEndMsg);
		}

		public static string FormatLeaderBoardHeader(string rawMessage)
		{
			return ReplaceVariables(rawMessage);
		}

		public static string FormatLeaderBoardHeader(string rawMessage, int n)
		{
			return ReplaceVariables(rawMessage).Replace("%N%", n.ToString());
		}

		public static string CleanCaretFormatting(string str)
		{
			string input = OpenCaretRegex.Replace(str, "", 1);
			return CloseCaretRegex.Replace(input, "", 1);
		}

		public static string FormatVector3AsPos(Vector3 vec3)
		{
			return Plugin.StaticConfig.PosVarFormat.Replace("%X%", vec3.x.ToString("F1")).Replace("%Y%", vec3.y.ToString("F1")).Replace("%Z%", vec3.z.ToString("F1"));
		}

		public static string FormatAppendedPos(Vector3 vec3)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			string newValue = FormatVector3AsPos(vec3);
			return Plugin.StaticConfig.AppendedPosFormat.Replace("%POS%", newValue);
		}
	}
	[BepInPlugin("games.nwest.valheim.discordconnector", "Valheim Discord Connector", "2.1.17")]
	public class Plugin : BaseUnityPlugin
	{
		internal static VDCLogger StaticLogger;

		internal static PluginConfig StaticConfig;

		internal static Database StaticDatabase;

		internal static LeaderBoard StaticLeaderBoards;

		internal static EventWatcher StaticEventWatcher;

		internal static ConfigWatcher StaticConfigWatcher;

		private static string _publicIpAddress;

		private Harmony _harmony;

		internal static string PublicIpAddress
		{
			get
			{
				if (!string.IsNullOrEmpty(_publicIpAddress))
				{
					return _publicIpAddress;
				}
				_publicIpAddress = ZNet.GetPublicIP();
				return _publicIpAddress;
			}
		}

		public Plugin()
		{
			StaticLogger = new VDCLogger(((BaseUnityPlugin)this).Logger);
			StaticConfig = new PluginConfig(((BaseUnityPlugin)this).Config);
			StaticDatabase = new Database(Paths.GameRootPath);
			StaticLeaderBoards = new LeaderBoard();
			StaticConfigWatcher = new ConfigWatcher();
			_publicIpAddress = "";
		}

		private void Awake()
		{
			StaticLogger.LogDebug("Plugin games.nwest.valheim.discordconnector is loaded!");
			if (!IsHeadless())
			{
				StaticLogger.LogInfo("Not running on a dedicated server, some features may break -- please report them!");
			}
			else
			{
				StaticEventWatcher = new EventWatcher();
			}
			if (string.IsNullOrEmpty(StaticConfig.PrimaryWebhook.Url) && string.IsNullOrEmpty(StaticConfig.SecondaryWebhook.Url))
			{
				StaticLogger.LogWarning("No value set for WebHookURL! Plugin will run without using a main Discord webhook.");
			}
			if (StaticConfig.LeaderBoards[0].Enabled)
			{
				Timer timer = new Timer();
				timer.Elapsed += StaticLeaderBoards.LeaderBoard1.SendLeaderBoardOnTimer;
				timer.Interval = 60000 * StaticConfig.LeaderBoards[0].PeriodInMinutes;
				StaticLogger.LogInfo("Enabling LeaderBoard.1 timer with interval " + Strings.HumanReadableMs(timer.Interval));
				timer.Start();
			}
			if (StaticConfig.LeaderBoards[1].Enabled)
			{
				Timer timer2 = new Timer();
				timer2.Elapsed += StaticLeaderBoards.LeaderBoard2.SendLeaderBoardOnTimer;
				timer2.Interval = 60000 * StaticConfig.LeaderBoards[1].PeriodInMinutes;
				StaticLogger.LogInfo("Enabling LeaderBoard.2 timer with interval " + Strings.HumanReadableMs(timer2.Interval));
				timer2.Start();
			}
			if (StaticConfig.LeaderBoards[2].Enabled)
			{
				Timer timer3 = new Timer();
				timer3.Elapsed += StaticLeaderBoards.LeaderBoard3.SendLeaderBoardOnTimer;
				timer3.Interval = 60000 * StaticConfig.LeaderBoards[2].PeriodInMinutes;
				StaticLogger.LogInfo("Enabling LeaderBoard.3 timer with interval " + Strings.HumanReadableMs(timer3.Interval));
				timer3.Start();
			}
			if (StaticConfig.LeaderBoards[3].Enabled)
			{
				Timer timer4 = new Timer();
				timer4.Elapsed += StaticLeaderBoards.LeaderBoard4.SendLeaderBoardOnTimer;
				timer4.Interval = 60000 * StaticConfig.LeaderBoards[3].PeriodInMinutes;
				StaticLogger.LogInfo("Enabling LeaderBoard.4 timer with interval " + Strings.HumanReadableMs(timer4.Interval));
				timer4.Start();
			}
			if (StaticConfig.LeaderBoards[4].Enabled)
			{
				Timer timer5 = new Timer();
				timer5.Elapsed += StaticLeaderBoards.LeaderBoard4.SendLeaderBoardOnTimer;
				timer5.Interval = 60000 * StaticConfig.LeaderBoards[4].PeriodInMinutes;
				StaticLogger.LogInfo("Enabling LeaderBoard.5 timer with interval " + Strings.HumanReadableMs(timer5.Interval));
				timer5.Start();
			}
			if (StaticConfig.ActivePlayersAnnouncement.Enabled)
			{
				Timer timer6 = new Timer();
				timer6.Elapsed += ActivePlayersAnnouncement.SendOnTimer;
				timer6.Interval = 60000 * StaticConfig.ActivePlayersAnnouncement.PeriodInMinutes;
				StaticLogger.LogInfo("Enabling Player Activity announcement with interval " + Strings.HumanReadableMs(timer6.Interval));
				timer6.Start();
			}
			_harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "games.nwest.valheim.discordconnector");
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
			StaticDatabase.Dispose();
		}

		public static bool IsHeadless()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			return (int)SystemInfo.graphicsDeviceType == 4;
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_ID = "games.nwest.valheim.discordconnector";

		public const string PLUGIN_NAME = "Valheim Discord Connector";

		public const string PLUGIN_VERSION = "2.1.17";

		public const string PLUGIN_REPO_SHORT = "github: nwesterhausen/valheim-discordconnector";

		public const string PLUGIN_AUTHOR = "Nicholas Westerhausen";

		public const string SHORT_PLUGIN_ID = "discordconnector";
	}
	internal static class Hashing
	{
		public static string GetMD5Checksum(string filename)
		{
			using MD5 mD = MD5.Create();
			using FileStream inputStream = File.OpenRead(filename);
			return BitConverter.ToString(mD.ComputeHash(inputStream)).Replace("-", "");
		}
	}
	internal static class Strings
	{
		public static string HumanReadableMs(double ms)
		{
			TimeSpan timeSpan = TimeSpan.FromMilliseconds(ms);
			if (timeSpan.Milliseconds == timeSpan.Seconds && timeSpan.Seconds == 0)
			{
				return $"{timeSpan.Hours:D2}h:{timeSpan.Minutes:D2}m";
			}
			return $"{timeSpan.Hours:D2}h:{timeSpan.Minutes:D2}m:{timeSpan.Seconds:D2}s:{timeSpan.Milliseconds:D3}ms";
		}
	}
	public class Webhook
	{
		public enum Event
		{
			ServerLaunch,
			ServerStart,
			ServerStop,
			ServerShutdown,
			ServerSave,
			EventStart,
			EventPaused,
			EventResumed,
			EventStop,
			PlayerJoin,
			PlayerLeave,
			PlayerShout,
			PlayerPing,
			PlayerDeath,
			PlayerFirstJoin,
			PlayerFirstLeave,
			PlayerFirstShout,
			PlayerFirstPing,
			PlayerFirstDeath,
			ActivePlayers,
			Leaderboard1,
			Leaderboard2,
			Leaderboard3,
			Leaderboard4,
			Leaderboard5,
			ALL,
			ServerLifecycle,
			EventLifecycle,
			PlayerAll,
			PlayerFirstAll,
			LeaderboardsAll,
			None,
			Other,
			CronJob
		}

		public static Event StringToEvent(string eventToken)
		{
			switch (eventToken)
			{
			case "ALL":
				return Event.ALL;
			case "serverLifecycle":
				return Event.ServerLifecycle;
			case "eventLifecycle":
				return Event.EventLifecycle;
			case "playerAll":
				return Event.PlayerAll;
			case "playerFirstAll":
				return Event.PlayerFirstAll;
			case "leaderboardsAll":
				return Event.LeaderboardsAll;
			case "serverLaunch":
				return Event.ServerLaunch;
			case "serverStart":
				return Event.ServerStart;
			case "serverStop":
				return Event.ServerStop;
			case "serverShutdown":
				return Event.ServerShutdown;
			case "serverSave":
				return Event.ServerSave;
			case "eventStart":
				return Event.EventStart;
			case "eventPaused":
				return Event.EventPaused;
			case "eventResumed":
				return Event.EventResumed;
			case "eventStop":
				return Event.EventStop;
			case "playerJoin":
				return Event.PlayerJoin;
			case "playerLeave":
				return Event.PlayerLeave;
			case "playerShout":
				return Event.PlayerShout;
			case "playerPing":
				return Event.PlayerPing;
			case "playerDeath":
				return Event.PlayerDeath;
			case "playerFirstJoin":
				return Event.PlayerFirstJoin;
			case "playerFirstLeave":
				return Event.PlayerFirstLeave;
			case "playerFirstShout":
				return Event.PlayerFirstShout;
			case "playerFirstPing":
				return Event.PlayerFirstPing;
			case "playerFirstDeath":
				return Event.PlayerFirstDeath;
			case "activePlayers":
				return Event.ActivePlayers;
			case "leaderboard1":
				return Event.Leaderboard1;
			case "leaderboard2":
				return Event.Leaderboard2;
			case "leaderboard3":
				return Event.Leaderboard3;
			case "leaderboard4":
				return Event.Leaderboard4;
			case "leaderboard5":
				return Event.Leaderboard5;
			case "cronjob":
				return Event.CronJob;
			default:
				Plugin.StaticLogger.LogDebug("Unmatched event token '" + eventToken + "'");
				return Event.None;
			}
		}

		public static List<Event> StringToEventList(string configEntry)
		{
			if (string.IsNullOrEmpty(configEntry))
			{
				return new List<Event>();
			}
			string text = Regex.Replace(configEntry, "[^;\\w]", "");
			Plugin.StaticLogger.LogDebug("Webhooks: cleaned config entry '" + configEntry + "' => '" + text + "'");
			if (text.Equals("ALL"))
			{
				return new List<Event> { Event.ALL };
			}
			List<Event> list = new List<Event>();
			string[] array = text.Split(new char[1] { ';' });
			foreach (string eventToken in array)
			{
				list.Add(StringToEvent(eventToken));
			}
			foreach (Event item in list)
			{
				Plugin.StaticLogger.LogDebug($"Added {item} to list");
			}
			return list;
		}
	}
	internal class WebhookEntry
	{
		public string Url { get; set; }

		public List<Webhook.Event> FireOnEvents { get; set; }

		public WebhookEntry(string url, List<Webhook.Event> fireOnEvents)
		{
			if (string.IsNullOrEmpty(url))
			{
				Plugin.StaticLogger.LogDebug("Coerced null or empty webhook url to empty string. Ignoring event list.");
				Url = "";
				FireOnEvents = new List<Webhook.Event>();
				return;
			}
			Url = url;
			if (fireOnEvents == null || fireOnEvents.Count == 0)
			{
				Plugin.StaticLogger.LogDebug("Coerced null or empty webhook event list to empty list.");
				FireOnEvents = new List<Webhook.Event>();
			}
			else
			{
				FireOnEvents = fireOnEvents;
			}
		}

		internal bool HasEvent(Webhook.Event ev)
		{
			if (FireOnEvents.Count == 0)
			{
				return false;
			}
			if (FireOnEvents.Contains(Webhook.Event.ALL))
			{
				Plugin.StaticLogger.LogDebug("Webhook has 'ALL' enabled");
				return true;
			}
			if (FireOnEvents.Contains(Webhook.Event.PlayerAll))
			{
				Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of PlayerAll");
				if (ev == Webhook.Event.PlayerDeath || ev == Webhook.Event.PlayerJoin || ev == Webhook.Event.PlayerLeave || ev == Webhook.Event.PlayerPing || ev == Webhook.Event.PlayerShout)
				{
					return true;
				}
			}
			if (FireOnEvents.Contains(Webhook.Event.PlayerFirstAll))
			{
				Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of PlayerFirstAll");
				if (ev == Webhook.Event.PlayerFirstDeath || ev == Webhook.Event.PlayerFirstJoin || ev == Webhook.Event.PlayerFirstLeave || ev == Webhook.Event.PlayerFirstPing || ev == Webhook.Event.PlayerFirstShout)
				{
					return true;
				}
			}
			if (FireOnEvents.Contains(Webhook.Event.EventLifecycle))
			{
				Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of EventLifecycle");
				if (ev == Webhook.Event.EventStart || ev == Webhook.Event.EventStop || ev == Webhook.Event.EventResumed || ev == Webhook.Event.EventPaused)
				{
					return true;
				}
			}
			if (FireOnEvents.Contains(Webhook.Event.ServerLifecycle))
			{
				Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of ServerLifecycle");
				if (ev == Webhook.Event.ServerLaunch || ev == Webhook.Event.ServerShutdown || ev == Webhook.Event.ServerStart || ev == Webhook.Event.ServerStop)
				{
					return true;
				}
			}
			if (FireOnEvents.Contains(Webhook.Event.LeaderboardsAll))
			{
				Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of LeaderboardsAll");
				if (ev == Webhook.Event.ActivePlayers || ev == Webhook.Event.Leaderboard1 || ev == Webhook.Event.Leaderboard2 || ev == Webhook.Event.Leaderboard3 || ev == Webhook.Event.Leaderboard4 || ev == Webhook.Event.Leaderboard5)
				{
					return true;
				}
			}
			Plugin.StaticLogger.LogDebug($"Checking for exact match of {ev}");
			return FireOnEvents.Contains(ev);
		}
	}
}
namespace DiscordConnector.Records
{
	public class CountResult
	{
		public string Name { get; }

		public int Count { get; }

		[BsonCtor]
		public CountResult(string name, int count)
		{
			Name = name;
			Count = count;
		}

		public static int CompareByCount(CountResult cr1, CountResult cr2)
		{
			return cr1.Count.CompareTo(cr2.Count);
		}

		public static int CompareByName(CountResult cr1, CountResult cr2)
		{
			return cr1.Name.CompareTo(cr2.Name);
		}

		public static List<CountResult> ConvertFromBsonDocuments(List<BsonDocument> bsonDocuments)
		{
			List<CountResult> list = new List<CountResult>();
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"ConvertBsonDocumentCountToDotNet r={bsonDocuments.Count}");
			}
			foreach (BsonDocument bsonDocument in bsonDocuments)
			{
				if (bsonDocument.ContainsKey("Count"))
				{
					if (bsonDocument.ContainsKey("Name"))
					{
						list.Add(new CountResult(((BsonValue)bsonDocument)["Name"].AsString, ((BsonValue)bsonDocument)["Count"].AsInt32));
					}
					else if (bsonDocument.ContainsKey("NamePlayer"))
					{
						list.Add(new CountResult(((BsonValue)bsonDocument)["NamePlayer"]["Name"].AsString, ((BsonValue)bsonDocument)["Count"].AsInt32));
					}
					else if (bsonDocument.ContainsKey("Player") && !((BsonValue)bsonDocument)["Player"].IsNull)
					{
						list.Add(new CountResult(Plugin.StaticDatabase.GetLatestCharacterNameForPlayer(BsonValue.op_Implicit(((BsonValue)bsonDocument)["Player"])), ((BsonValue)bsonDocument)["Count"].AsInt32));
					}
				}
			}
			return list;
		}

		public override string ToString()
		{
			return $"{Name}: {Count}";
		}
	}
	public class PlayerToName
	{
		public ObjectId _id { get; }

		public string CharacterName { get; }

		public string PlayerId { get; }

		public DateTime InsertedDate { get; }

		public PlayerToName(string characterName, string playerHostName)
		{
			_id = ObjectId.NewObjectId();
			CharacterName = characterName;
			PlayerId = playerHostName;
			InsertedDate = DateTime.Now;
		}

		public override string ToString()
		{
			return CharacterName + " (" + PlayerId + ")";
		}
	}
	public class Position
	{
		public float x { get; }

		public float y { get; }

		public float z { get; }

		public Position()
		{
			x = 0f;
			y = 0f;
			z = 0f;
		}

		public Position(float _x, float _y, float _z)
		{
			x = _x;
			y = _y;
			z = _z;
		}

		public override string ToString()
		{
			return $"({x},{y},{z})";
		}
	}
	public class SimpleStat
	{
		public ObjectId StatId { get; }

		public string Name { get; }

		public DateTime Date { get; }

		public string PlayerId { get; }

		public Position Pos { get; }

		public SimpleStat(string name, string playerHostName)
		{
			StatId = ObjectId.NewObjectId();
			Name = name;
			PlayerId = playerHostName;
			Date = DateTime.Now;
			Pos = new Position();
		}

		public SimpleStat(string name, string playerHostName, float x, float y, float z)
		{
			StatId = ObjectId.NewObjectId();
			Name = name;
			PlayerId = playerHostName;
			Date = DateTime.Now;
			Pos = new Position(x, y, z);
		}

		[BsonCtor]
		public SimpleStat(ObjectId _id, string name, DateTime date, string playerHostName, Position pos)
		{
			StatId = _id;
			Name = name;
			Date = date;
			PlayerId = playerHostName;
			Pos = pos;
		}

		public override string ToString()
		{
			return $"{Date.ToShortDateString()} {Date.ToShortTimeString()}: {Name} ({PlayerId}) at {Pos}";
		}
	}
	internal class Database
	{
		private const string DB_NAME = "records.db";

		private static string DbPath;

		private LiteDatabase db;

		private ILiteCollection<SimpleStat> DeathCollection;

		private ILiteCollection<SimpleStat> JoinCollection;

		private ILiteCollection<SimpleStat> LeaveCollection;

		private ILiteCollection<SimpleStat> ShoutCollection;

		private ILiteCollection<SimpleStat> PingCollection;

		private ILiteCollection<PlayerToName> PlayerToNameCollection;

		public Database(string rootStorePath)
		{
			DbPath = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector", "records.db");
			string text = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector-records.db");
			if (File.Exists(text))
			{
				File.Move(text, DbPath);
			}
			Initialize();
		}

		public void Initialize()
		{
			Task.Run(delegate
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				try
				{
					db = new LiteDatabase(DbPath, (BsonMapper)null);
					Plugin.StaticLogger.LogDebug("LiteDB Connection Established to " + DbPath);
					DeathCollection = db.GetCollection<SimpleStat>("deaths", (BsonAutoId)10);
					JoinCollection = db.GetCollection<SimpleStat>("joins", (BsonAutoId)10);
					LeaveCollection = db.GetCollection<SimpleStat>("leaves", (BsonAutoId)10);
					ShoutCollection = db.GetCollection<SimpleStat>("shouts", (BsonAutoId)10);
					PingCollection = db.GetCollection<SimpleStat>("pings", (BsonAutoId)10);
					PlayerToNameCollection = db.GetCollection<PlayerToName>("player_name", (BsonAutoId)10);
					Task.Run(delegate
					{
						EnsureIndicesOnCollections();
						Plugin.StaticLogger.LogDebug("Created indices on database collections");
					}).ConfigureAwait(continueOnCapturedContext: false);
				}
				catch (IOException ex)
				{
					Plugin.StaticLogger.LogError("Unable to acquire un-shared access to " + DbPath);
					Plugin.StaticLogger.LogDebug(ex.ToString());
				}
			}).ConfigureAwait(continueOnCapturedContext: false);
		}

		private void EnsureIndicesOnCollections()
		{
			DeathCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false);
			DeathCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false);
			JoinCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false);
			JoinCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false);
			LeaveCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false);
			LeaveCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false);
			ShoutCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false);
			ShoutCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false);
			PingCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false);
			PingCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false);
			PlayerToNameCollection.EnsureIndex<string>((Expression<Func<PlayerToName, string>>)((PlayerToName x) => x.PlayerId), false);
			PlayerToNameCollection.EnsureIndex<string>((Expression<Func<PlayerToName, string>>)((PlayerToName x) => x.CharacterName), false);
		}

		public void Dispose()
		{
			Plugin.StaticLogger.LogDebug("Closing LiteDB connection");
			db.Dispose();
		}

		private void InsertSimpleStatRecord(ILiteCollection<SimpleStat> collection, string playerName, string playerHostName, Vector3 pos)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Task.Run(delegate
			{
				SimpleStat simpleStat = new SimpleStat(playerName, playerHostName, pos.x, pos.y, pos.z);
				collection.Insert(simpleStat);
			}).ConfigureAwait(continueOnCapturedContext: false);
		}

		private void EnsurePlayerNameRecorded(string characterName, string playerHostName)
		{
			Task.Run(delegate
			{
				if (!PlayerToNameCollection.Exists((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName) && x.CharacterName.Equals(characterName))))
				{
					if (PlayerToNameCollection.Exists((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName))))
					{
						Plugin.StaticLogger.LogDebug("Multiple characters from " + playerHostName + ", latest is " + characterName);
					}
					PlayerToName playerToName = new PlayerToName(characterName, playerHostName);
					PlayerToNameCollection.Insert(playerToName);
				}
			}).ConfigureAwait(continueOnCapturedContext: false);
		}

		private void InsertSimpleStatRecord(ILiteCollection<SimpleStat> collection, string playerName, string playerHostName)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			InsertSimpleStatRecord(collection, playerName, playerHostName, Vector3.zero);
		}

		public void InsertSimpleStatRecord(string key, string playerName, string playerHostName, Vector3 pos)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			switch (key)
			{
			case "death":
				InsertSimpleStatRecord(DeathCollection, playerName, playerHostName, pos);
				break;
			case "join":
				EnsurePlayerNameRecorded(playerName, playerHostName);
				InsertSimpleStatRecord(JoinCollection, playerName, playerHostName, pos);
				break;
			case "leave":
				InsertSimpleStatRecord(LeaveCollection, playerName, playerHostName, pos);
				break;
			case "ping":
				InsertSimpleStatRecord(PingCollection, playerName, playerHostName, pos);
				break;
			case "shout":
				InsertSimpleStatRecord(ShoutCollection, playerName, playerHostName, pos);
				break;
			default:
				Plugin.StaticLogger.LogDebug("InsertSimpleStatRecord, invalid key '" + key + "'");
				break;
			}
		}

		public void InsertSimpleStatRecord(string key, string playerName, string playerHostName)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			InsertSimpleStatRecord(key, playerName, playerHostName, Vector3.zero);
		}

		internal string GetLatestCharacterNameForPlayer(string playerHostName)
		{
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug("GetLatestNameForCharacterId " + playerHostName + " begin");
			}
			if (PlayerToNameCollection.Exists((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName))))
			{
				try
				{
					return ((ILiteQueryableResult<PlayerToName>)(object)PlayerToNameCollection.Query().Where((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName))).OrderByDescending<DateTime>((Expression<Func<PlayerToName, DateTime>>)((PlayerToName x) => x.InsertedDate))).First().CharacterName;
				}
				catch (InvalidOperationException)
				{
					Plugin.StaticLogger.LogWarning("Should have found " + playerHostName + " in player_name table but did not!");
				}
			}
			List<BsonDocument> list = JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId.Equals(playerHostName))).OrderByDescending(BsonExpression.op_Implicit("Date"))
				.Select(BsonExpression.op_Implicit("$.Name"))
				.ToList();
			if (list.Count == 0)
			{
				if (Plugin.StaticConfig.DebugDatabaseMethods)
				{
					Plugin.StaticLogger.LogDebug("GetLatestNameForCharacterId " + playerHostName + " result = NONE");
				}
				return "undefined";
			}
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"nameQuery has {list.Count} results");
			}
			BsonDocument result = list[0];
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"GetLatestNameForCharacterId {playerHostName} result = {result}");
			}
			Task.Run(delegate
			{
				EnsurePlayerNameRecorded(BsonValue.op_Implicit(((BsonValue)result)["Name"]), playerHostName);
			}).ConfigureAwait(continueOnCapturedContext: false);
			return ((BsonValue)result)["Name"].AsString;
		}

		public List<CountResult> CountAllRecordsGrouped(string key)
		{
			switch (key)
			{
			case "death":
				return CountAllRecordsGrouped(DeathCollection);
			case "join":
				return CountAllRecordsGrouped(JoinCollection);
			case "leave":
				return CountAllRecordsGrouped(LeaveCollection);
			case "ping":
				return CountAllRecordsGrouped(PingCollection);
			case "shout":
				return CountAllRecordsGrouped(ShoutCollection);
			case "time_online":
				return AllTimeOnlineRecordsGrouped();
			default:
				Plugin.StaticLogger.LogDebug("CountAllRecordsGrouped, invalid key '" + key + "'");
				return new List<CountResult>();
			}
		}

		private List<CountResult> AllTimeOnlineRecordsGrouped()
		{
			PlayerToName[] array = ((ILiteQueryableResult<PlayerToName>)(object)PlayerToNameCollection.Query()).ToArray();
			List<CountResult> list = new List<CountResult>();
			PlayerToName[] array2 = array;
			foreach (PlayerToName player in array2)
			{
				Tuple.Create(player.PlayerId, player.CharacterName);
				TimeSpan timeSpan = TimeSpan.FromSeconds(0.0);
				SimpleStat[] array3 = ((ILiteQueryableResult<SimpleStat>)(object)JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
				SimpleStat[] array4 = ((ILiteQueryableResult<SimpleStat>)(object)LeaveCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
				Plugin.StaticLogger.LogDebug($"{player.PlayerId} as {player.CharacterName} has {array3.Length} joins, {array4.Length}");
				int num = array3.Length - array4.Length;
				if (num > 1)
				{
					Plugin.StaticLogger.LogDebug($"{num} more joins than leaves, timeOnline likely to be very inaccurate");
				}
				int num2 = array3.Length - num;
				for (int j = 0; j < num2; j++)
				{
					DateTime date = array3[j].Date;
					TimeSpan ts = array4[j].Date.Subtract(date);
					timeSpan.Add(ts);
				}
				Plugin.StaticLogger.LogDebug(timeSpan.ToString() + " total online time.");
				list.Add(new CountResult(player.CharacterName, (int)timeSpan.TotalSeconds));
			}
			return list;
		}

		private List<CountResult> TimeOnlineRecordsWhereDate(DateTime startDate, DateTime endDate, bool inclusiveStart = true, bool inclusiveEnd = true)
		{
			PlayerToName[] array = ((ILiteQueryableResult<PlayerToName>)(object)PlayerToNameCollection.Query()).ToArray();
			List<CountResult> list = new List<CountResult>();
			PlayerToName[] array2 = array;
			foreach (PlayerToName player in array2)
			{
				Tuple.Create(player.PlayerId, player.CharacterName);
				TimeSpan timeSpan = TimeSpan.FromSeconds(0.0);
				SimpleStat[] array3;
				SimpleStat[] array4;
				if (inclusiveStart && inclusiveEnd)
				{
					array3 = ((ILiteQueryableResult<SimpleStat>)(object)JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year >= ((DateTime)startDate).Date.Year && x.Date.Month >= ((DateTime)startDate).Date.Month && x.Date.Day >= ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
					array4 = ((ILiteQueryableResult<SimpleStat>)(object)LeaveCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year >= ((DateTime)startDate).Date.Year && x.Date.Month >= ((DateTime)startDate).Date.Month && x.Date.Day >= ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
				}
				else if (inclusiveEnd)
				{
					array3 = ((ILiteQueryableResult<SimpleStat>)(object)JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
					array4 = ((ILiteQueryableResult<SimpleStat>)(object)LeaveCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
				}
				else if (inclusiveStart)
				{
					array3 = ((ILiteQueryableResult<SimpleStat>)(object)JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year >= ((DateTime)startDate).Date.Year && x.Date.Month >= ((DateTime)startDate).Date.Month && x.Date.Day >= ((DateTime)startDate).Date.Day && x.Date.Year < ((DateTime)endDate).Date.Year && x.Date.Month < ((DateTime)endDate).Date.Month && x.Date.Day < ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
					array4 = ((ILiteQueryableResult<SimpleStat>)(object)LeaveCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year >= ((DateTime)startDate).Date.Year && x.Date.Month >= ((DateTime)startDate).Date.Month && x.Date.Day >= ((DateTime)startDate).Date.Day && x.Date.Year < ((DateTime)endDate).Date.Year && x.Date.Month < ((DateTime)endDate).Date.Month && x.Date.Day < ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
				}
				else
				{
					array3 = ((ILiteQueryableResult<SimpleStat>)(object)JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year < ((DateTime)endDate).Date.Year && x.Date.Month < ((DateTime)endDate).Date.Month && x.Date.Day < ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
					array4 = ((ILiteQueryableResult<SimpleStat>)(object)LeaveCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year < ((DateTime)endDate).Date.Year && x.Date.Month < ((DateTime)endDate).Date.Month && x.Date.Day < ((DateTime)endDate).Date.Day)).Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId == player.PlayerId && x.Name == player.CharacterName))).ToArray();
				}
				Plugin.StaticLogger.LogDebug($"{player.PlayerId} as {player.CharacterName} has {array3.Length} joins, {array4.Length}");
				int num = array3.Length - array4.Length;
				if (num > 1)
				{
					Plugin.StaticLogger.LogDebug($"{num} more joins than leaves, timeOnline likely to be very inaccurate");
				}
				int num2 = array3.Length - num;
				for (int j = 0; j < num2; j++)
				{
					DateTime date = array3[j].Date;
					TimeSpan ts = array4[j].Date.Subtract(date);
					timeSpan.Add(ts);
				}
				Plugin.StaticLogger.LogDebug(timeSpan.ToString() + " total online time.");
				list.Add(new CountResult(player.CharacterName, (int)timeSpan.TotalSeconds));
			}
			return list;
		}

		public int CountOfRecordsByName(string key, string playerName)
		{
			if (!Plugin.StaticConfig.CollectStatsEnabled)
			{
				return -1;
			}
			switch (key)
			{
			case "death":
				return CountOfRecordsByName(DeathCollection, playerName);
			case "join":
				return CountOfRecordsByName(JoinCollection, playerName);
			case "leave":
				return CountOfRecordsByName(LeaveCollection, playerName);
			case "ping":
				return CountOfRecordsByName(PingCollection, playerName);
			case "shout":
				return CountOfRecordsByName(ShoutCollection, playerName);
			default:
				Plugin.StaticLogger.LogDebug("CountOfRecordsBySteamId, invalid key '" + key + "'");
				return -2;
			}
		}

		public List<CountResult> CountAllRecordsGrouped(string key, TimeRange timeRange)
		{
			if (timeRange == TimeRange.AllTime)
			{
				return CountAllRecordsGrouped(key);
			}
			Tuple<DateTime, DateTime> tuple = DateHelper.StartEndDatesForTimeRange(timeRange);
			return CountRecordsBetweenDatesGrouped(key, tuple.Item1, tuple.Item2);
		}

		internal List<CountResult> CountRecordsBetweenDatesGrouped(string key, DateTime startDate, DateTime endDate, bool inclusiveStart = true, bool inclusiveEnd = true)
		{
			switch (key)
			{
			case "death":
				return CountAllRecordsGroupsWhereDate(DeathCollection, startDate, endDate, inclusiveStart, inclusiveEnd);
			case "join":
				return CountAllRecordsGroupsWhereDate(JoinCollection, startDate, endDate, inclusiveStart, inclusiveEnd);
			case "leave":
				return CountAllRecordsGroupsWhereDate(LeaveCollection, startDate, endDate, inclusiveStart, inclusiveEnd);
			case "ping":
				return CountAllRecordsGroupsWhereDate(PingCollection, startDate, endDate, inclusiveStart, inclusiveEnd);
			case "shout":
				return CountAllRecordsGroupsWhereDate(ShoutCollection, startDate, endDate, inclusiveStart, inclusiveEnd);
			case "time_online":
				return TimeOnlineRecordsWhereDate(startDate, endDate, inclusiveStart, inclusiveEnd);
			default:
				Plugin.StaticLogger.LogDebug("CountTodaysRecordsGrouped, invalid key '" + key + "'");
				return new List<CountResult>();
			}
		}

		internal int CountOfRecordsByName(ILiteCollection<SimpleStat> collection, string playerName)
		{
			try
			{
				return ((ILiteQueryableResult<SimpleStat>)(object)collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Name.Equals(playerName)))).Count();
			}
			catch
			{
				Plugin.StaticLogger.LogDebug("Error when trying to find " + playerName + " to count!");
				return -3;
			}
		}

		internal List<CountResult> CountAllRecordsGrouped(ILiteCollection<SimpleStat> collection)
		{
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"CountAllRecordsGrouped {Plugin.StaticConfig.RecordRetrievalDiscernmentMethod}");
			}
			if (collection.Count() == 0)
			{
				if (Plugin.StaticConfig.DebugDatabaseMethods)
				{
					Plugin.StaticLogger.LogDebug("Collection is empty, skipping.");
				}
				return new List<CountResult>();
			}
			string text = "PlayerId";
			string text2 = "{Player: @Key, Count: Count(*)}";
			if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.NameAndPlayerId)
			{
				text = "{Name,PlayerId}";
				text2 = "{NamePlayer: @Key, Count: COUNT(*)}";
			}
			if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.Name)
			{
				text = "Name";
				text2 = "{Name: @Key, Count: Count(*)}";
			}
			List<CountResult> list = CountResult.ConvertFromBsonDocuments(collection.Query().GroupBy(BsonExpression.op_Implicit(text)).Select(BsonExpression.op_Implicit(text2))
				.ToList());
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"CountAllRecordsGrouped {list.Count} records returned");
			}
			return list;
		}

		internal List<CountResult> CountAllRecordsGroupsWhereDate(ILiteCollection<SimpleStat> collection, DateTime startDate, DateTime endDate, bool inclusiveStart = true, bool inclusiveEnd = true)
		{
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"CountAllRecordsGroupsWhereDate {Plugin.StaticConfig.RecordRetrievalDiscernmentMethod} {startDate} {endDate}");
			}
			if (collection.Count() == 0)
			{
				if (Plugin.StaticConfig.DebugDatabaseMethods)
				{
					Plugin.StaticLogger.LogDebug("Collection is empty, skipping.");
				}
				return new List<CountResult>();
			}
			string text = "PlayerId";
			string text2 = "{Player: @Key, Count: Count(*)}";
			if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.NameAndPlayerId)
			{
				text = "{Name,PlayerId}";
				text2 = "{NamePlayer: @Key, Count: COUNT(*)}";
			}
			if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.Name)
			{
				text = "Name";
				text2 = "{Name: @Key, Count: Count(*)}";
			}
			List<CountResult> list = ((inclusiveStart && inclusiveEnd) ? CountResult.ConvertFromBsonDocuments(collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year >= ((DateTime)startDate).Date.Year && x.Date.Month >= ((DateTime)startDate).Date.Month && x.Date.Day >= ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).GroupBy(BsonExpression.op_Implicit(text))
				.Select(BsonExpression.op_Implicit(text2))
				.ToList()) : (inclusiveEnd ? CountResult.ConvertFromBsonDocuments(collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).GroupBy(BsonExpression.op_Implicit(text))
				.Select(BsonExpression.op_Implicit(text2))
				.ToList()) : ((!inclusiveStart) ? CountResult.ConvertFromBsonDocuments(collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year < ((DateTime)endDate).Date.Year && x.Date.Month < ((DateTime)endDate).Date.Month && x.Date.Day < ((DateTime)endDate).Date.Day)).GroupBy(BsonExpression.op_Implicit(text))
				.Select(BsonExpression.op_Implicit(text2))
				.ToList()) : CountResult.ConvertFromBsonDocuments(collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year >= ((DateTime)startDate).Date.Year && x.Date.Month >= ((DateTime)startDate).Date.Month && x.Date.Day >= ((DateTime)startDate).Date.Day && x.Date.Year < ((DateTime)endDate).Date.Year && x.Date.Month < ((DateTime)endDate).Date.Month && x.Date.Day < ((DateTime)endDate).Date.Day)).GroupBy(BsonExpression.op_Implicit(text))
				.Select(BsonExpression.op_Implicit(text2))
				.ToList()))));
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"CountAllRecordsGroupsWhereDate {list.Count} records returned");
			}
			return list;
		}
	}
	public static class Categories
	{
		public const string Death = "death";

		public const string Join = "join";

		public const string Leave = "leave";

		public const string Ping = "ping";

		public const string Shout = "shout";

		public const string TimeOnline = "time_online";

		public static readonly string[] All = new string[6] { "death", "join", "leave", "ping", "shout", "time_online" };
	}
	public static class Helper
	{
		public static List<CountResult> TopNResultForCategory(string key, int n)
		{
			return TopNResultForCategory(key, n, DateHelper.DummyDateTime, DateHelper.DummyDateTime);
		}

		public static List<CountResult> TopNResultForCategory(string key, int n, DateTime startDate, DateTime endDate)
		{
			if (Array.IndexOf(Categories.All, key) == -1)
			{
				Plugin.StaticLogger.LogWarning($"Invalid key \"{key}\" when getting top {n} results.");
				Plugin.StaticLogger.LogDebug("Empty list returned because of invalid key.");
				return new List<CountResult>();
			}
			List<CountResult> list = ((!(startDate != DateHelper.DummyDateTime) || !(endDate != DateHelper.DummyDateTime)) ? Plugin.StaticDatabase.CountAllRecordsGrouped(key) : Plugin.StaticDatabase.CountRecordsBetweenDatesGrouped(key, startDate, endDate));
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"TopNResultForCategory {key} n={n}, results={list.Count}");
			}
			if (list.Count == 0)
			{
				return list;
			}
			list.Sort(CountResult.CompareByCount);
			list.Reverse();
			if (list.Count <= n)
			{
				return list;
			}
			return list.GetRange(0, n);
		}

		public static List<CountResult> BottomNResultForCategory(string key, int n)
		{
			return BottomNResultForCategory(key, n, DateHelper.DummyDateTime, DateHelper.DummyDateTime);
		}

		public static List<CountResult> BottomNResultForCategory(string key, int n, DateTime startDate, DateTime endDate)
		{
			if (Array.IndexOf(Categories.All, key) == -1)
			{
				Plugin.StaticLogger.LogWarning($"Invalid key \"{key}\" when getting bottom {n} results.");
				Plugin.StaticLogger.LogDebug("Empty list returned because of invalid key.");
				return new List<CountResult>();
			}
			List<CountResult> list = ((!(startDate != DateHelper.DummyDateTime) || !(endDate != DateHelper.DummyDateTime)) ? Plugin.StaticDatabase.CountAllRecordsGrouped(key) : Plugin.StaticDatabase.CountRecordsBetweenDatesGrouped(key, startDate, endDate));
			if (Plugin.StaticConfig.DebugDatabaseMethods)
			{
				Plugin.StaticLogger.LogDebug($"BottomNResultForCategory {key} n={n}, results={list.Count}");
			}
			if (list.Count == 0)
			{
				return list;
			}
			list.Sort(CountResult.CompareByCount);
			if (list.Count <= n)
			{
				return list;
			}
			return list.GetRange(0, n);
		}

		internal static int CountUniquePlayers(string key, TimeRange timeRange)
		{
			if (Array.IndexOf(Categories.All, key) == -1)
			{
				Plugin.StaticLogger.LogWarning("Invalid key \"" + key + "\" when getting total unique players.");
				Plugin.StaticLogger.LogDebug("Zero returned because of invalid key.");
				return 0;
			}
			if (timeRange == TimeRange.AllTime)
			{
				return Plugin.StaticDatabase.CountAllRecordsGrouped(key).Count;
			}
			Tuple<DateTime, DateTime> tuple = DateHelper.StartEndDatesForTimeRange(timeRange);
			return CountUniquePlayers(key, tuple.Item1, tuple.Item2);
		}

		internal static int CountUniquePlayers(string key, DateTime startDate, DateTime endDate)
		{
			if (Array.IndexOf(Categories.All, key) == -1)
			{
				Plugin.StaticLogger.LogWarning("Invalid key \"" + key + "\" when getting total unique players.");
				Plugin.StaticLogger.LogDebug("Zero returned because of invalid key.");
				return 0;
			}
			return Plugin.StaticDatabase.CountRecordsBetweenDatesGrouped(key, startDate, endDate).Count;
		}
	}
}
namespace DiscordConnector.Patches
{
	internal class ChatPatches
	{
		[HarmonyPatch(typeof(Chat), "OnNewChatMessage")]
		internal class OnNewChatMessage
		{
			private static void Prefix(ref GameObject go, ref long senderID, ref Vector3 pos, ref Type type, ref UserInfo user, ref string text, ref string senderNetworkUserId)
			{
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_0119: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Invalid comparison between Unknown and I4
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_011f: Invalid comparison between Unknown and I4
				//IL_014e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0183: Unknown result type (might be due to invalid IL or missing references)
				//IL_0123: Unknown result type (might be due to invalid IL or missing references)
				Plugin.StaticLogger.LogDebug("User details: name:" + user.Name + " gamerTag:" + user.Gamertag + " networkUserId:" + user.NetworkUserId + " DisplayName():" + user.GetDisplayName(user.NetworkUserId));
				string name = user.Name;
				if (string.IsNullOrEmpty(name))
				{
					Plugin.StaticLogger.LogInfo("Ignored shout from invalid user (null reference)");
					return;
				}
				if (Plugin.StaticConfig.MutedPlayers.IndexOf(name) >= 0 || Plugin.StaticConfig.MutedPlayersRegex.IsMatch(name))
				{
					Plugin.StaticLogger.LogInfo("Ignored shout from user on muted list. User: " + name + " Shout: " + text + ".");
					return;
				}
				ZNetPeer peerByPlayerName = ZNet.instance.GetPeerByPlayerName(name);
				if (peerByPlayerName == null || peerByPlayerName.m_socket == null)
				{
					Handlers.NonPlayerChat(type, name, text);
					return;
				}
				peerByPlayerName.m_socket.GetHostName();
				Type val = type;
				if ((int)val != 2)
				{
					if ((int)val == 3)
					{
						Handlers.Ping(peerByPlayerName, pos);
						return;
					}
					Plugin.StaticLogger.LogDebug($"Unmatched chat message. [{type}] {name}: {text} at {pos}");
				}
				else if (text.Equals("I have arrived!"))
				{
					if (!Plugin.IsHeadless())
					{
						Handlers.Join(peerByPlayerName);
					}
				}
				else
				{
					Handlers.Shout(peerByPlayerName, pos, text);
				}
			}
		}

		private const string ArrivalShout = "I have arrived!";
	}
	internal class RandEventPatches
	{
		[HarmonyPatch(typeof(RandomEvent), "OnActivate")]
		internal class OnActivate
		{
			private static void Prefix(ref RandomEvent __instance)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: 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_0098: 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_022f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0175: Unknown result type (might be due to invalid IL or missing references)
				//IL_0263: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
				bool active = __instance.m_active;
				float duration = __instance.m_duration;
				string name = __instance.m_name;
				float time = __instance.m_time;
				Vector3 pos = __instance.m_pos;
				Plugin.StaticLogger.LogDebug($"Random event OnActivate {name}: {active} for {duration} at {pos}. (time: {time})");
				List<string> list = new List<string>();
				foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
				{
					if (RandEventSystem.instance.IsInsideRandomEventArea(__instance, player.m_position))
					{
						list.Add(player.m_name);
					}
				}
				Plugin.StaticLogger.LogDebug("Involved players in event: " + string.Join(",", list.ToArray()));
				if (__instance.m_time > 0f)
				{
					if (Plugin.StaticConfig.EventResumedMessageEnabled)
					{
						string text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventResumedMessage, Localization.instance.Localize(__instance.m_endMessage), Localization.instance.Localize(__instance.m_startMessage));
						if (!Plugin.StaticConfig.EventResumedPosEnabled)
						{
							DiscordApi.SendMessage(Webhook.Event.EventResumed, text);
							return;
						}
						if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
						{
							DiscordApi.SendMessage(Webhook.Event.EventResumed, text, pos);
							return;
						}
						text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventResumedMessage, Localization.instance.Localize(__instance.m_endMessage), Localization.instance.Localize(__instance.m_startMessage), pos);
						DiscordApi.SendMessage(Webhook.Event.EventResumed, text);
					}
				}
				else if (Plugin.StaticConfig.EventStartMessageEnabled)
				{
					string text2 = MessageTransformer.FormatEventStartMessage(Plugin.StaticConfig.EventResumedMessage, Localization.instance.Localize(__instance.m_endMessage), Localization.instance.Localize(__instance.m_startMessage));
					if (!Plugin.StaticConfig.EventStartPosEnabled)
					{
						DiscordApi.SendMessage(Webhook.Event.EventStart, text2);
						return;
					}
					if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text2.Contains("%POS%"))
					{
						DiscordApi.SendMessage(Webhook.Event.EventStart, text2, pos);
						return;
					}
					text2 = MessageTransformer.FormatEventStartMessage(Plugin.StaticConfig.EventResumedMessage, Localization.instance.Localize(__instance.m_endMessage), Localization.instance.Localize(__instance.m_startMessage), pos);
					DiscordApi.SendMessage(Webhook.Event.EventStart, text2);
				}
			}
		}

		[HarmonyPatch(typeof(RandomEvent), "OnDeactivate")]
		internal class OnDeactivate
		{
			private static void Prefix(ref RandomEvent __instance, ref bool end)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_00

plugins/LiteDB.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.AccessControl;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using LiteDB.Engine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Maurício David")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("MIT")]
[assembly: AssemblyDescription("LiteDB - A lightweight embedded .NET NoSQL document store in a single datafile")]
[assembly: AssemblyFileVersion("5.0.17")]
[assembly: AssemblyInformationalVersion("5.0.17")]
[assembly: AssemblyProduct("LiteDB")]
[assembly: AssemblyTitle("LiteDB")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/mbdavid/LiteDB")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("5.0.17.0")]
[module: UnverifiableCode]
namespace LiteDB
{
	public sealed class LiteCollection<T> : ILiteCollection<T>
	{
		private readonly string _collection;

		private readonly ILiteEngine _engine;

		private readonly List<BsonExpression> _includes;

		private readonly BsonMapper _mapper;

		private readonly EntityMapper _entity;

		private readonly MemberMapper _id;

		private readonly BsonAutoId _autoId;

		public string Name => _collection;

		public BsonAutoId AutoId => _autoId;

		public EntityMapper EntityMapper => _entity;

		public int Count()
		{
			return Query().Count();
		}

		public int Count(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).Count();
		}

		public int Count(string predicate, BsonDocument parameters)
		{
			return Count(BsonExpression.Create(predicate, parameters));
		}

		public int Count(string predicate, params BsonValue[] args)
		{
			return Count(BsonExpression.Create(predicate, args));
		}

		public int Count(Expression<Func<T, bool>> predicate)
		{
			return Count(_mapper.GetExpression(predicate));
		}

		public int Count(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count();
		}

		public long LongCount()
		{
			return Query().LongCount();
		}

		public long LongCount(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).LongCount();
		}

		public long LongCount(string predicate, BsonDocument parameters)
		{
			return LongCount(BsonExpression.Create(predicate, parameters));
		}

		public long LongCount(string predicate, params BsonValue[] args)
		{
			return LongCount(BsonExpression.Create(predicate, args));
		}

		public long LongCount(Expression<Func<T, bool>> predicate)
		{
			return LongCount(_mapper.GetExpression(predicate));
		}

		public long LongCount(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count();
		}

		public bool Exists(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).Exists();
		}

		public bool Exists(string predicate, BsonDocument parameters)
		{
			return Exists(BsonExpression.Create(predicate, parameters));
		}

		public bool Exists(string predicate, params BsonValue[] args)
		{
			return Exists(BsonExpression.Create(predicate, args));
		}

		public bool Exists(Expression<Func<T, bool>> predicate)
		{
			return Exists(_mapper.GetExpression(predicate));
		}

		public bool Exists(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Exists();
		}

		public BsonValue Min(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonDocument bsonDocument = Query().OrderBy(keySelector).Select(keySelector).ToDocuments()
				.First();
			return bsonDocument[bsonDocument.Keys.First()];
		}

		public BsonValue Min()
		{
			return Min("_id");
		}

		public K Min<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			BsonValue value = Min(expression);
			return (K)_mapper.Deserialize(typeof(K), value);
		}

		public BsonValue Max(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonDocument bsonDocument = Query().OrderByDescending(keySelector).Select(keySelector).ToDocuments()
				.First();
			return bsonDocument[bsonDocument.Keys.First()];
		}

		public BsonValue Max()
		{
			return Max("_id");
		}

		public K Max<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			BsonValue value = Max(expression);
			return (K)_mapper.Deserialize(typeof(K), value);
		}

		public bool Delete(BsonValue id)
		{
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			return _engine.Delete(_collection, new BsonValue[1] { id }) == 1;
		}

		public int DeleteAll()
		{
			return _engine.DeleteMany(_collection, null);
		}

		public int DeleteMany(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return _engine.DeleteMany(_collection, predicate);
		}

		public int DeleteMany(string predicate, BsonDocument parameters)
		{
			return DeleteMany(BsonExpression.Create(predicate, parameters));
		}

		public int DeleteMany(string predicate, params BsonValue[] args)
		{
			return DeleteMany(BsonExpression.Create(predicate, args));
		}

		public int DeleteMany(Expression<Func<T, bool>> predicate)
		{
			return DeleteMany(_mapper.GetExpression(predicate));
		}

		public ILiteQueryable<T> Query()
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, new Query()).Include(_includes);
		}

		public IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Include(_includes).Where(predicate).Skip(skip)
				.Limit(limit)
				.ToEnumerable();
		}

		public IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue)
		{
			if (query == null)
			{
				throw new ArgumentNullException("query");
			}
			if (skip != 0)
			{
				query.Offset = skip;
			}
			if (limit != int.MaxValue)
			{
				query.Limit = limit;
			}
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).ToEnumerable();
		}

		public IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue)
		{
			return Find(_mapper.GetExpression(predicate), skip, limit);
		}

		public T FindById(BsonValue id)
		{
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			return Find(BsonExpression.Create("_id = @0", id)).FirstOrDefault();
		}

		public T FindOne(BsonExpression predicate)
		{
			return Find(predicate).FirstOrDefault();
		}

		public T FindOne(string predicate, BsonDocument parameters)
		{
			return FindOne(BsonExpression.Create(predicate, parameters));
		}

		public T FindOne(BsonExpression predicate, params BsonValue[] args)
		{
			return FindOne(BsonExpression.Create(predicate, args));
		}

		public T FindOne(Expression<Func<T, bool>> predicate)
		{
			return FindOne(_mapper.GetExpression(predicate));
		}

		public T FindOne(Query query)
		{
			return Find(query).FirstOrDefault();
		}

		public IEnumerable<T> FindAll()
		{
			return Query().Include(_includes).ToEnumerable();
		}

		public ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			return Include(expression);
		}

		public ILiteCollection<T> Include(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			LiteCollection<T> liteCollection = new LiteCollection<T>(_collection, _autoId, _engine, _mapper);
			liteCollection._includes.AddRange(_includes);
			liteCollection._includes.Add(keySelector);
			return liteCollection;
		}

		public bool EnsureIndex(string name, BsonExpression expression, bool unique = false)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			return _engine.EnsureIndex(_collection, name, expression, unique);
		}

		public bool EnsureIndex(BsonExpression expression, bool unique = false)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			string name = Regex.Replace(expression.Source, "[^a-z0-9]", "", RegexOptions.IgnoreCase | RegexOptions.Compiled);
			return EnsureIndex(name, expression, unique);
		}

		public bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false)
		{
			BsonExpression indexExpression = GetIndexExpression(keySelector);
			return EnsureIndex(indexExpression, unique);
		}

		public bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false)
		{
			BsonExpression indexExpression = GetIndexExpression(keySelector);
			return EnsureIndex(name, indexExpression, unique);
		}

		private BsonExpression GetIndexExpression<K>(Expression<Func<T, K>> keySelector)
		{
			BsonExpression bsonExpression = _mapper.GetIndexExpression(keySelector);
			if (typeof(K).IsEnumerable() && bsonExpression.IsScalar)
			{
				if (bsonExpression.Type != BsonExpressionType.Path)
				{
					throw new LiteException(0, "Expression `" + bsonExpression.Source + "` must return a enumerable expression");
				}
				bsonExpression = bsonExpression.Source + "[*]";
			}
			return bsonExpression;
		}

		public bool DropIndex(string name)
		{
			return _engine.DropIndex(_collection, name);
		}

		public BsonValue Insert(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bool flag = RemoveDocId(bsonDocument);
			_engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId);
			BsonValue bsonValue = bsonDocument["_id"];
			if (flag)
			{
				_id.Setter(entity, bsonValue.RawValue);
			}
			return bsonValue;
		}

		public void Insert(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			_engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId);
		}

		public int Insert(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Insert(_collection, GetBsonDocs(entities), _autoId);
		}

		[Obsolete("Use normal Insert()")]
		public int InsertBulk(IEnumerable<T> entities, int batchSize = 5000)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Insert(_collection, GetBsonDocs(entities), _autoId);
		}

		private IEnumerable<BsonDocument> GetBsonDocs(IEnumerable<T> documents)
		{
			foreach (T document in documents)
			{
				BsonDocument doc = _mapper.ToDocument(document);
				bool removed = RemoveDocId(doc);
				yield return doc;
				if (removed && _id != null)
				{
					_id.Setter(document, doc["_id"].RawValue);
				}
			}
		}

		private bool RemoveDocId(BsonDocument doc)
		{
			if (_id != null && doc.TryGetValue("_id", out var value) && ((_autoId == BsonAutoId.Int32 && value.IsInt32 && value.AsInt32 == 0) || (_autoId == BsonAutoId.ObjectId && (value.IsNull || (value.IsObjectId && value.AsObjectId == ObjectId.Empty))) || (_autoId == BsonAutoId.Guid && value.IsGuid && value.AsGuid == Guid.Empty) || (_autoId == BsonAutoId.Int64 && value.IsInt64 && value.AsInt64 == 0L)))
			{
				doc.Remove("_id");
				return true;
			}
			return false;
		}

		public bool Update(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0;
		}

		public bool Update(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0;
		}

		public int Update(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Update(_collection, entities.Select((T x) => _mapper.ToDocument(x)));
		}

		public int UpdateMany(BsonExpression transform, BsonExpression predicate)
		{
			if (transform == null)
			{
				throw new ArgumentNullException("transform");
			}
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			if (transform.Type != BsonExpressionType.Document)
			{
				throw new ArgumentException("Extend expression must return a document. Eg: `col.UpdateMany('{ Name: UPPER(Name) }', 'Age > 10')`");
			}
			return _engine.UpdateMany(_collection, transform, predicate);
		}

		public int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate)
		{
			if (extend == null)
			{
				throw new ArgumentNullException("extend");
			}
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			BsonExpression expression = _mapper.GetExpression(extend);
			BsonExpression expression2 = _mapper.GetExpression(predicate);
			if (expression.Type != BsonExpressionType.Document)
			{
				throw new ArgumentException("Extend expression must return an anonymous class to be merge with entities. Eg: `col.UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10)`");
			}
			return _engine.UpdateMany(_collection, expression, expression2);
		}

		public bool Upsert(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			return Upsert(new T[1] { entity }) == 1;
		}

		public int Upsert(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Upsert(_collection, GetBsonDocs(entities), _autoId);
		}

		public bool Upsert(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			return _engine.Upsert(_collection, new BsonDocument[1] { bsonDocument }, _autoId) > 0;
		}

		internal LiteCollection(string name, BsonAutoId autoId, ILiteEngine engine, BsonMapper mapper)
		{
			_collection = name ?? mapper.ResolveCollectionName(typeof(T));
			_engine = engine;
			_mapper = mapper;
			_includes = new List<BsonExpression>();
			if (typeof(T) == typeof(BsonDocument))
			{
				_entity = null;
				_id = null;
				_autoId = autoId;
				return;
			}
			_entity = mapper.GetEntityMapper(typeof(T));
			_id = _entity.Id;
			if (_id != null && _id.AutoId)
			{
				_autoId = ((_id.DataType == typeof(int) || _id.DataType == typeof(int?)) ? BsonAutoId.Int32 : ((_id.DataType == typeof(long) || _id.DataType == typeof(long?)) ? BsonAutoId.Int64 : ((_id.DataType == typeof(Guid) || _id.DataType == typeof(Guid?)) ? BsonAutoId.Guid : BsonAutoId.ObjectId)));
			}
			else
			{
				_autoId = autoId;
			}
		}
	}
	public interface ILiteCollection<T>
	{
		string Name { get; }

		BsonAutoId AutoId { get; }

		EntityMapper EntityMapper { get; }

		ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector);

		ILiteCollection<T> Include(BsonExpression keySelector);

		bool Upsert(T entity);

		int Upsert(IEnumerable<T> entities);

		bool Upsert(BsonValue id, T entity);

		bool Update(T entity);

		bool Update(BsonValue id, T entity);

		int Update(IEnumerable<T> entities);

		int UpdateMany(BsonExpression transform, BsonExpression predicate);

		int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate);

		BsonValue Insert(T entity);

		void Insert(BsonValue id, T entity);

		int Insert(IEnumerable<T> entities);

		int InsertBulk(IEnumerable<T> entities, int batchSize = 5000);

		bool EnsureIndex(string name, BsonExpression expression, bool unique = false);

		bool EnsureIndex(BsonExpression expression, bool unique = false);

		bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false);

		bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false);

		bool DropIndex(string name);

		ILiteQueryable<T> Query();

		IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue);

		IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue);

		IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue);

		T FindById(BsonValue id);

		T FindOne(BsonExpression predicate);

		T FindOne(string predicate, BsonDocument parameters);

		T FindOne(BsonExpression predicate, params BsonValue[] args);

		T FindOne(Expression<Func<T, bool>> predicate);

		T FindOne(Query query);

		IEnumerable<T> FindAll();

		bool Delete(BsonValue id);

		int DeleteAll();

		int DeleteMany(BsonExpression predicate);

		int DeleteMany(string predicate, BsonDocument parameters);

		int DeleteMany(string predicate, params BsonValue[] args);

		int DeleteMany(Expression<Func<T, bool>> predicate);

		int Count();

		int Count(BsonExpression predicate);

		int Count(string predicate, BsonDocument parameters);

		int Count(string predicate, params BsonValue[] args);

		int Count(Expression<Func<T, bool>> predicate);

		int Count(Query query);

		long LongCount();

		long LongCount(BsonExpression predicate);

		long LongCount(string predicate, BsonDocument parameters);

		long LongCount(string predicate, params BsonValue[] args);

		long LongCount(Expression<Func<T, bool>> predicate);

		long LongCount(Query query);

		bool Exists(BsonExpression predicate);

		bool Exists(string predicate, BsonDocument parameters);

		bool Exists(string predicate, params BsonValue[] args);

		bool Exists(Expression<Func<T, bool>> predicate);

		bool Exists(Query query);

		BsonValue Min(BsonExpression keySelector);

		BsonValue Min();

		K Min<K>(Expression<Func<T, K>> keySelector);

		BsonValue Max(BsonExpression keySelector);

		BsonValue Max();

		K Max<K>(Expression<Func<T, K>> keySelector);
	}
	public interface ILiteDatabase : IDisposable
	{
		BsonMapper Mapper { get; }

		ILiteStorage<string> FileStorage { get; }

		int UserVersion { get; set; }

		TimeSpan Timeout { get; set; }

		bool UtcDate { get; set; }

		long LimitSize { get; set; }

		int CheckpointSize { get; set; }

		Collation Collation { get; }

		ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId);

		ILiteCollection<T> GetCollection<T>();

		ILiteCollection<T> GetCollection<T>(BsonAutoId autoId);

		ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId);

		bool BeginTrans();

		bool Commit();

		bool Rollback();

		ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks");

		IEnumerable<string> GetCollectionNames();

		bool CollectionExists(string name);

		bool DropCollection(string name);

		bool RenameCollection(string oldName, string newName);

		IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null);

		IBsonDataReader Execute(string command, BsonDocument parameters = null);

		IBsonDataReader Execute(string command, params BsonValue[] args);

		void Checkpoint();

		long Rebuild(RebuildOptions options = null);

		BsonValue Pragma(string name);

		BsonValue Pragma(string name, BsonValue value);
	}
	public interface ILiteQueryable<T> : ILiteQueryableResult<T>
	{
		ILiteQueryable<T> Include(BsonExpression path);

		ILiteQueryable<T> Include(List<BsonExpression> paths);

		ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path);

		ILiteQueryable<T> Where(BsonExpression predicate);

		ILiteQueryable<T> Where(string predicate, BsonDocument parameters);

		ILiteQueryable<T> Where(string predicate, params BsonValue[] args);

		ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate);

		ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1);

		ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1);

		ILiteQueryable<T> OrderByDescending(BsonExpression keySelector);

		ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector);

		ILiteQueryable<T> GroupBy(BsonExpression keySelector);

		ILiteQueryable<T> Having(BsonExpression predicate);

		ILiteQueryableResult<BsonDocument> Select(BsonExpression selector);

		ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector);
	}
	public interface ILiteQueryableResult<T>
	{
		ILiteQueryableResult<T> Limit(int limit);

		ILiteQueryableResult<T> Skip(int offset);

		ILiteQueryableResult<T> Offset(int offset);

		ILiteQueryableResult<T> ForUpdate();

		BsonDocument GetPlan();

		IBsonDataReader ExecuteReader();

		IEnumerable<BsonDocument> ToDocuments();

		IEnumerable<T> ToEnumerable();

		List<T> ToList();

		T[] ToArray();

		int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId);

		T First();

		T FirstOrDefault();

		T Single();

		T SingleOrDefault();

		int Count();

		long LongCount();

		bool Exists();
	}
	public interface ILiteRepository : IDisposable
	{
		ILiteDatabase Database { get; }

		BsonValue Insert<T>(T entity, string collectionName = null);

		int Insert<T>(IEnumerable<T> entities, string collectionName = null);

		bool Update<T>(T entity, string collectionName = null);

		int Update<T>(IEnumerable<T> entities, string collectionName = null);

		bool Upsert<T>(T entity, string collectionName = null);

		int Upsert<T>(IEnumerable<T> entities, string collectionName = null);

		bool Delete<T>(BsonValue id, string collectionName = null);

		int DeleteMany<T>(BsonExpression predicate, string collectionName = null);

		int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		ILiteQueryable<T> Query<T>(string collectionName = null);

		bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null);

		bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null);

		bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null);

		bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null);

		T SingleById<T>(BsonValue id, string collectionName = null);

		List<T> Fetch<T>(BsonExpression predicate, string collectionName = null);

		List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T First<T>(BsonExpression predicate, string collectionName = null);

		T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null);

		T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T Single<T>(BsonExpression predicate, string collectionName = null);

		T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null);

		T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null);
	}
	public class LiteDatabase : ILiteDatabase, IDisposable
	{
		private readonly ILiteEngine _engine;

		private readonly BsonMapper _mapper;

		private readonly bool _disposeOnClose;

		private ILiteStorage<string> _fs;

		public BsonMapper Mapper => _mapper;

		public ILiteStorage<string> FileStorage => _fs ?? (_fs = GetStorage<string>());

		public int UserVersion
		{
			get
			{
				return _engine.Pragma("USER_VERSION");
			}
			set
			{
				_engine.Pragma("USER_VERSION", value);
			}
		}

		public TimeSpan Timeout
		{
			get
			{
				return TimeSpan.FromSeconds(_engine.Pragma("TIMEOUT").AsInt32);
			}
			set
			{
				_engine.Pragma("TIMEOUT", (int)value.TotalSeconds);
			}
		}

		public bool UtcDate
		{
			get
			{
				return _engine.Pragma("UTC_DATE");
			}
			set
			{
				_engine.Pragma("UTC_DATE", value);
			}
		}

		public long LimitSize
		{
			get
			{
				return _engine.Pragma("LIMIT_SIZE");
			}
			set
			{
				_engine.Pragma("LIMIT_SIZE", value);
			}
		}

		public int CheckpointSize
		{
			get
			{
				return _engine.Pragma("CHECKPOINT");
			}
			set
			{
				_engine.Pragma("CHECKPOINT", value);
			}
		}

		public Collation Collation => new Collation(_engine.Pragma("COLLATION").AsString);

		public LiteDatabase(string connectionString, BsonMapper mapper = null)
			: this(new ConnectionString(connectionString), mapper)
		{
		}

		public LiteDatabase(ConnectionString connectionString, BsonMapper mapper = null)
		{
			if (connectionString == null)
			{
				throw new ArgumentNullException("connectionString");
			}
			if (connectionString.Upgrade)
			{
				LiteEngine.Upgrade(connectionString.Filename, connectionString.Password, connectionString.Collation);
			}
			_engine = connectionString.CreateEngine();
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = true;
		}

		public LiteDatabase(Stream stream, BsonMapper mapper = null, Stream logStream = null)
		{
			EngineSettings settings = new EngineSettings
			{
				DataStream = (stream ?? throw new ArgumentNullException("stream")),
				LogStream = logStream
			};
			_engine = new LiteEngine(settings);
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = true;
		}

		public LiteDatabase(ILiteEngine engine, BsonMapper mapper = null, bool disposeOnClose = true)
		{
			_engine = engine ?? throw new ArgumentNullException("engine");
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = disposeOnClose;
		}

		public ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			return new LiteCollection<T>(name, autoId, _engine, _mapper);
		}

		public ILiteCollection<T> GetCollection<T>()
		{
			return GetCollection<T>(null);
		}

		public ILiteCollection<T> GetCollection<T>(BsonAutoId autoId)
		{
			return GetCollection<T>(null, autoId);
		}

		public ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return new LiteCollection<BsonDocument>(name, autoId, _engine, _mapper);
		}

		public bool BeginTrans()
		{
			return _engine.BeginTrans();
		}

		public bool Commit()
		{
			return _engine.Commit();
		}

		public bool Rollback()
		{
			return _engine.Rollback();
		}

		public ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks")
		{
			return new LiteStorage<TFileId>(this, filesCollection, chunksCollection);
		}

		public IEnumerable<string> GetCollectionNames()
		{
			return (from x in GetCollection("$cols").Query().Where("type = 'user'").ToDocuments()
				select x["name"].AsString).ToArray();
		}

		public bool CollectionExists(string name)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return GetCollectionNames().Contains<string>(name, StringComparer.OrdinalIgnoreCase);
		}

		public bool DropCollection(string name)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return _engine.DropCollection(name);
		}

		public bool RenameCollection(string oldName, string newName)
		{
			if (oldName.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("oldName");
			}
			if (newName.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("newName");
			}
			return _engine.RenameCollection(oldName, newName);
		}

		public IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null)
		{
			if (commandReader == null)
			{
				throw new ArgumentNullException("commandReader");
			}
			Tokenizer tokenizer = new Tokenizer(commandReader);
			return new SqlParser(_engine, tokenizer, parameters).Execute();
		}

		public IBsonDataReader Execute(string command, BsonDocument parameters = null)
		{
			if (command == null)
			{
				throw new ArgumentNullException("command");
			}
			Tokenizer tokenizer = new Tokenizer(command);
			return new SqlParser(_engine, tokenizer, parameters).Execute();
		}

		public IBsonDataReader Execute(string command, params BsonValue[] args)
		{
			BsonDocument bsonDocument = new BsonDocument();
			int num = 0;
			foreach (BsonValue value in args)
			{
				bsonDocument[num.ToString()] = value;
				num++;
			}
			return Execute(command, bsonDocument);
		}

		public void Checkpoint()
		{
			_engine.Checkpoint();
		}

		public long Rebuild(RebuildOptions options = null)
		{
			return _engine.Rebuild(options);
		}

		public BsonValue Pragma(string name)
		{
			return _engine.Pragma(name);
		}

		public BsonValue Pragma(string name, BsonValue value)
		{
			return _engine.Pragma(name, value);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		~LiteDatabase()
		{
			Dispose(disposing: false);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing && _disposeOnClose)
			{
				_engine.Dispose();
			}
		}
	}
	public class LiteQueryable<T> : ILiteQueryable<T>, ILiteQueryableResult<T>
	{
		protected readonly ILiteEngine _engine;

		protected readonly BsonMapper _mapper;

		protected readonly string _collection;

		protected readonly Query _query;

		private readonly bool _isSimpleType = Reflection.IsSimpleType(typeof(T));

		internal LiteQueryable(ILiteEngine engine, BsonMapper mapper, string collection, Query query)
		{
			_engine = engine;
			_mapper = mapper;
			_collection = collection;
			_query = query;
		}

		public ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path)
		{
			_query.Includes.Add(_mapper.GetExpression(path));
			return this;
		}

		public ILiteQueryable<T> Include(BsonExpression path)
		{
			_query.Includes.Add(path);
			return this;
		}

		public ILiteQueryable<T> Include(List<BsonExpression> paths)
		{
			_query.Includes.AddRange(paths);
			return this;
		}

		public ILiteQueryable<T> Where(BsonExpression predicate)
		{
			_query.Where.Add(predicate);
			return this;
		}

		public ILiteQueryable<T> Where(string predicate, BsonDocument parameters)
		{
			_query.Where.Add(BsonExpression.Create(predicate, parameters));
			return this;
		}

		public ILiteQueryable<T> Where(string predicate, params BsonValue[] args)
		{
			_query.Where.Add(BsonExpression.Create(predicate, args));
			return this;
		}

		public ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate)
		{
			return Where(_mapper.GetExpression(predicate));
		}

		public ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1)
		{
			if (_query.OrderBy != null)
			{
				throw new ArgumentException("ORDER BY already defined in this query builder");
			}
			_query.OrderBy = keySelector;
			_query.Order = order;
			return this;
		}

		public ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1)
		{
			return OrderBy(_mapper.GetExpression(keySelector), order);
		}

		public ILiteQueryable<T> OrderByDescending(BsonExpression keySelector)
		{
			return OrderBy(keySelector, -1);
		}

		public ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector)
		{
			return OrderBy(keySelector, -1);
		}

		public ILiteQueryable<T> GroupBy(BsonExpression keySelector)
		{
			if (_query.GroupBy != null)
			{
				throw new ArgumentException("GROUP BY already defined in this query");
			}
			_query.GroupBy = keySelector;
			return this;
		}

		public ILiteQueryable<T> Having(BsonExpression predicate)
		{
			if (_query.Having != null)
			{
				throw new ArgumentException("HAVING already defined in this query");
			}
			_query.Having = predicate;
			return this;
		}

		public ILiteQueryableResult<BsonDocument> Select(BsonExpression selector)
		{
			_query.Select = selector;
			return new LiteQueryable<BsonDocument>(_engine, _mapper, _collection, _query);
		}

		public ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector)
		{
			if (_query.GroupBy != null)
			{
				throw new ArgumentException("Use Select(BsonExpression selector) when using GroupBy query");
			}
			_query.Select = _mapper.GetExpression(selector);
			return new LiteQueryable<K>(_engine, _mapper, _collection, _query);
		}

		public ILiteQueryableResult<T> ForUpdate()
		{
			_query.ForUpdate = true;
			return this;
		}

		public ILiteQueryableResult<T> Offset(int offset)
		{
			_query.Offset = offset;
			return this;
		}

		public ILiteQueryableResult<T> Skip(int offset)
		{
			return Offset(offset);
		}

		public ILiteQueryableResult<T> Limit(int limit)
		{
			_query.Limit = limit;
			return this;
		}

		public IBsonDataReader ExecuteReader()
		{
			_query.ExplainPlan = false;
			return _engine.Query(_collection, _query);
		}

		public IEnumerable<BsonDocument> ToDocuments()
		{
			using IBsonDataReader reader = ExecuteReader();
			while (reader.Read())
			{
				yield return reader.Current as BsonDocument;
			}
		}

		public IEnumerable<T> ToEnumerable()
		{
			if (_isSimpleType)
			{
				return from x in ToDocuments()
					select x[x.Keys.First()] into x
					select (T)_mapper.Deserialize(typeof(T), x);
			}
			return from x in ToDocuments()
				select (T)_mapper.Deserialize(typeof(T), x);
		}

		public List<T> ToList()
		{
			return ToEnumerable().ToList();
		}

		public T[] ToArray()
		{
			return ToEnumerable().ToArray();
		}

		public BsonDocument GetPlan()
		{
			_query.ExplainPlan = true;
			return _engine.Query(_collection, _query).ToEnumerable().FirstOrDefault()?.AsDocument;
		}

		public T Single()
		{
			return ToEnumerable().Single();
		}

		public T SingleOrDefault()
		{
			return ToEnumerable().SingleOrDefault();
		}

		public T First()
		{
			return ToEnumerable().First();
		}

		public T FirstOrDefault()
		{
			return ToEnumerable().FirstOrDefault();
		}

		public int Count()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ count: COUNT(*._id) }");
				return ToDocuments().Single()["count"].AsInt32;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public long LongCount()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ count: COUNT(*._id) }");
				return ToDocuments().Single()["count"].AsInt64;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public bool Exists()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ exists: ANY(*._id) }");
				return ToDocuments().Single()["exists"].AsBoolean;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			_query.Into = newCollection;
			_query.IntoAutoId = autoId;
			using IBsonDataReader bsonDataReader = ExecuteReader();
			return bsonDataReader.Current.AsInt32;
		}
	}
	public class LiteRepository : ILiteRepository, IDisposable
	{
		private readonly ILiteDatabase _db;

		public ILiteDatabase Database => _db;

		public LiteRepository(ILiteDatabase database)
		{
			_db = database;
		}

		public LiteRepository(string connectionString, BsonMapper mapper = null)
		{
			_db = new LiteDatabase(connectionString, mapper);
		}

		public LiteRepository(ConnectionString connectionString, BsonMapper mapper = null)
		{
			_db = new LiteDatabase(connectionString, mapper);
		}

		public LiteRepository(Stream stream, BsonMapper mapper = null, Stream logStream = null)
		{
			_db = new LiteDatabase(stream, mapper, logStream);
		}

		public BsonValue Insert<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Insert(entity);
		}

		public int Insert<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Insert(entities);
		}

		public bool Update<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Update(entity);
		}

		public int Update<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Update(entities);
		}

		public bool Upsert<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Upsert(entity);
		}

		public int Upsert<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Upsert(entities);
		}

		public bool Delete<T>(BsonValue id, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Delete(id);
		}

		public int DeleteMany<T>(BsonExpression predicate, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).DeleteMany(predicate);
		}

		public int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).DeleteMany(predicate);
		}

		public ILiteQueryable<T> Query<T>(string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Query();
		}

		public bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(name, expression, unique);
		}

		public bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(expression, unique);
		}

		public bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(keySelector, unique);
		}

		public bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(name, keySelector, unique);
		}

		public T SingleById<T>(BsonValue id, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Query().Where("_id = @0", id)
				.Single();
		}

		public List<T> Fetch<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).ToList();
		}

		public List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).ToList();
		}

		public T First<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).First();
		}

		public T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).First();
		}

		public T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).FirstOrDefault();
		}

		public T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).FirstOrDefault();
		}

		public T Single<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).Single();
		}

		public T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).Single();
		}

		public T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).SingleOrDefault();
		}

		public T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).SingleOrDefault();
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		~LiteRepository()
		{
			Dispose(disposing: false);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				_db.Dispose();
			}
		}
	}
	public class BsonCtorAttribute : Attribute
	{
	}
	public class BsonFieldAttribute : Attribute
	{
		public string Name { get; set; }

		public BsonFieldAttribute(string name)
		{
			Name = name;
		}

		public BsonFieldAttribute()
		{
		}
	}
	public class BsonIdAttribute : Attribute
	{
		public bool AutoId { get; private set; }

		public BsonIdAttribute()
		{
			AutoId = true;
		}

		public BsonIdAttribute(bool autoId)
		{
			AutoId = autoId;
		}
	}
	public class BsonIgnoreAttribute : Attribute
	{
	}
	public class BsonRefAttribute : Attribute
	{
		public string Collection { get; set; }

		public BsonRefAttribute(string collection)
		{
			Collection = collection;
		}

		public BsonRefAttribute()
		{
			Collection = null;
		}
	}
	public class BsonMapper
	{
		private Dictionary<Type, EntityMapper> _entities = new Dictionary<Type, EntityMapper>();

		private ConcurrentDictionary<Type, Func<object, BsonValue>> _customSerializer = new ConcurrentDictionary<Type, Func<object, BsonValue>>();

		private ConcurrentDictionary<Type, Func<BsonValue, object>> _customDeserializer = new ConcurrentDictionary<Type, Func<BsonValue, object>>();

		private readonly Func<Type, object> _typeInstantiator;

		private readonly ITypeNameBinder _typeNameBinder;

		public static BsonMapper Global = new BsonMapper();

		public Func<string, string> ResolveFieldName;

		public Action<Type, MemberInfo, MemberMapper> ResolveMember;

		public Func<Type, string> ResolveCollectionName;

		private Regex _lowerCaseDelimiter = new Regex("(?!(^[A-Z]))([A-Z])", RegexOptions.Compiled);

		private HashSet<Type> _bsonTypes = new HashSet<Type>
		{
			typeof(string),
			typeof(int),
			typeof(long),
			typeof(bool),
			typeof(Guid),
			typeof(DateTime),
			typeof(byte[]),
			typeof(ObjectId),
			typeof(double),
			typeof(decimal)
		};

		private HashSet<Type> _basicTypes = new HashSet<Type>
		{
			typeof(short),
			typeof(ushort),
			typeof(uint),
			typeof(float),
			typeof(char),
			typeof(byte),
			typeof(sbyte)
		};

		public bool SerializeNullValues { get; set; }

		public bool TrimWhitespace { get; set; }

		public bool EmptyStringToNull { get; set; }

		public bool EnumAsInteger { get; set; }

		public bool IncludeFields { get; set; }

		public bool IncludeNonPublic { get; set; }

		public int MaxDepth { get; set; }

		public BsonMapper(Func<Type, object> customTypeInstantiator = null, ITypeNameBinder typeNameBinder = null)
		{
			SerializeNullValues = false;
			TrimWhitespace = true;
			EmptyStringToNull = true;
			EnumAsInteger = false;
			ResolveFieldName = (string s) => s;
			ResolveMember = delegate
			{
			};
			ResolveCollectionName = (Type t) => (!Reflection.IsEnumerable(t)) ? t.Name : Reflection.GetListItemType(t).Name;
			IncludeFields = false;
			MaxDepth = 20;
			_typeInstantiator = customTypeInstantiator ?? ((Func<Type, object>)((Type t) => null));
			_typeNameBinder = typeNameBinder ?? DefaultTypeNameBinder.Instance;
			RegisterType((Uri uri) => uri.IsAbsoluteUri ? uri.AbsoluteUri : uri.ToString(), (BsonValue bson) => new Uri(bson.AsString));
			RegisterType((DateTimeOffset value) => new BsonValue(value.UtcDateTime), (BsonValue bson) => bson.AsDateTime.ToUniversalTime());
			RegisterType((TimeSpan value) => new BsonValue(value.Ticks), (BsonValue bson) => new TimeSpan(bson.AsInt64));
			RegisterType((Regex r) => (r.Options != 0) ? new BsonDocument
			{
				{
					"p",
					r.ToString()
				},
				{
					"o",
					(int)r.Options
				}
			} : new BsonValue(r.ToString()), (BsonValue value) => (!value.IsString) ? new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32) : new Regex(value));
		}

		public void RegisterType<T>(Func<T, BsonValue> serialize, Func<BsonValue, T> deserialize)
		{
			_customSerializer[typeof(T)] = (object o) => serialize((T)o);
			_customDeserializer[typeof(T)] = (BsonValue b) => deserialize(b);
		}

		public void RegisterType(Type type, Func<object, BsonValue> serialize, Func<BsonValue, object> deserialize)
		{
			_customSerializer[type] = (object o) => serialize(o);
			_customDeserializer[type] = (BsonValue b) => deserialize(b);
		}

		public EntityBuilder<T> Entity<T>()
		{
			return new EntityBuilder<T>(this, _typeNameBinder);
		}

		public BsonExpression GetExpression<T, K>(Expression<Func<T, K>> predicate)
		{
			return new LinqExpressionVisitor(this, predicate).Resolve(typeof(K) == typeof(bool));
		}

		public BsonExpression GetIndexExpression<T, K>(Expression<Func<T, K>> predicate)
		{
			return new LinqExpressionVisitor(this, predicate).Resolve(predicate: false);
		}

		public BsonMapper UseCamelCase()
		{
			ResolveFieldName = (string s) => char.ToLower(s[0]) + s.Substring(1);
			return this;
		}

		public BsonMapper UseLowerCaseDelimiter(char delimiter = '_')
		{
			ResolveFieldName = (string s) => _lowerCaseDelimiter.Replace(s, delimiter + "$2").ToLower();
			return this;
		}

		internal EntityMapper GetEntityMapper(Type type)
		{
			if (!_entities.TryGetValue(type, out var value))
			{
				lock (_entities)
				{
					if (!_entities.TryGetValue(type, out value))
					{
						return _entities[type] = BuildEntityMapper(type);
					}
				}
			}
			return value;
		}

		protected virtual EntityMapper BuildEntityMapper(Type type)
		{
			EntityMapper entityMapper = new EntityMapper(type);
			Type typeFromHandle = typeof(BsonIdAttribute);
			Type typeFromHandle2 = typeof(BsonIgnoreAttribute);
			Type typeFromHandle3 = typeof(BsonFieldAttribute);
			Type typeFromHandle4 = typeof(BsonRefAttribute);
			IEnumerable<MemberInfo> typeMembers = GetTypeMembers(type);
			MemberInfo idMember = GetIdMember(typeMembers);
			foreach (MemberInfo item in typeMembers)
			{
				if (!CustomAttributeExtensions.IsDefined(item, typeFromHandle2, inherit: true))
				{
					string name = ResolveFieldName(item.Name);
					BsonFieldAttribute bsonFieldAttribute = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle3, inherit: true).FirstOrDefault();
					if (bsonFieldAttribute != null && bsonFieldAttribute.Name != null)
					{
						name = bsonFieldAttribute.Name;
					}
					if (item == idMember)
					{
						name = "_id";
					}
					GenericGetter getter = Reflection.CreateGenericGetter(type, item);
					GenericSetter setter = Reflection.CreateGenericSetter(type, item);
					BsonIdAttribute bsonIdAttribute = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle, inherit: true).FirstOrDefault();
					Type type2 = ((item is PropertyInfo) ? (item as PropertyInfo).PropertyType : (item as FieldInfo).FieldType);
					bool flag = Reflection.IsEnumerable(type2);
					MemberMapper memberMapper = new MemberMapper
					{
						AutoId = (bsonIdAttribute?.AutoId ?? true),
						FieldName = name,
						MemberName = item.Name,
						DataType = type2,
						IsEnumerable = flag,
						UnderlyingType = (flag ? Reflection.GetListItemType(type2) : type2),
						Getter = getter,
						Setter = setter
					};
					BsonRefAttribute bsonRefAttribute = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle4, inherit: false).FirstOrDefault();
					if (bsonRefAttribute != null && item is PropertyInfo)
					{
						RegisterDbRef(this, memberMapper, _typeNameBinder, bsonRefAttribute.Collection ?? ResolveCollectionName((item as PropertyInfo).PropertyType));
					}
					ResolveMember?.Invoke(type, item, memberMapper);
					if (memberMapper.FieldName != null && !entityMapper.Members.Any((MemberMapper x) => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)))
					{
						entityMapper.Members.Add(memberMapper);
					}
				}
			}
			return entityMapper;
		}

		protected virtual MemberInfo GetIdMember(IEnumerable<MemberInfo> members)
		{
			return Reflection.SelectMember(members, (MemberInfo x) => CustomAttributeExtensions.IsDefined(x, typeof(BsonIdAttribute), inherit: true), (MemberInfo x) => x.Name.Equals("Id", StringComparison.OrdinalIgnoreCase), (MemberInfo x) => x.Name.Equals(x.DeclaringType.Name + "Id", StringComparison.OrdinalIgnoreCase));
		}

		protected virtual IEnumerable<MemberInfo> GetTypeMembers(Type type)
		{
			List<MemberInfo> list = new List<MemberInfo>();
			BindingFlags bindingAttr = (IncludeNonPublic ? (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : (BindingFlags.Instance | BindingFlags.Public));
			list.AddRange((from x in type.GetProperties(bindingAttr)
				where x.CanRead && x.GetIndexParameters().Length == 0
				select x).Select((Func<PropertyInfo, MemberInfo>)((PropertyInfo x) => x)));
			if (IncludeFields)
			{
				list.AddRange((from x in type.GetFields(bindingAttr)
					where !x.Name.EndsWith("k__BackingField") && !x.IsStatic
					select x).Select((Func<FieldInfo, MemberInfo>)((FieldInfo x) => x)));
			}
			return list;
		}

		protected virtual CreateObject GetTypeCtor(EntityMapper mapper)
		{
			ConstructorInfo[] constructors = mapper.ForType.GetConstructors();
			ConstructorInfo constructorInfo = constructors.FirstOrDefault((ConstructorInfo x) => x.GetCustomAttribute<BsonCtorAttribute>() != null && x.GetParameters().All((ParameterInfo p) => Reflection.ConvertType.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType) || p.ParameterType.GetTypeInfo().IsEnum)) ?? constructors.FirstOrDefault((ConstructorInfo x) => x.GetParameters().Length == 0) ?? constructors.FirstOrDefault((ConstructorInfo x) => x.GetParameters().All((ParameterInfo p) => Reflection.ConvertType.ContainsKey(p.ParameterType) || _customDeserializer.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType) || p.ParameterType.GetTypeInfo().IsEnum));
			if (constructorInfo == null)
			{
				return null;
			}
			List<Expression> list = new List<Expression>();
			ParameterExpression parameterExpression = Expression.Parameter(typeof(BsonDocument), "_doc");
			ParameterInfo[] parameters = constructorInfo.GetParameters();
			foreach (ParameterInfo p2 in parameters)
			{
				string value = mapper.Members.FirstOrDefault((MemberMapper x) => x.MemberName.Equals(p2.Name, StringComparison.OrdinalIgnoreCase))?.FieldName ?? p2.Name;
				IndexExpression indexExpression = Expression.MakeIndex(parameterExpression, Reflection.DocumentItemProperty, new ConstantExpression[1] { Expression.Constant(value) });
				if (_customDeserializer.TryGetValue(p2.ParameterType, out var value2))
				{
					UnaryExpression item = Expression.Convert(Expression.Invoke(Expression.Constant(value2), indexExpression), p2.ParameterType);
					list.Add(item);
				}
				else if (_basicTypes.Contains(p2.ParameterType))
				{
					ConstantExpression arg = Expression.Constant(p2.ParameterType);
					MemberExpression arg2 = Expression.Property(indexExpression, typeof(BsonValue).GetProperty("RawValue"));
					UnaryExpression item2 = Expression.Convert(Expression.Call(typeof(Convert).GetMethod("ChangeType", new Type[2]
					{
						typeof(object),
						typeof(Type)
					}), arg2, arg), p2.ParameterType);
					list.Add(item2);
				}
				else if (p2.ParameterType.GetTypeInfo().IsEnum && EnumAsInteger)
				{
					ConstantExpression arg3 = Expression.Constant(p2.ParameterType);
					MemberExpression arg4 = Expression.PropertyOrField(indexExpression, "AsInt32");
					UnaryExpression item3 = Expression.Convert(Expression.Call(typeof(Enum).GetMethod("ToObject", new Type[2]
					{
						typeof(Type),
						typeof(int)
					}), arg3, arg4), p2.ParameterType);
					list.Add(item3);
				}
				else if (p2.ParameterType.GetTypeInfo().IsEnum)
				{
					ConstantExpression arg5 = Expression.Constant(p2.ParameterType);
					MemberExpression arg6 = Expression.PropertyOrField(indexExpression, "AsString");
					UnaryExpression item4 = Expression.Convert(Expression.Call(typeof(Enum).GetMethod("Parse", new Type[2]
					{
						typeof(Type),
						typeof(string)
					}), arg5, arg6), p2.ParameterType);
					list.Add(item4);
				}
				else
				{
					PropertyInfo property = Reflection.ConvertType[p2.ParameterType];
					MemberExpression item5 = Expression.Property(indexExpression, property);
					list.Add(item5);
				}
			}
			NewExpression newExpression = Expression.New(constructorInfo, list.ToArray());
			if (!mapper.ForType.GetTypeInfo().IsClass)
			{
				return Expression.Lambda<CreateObject>(Expression.Convert(newExpression, typeof(object)), new ParameterExpression[1] { parameterExpression }).Compile();
			}
			return Expression.Lambda<CreateObject>(newExpression, new ParameterExpression[1] { parameterExpression }).Compile();
		}

		internal static void RegisterDbRef(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			member.IsDbRef = true;
			if (member.IsEnumerable)
			{
				RegisterDbRefList(mapper, member, typeNameBinder, collection);
			}
			else
			{
				RegisterDbRefItem(mapper, member, typeNameBinder, collection);
			}
		}

		private static void RegisterDbRefItem(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			EntityMapper entity = mapper.GetEntityMapper(member.DataType);
			member.Serialize = delegate(object obj, BsonMapper m)
			{
				if (obj == null)
				{
					return BsonValue.Null;
				}
				object obj2 = (entity.Id ?? throw new LiteException(0, "There is no _id field mapped in your type: " + member.DataType.FullName)).Getter(obj);
				BsonDocument bsonDocument = new BsonDocument
				{
					["$id"] = m.Serialize(obj2.GetType(), obj2, 0),
					["$ref"] = collection
				};
				if (member.DataType != obj.GetType())
				{
					bsonDocument["$type"] = typeNameBinder.GetName(obj.GetType());
				}
				return bsonDocument;
			};
			member.Deserialize = delegate(BsonValue bson, BsonMapper m)
			{
				if (bson == null || !bson.IsDocument)
				{
					return null;
				}
				BsonDocument asDocument = bson.AsDocument;
				BsonValue value = asDocument["$id"];
				bool num = asDocument["$missing"] == true;
				bool flag = !asDocument.ContainsKey("$ref");
				if (num)
				{
					return null;
				}
				if (flag)
				{
					asDocument["_id"] = value;
					if (asDocument.ContainsKey("$type"))
					{
						asDocument["_type"] = bson["$type"];
					}
					return m.Deserialize(entity.ForType, asDocument);
				}
				return m.Deserialize(entity.ForType, asDocument.ContainsKey("$type") ? new BsonDocument
				{
					["_id"] = value,
					["_type"] = bson["$type"]
				} : new BsonDocument { ["_id"] = value });
			};
		}

		private static void RegisterDbRefList(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			EntityMapper entity = mapper.GetEntityMapper(member.UnderlyingType);
			member.Serialize = delegate(object list, BsonMapper m)
			{
				if (list == null)
				{
					return BsonValue.Null;
				}
				BsonArray bsonArray2 = new BsonArray();
				MemberMapper id = entity.Id;
				foreach (object item in (IEnumerable)list)
				{
					if (item != null)
					{
						object obj = id.Getter(item);
						BsonDocument bsonDocument2 = new BsonDocument
						{
							["$id"] = m.Serialize(obj.GetType(), obj, 0),
							["$ref"] = collection
						};
						if (member.UnderlyingType != item.GetType())
						{
							bsonDocument2["$type"] = typeNameBinder.GetName(item.GetType());
						}
						bsonArray2.Add(bsonDocument2);
					}
				}
				return bsonArray2;
			};
			member.Deserialize = delegate(BsonValue bson, BsonMapper m)
			{
				if (!bson.IsArray)
				{
					return null;
				}
				BsonArray asArray = bson.AsArray;
				if (asArray.Count == 0)
				{
					return m.Deserialize(member.DataType, asArray);
				}
				BsonArray bsonArray = new BsonArray();
				foreach (BsonValue item2 in asArray)
				{
					if (item2.IsDocument)
					{
						BsonDocument asDocument = item2.AsDocument;
						BsonValue value = asDocument["$id"];
						bool flag = asDocument["$missing"] == true;
						bool flag2 = !asDocument.ContainsKey("$ref");
						if (!flag)
						{
							if (flag2)
							{
								item2["_id"] = value;
								if (item2.AsDocument.ContainsKey("$type"))
								{
									item2["_type"] = item2["$type"];
								}
								bsonArray.Add(item2);
							}
							else
							{
								BsonDocument bsonDocument = new BsonDocument { ["_id"] = value };
								if (item2.AsDocument.ContainsKey("$type"))
								{
									bsonDocument["_type"] = item2["$type"];
								}
								bsonArray.Add(bsonDocument);
							}
						}
					}
				}
				return m.Deserialize(member.DataType, bsonArray);
			};
		}

		public virtual object ToObject(Type type, BsonDocument doc)
		{
			if (doc == null)
			{
				throw new ArgumentNullException("doc");
			}
			if (type == typeof(BsonDocument))
			{
				return doc;
			}
			return Deserialize(type, doc);
		}

		public virtual T ToObject<T>(BsonDocument doc)
		{
			return (T)ToObject(typeof(T), doc);
		}

		public T Deserialize<T>(BsonValue value)
		{
			if (value == null)
			{
				return default(T);
			}
			return (T)Deserialize(typeof(T), value);
		}

		public object Deserialize(Type type, BsonValue value)
		{
			if (value.IsNull)
			{
				return null;
			}
			if (Reflection.IsNullable(type))
			{
				type = Reflection.UnderlyingTypeOf(type);
			}
			if (_customDeserializer.TryGetValue(type, out var value2))
			{
				return value2(value);
			}
			TypeInfo typeInfo = type.GetTypeInfo();
			if (type == typeof(BsonValue))
			{
				return value;
			}
			if (type == typeof(BsonDocument))
			{
				return value.AsDocument;
			}
			if (type == typeof(BsonArray))
			{
				return value.AsArray;
			}
			if (_bsonTypes.Contains(type))
			{
				return value.RawValue;
			}
			if (_basicTypes.Contains(type))
			{
				return Convert.ChangeType(value.RawValue, type);
			}
			if (type == typeof(ulong))
			{
				return (ulong)value.AsInt64;
			}
			if (typeInfo.IsEnum)
			{
				if (value.IsString)
				{
					return Enum.Parse(type, value.AsString);
				}
				if (value.IsNumber)
				{
					return Enum.ToObject(type, value.AsInt32);
				}
			}
			else
			{
				if (value.IsArray)
				{
					if (type == typeof(object))
					{
						return DeserializeArray(typeof(object), value.AsArray);
					}
					if (type.IsArray)
					{
						return DeserializeArray(type.GetElementType(), value.AsArray);
					}
					return DeserializeList(type, value.AsArray);
				}
				if (value.IsDocument)
				{
					if (type.IsAnonymousType())
					{
						return DeserializeAnonymousType(type, value.AsDocument);
					}
					BsonDocument asDocument = value.AsDocument;
					if (asDocument.TryGetValue("_type", out var value3) && value3.IsString)
					{
						Type type2 = _typeNameBinder.GetType(value3.AsString);
						if (type2 == null)
						{
							throw LiteException.InvalidTypedName(value3.AsString);
						}
						if (!type.IsAssignableFrom(type2))
						{
							throw LiteException.DataTypeNotAssignable(type.FullName, type2.FullName);
						}
						if (type2.FullName.Equals("System.Diagnostics.Process", StringComparison.OrdinalIgnoreCase))
						{
							throw LiteException.AvoidUseOfProcess();
						}
						type = type2;
					}
					else if (type == typeof(object))
					{
						type = typeof(Dictionary<string, object>);
					}
					EntityMapper entity = GetEntityMapper(type);
					if (entity.CreateInstance == null)
					{
						entity.CreateInstance = GetTypeCtor(entity) ?? ((CreateObject)((BsonDocument v) => Reflection.CreateInstance(entity.ForType)));
					}
					object obj = _typeInstantiator(type) ?? entity.CreateInstance(asDocument);
					if (obj is IDictionary dict)
					{
						if (obj.GetType().GetTypeInfo().IsGenericType)
						{
							Type k = type.GetGenericArguments()[0];
							Type t = type.GetGenericArguments()[1];
							DeserializeDictionary(k, t, dict, value.AsDocument);
						}
						else
						{
							DeserializeDictionary(typeof(object), typeof(object), dict, value.AsDocument);
						}
					}
					else
					{
						DeserializeObject(entity, obj, asDocument);
					}
					return obj;
				}
			}
			return value.RawValue;
		}

		private object DeserializeArray(Type type, BsonArray array)
		{
			Array array2 = Array.CreateInstance(type, array.Count);
			int num = 0;
			foreach (BsonValue item in array)
			{
				array2.SetValue(Deserialize(type, item), num++);
			}
			return array2;
		}

		private object DeserializeList(Type type, BsonArray value)
		{
			Type listItemType = Reflection.GetListItemType(type);
			IEnumerable enumerable = (IEnumerable)Reflection.CreateInstance(type);
			if (enumerable is IList list)
			{
				foreach (BsonValue item in value)
				{
					list.Add(Deserialize(listItemType, item));
				}
			}
			else
			{
				MethodInfo method = type.GetMethod("Add", new Type[1] { listItemType });
				foreach (BsonValue item2 in value)
				{
					method.Invoke(enumerable, new object[1] { Deserialize(listItemType, item2) });
				}
			}
			return enumerable;
		}

		private void DeserializeDictionary(Type K, Type T, IDictionary dict, BsonDocument value)
		{
			bool isEnum = K.GetTypeInfo().IsEnum;
			foreach (KeyValuePair<string, BsonValue> element in value.GetElements())
			{
				object key = (isEnum ? Enum.Parse(K, element.Key) : ((K == typeof(Uri)) ? new Uri(element.Key) : Convert.ChangeType(element.Key, K)));
				object value2 = Deserialize(T, element.Value);
				dict.Add(key, value2);
			}
		}

		private void DeserializeObject(EntityMapper entity, object obj, BsonDocument value)
		{
			foreach (MemberMapper item in entity.Members.Where((MemberMapper x) => x.Setter != null))
			{
				if (value.TryGetValue(item.FieldName, out var value2))
				{
					if (item.Deserialize != null)
					{
						item.Setter(obj, item.Deserialize(value2, this));
					}
					else
					{
						item.Setter(obj, Deserialize(item.DataType, value2));
					}
				}
			}
		}

		private object DeserializeAnonymousType(Type type, BsonDocument value)
		{
			List<object> list = new List<object>();
			ParameterInfo[] parameters = type.GetConstructors()[0].GetParameters();
			foreach (ParameterInfo parameterInfo in parameters)
			{
				object item = Deserialize(parameterInfo.ParameterType, value[parameterInfo.Name]);
				list.Add(item);
			}
			return Activator.CreateInstance(type, list.ToArray());
		}

		public virtual BsonDocument ToDocument(Type type, object entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (entity is BsonDocument)
			{
				return (BsonDocument)entity;
			}
			return Serialize(type, entity, 0).AsDocument;
		}

		public virtual BsonDocument ToDocument<T>(T entity)
		{
			return ToDocument(typeof(T), entity)?.AsDocument;
		}

		public BsonValue Serialize<T>(T obj)
		{
			return Serialize(typeof(T), obj, 0);
		}

		public BsonValue Serialize(Type type, object obj)
		{
			return Serialize(type, obj, 0);
		}

		internal BsonValue Serialize(Type type, object obj, int depth)
		{
			if (++depth > MaxDepth)
			{
				throw LiteException.DocumentMaxDepth(MaxDepth, type);
			}
			if (obj == null)
			{
				return BsonValue.Null;
			}
			if (obj is BsonValue result)
			{
				return result;
			}
			if (_customSerializer.TryGetValue(type, out var value) || _customSerializer.TryGetValue(obj.GetType(), out value))
			{
				return value(obj);
			}
			if (obj is string)
			{
				string text = (TrimWhitespace ? (obj as string).Trim() : ((string)obj));
				if (EmptyStringToNull && text.Length == 0)
				{
					return BsonValue.Null;
				}
				return new BsonValue(text);
			}
			if (obj is int)
			{
				return new BsonValue((int)obj);
			}
			if (obj is long)
			{
				return new BsonValue((long)obj);
			}
			if (obj is double)
			{
				return new BsonValue((double)obj);
			}
			if (obj is decimal)
			{
				return new BsonValue((decimal)obj);
			}
			if (obj is byte[])
			{
				return new BsonValue((byte[])obj);
			}
			if (obj is ObjectId)
			{
				return new BsonValue((ObjectId)obj);
			}
			if (obj is Guid)
			{
				return new BsonValue((Guid)obj);
			}
			if (obj is bool)
			{
				return new BsonValue((bool)obj);
			}
			if (obj is DateTime)
			{
				return new BsonValue((DateTime)obj);
			}
			if (obj is short || obj is ushort || obj is byte || obj is sbyte)
			{
				return new BsonValue(Convert.ToInt32(obj));
			}
			if (obj is uint)
			{
				return new BsonValue(Convert.ToInt64(obj));
			}
			if (obj is ulong)
			{
				return new BsonValue((long)(ulong)obj);
			}
			if (obj is float)
			{
				return new BsonValue(Convert.ToDouble(obj));
			}
			if (obj is char)
			{
				return new BsonValue(obj.ToString());
			}
			if (obj is Enum)
			{
				if (EnumAsInteger)
				{
					return new BsonValue((int)obj);
				}
				return new BsonValue(obj.ToString());
			}
			if (obj is IDictionary dict)
			{
				if (type == typeof(object))
				{
					type = obj.GetType();
				}
				Type type2 = (type.GetTypeInfo().IsGenericType ? type.GetGenericArguments()[1] : typeof(object));
				return SerializeDictionary(type2, dict, depth);
			}
			if (obj is IEnumerable)
			{
				return SerializeArray(Reflection.GetListItemType(type), obj as IEnumerable, depth);
			}
			return SerializeObject(type, obj, depth);
		}

		private BsonArray SerializeArray(Type type, IEnumerable array, int depth)
		{
			BsonArray bsonArray = new BsonArray();
			foreach (object item in array)
			{
				bsonArray.Add(Serialize(type, item, depth));
			}
			return bsonArray;
		}

		private BsonDocument SerializeDictionary(Type type, IDictionary dict, int depth)
		{
			BsonDocument bsonDocument = new BsonDocument();
			foreach (object key in dict.Keys)
			{
				object obj = dict[key];
				string name = key.ToString();
				if (key is DateTime dateTime)
				{
					name = dateTime.ToString("o");
				}
				bsonDocument[name] = Serialize(type, obj, depth);
			}
			return bsonDocument;
		}

		private BsonDocument SerializeObject(Type type, object obj, int depth)
		{
			Type type2 = obj.GetType();
			BsonDocument bsonDocument = new BsonDocument();
			EntityMapper entityMapper = GetEntityMapper(type2);
			if (type != type2)
			{
				bsonDocument["_type"] = new BsonValue(_typeNameBinder.GetName(type2));
			}
			foreach (MemberMapper item in entityMapper.Members.Where((MemberMapper x) => x.Getter != null))
			{
				object obj2 = item.Getter(obj);
				if (obj2 != null || SerializeNullValues || !(item.FieldName != "_id"))
				{
					if (item.Serialize != null)
					{
						bsonDocument[item.FieldName] = item.Serialize(obj2, this);
					}
					else
					{
						bsonDocument[item.FieldName] = Serialize(item.DataType, obj2, depth);
					}
				}
			}
			return bsonDocument;
		}
	}
	public class EntityBuilder<T>
	{
		private BsonMapper _mapper;

		private EntityMapper _entity;

		private ITypeNameBinder _typeNameBinder;

		internal EntityBuilder(BsonMapper mapper, ITypeNameBinder typeNameBinder)
		{
			_mapper = mapper;
			_typeNameBinder = typeNameBinder;
			_entity = mapper.GetEntityMapper(typeof(T));
		}

		public EntityBuilder<T> Ignore<K>(Expression<Func<T, K>> member)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				_entity.Members.Remove(p);
			});
		}

		public EntityBuilder<T> Field<K>(Expression<Func<T, K>> member, string field)
		{
			if (field.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("field");
			}
			return GetMember(member, delegate(MemberMapper p)
			{
				p.FieldName = field;
			});
		}

		public EntityBuilder<T> Id<K>(Expression<Func<T, K>> member, bool autoId = true)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				MemberMapper memberMapper = _entity.Members.FirstOrDefault((MemberMapper x) => x.FieldName == "_id");
				if (memberMapper != null)
				{
					memberMapper.FieldName = _mapper.ResolveFieldName(memberMapper.MemberName);
					memberMapper.AutoId = false;
				}
				p.FieldName = "_id";
				p.AutoId = autoId;
			});
		}

		public EntityBuilder<T> Ctor(Func<BsonDocument, T> createInstance)
		{
			_entity.CreateInstance = (BsonDocument v) => createInstance(v);
			return this;
		}

		public EntityBuilder<T> DbRef<K>(Expression<Func<T, K>> member, string collection = null)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				BsonMapper.RegisterDbRef(_mapper, p, _typeNameBinder, collection ?? _mapper.ResolveCollectionName(typeof(K)));
			});
		}

		private EntityBuilder<T> GetMember<TK, K>(Expression<Func<TK, K>> member, Action<MemberMapper> action)
		{
			if (member == null)
			{
				throw new ArgumentNullException("member");
			}
			MemberMapper member2 = _entity.GetMember(member);
			if (member2 == null)
			{
				throw new ArgumentNullException("Member '" + member.GetPath() + "' not found in type '" + _entity.ForType.Name + "' (use IncludeFields in BsonMapper)");
			}
			action(member2);
			return this;
		}
	}
	public class EntityMapper
	{
		public Type ForType { get; }

		public List<MemberMapper> Members { get; } = new List<MemberMapper>();


		public MemberMapper Id => Members.SingleOrDefault((MemberMapper x) => x.FieldName == "_id");

		public CreateObject CreateInstance { get; set; }

		public EntityMapper(Type forType)
		{
			ForType = forType;
		}

		public MemberMapper GetMember(Expression expr)
		{
			return Members.FirstOrDefault((MemberMapper x) => x.MemberName == expr.GetPath());
		}
	}
	internal class LinqExpressionVisitor : ExpressionVisitor
	{
		private static Dictionary<Type, ITypeResolver> _resolver = new Dictionary<Type, ITypeResolver>
		{
			[typeof(BsonValue)] = new BsonValueResolver(),
			[typeof(BsonArray)] = new BsonValueResolver(),
			[typeof(BsonDocument)] = new BsonValueResolver(),
			[typeof(Convert)] = new ConvertResolver(),
			[typeof(DateTime)] = new DateTimeResolver(),
			[typeof(int)] = new NumberResolver("INT32"),
			[typeof(long)] = new NumberResolver("INT64"),
			[typeof(decimal)] = new NumberResolver("DECIMAL"),
			[typeof(double)] = new NumberResolver("DOUBLE"),
			[typeof(ICollection)] = new ICollectionResolver(),
			[typeof(Enumerable)] = new EnumerableResolver(),
			[typeof(Guid)] = new GuidResolver(),
			[typeof(Math)] = new MathResolver(),
			[typeof(Regex)] = new RegexResolver(),
			[typeof(ObjectId)] = new ObjectIdResolver(),
			[typeof(string)] = new StringResolver(),
			[typeof(Nullable)] = new NullableResolver()
		};

		private readonly BsonMapper _mapper;

		private readonly Expression _expr;

		private readonly ParameterExpression _rootParameter;

		private readonly BsonDocument _parameters = new BsonDocument();

		private int _paramIndex;

		private Type _dbRefType;

		private readonly StringBuilder _builder = new StringBuilder();

		private readonly Stack<Expression> _nodes = new Stack<Expression>();

		public LinqExpressionVisitor(BsonMapper mapper, Expression expr)
		{
			_mapper = mapper;
			_expr = expr;
			if (expr is LambdaExpression lambdaExpression)
			{
				_rootParameter = lambdaExpression.Parameters.First();
				return;
			}
			throw new NotSupportedException("Expression " + expr.ToString() + " must be a lambda expression");
		}

		public BsonExpression Resolve(bool predicate)
		{
			Visit(_expr);
			Constants.ENSURE(_nodes.Count == 0, "node stack must be empty when finish expression resolve");
			string text = _builder.ToString();
			try
			{
				BsonExpression bsonExpression = BsonExpression.Create(text, _parameters);
				if (predicate && (bsonExpression.Type == BsonExpressionType.Path || bsonExpression.Type == BsonExpressionType.Call || bsonExpression.Type == BsonExpressionType.Parameter))
				{
					text = "(" + text + " = true)";
					bsonExpression = BsonExpression.Create(text, _parameters);
				}
				return bsonExpression;
			}
			catch (Exception innerException)
			{
				throw new NotSupportedException("Invalid BsonExpression when converted from Linq expression: " + _expr.ToString() + " - `" + text + "`", innerException);
			}
		}

		protected override Expression VisitLambda<T>(Expression<T> node)
		{
			Expression result = base.VisitLambda(node);
			_builder.Length--;
			return result;
		}

		protected override Expression VisitInvocation(InvocationExpression node)
		{
			Expression result = base.VisitInvocation(node);
			_builder.Length--;
			return result;
		}

		protected override Expression VisitParameter(ParameterExpression node)
		{
			_builder.Append(_rootParameter.Equals(node) ? "$" : "@");
			return base.VisitParameter(node);
		}

		protected override Expression VisitMember(MemberExpression node)
		{
			bool flag = ParameterExpressionVisitor.Test(node);
			MemberInfo member = node.Member;
			if (TryGetResolver(member.DeclaringType, out var typeResolver))
			{
				string text = typeResolver.ResolveMember(member);
				if (text == null)
				{
					throw new NotSupportedException("Member " + member.Name + " are not support in " + member.DeclaringType.Name + " when convert to BsonExpression (" + node.ToString() + ").");
				}
				ResolvePattern(text, node.Expression, new Expression[0]);
			}
			else if (node.Expression != null)
			{
				_nodes.Push(node);
				base.Visit(node.Expression);
				if (flag)
				{
					string value = ResolveMember(member);
					_builder.Append(value);
				}
			}
			else
			{
				object value2 = Evaluate(node);
				base.Visit(Expression.Constant(value2));
			}
			if (_nodes.Count > 0)
			{
				_nodes.Pop();
			}
			return node;
		}

		protected override Expression VisitMethodCall(MethodCallExpression node)
		{
			if (IsMethodIndexEval(node, out var obj, out var idx))
			{
				Visit(obj);
				object obj2 = Evaluate(idx, typeof(string), typeof(int));
				if (obj2 is string)
				{
					_builder.Append(".");
					_builder.Append($"['{obj2}']");
				}
				else
				{
					_builder.Append($"[{obj2}]");
				}
				return node;
			}
			if (!TryGetResolver(node.Method.DeclaringType, out var typeResolver))
			{
				if (ParameterExpressionVisitor.Test(node))
				{
					throw new NotSupportedException("Method " + node.Method.Name + " not available to convert to BsonExpression (" + node.ToString() + ").");
				}
				object value = Evaluate(node);
				base.Visit(Expression.Constant(value));
				return node;
			}
			string text = typeResolver.ResolveMethod(node.Method);
			if (text == null)
			{
				throw new NotSupportedException("Method " + Reflection.MethodName(node.Method) + " in " + node.Method.DeclaringType.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ").");
			}
			ResolvePattern(text, node.Object, node.Arguments);
			return node;
		}

		protected override Expression VisitConstant(ConstantExpression node)
		{
			object value = node.Value;
			while (_nodes.Count > 0 && _nodes.Peek() is MemberExpression memberExpression)
			{
				if (memberExpression.Member is FieldInfo fieldInfo)
				{
					value = fieldInfo.GetValue(value);
				}
				else if (memberExpression.Member is PropertyInfo propertyInfo)
				{
					value = propertyInfo.GetValue(value);
				}
				_nodes.Pop();
			}
			Constants.ENSURE(_nodes.Count == 0, "counter stack must be zero to eval all properties/field over object");
			string text = "p" + _paramIndex++;
			_builder.AppendFormat("@" + text);
			Type type = value?.GetType();
			BsonValue value2 = ((type == null) ? BsonValue.Null : ((type == typeof(string)) ? new BsonValue((string)value) : _mapper.Serialize(value.GetType(), value)));
			_parameters[text] = value2;
			return node;
		}

		protected override Expression VisitUnary(UnaryExpression node)
		{
			if (node.NodeType == ExpressionType.Not)
			{
				if (node.Operand.NodeType == ExpressionType.MemberAccess)
				{
					_builder.Append("(");
					Visit(node.Operand);
					_builder.Append(" = false)");
				}
				else
				{
					_builder.Append("(");
					Visit(node.Operand);
					_builder.Append(")");
					_builder.Append(" = false");
				}
			}
			else if (node.NodeType == ExpressionType.Convert)
			{
				Type fromType = node.Operand.Type;
				Type type = node.Type;
				if ((fromType == typeof(double) || fromType == typeof(decimal)) && (type == typeof(int) || type == typeof(long)))
				{
					string methodName = "To" + type.Name.ToString();
					MethodInfo methodInfo = (from x in typeof(Convert).GetMethods()
						where x.Name == methodName
						where x.GetParameters().Length == 1 && x.GetParameters().Any((ParameterInfo z) => z.ParameterType == fromType)
						select x).FirstOrDefault();
					if (methodInfo == null)
					{
						throw new NotSupportedException("Cast from " + fromType.Name + " are not supported when convert to BsonExpression");
					}
					MethodCallExpression node2 = Expression.Call(null, methodInfo, node.Operand);
					VisitMethodCall(node2);
				}
				else
				{
					base.VisitUnary(node);
				}
			}
			else if (node.NodeType == ExpressionType.ArrayLength)
			{
				_builder.Append("LENGTH(");
				Visit(node.Operand);
				_builder.Append(")");
			}
			else
			{
				base.VisitUnary(node);
			}
			return node;
		}

		protected override Expression VisitNew(NewExpression node)
		{
			if (node.Members == null)
			{
				if (!TryGetResolver(node.Type, out var typeResolver))
				{
					throw new NotSupportedException($"New instance are not supported for {node.Type} when convert to BsonExpression ({node.ToString()}).");
				}
				string text = typeResolver.ResolveCtor(node.Constructor);
				if (text == null)
				{
					throw new NotSupportedException("Constructor for " + node.Type.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ").");
				}
				ResolvePattern(text, null, node.Arguments);
			}
			else
			{
				_builder.Append("{ ");
				for (int i = 0; i < node.Members.Count; i++)
				{
					MemberInfo memberInfo = node.Members[i];
					_builder.Append((i > 0) ? ", " : "");
					_builder.AppendFormat("'{0}': ", memberInfo.Name);
					Visit(node.Arguments[i]);
				}
				_builder.Append(" }");
			}
			return node;
		}

		protected override Expression VisitMemberInit(MemberInitExpression node)
		{
			if (node.NewExpression.Constructor.GetParameters().Length != 0)
			{
				throw new NotSupportedException($"New instance of {node.Type} are not supported because contains ctor with parameter. Try use only property initializers: `new {node.Type.Name} {{ PropA = 1, PropB == \"John\" }}`.");
			}
			_builder.Append("{");
			for (int i = 0; i < node.Bindings.Count; i++)
			{
				MemberAssignment memberAssignment = node.Bindings[i] as MemberAssignment;
				string text = ResolveMember(memberAssignment.Member);
				_builder.Append((i > 0) ? ", " : "");
				_builder.Append(text.Substring(1));
				_builder.Append(":");
				Visit(memberAssignment.Expression);
			}
			_builder.Append("}");
			return node;
		}

		protected override Expression VisitNewArray(NewArrayExpression node)
		{
			_builder.Append("[ ");
			for (int i = 0; i < node.Expressions.Count; i++)
			{
				_builder.Append((i > 0) ? ", " : "");
				Visit(node.Expressions[i]);
			}
			_builder.Append(" ]");
			return node;
		}

		protected override Expression VisitBinary(BinaryExpression node)
		{
			bool ensurePredicate = node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse;
			if (node.NodeType == ExpressionType.Coalesce)
			{
				return VisitCoalesce(node);
			}
			if (node.NodeType == ExpressionType.ArrayIndex)
			{
				return VisitArrayIndex(node);
			}
			string @operator = GetOperator(node.NodeType);
			_builder.Append("(");
			VisitAsPredicate(node.Left, ensurePredicate);
			_builder.Append(@operator);
			if (!_mapper.EnumAsInteger && node.Left.NodeType == ExpressionType.Convert && node.Left is UnaryExpression unaryExpression && unaryExpression.Operand.Type.GetTypeInfo().IsEnum && unaryExpression.Type == typeof(int))
			{
				VisitAsPredicate(Expression.Constant(Enum.GetName(unaryExpression.Operand.Type, Evaluate(node.Right))), ensurePredicate);
			}
			else
			{
				VisitAsPredicate(node.Right, ensurePredicate);
			}
			_builder.Append(")");
			return node;
		}

		protected override Expression VisitConditional(ConditionalExpression node)
		{
			_builder.Append("IIF(");
			Visit(node.Test);
			_builder.Append(", ");
			Visit(node.IfTrue);
			_builder.Append(", ");
			Visit(node.IfFalse);
			_builder.Append(")");
			return node;
		}

		private Expression VisitCoalesce(BinaryExpression node)
		{
			_builder.Append("COALESCE(");
			Visit(node.Left);
			_builder.Append(", ");
			Visit(node.Right);
			_builder.Append(")");
			return node;
		}

		private Expression VisitArrayIndex(BinaryExpression node)
		{
			Visit(node.Left);
			_builder.Append("[");
			object value = Evaluate(node.Right, typeof(int));
			_builder.Append(value);
			_builder.Append("]");
			return node;
		}

		private void ResolvePattern(string pattern, Expression obj, IList<Expression> args)
		{
			Tokenizer tokenizer = new Tokenizer(pattern);
			while (!tokenizer.EOF)
			{
				Token token = tokenizer.ReadToken(eatWhitespace: false);
				if (token.Type == TokenType.Hashtag)
				{
					Visit(obj);
				}
				else if (token.Type == TokenType.At && tokenizer.LookAhead(eatWhitespace: false).Type == TokenType.Int)
				{
					int index = Convert.ToInt32(tokenizer.ReadToken(eatWhitespace: false).Expect(TokenType.Int).Value);
					Visit(args[index]);
				}
				else if (token.Type == TokenType.Percent)
				{
					VisitEnumerablePredicate(args[1] as LambdaExpression);
				}
				else
				{
					_builder.Append((token.Type == TokenType.String) ? ("'" + token.Value + "'") : token.Value);
				}
			}
		}

		private void VisitEnumerablePredicate(LambdaExpression lambda)
		{
			Expression body = lambda.Body;
			if (body is BinaryExpression binaryExpression)
			{
				if (binaryExpression.Left.NodeType != ExpressionType.Parameter)
				{
					throw new LiteException(0, "Any/All requires simple parameter on left side. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`");
				}
				string @operator = GetOperator(binaryExpression.NodeType);
				_builder.Append(@operator);
				VisitAsPredicate(binaryExpression.Right, ensurePredicate: false);
				return;
			}
			if (body is MethodCallExpression methodCallExpression)
			{
				if (methodCallExpression.Object.NodeType != ExpressionType.Parameter)
				{
					throw new NotSupportedException("Any/All requires simple parameter on left side. Eg: `x.Customers.Select(c => c.Name).Any(n => n.StartsWith('J'))`");
				}
				if (!TryGetResolver(methodCallExpression.Method.DeclaringType, out var typeResolver))
				{
					throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call.");
				}
				string text = typeResolver.ResolveMethod(methodCallExpression.Method);
				if (text == null || !text.StartsWith("#"))
				{
					throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call.");
				}
				ResolvePattern(text.Substring(1), methodCallExpression.Object, methodCallExpression.Arguments);
				return;
			}
			throw new LiteException(0, "When using Any/All method test do only simple predicate variable. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`");
		}

		private string GetOperator(ExpressionType nodeType)
		{
			return nodeType switch
			{
				ExpressionType.Add => " + ", 
				ExpressionType.Multiply => " * ", 
				ExpressionType.Subtract => " - ", 
				ExpressionType.Divide => " / ", 
				ExpressionType.Equal => " = ", 
				ExpressionType.NotEqual => " != ", 
				ExpressionType.GreaterThan => " > ", 
				ExpressionType.GreaterThanOrEqual => " >= ", 
				ExpressionType.LessThan => " < ", 
				ExpressionType.LessThanOrEqual => " <= ", 
				ExpressionType.And => " AND ", 
				ExpressionType.AndAlso => " AND ", 
				ExpressionType.Or => " OR ", 
				ExpressionType.OrElse => " OR ", 
				_ => throw new NotSupportedException($"Operator not supported {nodeType}"), 
			};
		}

		private string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			bool flag = _dbRefType != null && member.DeclaringType.IsAssignableFrom(_dbRefType);
			MemberMapper memberMapper = _mapper.GetEntityMapper(member.DeclaringType).Members.FirstOrDefault((MemberMapper x) => x.MemberName == name);
			if (memberMapper == null)
			{
				throw new NotSupportedException($"Member {name} not found on BsonMapper for type {member.DeclaringType}.");
			}
			_dbRefType = (memberMapper.IsDbRef ? memberMapper.UnderlyingType : null);
			return "." + ((flag && memberMapper.FieldName == "_id") ? "$id" : memberMapper.FieldName);
		}

		private bool IsMethodIndexEval(MethodCallExpression node, out Expression obj, out Expression idx)
		{
			MethodInfo method = node.Method;
			_ = method.DeclaringType;
			ParameterInfo[] parameters = method.GetParameters();
			if (method.Name == "get_Item" && parameters.Length == 1 && (parameters[0].ParameterType == typeof(int) || parameters[0].ParameterType == typeof(string)))
			{
				obj = node.Object;
				idx = node.Arguments[0];
				return true;
			}
			obj = null;
			idx = null;
			return false;
		}

		private void VisitAsPredicate(Expression expr, bool ensurePredicate)
		{
			ensurePredicate = ensurePredicate && (expr.NodeType == ExpressionType.MemberAccess || expr.NodeType == ExpressionType.Call || expr.NodeType == ExpressionType.Invoke || expr.NodeType == ExpressionType.Constant);
			if (ensurePredicate)
			{
				_builder.Append("(");
				_builder.Append("(");
				base.Visit(expr);
				_builder.Append(")");
				_builder.Append(" = true)");
			}
			else
			{
				base.Visit(expr);
			}
		}

		private object Evaluate(Expression expr, params Type[] validTypes)
		{
			object value = null;
			if (expr.NodeType == ExpressionType.Constant)
			{
				ConstantExpression constantExpression = (ConstantExpression)expr;
				value = constantExpression.Value;
			}
			else
			{
				Delegate @delegate = Expression.Lambda(expr).Compile();
				value = @delegate.DynamicInvoke();
			}
			if (validTypes.Length != 0 && value == null)
			{
				throw new NotSupportedException($"Expression {expr} can't return null value");
			}
			if (validTypes.Length != 0 && !validTypes.Any((Type x) => x == value.GetType()))
			{
				throw new NotSupportedException(string.Format("Expression {0} must return on of this types: {1}", expr, string.Join(", ", validTypes.Select((Type x) => "`" + x.Name + "`"))));
			}
			return value;
		}

		private bool TryGetResolver(Type declaringType, out ITypeResolver typeResolver)
		{
			bool num = Reflection.IsCollection(declaringType);
			bool flag = Reflection.IsEnumerable(declaringType);
			bool flag2 = Reflection.IsNullable(declaringType);
			Type key = (num ? typeof(ICollection) : (flag ? typeof(Enumerable) : (flag2 ? typeof(Nullable) : declaringType)));
			return _resolver.TryGetValue(key, out typeResolver);
		}
	}
	internal class ParameterExpressionVisitor : ExpressionVisitor
	{
		public bool IsParameter { get; private set; }

		protected override Expression VisitParameter(ParameterExpression node)
		{
			IsParameter = true;
			return base.VisitParameter(node);
		}

		public static bool Test(Expression node)
		{
			ParameterExpressionVisitor parameterExpressionVisitor = new ParameterExpressionVisitor();
			parameterExpressionVisitor.Visit(node);
			return parameterExpressionVisitor.IsParameter;
		}
	}
	internal class BsonValueResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			switch (member.Name)
			{
			case "AsInt32":
			case "AsInt64":
			case "AsArray":
			case "AsDateTime":
			case "AsDocument":
			case "AsObjectId":
			case "AsString":
			case "AsBinary":
			case "AsDouble":
			case "AsBoolean":
			case "AsDecimal":
			case "AsGuid":
				return "#";
			case "IsNull":
				return "IS_NULL(#)";
			case "IsArray":
				return "IS_ARRAY(#)";
			case "IsDocument":
				return "IS_DOCUMENT(#)";
			case "IsInt32":
				return "IS_INT32(#)";
			case "IsInt64":
				return "IS_INT64(#)";
			case "IsDouble":
				return "IS_DOUBLE(#)";
			case "IsDecimal":
				return "IS_DECIMAL(#)";
			case "IsNumber":
				return "IS_NUMBER(#)";
			case "IsBinary":
				return "IS_BINARY(#)";
			case "IsBoolean":
				return "IS_BOOLEAN(#)";
			case "IsString":
				return "IS_STRING(#)";
			case "IsObjectId":
				return "IS_OBJECTID(#)";
			case "IsGuid":
				return "IS_GUID(#)";
			case "IsDateTime":
				return "IS_DATETIME(#)";
			case "IsMinValue":
				return "IS_MINVALUE(#)";
			case "IsMaxValue":
				return "IS_MAXVALUE(#)";
			default:
				return null;
			}
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class ConvertResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return method.Name switch
			{
				"ToInt32" => "INT32(@0)", 
				"ToInt64" => "INT64(@0)", 
				"ToDouble" => "DOUBLE(@0)", 
				"ToDecimal" => "DECIMAL(@0)", 
				"ToDateTime" => "DATE(@0)", 
				"FromBase64String" => "BINARY(@0)", 
				"ToBoolean" => "BOOL(@0)", 
				"ToString" => "STRING(@0)", 
				_ => null, 
			};
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class DateTimeResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			switch (method.Name)
			{
			case "AddYears":
				return "DATEADD('y', @0, #)";
			case "AddMonths":
				return "DATEADD('M', @0, #)";
			case "AddDays":
				return "DATEADD('d', @0, #)";
			case "AddHours":
				return "DATEADD('h', @0, #)";
			case "AddMinutes":
				return "DATEADD('m', @0, #)";
			case "AddSeconds":
				return "DATEADD('s', @0, #)";
			case "ToString":
			{
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length == 0)
				{
					return "STRING(#)";
				}
				if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
				{
					return "FORMAT(#, @0)";
				}
				break;
			}
			case "ToUniversalTime":
				return "TO_UTC(#)";
			case "Parse":
				return "DATETIME(@0)";
			case "Equals":
				return "# = @0";
			}
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			return member.Name switch
			{
				"Now" => "NOW()", 
				"UtcNow" => "NOW_UTC()", 
				"Today" => "TODAY()", 
				"Year" => "YEAR(#)", 
				"Month" => "MONTH(#)", 
				"Day" => "DAY(#)", 
				"Hour" => "HOUR(#)", 
				"Minute" => "MINUTE(#)", 
				"Second" => "SECOND(#)", 
				"Date" => "DATETIME(YEAR(#), MONTH(#), DAY(#))", 
				"ToLocalTime" => "TO_LOCAL(#)", 
				"ToUniversalTime" => "TO_UTC(#)", 
				_ => null, 
			};
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 3 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(int))
			{
				return "DATETIME(@0, @1, @2)";
			}
			return null;
		}
	}
	internal class EnumerableResolver : ITypeResolver
	{
		public virtual string ResolveMethod(MethodInfo method)
		{
			switch (Reflection.MethodName(method, 1))
			{
			case "AsEnumerable()":
				return "@0[*]";
			case "get_Item(int)":
				return "#[@0]";
			case "ElementAt(int)":
				return "@0[@1]";
			case "Single()":
			case "First()":
			case "SingleOrDefault()":
			case "FirstOrDefault()":
				return "@0[0]";
			case "Last()":
			case "LastOrDefault()":
				return "@0[-1]";
			case "Single(Func<T,TResult>)":
			case "First(Func<T,TResult>)":
			case "SingleOrDefault(Func<T,TResult>)":
			case "FirstOrDefault(Func<T,TResult>)":
				return "FIRST(FILTER(@0 => @1))";
			case "Last(Func<T,TResult>)":
			case "LastOrDefault(Func<T,TResult>)":
				return "LAST(FILTER(@0 => @1))";
			case "Where(Func<T,TResult>)":
				return "FILTER(@0 => @1)";
			case "Select(Func<T,TResult>)":
				return "MAP(@0 => @1)";
			case "Count()":
				return "COUNT(@0)";
			case "Sum()":
				return "SUM(@0)";
			case "Average()":
				return "AVG(@0)";
			case "Max()":
				return "MAX(@0)";
			case "Min()":
				return "MIN(@0)";
			case "Count(Func<T,TResult>)":
				return "COUNT(FILTER(@0 => @1))";
			case "Sum(Func<T,TResult>)":
				return "SUM(MAP(@0 => @1))";
			case "Average(Func<T,TResult>)":
				return "AVG(MAP(@0 => @1))";
			case "Max(Func<T,TResult>)":
				return "MAX(MAP(@0 => @1))";
			case "Min(Func<T,TResult>)":
				return "MIN(MAP(@0 => @1))";
			case "ToList()":
			case "ToArray()":
				return "ARRAY(@0)";
			case "Any(Func<T,TResult>)":
				return "@0 ANY %";
			case "All(Func<T,TResult>)":
				return "@0 ALL %";
			case "Any()":
				return "COUNT(@0) > 0";
			default:
				if (method.Name == "Contains")
				{
					return "@0 ANY = @1";
				}
				return null;
			}
		}

		public virtual string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Length"))
			{
				if (name == "Count")
				{
					return "COUNT(#)";
				}
				return null;
			}
			return "LENGTH(#)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class GuidResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return method.Name switch
			{
				"ToString" => "STRING(#)", 
				"NewGuid" => "GUID()", 
				"Parse" => "GUID(@0)", 
				"TryParse" => throw new NotSupportedException("There is no TryParse translate. Use Guid.Parse()"), 
				"Equals" => "# = @0", 
				_ => null, 
			};
		}

		public string ResolveMember(MemberInfo member)
		{
			if (member.Name == "Empty")
			{
				return "GUID('00000000-0000-0000-0000-000000000000')";
			}
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
			{
				return "GUID(@0)";
			}
			return null;
		}
	}
	internal class ICollectionResolver : EnumerableResolver
	{
		public override string ResolveMethod(MethodInfo method)
		{
			if (method.Name == "Contains")
			{
				return "# ANY = @0";
			}
			return base.ResolveMethod(method);
		}
	}
	internal interface ITypeResolver
	{
		string ResolveMethod(MethodInfo method);

		string ResolveMember(MemberInfo member);

		string ResolveCtor(ConstructorInfo ctor);
	}
	internal class MathResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			int num = method.GetParameters().Length;
			switch (method.Name)
			{
			case "Abs":
				return "ABS(@0)";
			case "Pow":
				return "POW(@0, @1)";
			case "Round":
				if (num != 2)
				{
					throw new ArgumentOutOfRangeException("Method Round need 2 arguments when convert to BsonExpression");
				}
				return "ROUND(@0, @1)";
			default:
				return null;
			}
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class NullableResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "HasValue"))
			{
				if (name == "Value")
				{
					return "#";
				}
				return null;
			}
			return "(IS_NULL(#) = false)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class NumberResolver : ITypeResolver
	{
		private readonly string _parseMethod;

		public NumberResolver(string parseMethod)
		{
			_parseMethod = parseMethod;
		}

		public string ResolveMethod(MethodInfo method)
		{
			switch (method.Name)
			{
			case "ToString":
			{
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length == 0)
				{
					return "STRING(#)";
				}
				if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
				{
					return "FORMAT(#, @0)";
				}
				break;
			}
			case "Parse":
				return _parseMethod + "(@0)";
			case "Equals":
				return "# = @0";
			}
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class ObjectIdResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			string name = method.Name;
			if (!(name == "ToString"))
			{
				if (name == "Equals")
				{
					return "# = @0";
				}
				return null;
			}
			return "STRING(#)";
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Empty"))
			{
				if (name == "CreationTime")
				{
					return "OID_CREATIONTIME(#)";
				}
				return null;
			}
			return "OBJECTID('000000000000000000000000')";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
			{
				return "OBJECTID(@0)";
			}
			return null;
		}
	}
	internal class RegexResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			string name = method.Name;
			if (!(name == "Split"))
			{
				if (name == "IsMatch")
				{
					return "IS_MATCH(@0, @1)";
				}
				return null;
			}
			return "SPLIT(@0, @1, true)";
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class StringResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			int num = method.GetParameters().Length;
			switch (method.Name)
			{
			case "Count":
				return "LENGTH(#)";
			case "Trim":
				return "TRIM(#)";
			case "TrimStart":
				return "LTRIM(#)";
			case "TrimEnd":
				return "RTRIM(#)";
			case "ToUpper":
				return "UPPER(#)";
			case "ToLower":
				return "LOWER(#)";
			case "Replace":
				return "REPLACE(#, @0, @1)";
			case "PadLeft":
				return "LPAD(#, @0, @1)";
			case "RightLeft":
				return "RPAD(#, @0, @1)";
			case "IndexOf":
				if (num != 1)
				{
					return "INDEXOF(#, @0, @1)";
				}
				return "INDEXOF(#, @0)";
			case "Substring":
				if (num != 1)
				{
					return "SUBSTRING(#, @0, @1)";
				}
				return "SUBSTRING(#, @0)";
			case "StartsWith":
				return "# LIKE (@0 + '%')";
			case "Contains":
				return "# LIKE ('%' + @0 + '%')";
			case "EndsWith":
				return "# LIKE ('%' + @0)";
			case "ToString":
				return "#";
			case "Equals":
				return "# = @0";
			case "IsNullOrEmpty":
				return "(LENGTH(@0) = 0)";
			case "IsNullOrWhiteSpace":
				return "(LENGTH(TRIM(@0)) = 0)";
			case "Format":
				throw new NotImplementedException();
			case "Join":
				throw new NotImplementedException();
			default:
				return null;
			}
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Length"))
			{
				if (name == "Empty")
				{
					return "''";
				}
				return null;
			}
			return "LENGTH(#)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	public class MemberMapper
	{
		public bool AutoId { get; set; }

		public string MemberName { get; set; }

		public Type DataType { get; set; }

		public string FieldName { get; set; }

		public GenericGetter Getter { get; set; }

		public GenericSetter Setter { get; set; }

		public Func<object, BsonMapper, BsonValue> Serialize { get; set; }

		public Func<BsonValue, BsonMapper, object> Deserialize { get; set; }

		public bool IsDbRef { get; set; }

		public bool IsEnumerable { get; set; }

		public Type UnderlyingType { get; set; }
	}
	public delegate object CreateObject(BsonDocument value);
	public delegate void GenericSetter(object target, object value);
	public delegate object GenericGetter(object obj);
	internal class Reflection
	{
		private static Dictionary<Type, CreateObject> _cacheCtor = new Dictionary<Type, CreateObject>();

		public static readonly Dictionary<Type, PropertyInfo> ConvertType = new Dictionary<Type, PropertyInfo>
		{
			[typeof(DateTime)] = typeof(BsonValue).GetProperty("AsDateTime"),
			[typeof(decimal)] = typeof(BsonValue).GetProperty("AsDecimal"),
			[typeof(double)] = typeof(BsonValue).GetProperty("AsDouble"),
			[typeof(long)] = typeof(BsonValue).GetProperty("AsInt64"),
			[typeof(int)] = typeof(BsonValue).GetProperty("AsInt32"),
			[typeof(bool)] = typeof(BsonValue).GetProperty("AsBoolean"),
			[typeof(byte[])] = typeof(BsonValue).GetProperty("AsBinary"),
			[typeof(BsonDocument)] = typeof(BsonValue).GetProperty("AsDocument"),
			[typeof(BsonArray)] = typeof(BsonValue).GetProperty("AsArray"),
			[typeof(ObjectId)] = typeof(BsonValue).GetProperty("AsObjectId"),
			[typeof(string)] = typeof(BsonValue).GetProperty("AsString"),
			[typeof(Guid)] = typeof(BsonValue).GetProperty("AsGuid")
		};

		public static readonly PropertyInfo DocumentItemProperty = (from x in typeof(BsonDocument).GetProperties()
			where x.Name == "Item" && x.GetGetMethod().GetParameters().First()
				.ParameterType == typeof(string)
			select x).First();

		pri

plugins/Newtonsoft.Json.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Schema, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")]
[assembly: CLSCompliant(true)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Newtonsoft")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © James Newton-King 2008")]
[assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")]
[assembly: AssemblyFileVersion("13.0.3.27908")]
[assembly: AssemblyInformationalVersion("13.0.3+0a2e291c0d9c0c7675d445703e51750363a549ef")]
[assembly: AssemblyProduct("Json.NET")]
[assembly: AssemblyTitle("Json.NET .NET 4.5")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JamesNK/Newtonsoft.Json")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("13.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[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.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
	internal sealed class NotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class NotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public NotNullWhenAttribute(bool returnValue)
		{
			ReturnValue = returnValue;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
	internal sealed class MaybeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
	internal sealed class AllowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	internal class DoesNotReturnIfAttribute : Attribute
	{
		public bool ParameterValue { get; }

		public DoesNotReturnIfAttribute(bool parameterValue)
		{
			ParameterValue = parameterValue;
		}
	}
}
namespace Newtonsoft.Json
{
	public enum ConstructorHandling
	{
		Default,
		AllowNonPublicDefaultConstructor
	}
	public enum DateFormatHandling
	{
		IsoDateFormat,
		MicrosoftDateFormat
	}
	public enum DateParseHandling
	{
		None,
		DateTime,
		DateTimeOffset
	}
	public enum DateTimeZoneHandling
	{
		Local,
		Utc,
		Unspecified,
		RoundtripKind
	}
	public class DefaultJsonNameTable : JsonNameTable
	{
		private class Entry
		{
			internal readonly string Value;

			internal readonly int HashCode;

			internal Entry Next;

			internal Entry(string value, int hashCode, Entry next)
			{
				Value = value;
				HashCode = hashCode;
				Next = next;
			}
		}

		private static readonly int HashCodeRandomizer;

		private int _count;

		private Entry[] _entries;

		private int _mask = 31;

		static DefaultJsonNameTable()
		{
			HashCodeRandomizer = Environment.TickCount;
		}

		public DefaultJsonNameTable()
		{
			_entries = new Entry[_mask + 1];
		}

		public override string? Get(char[] key, int start, int length)
		{
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			num += (num << 7) ^ key[start];
			int num2 = start + length;
			for (int i = start + 1; i < num2; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			int num3 = Volatile.Read(ref _mask);
			int num4 = num & num3;
			for (Entry entry = _entries[num4]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && TextEquals(entry.Value, key, start, length))
				{
					return entry.Value;
				}
			}
			return null;
		}

		public string Add(string key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			int length = key.Length;
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			for (int i = 0; i < key.Length; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			for (Entry entry = _entries[num & _mask]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && entry.Value.Equals(key, StringComparison.Ordinal))
				{
					return entry.Value;
				}
			}
			return AddEntry(key, num);
		}

		private string AddEntry(string str, int hashCode)
		{
			int num = hashCode & _mask;
			Entry entry = new Entry(str, hashCode, _entries[num]);
			_entries[num] = entry;
			if (_count++ == _mask)
			{
				Grow();
			}
			return entry.Value;
		}

		private void Grow()
		{
			Entry[] entries = _entries;
			int num = _mask * 2 + 1;
			Entry[] array = new Entry[num + 1];
			for (int i = 0; i < entries.Length; i++)
			{
				Entry entry = entries[i];
				while (entry != null)
				{
					int num2 = entry.HashCode & num;
					Entry next = entry.Next;
					entry.Next = array[num2];
					array[num2] = entry;
					entry = next;
				}
			}
			_entries = array;
			Volatile.Write(ref _mask, num);
		}

		private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
		{
			if (str1.Length != str2Length)
			{
				return false;
			}
			for (int i = 0; i < str1.Length; i++)
			{
				if (str1[i] != str2[str2Start + i])
				{
					return false;
				}
			}
			return true;
		}
	}
	[Flags]
	public enum DefaultValueHandling
	{
		Include = 0,
		Ignore = 1,
		Populate = 2,
		IgnoreAndPopulate = 3
	}
	public enum FloatFormatHandling
	{
		String,
		Symbol,
		DefaultValue
	}
	public enum FloatParseHandling
	{
		Double,
		Decimal
	}
	public enum Formatting
	{
		None,
		Indented
	}
	public interface IArrayPool<T>
	{
		T[] Rent(int minimumLength);

		void Return(T[]? array);
	}
	public interface IJsonLineInfo
	{
		int LineNumber { get; }

		int LinePosition { get; }

		bool HasLineInfo();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonArrayAttribute : JsonContainerAttribute
	{
		private bool _allowNullItems;

		public bool AllowNullItems
		{
			get
			{
				return _allowNullItems;
			}
			set
			{
				_allowNullItems = value;
			}
		}

		public JsonArrayAttribute()
		{
		}

		public JsonArrayAttribute(bool allowNullItems)
		{
			_allowNullItems = allowNullItems;
		}

		public JsonArrayAttribute(string id)
			: base(id)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
	public sealed class JsonConstructorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public abstract class JsonContainerAttribute : Attribute
	{
		internal bool? _isReference;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		private Type? _namingStrategyType;

		private object[]? _namingStrategyParameters;

		public string? Id { get; set; }

		public string? Title { get; set; }

		public string? Description { get; set; }

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType
		{
			get
			{
				return _namingStrategyType;
			}
			set
			{
				_namingStrategyType = value;
				NamingStrategyInstance = null;
			}
		}

		public object[]? NamingStrategyParameters
		{
			get
			{
				return _namingStrategyParameters;
			}
			set
			{
				_namingStrategyParameters = value;
				NamingStrategyInstance = null;
			}
		}

		internal NamingStrategy? NamingStrategyInstance { get; set; }

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		protected JsonContainerAttribute()
		{
		}

		protected JsonContainerAttribute(string id)
		{
			Id = id;
		}
	}
	public static class JsonConvert
	{
		public static readonly string True = "true";

		public static readonly string False = "false";

		public static readonly string Null = "null";

		public static readonly string Undefined = "undefined";

		public static readonly string PositiveInfinity = "Infinity";

		public static readonly string NegativeInfinity = "-Infinity";

		public static readonly string NaN = "NaN";

		public static Func<JsonSerializerSettings>? DefaultSettings { get; set; }

		public static string ToString(DateTime value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
		}

		public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
		{
			DateTime value2 = DateTimeUtils.EnsureDateTime(value, timeZoneHandling);
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeString(stringWriter, value2, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(DateTimeOffset value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat);
		}

		public static string ToString(DateTimeOffset value, DateFormatHandling format)
		{
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeOffsetString(stringWriter, value, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(bool value)
		{
			if (!value)
			{
				return False;
			}
			return True;
		}

		public static string ToString(char value)
		{
			return ToString(char.ToString(value));
		}

		public static string ToString(Enum value)
		{
			return value.ToString("D");
		}

		public static string ToString(int value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(short value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ushort value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(uint value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(long value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		private static string ToStringInternal(BigInteger value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ulong value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(float value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			if (floatFormatHandling == FloatFormatHandling.Symbol || (!double.IsInfinity(value) && !double.IsNaN(value)))
			{
				return text;
			}
			if (floatFormatHandling == FloatFormatHandling.DefaultValue)
			{
				if (nullable)
				{
					return Null;
				}
				return "0.0";
			}
			return quoteChar + text + quoteChar;
		}

		public static string ToString(double value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureDecimalPlace(double value, string text)
		{
			if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		private static string EnsureDecimalPlace(string text)
		{
			if (StringUtils.IndexOf(text, '.') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		public static string ToString(byte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(sbyte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(decimal value)
		{
			return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
		}

		public static string ToString(Guid value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(Guid value, char quoteChar)
		{
			string text = value.ToString("D", CultureInfo.InvariantCulture);
			string text2 = quoteChar.ToString(CultureInfo.InvariantCulture);
			return text2 + text + text2;
		}

		public static string ToString(TimeSpan value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(TimeSpan value, char quoteChar)
		{
			return ToString(value.ToString(), quoteChar);
		}

		public static string ToString(Uri? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ToString(value, '"');
		}

		internal static string ToString(Uri value, char quoteChar)
		{
			return ToString(value.OriginalString, quoteChar);
		}

		public static string ToString(string? value)
		{
			return ToString(value, '"');
		}

		public static string ToString(string? value, char delimiter)
		{
			return ToString(value, delimiter, StringEscapeHandling.Default);
		}

		public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling)
		{
			if (delimiter != '"' && delimiter != '\'')
			{
				throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter");
			}
			return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, appendDelimiters: true, stringEscapeHandling);
		}

		public static string ToString(object? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ConvertUtils.GetTypeCode(value.GetType()) switch
			{
				PrimitiveTypeCode.String => ToString((string)value), 
				PrimitiveTypeCode.Char => ToString((char)value), 
				PrimitiveTypeCode.Boolean => ToString((bool)value), 
				PrimitiveTypeCode.SByte => ToString((sbyte)value), 
				PrimitiveTypeCode.Int16 => ToString((short)value), 
				PrimitiveTypeCode.UInt16 => ToString((ushort)value), 
				PrimitiveTypeCode.Int32 => ToString((int)value), 
				PrimitiveTypeCode.Byte => ToString((byte)value), 
				PrimitiveTypeCode.UInt32 => ToString((uint)value), 
				PrimitiveTypeCode.Int64 => ToString((long)value), 
				PrimitiveTypeCode.UInt64 => ToString((ulong)value), 
				PrimitiveTypeCode.Single => ToString((float)value), 
				PrimitiveTypeCode.Double => ToString((double)value), 
				PrimitiveTypeCode.DateTime => ToString((DateTime)value), 
				PrimitiveTypeCode.Decimal => ToString((decimal)value), 
				PrimitiveTypeCode.DBNull => Null, 
				PrimitiveTypeCode.DateTimeOffset => ToString((DateTimeOffset)value), 
				PrimitiveTypeCode.Guid => ToString((Guid)value), 
				PrimitiveTypeCode.Uri => ToString((Uri)value), 
				PrimitiveTypeCode.TimeSpan => ToString((TimeSpan)value), 
				PrimitiveTypeCode.BigInteger => ToStringInternal((BigInteger)value), 
				_ => throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())), 
			};
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value)
		{
			return SerializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting)
		{
			return SerializeObject(value, formatting, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			jsonSerializer.Formatting = formatting;
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer)
		{
			StringWriter stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
			using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter))
			{
				jsonTextWriter.Formatting = jsonSerializer.Formatting;
				jsonSerializer.Serialize(jsonTextWriter, value, type);
			}
			return stringWriter.ToString();
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value)
		{
			return DeserializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, JsonSerializerSettings settings)
		{
			return DeserializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type)
		{
			return DeserializeObject(value, type, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value)
		{
			return JsonConvert.DeserializeObject<T>(value, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
		{
			return DeserializeObject<T>(value);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject, JsonSerializerSettings settings)
		{
			return DeserializeObject<T>(value, settings);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, params JsonConverter[] converters)
		{
			return (T)DeserializeObject(value, typeof(T), converters);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, JsonSerializerSettings? settings)
		{
			return (T)DeserializeObject(value, typeof(T), settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return DeserializeObject(value, type, settings);
		}

		public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings)
		{
			ValidationUtils.ArgumentNotNull(value, "value");
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			if (!jsonSerializer.IsCheckAdditionalContentSet())
			{
				jsonSerializer.CheckAdditionalContent = true;
			}
			using JsonTextReader reader = new JsonTextReader(new StringReader(value));
			return jsonSerializer.Deserialize(reader, type);
		}

		[DebuggerStepThrough]
		public static void PopulateObject(string value, object target)
		{
			PopulateObject(value, target, null);
		}

		public static void PopulateObject(string value, object target, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			using JsonReader jsonReader = new JsonTextReader(new StringReader(value));
			jsonSerializer.Populate(jsonReader, target);
			if (settings == null || !settings.CheckAdditionalContent)
			{
				return;
			}
			while (jsonReader.Read())
			{
				if (jsonReader.TokenType != JsonToken.Comment)
				{
					throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object.");
				}
			}
		}

		public static string SerializeXmlNode(XmlNode? node)
		{
			return SerializeXmlNode(node, Formatting.None);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XmlDocument? DeserializeXmlNode(string value)
		{
			return DeserializeXmlNode(value, null);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), xmlNodeConverter);
		}

		public static string SerializeXNode(XObject? node)
		{
			return SerializeXNode(node, Formatting.None);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting)
		{
			return SerializeXNode(node, formatting, omitRootObject: false);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XDocument? DeserializeXNode(string value)
		{
			return DeserializeXNode(value, null);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XDocument)DeserializeObject(value, typeof(XDocument), xmlNodeConverter);
		}
	}
	public abstract class JsonConverter
	{
		public virtual bool CanRead => true;

		public virtual bool CanWrite => true;

		public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);

		public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

		public abstract bool CanConvert(Type objectType);
	}
	public abstract class JsonConverter<T> : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (!((value != null) ? (value is T) : ReflectionUtils.IsNullable(typeof(T))))
			{
				throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			WriteJson(writer, (T)value, serializer);
		}

		public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			bool flag = existingValue == null;
			if (!flag && !(existingValue is T))
			{
				throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			return ReadJson(reader, objectType, flag ? default(T) : ((T)existingValue), !flag, serializer);
		}

		public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);

		public sealed override bool CanConvert(Type objectType)
		{
			return typeof(T).IsAssignableFrom(objectType);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonConverterAttribute : Attribute
	{
		private readonly Type _converterType;

		public Type ConverterType => _converterType;

		public object[]? ConverterParameters { get; }

		public JsonConverterAttribute(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			_converterType = converterType;
		}

		public JsonConverterAttribute(Type converterType, params object[] converterParameters)
			: this(converterType)
		{
			ConverterParameters = converterParameters;
		}
	}
	public class JsonConverterCollection : Collection<JsonConverter>
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonDictionaryAttribute : JsonContainerAttribute
	{
		public JsonDictionaryAttribute()
		{
		}

		public JsonDictionaryAttribute(string id)
			: base(id)
		{
		}
	}
	[Serializable]
	public class JsonException : Exception
	{
		public JsonException()
		{
		}

		public JsonException(string message)
			: base(message)
		{
		}

		public JsonException(string message, Exception? innerException)
			: base(message, innerException)
		{
		}

		public JsonException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			return new JsonException(message);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public class JsonExtensionDataAttribute : Attribute
	{
		public bool WriteData { get; set; }

		public bool ReadData { get; set; }

		public JsonExtensionDataAttribute()
		{
			WriteData = true;
			ReadData = true;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonIgnoreAttribute : Attribute
	{
	}
	public abstract class JsonNameTable
	{
		public abstract string? Get(char[] key, int start, int length);
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonObjectAttribute : JsonContainerAttribute
	{
		private MemberSerialization _memberSerialization;

		internal MissingMemberHandling? _missingMemberHandling;

		internal Required? _itemRequired;

		internal NullValueHandling? _itemNullValueHandling;

		public MemberSerialization MemberSerialization
		{
			get
			{
				return _memberSerialization;
			}
			set
			{
				_memberSerialization = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public NullValueHandling ItemNullValueHandling
		{
			get
			{
				return _itemNullValueHandling.GetValueOrDefault();
			}
			set
			{
				_itemNullValueHandling = value;
			}
		}

		public Required ItemRequired
		{
			get
			{
				return _itemRequired.GetValueOrDefault();
			}
			set
			{
				_itemRequired = value;
			}
		}

		public JsonObjectAttribute()
		{
		}

		public JsonObjectAttribute(MemberSerialization memberSerialization)
		{
			MemberSerialization = memberSerialization;
		}

		public JsonObjectAttribute(string id)
			: base(id)
		{
		}
	}
	internal enum JsonContainerType
	{
		None,
		Object,
		Array,
		Constructor
	}
	internal struct JsonPosition
	{
		private static readonly char[] SpecialCharacters = new char[18]
		{
			'.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t',
			'\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029'
		};

		internal JsonContainerType Type;

		internal int Position;

		internal string? PropertyName;

		internal bool HasIndex;

		public JsonPosition(JsonContainerType type)
		{
			Type = type;
			HasIndex = TypeHasIndex(type);
			Position = -1;
			PropertyName = null;
		}

		internal int CalculateLength()
		{
			switch (Type)
			{
			case JsonContainerType.Object:
				return PropertyName.Length + 5;
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				return MathUtils.IntLength((ulong)Position) + 2;
			default:
				throw new ArgumentOutOfRangeException("Type");
			}
		}

		internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer)
		{
			switch (Type)
			{
			case JsonContainerType.Object:
			{
				string propertyName = PropertyName;
				if (propertyName.IndexOfAny(SpecialCharacters) != -1)
				{
					sb.Append("['");
					if (writer == null)
					{
						writer = new StringWriter(sb);
					}
					JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', appendDelimiters: false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
					sb.Append("']");
				}
				else
				{
					if (sb.Length > 0)
					{
						sb.Append('.');
					}
					sb.Append(propertyName);
				}
				break;
			}
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				sb.Append('[');
				sb.Append(Position);
				sb.Append(']');
				break;
			}
		}

		internal static bool TypeHasIndex(JsonContainerType type)
		{
			if (type != JsonContainerType.Array)
			{
				return type == JsonContainerType.Constructor;
			}
			return true;
		}

		internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition)
		{
			int num = 0;
			if (positions != null)
			{
				for (int i = 0; i < positions.Count; i++)
				{
					num += positions[i].CalculateLength();
				}
			}
			if (currentPosition.HasValue)
			{
				num += currentPosition.GetValueOrDefault().CalculateLength();
			}
			StringBuilder stringBuilder = new StringBuilder(num);
			StringWriter writer = null;
			char[] buffer = null;
			if (positions != null)
			{
				foreach (JsonPosition position in positions)
				{
					position.WriteTo(stringBuilder, ref writer, ref buffer);
				}
			}
			currentPosition?.WriteTo(stringBuilder, ref writer, ref buffer);
			return stringBuilder.ToString();
		}

		internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message)
		{
			if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
			{
				message = message.Trim();
				if (!StringUtils.EndsWith(message, '.'))
				{
					message += ".";
				}
				message += " ";
			}
			message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
			}
			message += ".";
			return message;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonPropertyAttribute : Attribute
	{
		internal NullValueHandling? _nullValueHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal bool? _isReference;

		internal int? _order;

		internal Required? _required;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType { get; set; }

		public object[]? NamingStrategyParameters { get; set; }

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameHandling = value;
			}
		}

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public int Order
		{
			get
			{
				return _order.GetValueOrDefault();
			}
			set
			{
				_order = value;
			}
		}

		public Required Required
		{
			get
			{
				return _required.GetValueOrDefault();
			}
			set
			{
				_required = value;
			}
		}

		public string? PropertyName { get; set; }

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public JsonPropertyAttribute()
		{
		}

		public JsonPropertyAttribute(string propertyName)
		{
			PropertyName = propertyName;
		}
	}
	public abstract class JsonReader : IDisposable
	{
		protected internal enum State
		{
			Start,
			Complete,
			Property,
			ObjectStart,
			Object,
			ArrayStart,
			Array,
			Closed,
			PostValue,
			ConstructorStart,
			Constructor,
			Error,
			Finished
		}

		private JsonToken _tokenType;

		private object? _value;

		internal char _quoteChar;

		internal State _currentState;

		private JsonPosition _currentPosition;

		private CultureInfo? _culture;

		private DateTimeZoneHandling _dateTimeZoneHandling;

		private int? _maxDepth;

		private bool _hasExceededMaxDepth;

		internal DateParseHandling _dateParseHandling;

		internal FloatParseHandling _floatParseHandling;

		private string? _dateFormatString;

		private List<JsonPosition>? _stack;

		protected State CurrentState => _currentState;

		public bool CloseInput { get; set; }

		public bool SupportMultipleContent { get; set; }

		public virtual char QuoteChar
		{
			get
			{
				return _quoteChar;
			}
			protected internal set
			{
				_quoteChar = value;
			}
		}

		public DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling;
			}
			set
			{
				if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateTimeZoneHandling = value;
			}
		}

		public DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling;
			}
			set
			{
				if (value < DateParseHandling.None || value > DateParseHandling.DateTimeOffset)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateParseHandling = value;
			}
		}

		public FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling;
			}
			set
			{
				if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_floatParseHandling = value;
			}
		}

		public string? DateFormatString
		{
			get
			{
				return _dateFormatString;
			}
			set
			{
				_dateFormatString = value;
			}
		}

		public int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
			}
		}

		public virtual JsonToken TokenType => _tokenType;

		public virtual object? Value => _value;

		public virtual Type? ValueType => _value?.GetType();

		public virtual int Depth
		{
			get
			{
				int num = _stack?.Count ?? 0;
				if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
				{
					return num;
				}
				return num + 1;
			}
		}

		public virtual string Path
		{
			get
			{
				if (_currentPosition.Type == JsonContainerType.None)
				{
					return string.Empty;
				}
				JsonPosition? currentPosition = ((_currentState != State.ArrayStart && _currentState != State.ConstructorStart && _currentState != State.ObjectStart) ? new JsonPosition?(_currentPosition) : null);
				return JsonPosition.BuildPath(_stack, currentPosition);
			}
		}

		public CultureInfo Culture
		{
			get
			{
				return _culture ?? CultureInfo.InvariantCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool>() ?? Read().ToAsync();
		}

		public async Task SkipAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (TokenType == JsonToken.PropertyName)
			{
				await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false) && depth < Depth)
				{
				}
			}
		}

		internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken)
		{
			if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
			{
				throw CreateUnexpectedEndException();
			}
		}

		public virtual Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool?>() ?? Task.FromResult(ReadAsBoolean());
		}

		public virtual Task<byte[]?> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<byte[]>() ?? Task.FromResult(ReadAsBytes());
		}

		internal async Task<byte[]?> ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken)
		{
			List<byte> buffer = new List<byte>();
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(buffer));
			byte[] array = buffer.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		public virtual Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTime?>() ?? Task.FromResult(ReadAsDateTime());
		}

		public virtual Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTimeOffset?>() ?? Task.FromResult(ReadAsDateTimeOffset());
		}

		public virtual Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<decimal?>() ?? Task.FromResult(ReadAsDecimal());
		}

		public virtual Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return Task.FromResult(ReadAsDouble());
		}

		public virtual Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<int?>() ?? Task.FromResult(ReadAsInt32());
		}

		public virtual Task<string?> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<string>() ?? Task.FromResult(ReadAsString());
		}

		internal async Task<bool> ReadAndMoveToContentAsync(CancellationToken cancellationToken)
		{
			bool flag = await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			if (flag)
			{
				flag = await MoveToContentAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			return flag;
		}

		internal Task<bool> MoveToContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType = TokenType;
			if (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				return MoveToContentFromNonContentAsync(cancellationToken);
			}
			return AsyncUtils.True;
		}

		private async Task<bool> MoveToContentFromNonContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType;
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					return false;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment);
			return true;
		}

		internal JsonPosition GetPosition(int depth)
		{
			if (_stack != null && depth < _stack.Count)
			{
				return _stack[depth];
			}
			return _currentPosition;
		}

		protected JsonReader()
		{
			_currentState = State.Start;
			_dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
			_dateParseHandling = DateParseHandling.DateTime;
			_floatParseHandling = FloatParseHandling.Double;
			_maxDepth = 64;
			CloseInput = true;
		}

		private void Push(JsonContainerType value)
		{
			UpdateScopeWithFinishedValue();
			if (_currentPosition.Type == JsonContainerType.None)
			{
				_currentPosition = new JsonPosition(value);
				return;
			}
			if (_stack == null)
			{
				_stack = new List<JsonPosition>();
			}
			_stack.Add(_currentPosition);
			_currentPosition = new JsonPosition(value);
			if (!_maxDepth.HasValue || !(Depth + 1 > _maxDepth) || _hasExceededMaxDepth)
			{
				return;
			}
			_hasExceededMaxDepth = true;
			throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
		}

		private JsonContainerType Pop()
		{
			JsonPosition currentPosition;
			if (_stack != null && _stack.Count > 0)
			{
				currentPosition = _currentPosition;
				_currentPosition = _stack[_stack.Count - 1];
				_stack.RemoveAt(_stack.Count - 1);
			}
			else
			{
				currentPosition = _currentPosition;
				_currentPosition = default(JsonPosition);
			}
			if (_maxDepth.HasValue && Depth <= _maxDepth)
			{
				_hasExceededMaxDepth = false;
			}
			return currentPosition.Type;
		}

		private JsonContainerType Peek()
		{
			return _currentPosition.Type;
		}

		public abstract bool Read();

		public virtual int? ReadAsInt32()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is int)
				{
					return (int)value;
				}
				int num;
				if (value is BigInteger bigInteger)
				{
					num = (int)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToInt32(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Integer, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadInt32String(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal int? ReadInt32String(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (int.TryParse(s, NumberStyles.Integer, Culture, out var result))
			{
				SetToken(JsonToken.Integer, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual string? ReadAsString()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.String:
				return (string)Value;
			default:
				if (JsonTokenUtils.IsPrimitiveToken(contentToken))
				{
					object value = Value;
					if (value != null)
					{
						string text = ((!(value is IFormattable formattable)) ? ((value is Uri uri) ? uri.OriginalString : value.ToString()) : formattable.ToString(null, Culture));
						SetToken(JsonToken.String, text, updateIndex: false);
						return text;
					}
				}
				throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		public virtual byte[]? ReadAsBytes()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.StartObject:
			{
				ReadIntoWrappedTypeObject();
				byte[] array2 = ReadAsBytes();
				ReaderReadAndAssert();
				if (TokenType != JsonToken.EndObject)
				{
					throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
				}
				SetToken(JsonToken.Bytes, array2, updateIndex: false);
				return array2;
			}
			case JsonToken.String:
			{
				string text = (string)Value;
				Guid g;
				byte[] array3 = ((text.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((!ConvertUtils.TryConvertGuid(text, out g)) ? Convert.FromBase64String(text) : g.ToByteArray()));
				SetToken(JsonToken.Bytes, array3, updateIndex: false);
				return array3;
			}
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Bytes:
				if (Value is Guid guid)
				{
					byte[] array = guid.ToByteArray();
					SetToken(JsonToken.Bytes, array, updateIndex: false);
					return array;
				}
				return (byte[])Value;
			case JsonToken.StartArray:
				return ReadArrayIntoByteArray();
			default:
				throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal byte[] ReadArrayIntoByteArray()
		{
			List<byte> list = new List<byte>();
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(list));
			byte[] array = list.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		private bool ReadArrayElementIntoByteArrayReportDone(List<byte> buffer)
		{
			switch (TokenType)
			{
			case JsonToken.None:
				throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
			case JsonToken.Integer:
				buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
				return false;
			case JsonToken.EndArray:
				return true;
			case JsonToken.Comment:
				return false;
			default:
				throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		public virtual double? ReadAsDouble()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is double)
				{
					return (double)value;
				}
				double num = ((!(value is BigInteger bigInteger)) ? Convert.ToDouble(value, CultureInfo.InvariantCulture) : ((double)bigInteger));
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDoubleString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal double? ReadDoubleString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual bool? ReadAsBoolean()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				bool flag = ((!(Value is BigInteger bigInteger)) ? Convert.ToBoolean(Value, CultureInfo.InvariantCulture) : (bigInteger != 0L));
				SetToken(JsonToken.Boolean, flag, updateIndex: false);
				return flag;
			}
			case JsonToken.String:
				return ReadBooleanString((string)Value);
			case JsonToken.Boolean:
				return (bool)Value;
			default:
				throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal bool? ReadBooleanString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (bool.TryParse(s, out var result))
			{
				SetToken(JsonToken.Boolean, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual decimal? ReadAsDecimal()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is decimal)
				{
					return (decimal)value;
				}
				decimal num;
				if (value is BigInteger bigInteger)
				{
					num = (decimal)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToDecimal(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDecimalString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal decimal? ReadDecimalString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (decimal.TryParse(s, NumberStyles.Number, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			if (ConvertUtils.DecimalTryParse(s.ToCharArray(), 0, s.Length, out result) == ParseResult.Success)
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTime? ReadAsDateTime()
		{
			switch (GetContentToken())
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTimeOffset dateTimeOffset)
				{
					SetToken(JsonToken.Date, dateTimeOffset.DateTime, updateIndex: false);
				}
				return (DateTime)Value;
			case JsonToken.String:
				return ReadDateTimeString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		internal DateTime? ReadDateTimeString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out var dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTimeOffset? ReadAsDateTimeOffset()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTime dateTime)
				{
					SetToken(JsonToken.Date, new DateTimeOffset(dateTime), updateIndex: false);
				}
				return (DateTimeOffset)Value;
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadDateTimeOffsetString(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal DateTimeOffset? ReadDateTimeOffsetString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out var dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		internal void ReaderReadAndAssert()
		{
			if (!Read())
			{
				throw CreateUnexpectedEndException();
			}
		}

		internal JsonReaderException CreateUnexpectedEndException()
		{
			return JsonReaderException.Create(this, "Unexpected end when reading JSON.");
		}

		internal void ReadIntoWrappedTypeObject()
		{
			ReaderReadAndAssert();
			if (Value != null && Value.ToString() == "$type")
			{
				ReaderReadAndAssert();
				if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
				{
					ReaderReadAndAssert();
					if (Value.ToString() == "$value")
					{
						return;
					}
				}
			}
			throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
		}

		public void Skip()
		{
			if (TokenType == JsonToken.PropertyName)
			{
				Read();
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (Read() && depth < Depth)
				{
				}
			}
		}

		protected void SetToken(JsonToken newToken)
		{
			SetToken(newToken, null, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value)
		{
			SetToken(newToken, value, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value, bool updateIndex)
		{
			_tokenType = newToken;
			_value = value;
			switch (newToken)
			{
			case JsonToken.StartObject:
				_currentState = State.ObjectStart;
				Push(JsonContainerType.Object);
				break;
			case JsonToken.StartArray:
				_currentState = State.ArrayStart;
				Push(JsonContainerType.Array);
				break;
			case JsonToken.StartConstructor:
				_currentState = State.ConstructorStart;
				Push(JsonContainerType.Constructor);
				break;
			case JsonToken.EndObject:
				ValidateEnd(JsonToken.EndObject);
				break;
			case JsonToken.EndArray:
				ValidateEnd(JsonToken.EndArray);
				break;
			case JsonToken.EndConstructor:
				ValidateEnd(JsonToken.EndConstructor);
				break;
			case JsonToken.PropertyName:
				_currentState = State.Property;
				_currentPosition.PropertyName = (string)value;
				break;
			case JsonToken.Raw:
			case JsonToken.Integer:
			case JsonToken.Float:
			case JsonToken.String:
			case JsonToken.Boolean:
			case JsonToken.Null:
			case JsonToken.Undefined:
			case JsonToken.Date:
			case JsonToken.Bytes:
				SetPostValueState(updateIndex);
				break;
			case JsonToken.Comment:
				break;
			}
		}

		internal void SetPostValueState(bool updateIndex)
		{
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
			if (updateIndex)
			{
				UpdateScopeWithFinishedValue();
			}
		}

		private void UpdateScopeWithFinishedValue()
		{
			if (_currentPosition.HasIndex)
			{
				_currentPosition.Position++;
			}
		}

		private void ValidateEnd(JsonToken endToken)
		{
			JsonContainerType jsonContainerType = Pop();
			if (GetTypeForCloseToken(endToken) != jsonContainerType)
			{
				throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, jsonContainerType));
			}
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
		}

		protected void SetStateBasedOnCurrent()
		{
			JsonContainerType jsonContainerType = Peek();
			switch (jsonContainerType)
			{
			case JsonContainerType.Object:
				_currentState = State.Object;
				break;
			case JsonContainerType.Array:
				_currentState = State.Array;
				break;
			case JsonContainerType.Constructor:
				_currentState = State.Constructor;
				break;
			case JsonContainerType.None:
				SetFinished();
				break;
			default:
				throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, jsonContainerType));
			}
		}

		private void SetFinished()
		{
			_currentState = ((!SupportMultipleContent) ? State.Finished : State.Start);
		}

		private JsonContainerType GetTypeForCloseToken(JsonToken token)
		{
			return token switch
			{
				JsonToken.EndObject => JsonContainerType.Object, 
				JsonToken.EndArray => JsonContainerType.Array, 
				JsonToken.EndConstructor => JsonContainerType.Constructor, 
				_ => throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token)), 
			};
		}

		void IDisposable.Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (_currentState != State.Closed && disposing)
			{
				Close();
			}
		}

		public virtual void Close()
		{
			_currentState = State.Closed;
			_tokenType = JsonToken.None;
			_value = null;
		}

		internal void ReadAndAssert()
		{
			if (!Read())
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter)
		{
			if (!ReadForType(contract, hasConverter))
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal bool ReadForType(JsonContract? contract, bool hasConverter)
		{
			if (hasConverter)
			{
				return Read();
			}
			switch (contract?.InternalReadType ?? ReadType.Read)
			{
			case ReadType.Read:
				return ReadAndMoveToContent();
			case ReadType.ReadAsInt32:
				ReadAsInt32();
				break;
			case ReadType.ReadAsInt64:
			{
				bool result = ReadAndMoveToContent();
				if (TokenType == JsonToken.Undefined)
				{
					throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long)));
				}
				return result;
			}
			case ReadType.ReadAsDecimal:
				ReadAsDecimal();
				break;
			case ReadType.ReadAsDouble:
				ReadAsDouble();
				break;
			case ReadType.ReadAsBytes:
				ReadAsBytes();
				break;
			case ReadType.ReadAsBoolean:
				ReadAsBoolean();
				break;
			case ReadType.ReadAsString:
				ReadAsString();
				break;
			case ReadType.ReadAsDateTime:
				ReadAsDateTime();
				break;
			case ReadType.ReadAsDateTimeOffset:
				ReadAsDateTimeOffset();
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			return TokenType != JsonToken.None;
		}

		internal bool ReadAndMoveToContent()
		{
			if (Read())
			{
				return MoveToContent();
			}
			return false;
		}

		internal bool MoveToContent()
		{
			JsonToken tokenType = TokenType;
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				if (!Read())
				{
					return false;
				}
				tokenType = TokenType;
			}
			return true;
		}

		private JsonToken GetContentToken()
		{
			JsonToken tokenType;
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
					return JsonToken.None;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.Comment);
			return tokenType;
		}
	}
	[Serializable]
	public class JsonReaderException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonReaderException()
		{
		}

		public JsonReaderException(string message)
			: base(message)
		{
		}

		public JsonReaderException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonReaderException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonReaderException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonReaderException(message, path, lineNumber, linePosition, ex);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonRequiredAttribute : Attribute
	{
	}
	[Serializable]
	public class JsonSerializationException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonSerializationException()
		{
		}

		public JsonSerializationException(string message)
			: base(message)
		{
		}

		public JsonSerializationException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonSerializationException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonSerializationException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonSerializationException(message, path, lineNumber, linePosition, ex);
		}
	}
	public class JsonSerializer
	{
		internal TypeNameHandling _typeNameHandling;

		internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling;

		internal PreserveReferencesHandling _preserveReferencesHandling;

		internal ReferenceLoopHandling _referenceLoopHandling;

		internal MissingMemberHandling _missingMemberHandling;

		internal ObjectCreationHandling _objectCreationHandling;

		internal NullValueHandling _nullValueHandling;

		internal DefaultValueHandling _defaultValueHandling;

		internal ConstructorHandling _constructorHandling;

		internal MetadataPropertyHandling _metadataPropertyHandling;

		internal JsonConverterCollection? _converters;

		internal IContractResolver _contractResolver;

		internal ITraceWriter? _traceWriter;

		internal IEqualityComparer? _equalityComparer;

		internal ISerializationBinder _serializationBinder;

		internal StreamingContext _context;

		private IReferenceResolver? _referenceResolver;

		private Formatting? _formatting;

		private DateFormatHandling? _dateFormatHandling;

		private DateTimeZoneHandling? _dateTimeZoneHandling;

		private DateParseHandling? _dateParseHandling;

		private FloatFormatHandling? _floatFormatHandling;

		private FloatParseHandling? _floatParseHandling;

		private StringEscapeHandling? _stringEscapeHandling;

		private CultureInfo _culture;

		private int? _maxDepth;

		private bool _maxDepthSet;

		private bool? _checkAdditionalContent;

		private string? _dateFormatString;

		private bool _dateFormatStringSet;

		public virtual IReferenceResolver? ReferenceResolver
		{
			get
			{
				return GetReferenceResolver();
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Reference resolver cannot be null.");
				}
				_referenceResolver = value;
			}
		}

		[Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
		public virtual SerializationBinder Binder
		{
			get
			{
				if (_serializationBinder is SerializationBinder result)
				{
					return result;
				}
				if (_serializationBinder is SerializationBinderAdapter serializationBinderAdapter)
				{
					return serializationBinderAdapter.SerializationBinder;
				}
				throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = (value as ISerializationBinder) ?? new SerializationBinderAdapter(value);
			}
		}

		public virtual ISerializationBinder SerializationBinder
		{
			get
			{
				return _serializationBinder;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = value;
			}
		}

		public virtual ITraceWriter? TraceWriter
		{
			get
			{
				return _traceWriter;
			}
			set
			{
				_traceWriter = value;
			}
		}

		public virtual IEqualityComparer? EqualityComparer
		{
			get
			{
				return _equalityComparer;
			}
			set
			{
				_equalityComparer = value;
			}
		}

		public virtual TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling;
			}
			set
			{
				if (value < TypeNameHandling.None || value > TypeNameHandling.Auto)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameHandling = value;
			}
		}

		[Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
		public virtual FormatterAssemblyStyle TypeNameAssemblyFormat
		{
			get
			{
				return (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
			}
		}

		public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
		{
			get
			{
				return _typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = value;
			}
		}

		public virtual PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling;
			}
			set
			{
				if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_preserveReferencesHandling = value;
			}
		}

		public virtual ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling;
			}
			set
			{
				if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_referenceLoopHandling = value;
			}
		}

		public virtual MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling;
			}
			set
			{
				if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_missingMemberHandling = value;
			}
		}

		public virtual NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling;
			}
			set
			{
				if (value < NullValueHandling.Include || value > NullValueHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_nullValueHandling = value;
			}
		}

		public virtual DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling;
			}
			set
			{
				if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_defaultValueHandling = value;
			}
		}

		public virtual ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling;
			}
			set
			{
				if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_objectCreationHandling = value;
			}
		}

		public virtual ConstructorHandling ConstructorHandling
		{
			get
			{
				return _constructorHandling;
			}
			set
			{
				if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_constructorHandling = value;
			}
		}

		public virtual MetadataPropertyHandling MetadataPropertyHandling
		{
			get
			{
				return _metadataPropertyHandling;
			}
			set
			{
				if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_metadataPropertyHandling = value;
			}
		}

		public virtual JsonConverterCollection Converters
		{
			get
			{
				if (_converters == null)
				{
					_converters = new JsonConverterCollection();
				}
				return _converters;
			}
		}

		public virtual IContractResolver ContractResolver
		{
			get
			{
				return _contractResolver;
			}
			set
			{
				_contractResolver = value ?? DefaultContractResolver.Instance;
			}
		}

		public virtual StreamingContext Context
		{
			get
			{
				return _context;
			}
			set
			{
				_context = value;
			}
		}

		public virtual Formatting Formatting
		{
			get
			{
				return _formatting.GetValueOrDefault();
			}
			set
			{
				_formatting = value;
			}
		}

		public virtual DateFormatHandling DateFormatHandling
		{
			get
			{
				return _dateFormatHandling.GetValueOrDefault();
			}
			set
			{
				_dateFormatHandling = value;
			}
		}

		public virtual DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling ?? DateTimeZoneHandling.RoundtripKind;
			}
			set
			{
				_dateTimeZoneHandling = value;
			}
		}

		public virtual DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling ?? DateParseHandling.DateTime;
			}
			set
			{
				_dateParseHandling = value;
			}
		}

		public virtual FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling.GetValueOrDefault();
			}
			set
			{
				_floatParseHandling = value;
			}
		}

		public virtual FloatFormatHandling FloatFormatHandling
		{
			get
			{
				return _floatFormatHandling.GetValueOrDefault();
			}
			set
			{
				_floatFormatHandling = value;
			}
		}

		public virtual StringEscapeHandling StringEscapeHandling
		{
			get
			{
				return _stringEscapeHandling.GetValueOrDefault();
			}
			set
			{
				_stringEscapeHandling = value;
			}
		}

		public virtual string DateFormatString
		{
			get
			{
				return _dateFormatString ?? "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
			}
			set
			{
				_dateFormatString = value;
				_dateFormatStringSet = true;
			}
		}

		public virtual CultureInfo Culture
		{
			get
			{
				return _culture ?? JsonSerializerSettings.DefaultCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
				_maxDepthSet = true;
			}
		}

		public virtual bool CheckAdditionalContent
		{
			get
			{
				return _checkAdditionalContent.GetValueOrDefault();
			}
			set
			{
				_checkAdditionalContent = value;
			}
		}

		public virtual event EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs>? Error;

		internal bool IsCheckAdditionalContentSet()
		{
			return _checkAdditionalContent.HasValue;
		}

		public JsonSerializer()
		{
			_referenceLoopHandling = ReferenceLoopHandling.Error;
			_missingMemberHandling = MissingMemberHandling.Ignore;
			_nullValueHandling = NullValueHandling.Include;
			_defaultValueHandling = DefaultValueHandling.Include;
			_objectCreationHandling = ObjectCreationHandling.Auto;
			_preserveReferencesHandling = PreserveReferencesHandling.None;
			_constructorHandling = ConstructorHandling.Default;
			_typeNameHandling = TypeNameHandling.None;
			_metadataPropertyHandling = MetadataPropertyHandling.Default;
			_context = JsonSerializerSettings.DefaultContext;
			_serializationBinder = DefaultSerializationBinder.Instance;
			_culture = JsonSerializerSettings.DefaultCulture;
			_contractResolver = DefaultContractResolver.Instance;
		}

		public static JsonSerializer Create()
		{
			return new JsonSerializer();
		}

		public static JsonSerializer Create(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = Create();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		public static JsonSerializer CreateDefault()
		{
			return Create(JsonConvert.DefaultSettings?.Invoke());
		}

		public static JsonSerializer CreateDefault(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = CreateDefault();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings)
		{
			if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
			{
				for (int i = 0; i < settings.Converters.Count; i++)
				{
					serializer.Converters.Insert(i, settings.Converters[i]);
				}
			}
			if (settings._typeNameHandling.HasValue)
			{
				serializer.TypeNameHandling = settings.TypeNameHandling;
			}
			if (settings._metadataPropertyHandling.HasValue)
			{
				serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling;
			}
			if (settings._typeNameAssemblyFormatHandling.HasValue)
			{
				serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling;
			}
			if (settings._preserveReferencesHandling.HasValue)
			{
				serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
			}
			if (settings._referenceLoopHandling.HasValue)
			{
				serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
			}
			if (settings._missingMemberHandling.HasValue)
			{
				serializer.MissingMemberHandling = settings.MissingMemberHandling;
			}
			if (settings._objectCreationHandling.HasValue)
			{
				serializer.ObjectCreationHandling = settings.ObjectCreationHandling;
			}
			if (settings._nullValueHandling.HasValue)
			{
				serializer.NullValueHandling = settings.NullValueHandling;
			}
			if (settings._defaultValueHandling.HasValue)
			{
				serializer.DefaultValueHandling = settings.DefaultValueHandling;
			}
			if (settings._constructorHandling.HasValue)
			{
				serializer.ConstructorHandling = settings.ConstructorHandling;
			}
			if (settings._context.HasValue)
			{
				serializer.Context = settings.Context;
			}
			if (settings._checkAdditionalContent.HasValue)
			{
				serializer._checkAdditionalContent = settings._checkAdditionalContent;
			}
			if (settings.Error != null)
			{
				serializer.Error += settings.Error;
			}
			if (settings.ContractResolver != null)
			{
				serializer.ContractResolver = settings.ContractResolver;
			}
			if (settings.ReferenceResolverProvider != null)
			{
				serializer.ReferenceResolver = settings.ReferenceResolverProvider();
			}
			if (settings.TraceWriter != null)
			{
				serializer.TraceWriter = settings.TraceWriter;
			}
			if (settings.EqualityComparer != null)
			{
				serializer.EqualityComparer = settings.EqualityComparer;
			}
			if (settings.SerializationBinder != null)
			{
				serializer.SerializationBinder = settings.SerializationBinder;
			}
			if (settings._formatting.HasValue)
			{
				serializer._formatting = settings._formatting;
			}
			if (settings._dateFormatHandling.HasValue)
			{
				serializer._dateFormatHandling = settings._dateFormatHandling;
			}
			if (settings._dateTimeZoneHandling.HasValue)
			{
				serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling;
			}
			if (settings._dateParseHandling.HasValue)
			{
				serializer._dateParseHandling = settings._dateParseHandling;
			}
			if (settings._dateFormatStringSet)
			{
				serializer._dateFormatString = settings._dateFormatString;
				serializer._dateFormatStringSet = settings._dateFormatStringSet;
			}
			if (settings._floatFormatHandling.HasValue)
			{
				serializer._floatFormatHandling = settings._floatFormatHandling;
			}
			if (settings._floatParseHandling.HasValue)
			{
				serializer._floatParseHandling = settings._floatParseHandling;
			}
			if (settings._stringEscapeHandling.HasValue)
			{
				serializer._stringEscapeHandling = settings._stringEscapeHandling;
			}
			if (settings._culture != null)
			{
				serializer._culture = settings._culture;
			}
			if (settings._maxDepthSet)
			{
				serializer._maxDepth = settings._maxDepth;
				serializer._maxDepthSet = settings._maxDepthSet;
			}
		}

		[DebuggerStepThrough]
		public void Populate(TextReader reader, object target)
		{
			Populate(new JsonTextReader(reader), target);
		}

		[DebuggerStepThrough]
		public void Populate(JsonReader reader, object target)
		{
			PopulateInternal(reader, target);
		}

		internal virtual void PopulateInternal(JsonReader reader, object target)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			ValidationUtils.ArgumentNotNull(target, "target");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			new JsonSerializerInternalReader(this).Populate(traceJsonReader ?? reader, target);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader)
		{
			return Deserialize(reader, null);
		}

		[DebuggerStepThrough]
		public object? Deserialize(TextReader reader, Type objectType)
		{
			return Deserialize(new JsonTextReader(reader), objectType);
		}

		[DebuggerStepThrough]
		public T? Deserialize<T>(JsonReader reader)
		{
			return (T)Deserialize(reader, typeof(T));
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader, Type? objectType)
		{
			return DeserializeInternal(reader, objectType);
		}

		internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			object? result = new JsonSerializerInternalReader(this).Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
			return result;
		}

		internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
		{
			if (_culture != null && !_culture.Equals(reader.Culture))
			{
				previousCulture = reader.Culture;
				reader.Culture = _culture;
			}
			else
			{
				previousCulture = null;
			}
			if (_dateTimeZoneHandling.HasValue && reader.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				previousDateTimeZoneHandling = reader.DateTimeZoneHandling;
				reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			else
			{
				previousDateTimeZoneHandling = null;
			}
			if (_dateParseHandling.HasValue && reader.DateParseHandling != _dateParseHandling)
			{
				previousDateParseHandling = reader.DateParseHandling;
				reader.DateParseHandling = _dateParseHandling.GetValueOrDefault();
			}
			else
			{
				previousDateParseHandling = null;
			}
			if (_floatParseHandling.HasValue && reader.FloatParseHandling != _floatParseHandling)
			{
				previousFloatParseHandling = reader.FloatParseHandling;
				reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault();
			}
			else
			{
				previousFloatParseHandling = null;
			}
			if (_maxDepthSet && reader.MaxDepth != _maxDepth)
			{
				previousMaxDepth = reader.MaxDepth;
				reader.MaxDepth = _maxDepth;
			}
			else
			{
				previousMaxDepth = null;
			}
			if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString)
			{
				previousDateFormatString = reader.DateFormatString;
				reader.DateFormatString = _dateFormatString;
			}
			else
			{
				previousDateFormatString = null;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver defaultContractResolver)
			{
				jsonTextReader.PropertyNameTable = defaultContractResolver.GetNameTable();
			}
		}

		private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString)
		{
			if (previousCulture != null)
			{
				reader.Culture = previousCulture;
			}
			if (previousDateTimeZoneHandling.HasValue)
			{
				reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
			}
			if (previousDateParseHandling.HasValue)
			{
				reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault();
			}
			if (previousFloatParseHandling.HasValue)
			{
				reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault();
			}
			if (_maxDepthSet)
			{
				reader.MaxDepth = previousMaxDepth;
			}
			if (_dateFormatStringSet)
			{
				reader.DateFormatString = previousDateFormatString;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable != null && _contractResolver is DefaultContractResolver defaultContractResolver && jsonTextReader.PropertyNameTable == defaultContractResolver.GetNameTable())
			{
				jsonTextReader.PropertyNameTable = null;
			}
		}

		public void Serialize(TextWriter textWriter, object? value)
		{
			Serialize(new JsonTextWriter(textWriter), value);
		}

		public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			SerializeInternal(jsonWriter, value, objectType);
		}

		public void Serialize(TextWriter textWriter, object? value, Type objectType)
		{
			Serialize(new JsonTextWriter(textWriter), value, objectType);
		}

		public void Serialize(JsonWriter jsonWriter, object? value)
		{
			SerializeInternal(jsonWriter, value, null);
		}

		private TraceJsonReader CreateTraceJsonReader(JsonReader reader)
		{
			TraceJsonReader traceJsonReader = new TraceJsonReader(reader);
			if (reader.TokenType != 0)
			{
				traceJsonReader.WriteCurrentToken();
			}
			return traceJsonReader;
		}

		internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
			Formatting? formatting = null;
			if (_formatting.HasValue && jsonWriter.Formatting != _formatting)
			{
				formatting = jsonWriter.Formatting;
				jsonWriter.Formatting = _formatting.GetValueOrDefault();
			}
			DateFormatHandling? dateFormatHandling = null;
			if (_dateFormatHandling.HasValue && jsonWriter.DateFormatHandling != _dateFormatHandling)
			{
				dateFormatHandling = jsonWriter.DateFormatHandling;
				jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault();
			}
			DateTimeZoneHandling? dateTimeZoneHandling = null;
			if (_dateTimeZoneHandling.HasValue && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				dateTimeZoneHandling = jsonWriter.DateTimeZoneHandling;
				jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			FloatFormatHandling? floatFormatHandling = null;
			if (_floatFormatHandling.HasValue && jsonWriter.FloatFormatHandling != _floatFormatHandling)
			{
				floatFormatHandling = jsonWriter.FloatFormatHandling;
				jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault();
			}
			StringEscapeHandling? stringEscapeHandling = null;
			if (_stringEscapeHandling.HasValue && jsonWriter.StringEscapeHandling != _stringEscapeHandling)
			{
				stringEscapeHandling = jsonWriter.StringEscapeHandling;
				jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault();
			}
			CultureInfo cultureInfo = null;
			if (_culture != null && !_culture.Equals(jsonWriter.Culture))
			{
				cultureInfo = jsonWriter.Culture;
				jsonWriter.Culture = _culture;
			}
			string dateFormatString = null;
			if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString)
			{
				dateFormatString = jsonWriter.DateFormatString;
				jsonWriter.DateFormatString = _dateFormatString;
			}
			TraceJsonWriter traceJsonWriter = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null);
			new JsonSerializerInternalWriter(this).Serialize(traceJsonWriter ?? jsonWriter, value, objectType);
			if (traceJsonWriter != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null);
			}
			if (formatting.HasValue)
			{
				jsonWriter.Formatting = formatting.GetValueOrDefault();
			}
			if (dateFormatHandling.HasValue)
			{
				jsonWriter.DateFormatHandling = dateFormatHandling.GetValueOrDefault();
			}
			if (dateTimeZoneHandling.HasValue)
			{
				jsonWriter.DateTimeZoneHandling = dateTimeZoneHandling.GetValueOrDefault();
			}
			if (floatFormatHandling.HasValue)
			{
				jsonWriter.FloatFormatHandling = floatFormatHandling.GetValueOrDefault();
			}
			if (stringEscapeHandling.HasValue)
			{
				jsonWriter.StringEscapeHandling = stringEscapeHandling.GetValueOrDefault();
			}
			if (_dateFormatStringSet)
			{
				jsonWriter.DateFormatString = dateFormatString;
			}
			if (cultureInfo != null)
			{
				jsonWriter.Culture = cultureInfo;
			}
		}

		internal IReferenceResolver GetReferenceResolver()
		{
			if (_referenceResolver == null)
			{
				_referenceResolver = new DefaultReferenceResolver();
			}
			return _referenceResolver;
		}

		internal JsonConverter? GetMatchingConverter(Type type)
		{
			return GetMatchingConverter(_converters, type);
		}

		internal static JsonConverter? GetMatchingConverter(IList<JsonConverter>? converters, Type objectType)
		{
			if (converters != null)
			{
				for (int i = 0; i < converters.Count; i++)
				{
					JsonConverter jsonConverter = converters[i];
					if (jsonConverter.CanConvert(objectType))
					{
						return jsonConverter;
					}
				}
			}
			return null;
		}

		internal void OnError(Newtonsoft.Json.Serialization.ErrorEventArgs e)
		{
			this.Error?.Invoke(this, e);
		}
	}
	public class JsonSerializerSettings
	{
		internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error;

		internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore;

		internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;

		internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;

		internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;

		internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;

		internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;

		internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;

		internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default;

		internal static readonly StreamingContext DefaultContext;

		internal const Formatting DefaultFormatting = Formatting.None;

		internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;

		internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;

		internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime;

		internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double;

		internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String;

		internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default;

		internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;

		internal static readonly CultureInfo DefaultCulture;

		internal const bool DefaultCheckAdditionalContent = false;

		internal const string DefaultDateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";

		internal const int DefaultMaxDepth = 64;

		internal Formatting? _formatting;

		internal DateFormatHandling? _dateFormatHandling;

		internal DateTimeZoneHandling? _dateTimeZoneHandling;

		internal DateParseHandling? _dateParseHandling;

		internal FloatFormatHandling? _floatFormatHandling;

		internal FloatParseHandling? _floatParseHandling;

		internal StringEscapeHandling? _stringEscapeHandling;

		internal CultureInfo? _culture;

		internal bool? _checkAdditionalContent;

		internal int? _maxDepth;

		internal bool _maxDepthSet;

		internal string? _dateFormatString;

		internal bool _dateFormatStringSet;

		internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal PreserveReferencesHandling? _preserveReferencesHandling;

		internal NullValueHandling? _nullValueHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal MissingMemberHandling? _missingMemberHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal StreamingContext? _context;

		internal ConstructorHandling? _constructorHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal MetadataPropertyHandling? _metadataPropertyHandling;

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public IList<JsonConverter> Converters { get; set; }

		public PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling.GetValueOrDef

plugins/System.Runtime.Serialization.dll

Decompiled 4 months ago
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Configuration;
using System.Runtime.Serialization.Diagnostics;
using System.Runtime.Serialization.Diagnostics.Application;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Json;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Xml.XPath;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("System.Runtime.Serialization.dll")]
[assembly: AssemblyDescription("System.Runtime.Serialization.dll")]
[assembly: AssemblyDefaultAlias("System.Runtime.Serialization.dll")]
[assembly: AssemblyCompany("Mono development team")]
[assembly: AssemblyProduct("Mono Common Language Infrastructure")]
[assembly: AssemblyCopyright("(c) Various Mono authors")]
[assembly: SatelliteContractVersion("4.0.0.0")]
[assembly: AssemblyInformationalVersion("4.6.57.0")]
[assembly: AssemblyFileVersion("4.6.57.0")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyDelaySign(true)]
[assembly: AssemblyKeyFile("../ecma.pub")]
[assembly: AllowPartiallyTrustedCallers]
[assembly: ComCompatibleVersion(1, 0, 3300, 0)]
[assembly: SecurityCritical(SecurityCriticalScope.Explicit)]
[assembly: ComVisible(false)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("4.0.0.0")]
[module: UnverifiableCode]
internal static class SR
{
	internal static string GetString(string name, params object[] args)
	{
		return GetString(CultureInfo.InvariantCulture, name, args);
	}

	internal static string GetString(CultureInfo culture, string name, params object[] args)
	{
		return string.Format(culture, name, args);
	}

	internal static string GetString(string name)
	{
		return name;
	}

	internal static string GetString(CultureInfo culture, string name)
	{
		return name;
	}

	internal static string Format(string resourceFormat, params object[] args)
	{
		if (args != null)
		{
			return string.Format(CultureInfo.InvariantCulture, resourceFormat, args);
		}
		return resourceFormat;
	}

	internal static string Format(string resourceFormat, object p1)
	{
		return string.Format(CultureInfo.InvariantCulture, resourceFormat, p1);
	}

	internal static string Format(string resourceFormat, object p1, object p2)
	{
		return string.Format(CultureInfo.InvariantCulture, resourceFormat, p1, p2);
	}

	internal static string Format(CultureInfo ci, string resourceFormat, object p1, object p2)
	{
		return string.Format(ci, resourceFormat, p1, p2);
	}

	internal static string Format(string resourceFormat, object p1, object p2, object p3)
	{
		return string.Format(CultureInfo.InvariantCulture, resourceFormat, p1, p2, p3);
	}

	internal static string GetResourceString(string str)
	{
		return str;
	}
}
namespace System
{
	internal static class LocalAppContextSwitches
	{
		public static readonly bool DoNotUseTimeZoneInfo;

		public static readonly bool DoNotUseEcmaScriptV6EscapeControlCharacter;
	}
	internal static class NotImplemented
	{
		internal static Exception ByDesign => new NotImplementedException();

		internal static Exception ByDesignWithMessage(string message)
		{
			return new NotImplementedException(message);
		}
	}
}
namespace System.Xml
{
	internal abstract class ArrayHelper<TArgument, TArray>
	{
		public TArray[] ReadArray(XmlDictionaryReader reader, TArgument localName, TArgument namespaceUri, int maxArrayLength)
		{
			TArray[][] array = null;
			TArray[] array2 = null;
			int num = 0;
			int num2 = 0;
			if (reader.TryGetArrayLength(out var count))
			{
				if (count > maxArrayLength)
				{
					XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength);
				}
				if (count > 65535)
				{
					count = 65535;
				}
			}
			else
			{
				count = 32;
			}
			while (true)
			{
				array2 = new TArray[count];
				int i;
				int num3;
				for (i = 0; i < array2.Length; i += num3)
				{
					num3 = ReadArray(reader, localName, namespaceUri, array2, i, array2.Length - i);
					if (num3 == 0)
					{
						break;
					}
				}
				if (num2 > maxArrayLength - i)
				{
					XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength);
				}
				num2 += i;
				if (i < array2.Length || reader.NodeType == XmlNodeType.EndElement)
				{
					break;
				}
				if (array == null)
				{
					array = new TArray[32][];
				}
				array[num++] = array2;
				count *= 2;
			}
			if (num2 != array2.Length || num > 0)
			{
				TArray[] array3 = new TArray[num2];
				int num4 = 0;
				for (int j = 0; j < num; j++)
				{
					Array.Copy(array[j], 0, array3, num4, array[j].Length);
					num4 += array[j].Length;
				}
				Array.Copy(array2, 0, array3, num4, num2 - num4);
				array2 = array3;
			}
			return array2;
		}

		public void WriteArray(XmlDictionaryWriter writer, string prefix, TArgument localName, TArgument namespaceUri, XmlDictionaryReader reader)
		{
			int count = ((!reader.TryGetArrayLength(out count)) ? 256 : Math.Min(count, 256));
			TArray[] array = new TArray[count];
			while (true)
			{
				int num = ReadArray(reader, localName, namespaceUri, array, 0, array.Length);
				if (num != 0)
				{
					WriteArray(writer, prefix, localName, namespaceUri, array, 0, num);
					continue;
				}
				break;
			}
		}

		protected abstract int ReadArray(XmlDictionaryReader reader, TArgument localName, TArgument namespaceUri, TArray[] array, int offset, int count);

		protected abstract void WriteArray(XmlDictionaryWriter writer, string prefix, TArgument localName, TArgument namespaceUri, TArray[] array, int offset, int count);
	}
	internal class BooleanArrayHelperWithString : ArrayHelper<string, bool>
	{
		public static readonly BooleanArrayHelperWithString Instance = new BooleanArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, bool[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, bool[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class BooleanArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, bool>
	{
		public static readonly BooleanArrayHelperWithDictionaryString Instance = new BooleanArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, bool[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, bool[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class Int16ArrayHelperWithString : ArrayHelper<string, short>
	{
		public static readonly Int16ArrayHelperWithString Instance = new Int16ArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, short[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, short[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class Int16ArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, short>
	{
		public static readonly Int16ArrayHelperWithDictionaryString Instance = new Int16ArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, short[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, short[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class Int32ArrayHelperWithString : ArrayHelper<string, int>
	{
		public static readonly Int32ArrayHelperWithString Instance = new Int32ArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, int[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, int[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class Int32ArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, int>
	{
		public static readonly Int32ArrayHelperWithDictionaryString Instance = new Int32ArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, int[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, int[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class Int64ArrayHelperWithString : ArrayHelper<string, long>
	{
		public static readonly Int64ArrayHelperWithString Instance = new Int64ArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, long[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, long[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class Int64ArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, long>
	{
		public static readonly Int64ArrayHelperWithDictionaryString Instance = new Int64ArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, long[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, long[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class SingleArrayHelperWithString : ArrayHelper<string, float>
	{
		public static readonly SingleArrayHelperWithString Instance = new SingleArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, float[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, float[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class SingleArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, float>
	{
		public static readonly SingleArrayHelperWithDictionaryString Instance = new SingleArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, float[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, float[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class DoubleArrayHelperWithString : ArrayHelper<string, double>
	{
		public static readonly DoubleArrayHelperWithString Instance = new DoubleArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, double[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, double[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class DoubleArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, double>
	{
		public static readonly DoubleArrayHelperWithDictionaryString Instance = new DoubleArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, double[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, double[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class DecimalArrayHelperWithString : ArrayHelper<string, decimal>
	{
		public static readonly DecimalArrayHelperWithString Instance = new DecimalArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, decimal[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, decimal[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class DecimalArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, decimal>
	{
		public static readonly DecimalArrayHelperWithDictionaryString Instance = new DecimalArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, decimal[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, decimal[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class DateTimeArrayHelperWithString : ArrayHelper<string, DateTime>
	{
		public static readonly DateTimeArrayHelperWithString Instance = new DateTimeArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, DateTime[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, DateTime[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class DateTimeArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, DateTime>
	{
		public static readonly DateTimeArrayHelperWithDictionaryString Instance = new DateTimeArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, DateTime[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, DateTime[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class GuidArrayHelperWithString : ArrayHelper<string, Guid>
	{
		public static readonly GuidArrayHelperWithString Instance = new GuidArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, Guid[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, Guid[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class GuidArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, Guid>
	{
		public static readonly GuidArrayHelperWithDictionaryString Instance = new GuidArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, Guid[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, Guid[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class TimeSpanArrayHelperWithString : ArrayHelper<string, TimeSpan>
	{
		public static readonly TimeSpanArrayHelperWithString Instance = new TimeSpanArrayHelperWithString();

		protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, TimeSpan[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, TimeSpan[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class TimeSpanArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, TimeSpan>
	{
		public static readonly TimeSpanArrayHelperWithDictionaryString Instance = new TimeSpanArrayHelperWithDictionaryString();

		protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, TimeSpan[] array, int offset, int count)
		{
			return reader.ReadArray(localName, namespaceUri, array, offset, count);
		}

		protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, TimeSpan[] array, int offset, int count)
		{
			writer.WriteArray(prefix, localName, namespaceUri, array, offset, count);
		}
	}
	internal class EncodingStreamWrapper : Stream
	{
		private enum SupportedEncoding
		{
			UTF8,
			UTF16LE,
			UTF16BE,
			None
		}

		private static readonly UTF8Encoding SafeUTF8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);

		private static readonly UnicodeEncoding SafeUTF16 = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: false);

		private static readonly UnicodeEncoding SafeBEUTF16 = new UnicodeEncoding(bigEndian: true, byteOrderMark: false, throwOnInvalidBytes: false);

		private static readonly UTF8Encoding ValidatingUTF8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);

		private static readonly UnicodeEncoding ValidatingUTF16 = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true);

		private static readonly UnicodeEncoding ValidatingBEUTF16 = new UnicodeEncoding(bigEndian: true, byteOrderMark: false, throwOnInvalidBytes: true);

		private const int BufferLength = 128;

		private static readonly byte[] encodingAttr = new byte[8] { 101, 110, 99, 111, 100, 105, 110, 103 };

		private static readonly byte[] encodingUTF8 = new byte[5] { 117, 116, 102, 45, 56 };

		private static readonly byte[] encodingUnicode = new byte[6] { 117, 116, 102, 45, 49, 54 };

		private static readonly byte[] encodingUnicodeLE = new byte[8] { 117, 116, 102, 45, 49, 54, 108, 101 };

		private static readonly byte[] encodingUnicodeBE = new byte[8] { 117, 116, 102, 45, 49, 54, 98, 101 };

		private SupportedEncoding encodingCode;

		private Encoding encoding;

		private Encoder enc;

		private Decoder dec;

		private bool isReading;

		private Stream stream;

		private char[] chars;

		private byte[] bytes;

		private int byteOffset;

		private int byteCount;

		private byte[] byteBuffer = new byte[1];

		public override bool CanRead
		{
			get
			{
				if (!isReading)
				{
					return false;
				}
				return stream.CanRead;
			}
		}

		public override bool CanSeek => false;

		public override bool CanWrite
		{
			get
			{
				if (isReading)
				{
					return false;
				}
				return stream.CanWrite;
			}
		}

		public override long Position
		{
			get
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
			}
			set
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
			}
		}

		public override bool CanTimeout => stream.CanTimeout;

		public override long Length => stream.Length;

		public override int ReadTimeout
		{
			get
			{
				return stream.ReadTimeout;
			}
			set
			{
				stream.ReadTimeout = value;
			}
		}

		public override int WriteTimeout
		{
			get
			{
				return stream.WriteTimeout;
			}
			set
			{
				stream.WriteTimeout = value;
			}
		}

		public EncodingStreamWrapper(Stream stream, Encoding encoding)
		{
			try
			{
				isReading = true;
				this.stream = new BufferedStream(stream);
				SupportedEncoding supportedEncoding = GetSupportedEncoding(encoding);
				SupportedEncoding supportedEncoding2 = ReadBOMEncoding(encoding == null);
				if (supportedEncoding != SupportedEncoding.None && supportedEncoding != supportedEncoding2)
				{
					ThrowExpectedEncodingMismatch(supportedEncoding, supportedEncoding2);
				}
				if (supportedEncoding2 == SupportedEncoding.UTF8)
				{
					FillBuffer(2);
					if (bytes[byteOffset + 1] == 63 && bytes[byteOffset] == 60)
					{
						FillBuffer(128);
						CheckUTF8DeclarationEncoding(bytes, byteOffset, byteCount, supportedEncoding2, supportedEncoding);
					}
					return;
				}
				EnsureBuffers();
				FillBuffer(254);
				SetReadDocumentEncoding(supportedEncoding2);
				CleanupCharBreak();
				int charCount = this.encoding.GetChars(bytes, byteOffset, byteCount, chars, 0);
				byteOffset = 0;
				byteCount = ValidatingUTF8.GetBytes(chars, 0, charCount, bytes, 0);
				if (bytes[1] == 63 && bytes[0] == 60)
				{
					CheckUTF8DeclarationEncoding(bytes, 0, byteCount, supportedEncoding2, supportedEncoding);
				}
				else if (supportedEncoding == SupportedEncoding.None)
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents.")));
				}
			}
			catch (DecoderFallbackException innerException)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Invalid byte encoding."), innerException));
			}
		}

		private void SetReadDocumentEncoding(SupportedEncoding e)
		{
			EnsureBuffers();
			encodingCode = e;
			encoding = GetEncoding(e);
		}

		private static Encoding GetEncoding(SupportedEncoding e)
		{
			return e switch
			{
				SupportedEncoding.UTF8 => ValidatingUTF8, 
				SupportedEncoding.UTF16LE => ValidatingUTF16, 
				SupportedEncoding.UTF16BE => ValidatingBEUTF16, 
				_ => throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported."))), 
			};
		}

		private static Encoding GetSafeEncoding(SupportedEncoding e)
		{
			return e switch
			{
				SupportedEncoding.UTF8 => SafeUTF8, 
				SupportedEncoding.UTF16LE => SafeUTF16, 
				SupportedEncoding.UTF16BE => SafeBEUTF16, 
				_ => throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported."))), 
			};
		}

		private static string GetEncodingName(SupportedEncoding enc)
		{
			return enc switch
			{
				SupportedEncoding.UTF8 => "utf-8", 
				SupportedEncoding.UTF16LE => "utf-16LE", 
				SupportedEncoding.UTF16BE => "utf-16BE", 
				_ => throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported."))), 
			};
		}

		private static SupportedEncoding GetSupportedEncoding(Encoding encoding)
		{
			if (encoding == null)
			{
				return SupportedEncoding.None;
			}
			if (encoding.WebName == ValidatingUTF8.WebName)
			{
				return SupportedEncoding.UTF8;
			}
			if (encoding.WebName == ValidatingUTF16.WebName)
			{
				return SupportedEncoding.UTF16LE;
			}
			if (encoding.WebName == ValidatingBEUTF16.WebName)
			{
				return SupportedEncoding.UTF16BE;
			}
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported.")));
		}

		public EncodingStreamWrapper(Stream stream, Encoding encoding, bool emitBOM)
		{
			isReading = false;
			this.encoding = encoding;
			this.stream = new BufferedStream(stream);
			encodingCode = GetSupportedEncoding(encoding);
			if (encodingCode == SupportedEncoding.UTF8)
			{
				return;
			}
			EnsureBuffers();
			dec = ValidatingUTF8.GetDecoder();
			enc = this.encoding.GetEncoder();
			if (emitBOM)
			{
				byte[] preamble = this.encoding.GetPreamble();
				if (preamble.Length != 0)
				{
					this.stream.Write(preamble, 0, preamble.Length);
				}
			}
		}

		private SupportedEncoding ReadBOMEncoding(bool notOutOfBand)
		{
			int num = stream.ReadByte();
			int num2 = stream.ReadByte();
			int num3 = stream.ReadByte();
			int num4 = stream.ReadByte();
			if (num4 == -1)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file.")));
			}
			int preserve;
			SupportedEncoding result = ReadBOMEncoding((byte)num, (byte)num2, (byte)num3, (byte)num4, notOutOfBand, out preserve);
			EnsureByteBuffer();
			switch (preserve)
			{
			case 1:
				bytes[0] = (byte)num4;
				break;
			case 2:
				bytes[0] = (byte)num3;
				bytes[1] = (byte)num4;
				break;
			case 4:
				bytes[0] = (byte)num;
				bytes[1] = (byte)num2;
				bytes[2] = (byte)num3;
				bytes[3] = (byte)num4;
				break;
			}
			byteCount = preserve;
			return result;
		}

		private static SupportedEncoding ReadBOMEncoding(byte b1, byte b2, byte b3, byte b4, bool notOutOfBand, out int preserve)
		{
			SupportedEncoding result = SupportedEncoding.UTF8;
			preserve = 0;
			if (b1 == 60 && b2 != 0)
			{
				result = SupportedEncoding.UTF8;
				preserve = 4;
			}
			else if (b1 == byte.MaxValue && b2 == 254)
			{
				result = SupportedEncoding.UTF16LE;
				preserve = 2;
			}
			else if (b1 == 254 && b2 == byte.MaxValue)
			{
				result = SupportedEncoding.UTF16BE;
				preserve = 2;
			}
			else if (b1 == 0 && b2 == 60)
			{
				result = SupportedEncoding.UTF16BE;
				if (notOutOfBand && (b3 != 0 || b4 != 63))
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration is required for all non-UTF8 documents.")));
				}
				preserve = 4;
			}
			else if (b1 == 60 && b2 == 0)
			{
				result = SupportedEncoding.UTF16LE;
				if (notOutOfBand && (b3 != 63 || b4 != 0))
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration is required for all non-UTF8 documents.")));
				}
				preserve = 4;
			}
			else if (b1 == 239 && b2 == 187)
			{
				if (notOutOfBand && b3 != 191)
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unrecognized Byte Order Mark.")));
				}
				preserve = 1;
			}
			else
			{
				preserve = 4;
			}
			return result;
		}

		private void FillBuffer(int count)
		{
			count -= byteCount;
			while (count > 0)
			{
				int num = stream.Read(bytes, byteOffset + byteCount, count);
				if (num != 0)
				{
					byteCount += num;
					count -= num;
					continue;
				}
				break;
			}
		}

		private void EnsureBuffers()
		{
			EnsureByteBuffer();
			if (chars == null)
			{
				chars = new char[128];
			}
		}

		private void EnsureByteBuffer()
		{
			if (bytes == null)
			{
				bytes = new byte[512];
				byteOffset = 0;
				byteCount = 0;
			}
		}

		private static void CheckUTF8DeclarationEncoding(byte[] buffer, int offset, int count, SupportedEncoding e, SupportedEncoding expectedEnc)
		{
			byte b = 0;
			int num = -1;
			int num2 = offset + Math.Min(count, 128);
			int num3 = 0;
			int num4 = 0;
			for (num3 = offset + 2; num3 < num2; num3++)
			{
				if (b != 0)
				{
					if (buffer[num3] == b)
					{
						b = 0;
					}
				}
				else if (buffer[num3] == 39 || buffer[num3] == 34)
				{
					b = buffer[num3];
				}
				else if (buffer[num3] == 61)
				{
					if (num4 == 1)
					{
						num = num3;
						break;
					}
					num4++;
				}
				else if (buffer[num3] == 63)
				{
					break;
				}
			}
			if (num == -1)
			{
				if (e != 0 && expectedEnc == SupportedEncoding.None)
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents.")));
				}
				return;
			}
			if (num < 28)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Malformed XML declaration.")));
			}
			num3 = num - 1;
			while (IsWhitespace(buffer[num3]))
			{
				num3--;
			}
			if (!Compare(encodingAttr, buffer, num3 - encodingAttr.Length + 1))
			{
				if (e == SupportedEncoding.UTF8 || expectedEnc != SupportedEncoding.None)
				{
					return;
				}
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents.")));
			}
			for (num3 = num + 1; num3 < num2 && IsWhitespace(buffer[num3]); num3++)
			{
			}
			if (buffer[num3] != 39 && buffer[num3] != 34)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Malformed XML declaration.")));
			}
			b = buffer[num3];
			int num5 = num3++;
			for (; buffer[num3] != b && num3 < num2; num3++)
			{
			}
			if (buffer[num3] != b)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Malformed XML declaration.")));
			}
			int num6 = num5 + 1;
			int num7 = num3 - num6;
			SupportedEncoding supportedEncoding = e;
			if (num7 == encodingUTF8.Length && CompareCaseInsensitive(encodingUTF8, buffer, num6))
			{
				supportedEncoding = SupportedEncoding.UTF8;
			}
			else if (num7 == encodingUnicodeLE.Length && CompareCaseInsensitive(encodingUnicodeLE, buffer, num6))
			{
				supportedEncoding = SupportedEncoding.UTF16LE;
			}
			else if (num7 == encodingUnicodeBE.Length && CompareCaseInsensitive(encodingUnicodeBE, buffer, num6))
			{
				supportedEncoding = SupportedEncoding.UTF16BE;
			}
			else if (num7 == encodingUnicode.Length && CompareCaseInsensitive(encodingUnicode, buffer, num6))
			{
				if (e == SupportedEncoding.UTF8)
				{
					ThrowEncodingMismatch(SafeUTF8.GetString(buffer, num6, num7), SafeUTF8.GetString(encodingUTF8, 0, encodingUTF8.Length));
				}
			}
			else
			{
				ThrowEncodingMismatch(SafeUTF8.GetString(buffer, num6, num7), e);
			}
			if (e != supportedEncoding)
			{
				ThrowEncodingMismatch(SafeUTF8.GetString(buffer, num6, num7), e);
			}
		}

		private static bool CompareCaseInsensitive(byte[] key, byte[] buffer, int offset)
		{
			for (int i = 0; i < key.Length; i++)
			{
				if (key[i] != buffer[offset + i] && key[i] != char.ToLower((char)buffer[offset + i], CultureInfo.InvariantCulture))
				{
					return false;
				}
			}
			return true;
		}

		private static bool Compare(byte[] key, byte[] buffer, int offset)
		{
			for (int i = 0; i < key.Length; i++)
			{
				if (key[i] != buffer[offset + i])
				{
					return false;
				}
			}
			return true;
		}

		private static bool IsWhitespace(byte ch)
		{
			if (ch != 32 && ch != 10 && ch != 9)
			{
				return ch == 13;
			}
			return true;
		}

		internal static ArraySegment<byte> ProcessBuffer(byte[] buffer, int offset, int count, Encoding encoding)
		{
			if (count < 4)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file.")));
			}
			try
			{
				SupportedEncoding supportedEncoding = GetSupportedEncoding(encoding);
				int preserve;
				SupportedEncoding supportedEncoding2 = ReadBOMEncoding(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3], encoding == null, out preserve);
				if (supportedEncoding != SupportedEncoding.None && supportedEncoding != supportedEncoding2)
				{
					ThrowExpectedEncodingMismatch(supportedEncoding, supportedEncoding2);
				}
				offset += 4 - preserve;
				count -= 4 - preserve;
				if (supportedEncoding2 == SupportedEncoding.UTF8)
				{
					if (buffer[offset + 1] != 63 || buffer[offset] != 60)
					{
						return new ArraySegment<byte>(buffer, offset, count);
					}
					CheckUTF8DeclarationEncoding(buffer, offset, count, supportedEncoding2, supportedEncoding);
					return new ArraySegment<byte>(buffer, offset, count);
				}
				Encoding safeEncoding = GetSafeEncoding(supportedEncoding2);
				int num = Math.Min(count, 256);
				char[] array = new char[safeEncoding.GetMaxCharCount(num)];
				int charCount = safeEncoding.GetChars(buffer, offset, num, array, 0);
				byte[] array2 = new byte[ValidatingUTF8.GetMaxByteCount(charCount)];
				int count2 = ValidatingUTF8.GetBytes(array, 0, charCount, array2, 0);
				if (array2[1] == 63 && array2[0] == 60)
				{
					CheckUTF8DeclarationEncoding(array2, 0, count2, supportedEncoding2, supportedEncoding);
				}
				else if (supportedEncoding == SupportedEncoding.None)
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents.")));
				}
				return new ArraySegment<byte>(ValidatingUTF8.GetBytes(GetEncoding(supportedEncoding2).GetChars(buffer, offset, count)));
			}
			catch (DecoderFallbackException innerException)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Invalid byte encoding."), innerException));
			}
		}

		private static void ThrowExpectedEncodingMismatch(SupportedEncoding expEnc, SupportedEncoding actualEnc)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("The expected encoding '{0}' does not match the actual encoding '{1}'.", GetEncodingName(expEnc), GetEncodingName(actualEnc))));
		}

		private static void ThrowEncodingMismatch(string declEnc, SupportedEncoding enc)
		{
			ThrowEncodingMismatch(declEnc, GetEncodingName(enc));
		}

		private static void ThrowEncodingMismatch(string declEnc, string docEnc)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("The encoding in the declaration '{0}' does not match the encoding of the document '{1}'.", declEnc, docEnc)));
		}

		public override void Close()
		{
			Flush();
			base.Close();
			stream.Close();
		}

		public override void Flush()
		{
			stream.Flush();
		}

		public override int ReadByte()
		{
			if (byteCount == 0 && encodingCode == SupportedEncoding.UTF8)
			{
				return stream.ReadByte();
			}
			if (Read(byteBuffer, 0, 1) == 0)
			{
				return -1;
			}
			return byteBuffer[0];
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			try
			{
				if (byteCount == 0)
				{
					if (encodingCode == SupportedEncoding.UTF8)
					{
						return stream.Read(buffer, offset, count);
					}
					byteOffset = 0;
					byteCount = stream.Read(bytes, byteCount, (chars.Length - 1) * 2);
					if (byteCount == 0)
					{
						return 0;
					}
					CleanupCharBreak();
					int charCount = encoding.GetChars(bytes, 0, byteCount, chars, 0);
					byteCount = Encoding.UTF8.GetBytes(chars, 0, charCount, bytes, 0);
				}
				if (byteCount < count)
				{
					count = byteCount;
				}
				Buffer.BlockCopy(bytes, byteOffset, buffer, offset, count);
				byteOffset += count;
				byteCount -= count;
				return count;
			}
			catch (DecoderFallbackException innerException)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Invalid byte encoding."), innerException));
			}
		}

		private void CleanupCharBreak()
		{
			int num = byteOffset + byteCount;
			if (byteCount % 2 != 0)
			{
				int num2 = stream.ReadByte();
				if (num2 < 0)
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file.")));
				}
				bytes[num++] = (byte)num2;
				byteCount++;
			}
			int num3 = ((encodingCode != SupportedEncoding.UTF16LE) ? (bytes[num - 1] + (bytes[num - 2] << 8)) : (bytes[num - 2] + (bytes[num - 1] << 8)));
			if ((num3 & 0xDC00) != 56320 && num3 >= 55296 && num3 <= 56319)
			{
				int num4 = stream.ReadByte();
				int num5 = stream.ReadByte();
				if (num5 < 0)
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file.")));
				}
				bytes[num++] = (byte)num4;
				bytes[num++] = (byte)num5;
				byteCount += 2;
			}
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
		}

		public override void WriteByte(byte b)
		{
			if (encodingCode == SupportedEncoding.UTF8)
			{
				stream.WriteByte(b);
				return;
			}
			byteBuffer[0] = b;
			Write(byteBuffer, 0, 1);
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			if (encodingCode == SupportedEncoding.UTF8)
			{
				stream.Write(buffer, offset, count);
				return;
			}
			while (count > 0)
			{
				int num = ((chars.Length < count) ? chars.Length : count);
				int charCount = dec.GetChars(buffer, offset, num, chars, 0, flush: false);
				byteCount = enc.GetBytes(chars, 0, charCount, bytes, 0, flush: false);
				stream.Write(bytes, 0, byteCount);
				offset += num;
				count -= num;
			}
		}

		public override void SetLength(long value)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
		}
	}
	public interface IFragmentCapableXmlDictionaryWriter
	{
		bool CanFragment { get; }

		void StartFragment(Stream stream, bool generateSelfContainedTextFragment);

		void EndFragment();

		void WriteFragment(byte[] buffer, int offset, int count);
	}
	public interface IStreamProvider
	{
		Stream GetStream();

		void ReleaseStream(Stream stream);
	}
	public interface IXmlDictionary
	{
		bool TryLookup(string value, out XmlDictionaryString result);

		bool TryLookup(int key, out XmlDictionaryString result);

		bool TryLookup(XmlDictionaryString value, out XmlDictionaryString result);
	}
	internal enum PrefixHandleType
	{
		Empty,
		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,
		Buffer,
		Max
	}
	internal class PrefixHandle
	{
		private XmlBufferReader bufferReader;

		private PrefixHandleType type;

		private int offset;

		private int length;

		private static string[] prefixStrings = new string[27]
		{
			"", "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 byte[] prefixBuffer = new byte[26]
		{
			97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
			107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
			117, 118, 119, 120, 121, 122
		};

		public bool IsEmpty => type == PrefixHandleType.Empty;

		public bool IsXmlns
		{
			get
			{
				if (type != PrefixHandleType.Buffer)
				{
					return false;
				}
				if (length != 5)
				{
					return false;
				}
				byte[] buffer = bufferReader.Buffer;
				int num = offset;
				if (buffer[num] == 120 && buffer[num + 1] == 109 && buffer[num + 2] == 108 && buffer[num + 3] == 110)
				{
					return buffer[num + 4] == 115;
				}
				return false;
			}
		}

		public bool IsXml
		{
			get
			{
				if (type != PrefixHandleType.Buffer)
				{
					return false;
				}
				if (length != 3)
				{
					return false;
				}
				byte[] buffer = bufferReader.Buffer;
				int num = offset;
				if (buffer[num] == 120 && buffer[num + 1] == 109)
				{
					return buffer[num + 2] == 108;
				}
				return false;
			}
		}

		public PrefixHandle(XmlBufferReader bufferReader)
		{
			this.bufferReader = bufferReader;
		}

		public void SetValue(PrefixHandleType type)
		{
			this.type = type;
		}

		public void SetValue(PrefixHandle prefix)
		{
			type = prefix.type;
			offset = prefix.offset;
			length = prefix.length;
		}

		public void SetValue(int offset, int length)
		{
			switch (length)
			{
			case 0:
				SetValue(PrefixHandleType.Empty);
				return;
			case 1:
			{
				byte @byte = bufferReader.GetByte(offset);
				if (@byte >= 97 && @byte <= 122)
				{
					SetValue(GetAlphaPrefix(@byte - 97));
					return;
				}
				break;
			}
			}
			type = PrefixHandleType.Buffer;
			this.offset = offset;
			this.length = length;
		}

		public bool TryGetShortPrefix(out PrefixHandleType type)
		{
			type = this.type;
			return type != PrefixHandleType.Buffer;
		}

		public static string GetString(PrefixHandleType type)
		{
			return prefixStrings[(int)type];
		}

		public static PrefixHandleType GetAlphaPrefix(int index)
		{
			return (PrefixHandleType)(1 + index);
		}

		public static byte[] GetString(PrefixHandleType type, out int offset, out int length)
		{
			if (type == PrefixHandleType.Empty)
			{
				offset = 0;
				length = 0;
			}
			else
			{
				length = 1;
				offset = (int)(type - 1);
			}
			return prefixBuffer;
		}

		public string GetString(XmlNameTable nameTable)
		{
			PrefixHandleType prefixHandleType = type;
			if (prefixHandleType != PrefixHandleType.Buffer)
			{
				return GetString(prefixHandleType);
			}
			return bufferReader.GetString(offset, length, nameTable);
		}

		public string GetString()
		{
			PrefixHandleType prefixHandleType = type;
			if (prefixHandleType != PrefixHandleType.Buffer)
			{
				return GetString(prefixHandleType);
			}
			return bufferReader.GetString(offset, length);
		}

		public byte[] GetString(out int offset, out int length)
		{
			PrefixHandleType prefixHandleType = type;
			if (prefixHandleType != PrefixHandleType.Buffer)
			{
				return GetString(prefixHandleType, out offset, out length);
			}
			offset = this.offset;
			length = this.length;
			return bufferReader.Buffer;
		}

		public int CompareTo(PrefixHandle that)
		{
			return GetString().CompareTo(that.GetString());
		}

		private bool Equals2(PrefixHandle prefix2)
		{
			PrefixHandleType prefixHandleType = type;
			PrefixHandleType prefixHandleType2 = prefix2.type;
			if (prefixHandleType != prefixHandleType2)
			{
				return false;
			}
			if (prefixHandleType != PrefixHandleType.Buffer)
			{
				return true;
			}
			if (bufferReader == prefix2.bufferReader)
			{
				return bufferReader.Equals2(offset, length, prefix2.offset, prefix2.length);
			}
			return bufferReader.Equals2(offset, length, prefix2.bufferReader, prefix2.offset, prefix2.length);
		}

		private bool Equals2(string prefix2)
		{
			PrefixHandleType prefixHandleType = type;
			if (prefixHandleType != PrefixHandleType.Buffer)
			{
				return GetString(prefixHandleType) == prefix2;
			}
			return bufferReader.Equals2(offset, length, prefix2);
		}

		private bool Equals2(XmlDictionaryString prefix2)
		{
			return Equals2(prefix2.Value);
		}

		public static bool operator ==(PrefixHandle prefix1, string prefix2)
		{
			return prefix1.Equals2(prefix2);
		}

		public static bool operator !=(PrefixHandle prefix1, string prefix2)
		{
			return !prefix1.Equals2(prefix2);
		}

		public static bool operator ==(PrefixHandle prefix1, XmlDictionaryString prefix2)
		{
			return prefix1.Equals2(prefix2);
		}

		public static bool operator !=(PrefixHandle prefix1, XmlDictionaryString prefix2)
		{
			return !prefix1.Equals2(prefix2);
		}

		public static bool operator ==(PrefixHandle prefix1, PrefixHandle prefix2)
		{
			return prefix1.Equals2(prefix2);
		}

		public static bool operator !=(PrefixHandle prefix1, PrefixHandle prefix2)
		{
			return !prefix1.Equals2(prefix2);
		}

		public override bool Equals(object obj)
		{
			if (!(obj is PrefixHandle prefixHandle))
			{
				return false;
			}
			return this == prefixHandle;
		}

		public override string ToString()
		{
			return GetString();
		}

		public override int GetHashCode()
		{
			return GetString().GetHashCode();
		}
	}
	internal enum StringHandleConstStringType
	{
		Type,
		Root,
		Item
	}
	internal class StringHandle
	{
		private enum StringHandleType
		{
			Dictionary,
			UTF8,
			EscapedUTF8,
			ConstString
		}

		private XmlBufferReader bufferReader;

		private StringHandleType type;

		private int key;

		private int offset;

		private int length;

		private static string[] constStrings = new string[3] { "type", "root", "item" };

		public bool IsEmpty
		{
			get
			{
				if (type == StringHandleType.UTF8)
				{
					return length == 0;
				}
				return Equals2(string.Empty);
			}
		}

		public bool IsXmlns
		{
			get
			{
				if (type == StringHandleType.UTF8)
				{
					if (length != 5)
					{
						return false;
					}
					byte[] buffer = bufferReader.Buffer;
					int num = offset;
					if (buffer[num] == 120 && buffer[num + 1] == 109 && buffer[num + 2] == 108 && buffer[num + 3] == 110)
					{
						return buffer[num + 4] == 115;
					}
					return false;
				}
				return Equals2("xmlns");
			}
		}

		public StringHandle(XmlBufferReader bufferReader)
		{
			this.bufferReader = bufferReader;
			SetValue(0, 0);
		}

		public void SetValue(int offset, int length)
		{
			type = StringHandleType.UTF8;
			this.offset = offset;
			this.length = length;
		}

		public void SetConstantValue(StringHandleConstStringType constStringType)
		{
			type = StringHandleType.ConstString;
			key = (int)constStringType;
		}

		public void SetValue(int offset, int length, bool escaped)
		{
			type = ((!escaped) ? StringHandleType.UTF8 : StringHandleType.EscapedUTF8);
			this.offset = offset;
			this.length = length;
		}

		public void SetValue(int key)
		{
			type = StringHandleType.Dictionary;
			this.key = key;
		}

		public void SetValue(StringHandle value)
		{
			type = value.type;
			key = value.key;
			offset = value.offset;
			length = value.length;
		}

		public void ToPrefixHandle(PrefixHandle prefix)
		{
			prefix.SetValue(offset, length);
		}

		public string GetString(XmlNameTable nameTable)
		{
			return type switch
			{
				StringHandleType.UTF8 => bufferReader.GetString(offset, length, nameTable), 
				StringHandleType.Dictionary => nameTable.Add(bufferReader.GetDictionaryString(key).Value), 
				StringHandleType.ConstString => nameTable.Add(constStrings[key]), 
				_ => bufferReader.GetEscapedString(offset, length, nameTable), 
			};
		}

		public string GetString()
		{
			return type switch
			{
				StringHandleType.UTF8 => bufferReader.GetString(offset, length), 
				StringHandleType.Dictionary => bufferReader.GetDictionaryString(key).Value, 
				StringHandleType.ConstString => constStrings[key], 
				_ => bufferReader.GetEscapedString(offset, length), 
			};
		}

		public byte[] GetString(out int offset, out int length)
		{
			switch (type)
			{
			case StringHandleType.UTF8:
				offset = this.offset;
				length = this.length;
				return bufferReader.Buffer;
			case StringHandleType.Dictionary:
			{
				byte[] array3 = bufferReader.GetDictionaryString(key).ToUTF8();
				offset = 0;
				length = array3.Length;
				return array3;
			}
			case StringHandleType.ConstString:
			{
				byte[] array2 = XmlConverter.ToBytes(constStrings[key]);
				offset = 0;
				length = array2.Length;
				return array2;
			}
			default:
			{
				byte[] array = XmlConverter.ToBytes(bufferReader.GetEscapedString(this.offset, this.length));
				offset = 0;
				length = array.Length;
				return array;
			}
			}
		}

		public bool TryGetDictionaryString(out XmlDictionaryString value)
		{
			if (type == StringHandleType.Dictionary)
			{
				value = bufferReader.GetDictionaryString(key);
				return true;
			}
			if (IsEmpty)
			{
				value = XmlDictionaryString.Empty;
				return true;
			}
			value = null;
			return false;
		}

		public override string ToString()
		{
			return GetString();
		}

		private bool Equals2(int key2, XmlBufferReader bufferReader2)
		{
			return type switch
			{
				StringHandleType.Dictionary => bufferReader.Equals2(key, key2, bufferReader2), 
				StringHandleType.UTF8 => bufferReader.Equals2(offset, length, bufferReader2.GetDictionaryString(key2).Value), 
				_ => GetString() == bufferReader.GetDictionaryString(key2).Value, 
			};
		}

		private bool Equals2(XmlDictionaryString xmlString2)
		{
			return type switch
			{
				StringHandleType.Dictionary => bufferReader.Equals2(key, xmlString2), 
				StringHandleType.UTF8 => bufferReader.Equals2(offset, length, xmlString2.ToUTF8()), 
				_ => GetString() == xmlString2.Value, 
			};
		}

		private bool Equals2(string s2)
		{
			return type switch
			{
				StringHandleType.Dictionary => bufferReader.GetDictionaryString(key).Value == s2, 
				StringHandleType.UTF8 => bufferReader.Equals2(offset, length, s2), 
				_ => GetString() == s2, 
			};
		}

		private bool Equals2(int offset2, int length2, XmlBufferReader bufferReader2)
		{
			return type switch
			{
				StringHandleType.Dictionary => bufferReader2.Equals2(offset2, length2, bufferReader.GetDictionaryString(key).Value), 
				StringHandleType.UTF8 => bufferReader.Equals2(offset, length, bufferReader2, offset2, length2), 
				_ => GetString() == bufferReader.GetString(offset2, length2), 
			};
		}

		private bool Equals2(StringHandle s2)
		{
			return s2.type switch
			{
				StringHandleType.Dictionary => Equals2(s2.key, s2.bufferReader), 
				StringHandleType.UTF8 => Equals2(s2.offset, s2.length, s2.bufferReader), 
				_ => Equals2(s2.GetString()), 
			};
		}

		public static bool operator ==(StringHandle s1, XmlDictionaryString xmlString2)
		{
			return s1.Equals2(xmlString2);
		}

		public static bool operator !=(StringHandle s1, XmlDictionaryString xmlString2)
		{
			return !s1.Equals2(xmlString2);
		}

		public static bool operator ==(StringHandle s1, string s2)
		{
			return s1.Equals2(s2);
		}

		public static bool operator !=(StringHandle s1, string s2)
		{
			return !s1.Equals2(s2);
		}

		public static bool operator ==(StringHandle s1, StringHandle s2)
		{
			return s1.Equals2(s2);
		}

		public static bool operator !=(StringHandle s1, StringHandle s2)
		{
			return !s1.Equals2(s2);
		}

		public int CompareTo(StringHandle that)
		{
			if (type == StringHandleType.UTF8 && that.type == StringHandleType.UTF8)
			{
				return bufferReader.Compare(offset, length, that.offset, that.length);
			}
			return string.Compare(GetString(), that.GetString(), StringComparison.Ordinal);
		}

		public override bool Equals(object obj)
		{
			if (!(obj is StringHandle stringHandle))
			{
				return false;
			}
			return this == stringHandle;
		}

		public override int GetHashCode()
		{
			return GetString().GetHashCode();
		}
	}
	public class UniqueId
	{
		private long idLow;

		private long idHigh;

		[SecurityCritical]
		private string s;

		private const int guidLength = 16;

		private const int uuidLength = 45;

		private static short[] char2val = new short[256]
		{
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 0, 16,
			32, 48, 64, 80, 96, 112, 128, 144, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 160, 176, 192,
			208, 224, 240, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 0, 1, 2, 3,
			4, 5, 6, 7, 8, 9, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 10, 11, 12, 13, 14,
			15, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
			256, 256, 256, 256, 256, 256
		};

		private const string val2char = "0123456789abcdef";

		public int CharArrayLength
		{
			[SecuritySafeCritical]
			get
			{
				if (s != null)
				{
					return s.Length;
				}
				return 45;
			}
		}

		public bool IsGuid => (idLow | idHigh) != 0;

		public UniqueId()
			: this(Guid.NewGuid())
		{
		}

		public UniqueId(Guid guid)
			: this(guid.ToByteArray())
		{
		}

		public UniqueId(byte[] guid)
			: this(guid, 0)
		{
		}

		[SecuritySafeCritical]
		public unsafe UniqueId(byte[] guid, int offset)
		{
			if (guid == null)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("guid"));
			}
			if (offset < 0)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative.")));
			}
			if (offset > guid.Length)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", guid.Length)));
			}
			if (16 > guid.Length - offset)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(System.Runtime.Serialization.SR.GetString("Array too small.  Length of available data must be at least {0}.", 16), "guid"));
			}
			fixed (byte* ptr = &guid[offset])
			{
				idLow = UnsafeGetInt64(ptr);
				idHigh = UnsafeGetInt64(ptr + 8);
			}
		}

		[SecuritySafeCritical]
		public unsafe UniqueId(string value)
		{
			if (value == null)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
			}
			if (value.Length == 0)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(System.Runtime.Serialization.SR.GetString("UniqueId cannot be zero length.")));
			}
			fixed (char* chars = value)
			{
				UnsafeParse(chars, value.Length);
			}
			s = value;
		}

		[SecuritySafeCritical]
		public unsafe UniqueId(char[] chars, int offset, int count)
		{
			if (chars == null)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
			}
			if (offset < 0)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative.")));
			}
			if (offset > chars.Length)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", chars.Length)));
			}
			if (count < 0)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative.")));
			}
			if (count > chars.Length - offset)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString("The specified size exceeds the remaining buffer space ({0} bytes).", chars.Length - offset)));
			}
			if (count == 0)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(System.Runtime.Serialization.SR.GetString("UniqueId cannot be zero length.")));
			}
			fixed (char* chars2 = &chars[offset])
			{
				UnsafeParse(chars2, count);
			}
			if (!IsGuid)
			{
				s = new string(chars, offset, count);
			}
		}

		[SecurityCritical]
		private unsafe int UnsafeDecode(short* char2val, char ch1, char ch2)
		{
			if ((ch1 | ch2) >= 128)
			{
				return 256;
			}
			return char2val[(int)ch1] | char2val[128 + ch2];
		}

		[SecurityCritical]
		private unsafe void UnsafeEncode(char* val2char, byte b, char* pch)
		{
			*pch = val2char[b >> 4];
			pch[1] = val2char[b & 0xF];
		}

		[SecurityCritical]
		private unsafe void UnsafeParse(char* chars, int charCount)
		{
			if (charCount != 45 || *chars != 'u' || chars[1] != 'r' || chars[2] != 'n' || chars[3] != ':' || chars[4] != 'u' || chars[5] != 'u' || chars[6] != 'i' || chars[7] != 'd' || chars[8] != ':' || chars[17] != '-' || chars[22] != '-' || chars[27] != '-' || chars[32] != '-')
			{
				return;
			}
			byte* ptr = stackalloc byte[16];
			int num = 0;
			fixed (short* ptr2 = char2val)
			{
				short* ptr3 = ptr2;
				num = UnsafeDecode(ptr3, chars[15], chars[16]);
				*ptr = (byte)num;
				int num2 = 0 | num;
				num = UnsafeDecode(ptr3, chars[13], chars[14]);
				ptr[1] = (byte)num;
				int num3 = num2 | num;
				num = UnsafeDecode(ptr3, chars[11], chars[12]);
				ptr[2] = (byte)num;
				int num4 = num3 | num;
				num = UnsafeDecode(ptr3, chars[9], chars[10]);
				ptr[3] = (byte)num;
				int num5 = num4 | num;
				num = UnsafeDecode(ptr3, chars[20], chars[21]);
				ptr[4] = (byte)num;
				int num6 = num5 | num;
				num = UnsafeDecode(ptr3, chars[18], chars[19]);
				ptr[5] = (byte)num;
				int num7 = num6 | num;
				num = UnsafeDecode(ptr3, chars[25], chars[26]);
				ptr[6] = (byte)num;
				int num8 = num7 | num;
				num = UnsafeDecode(ptr3, chars[23], chars[24]);
				ptr[7] = (byte)num;
				int num9 = num8 | num;
				num = UnsafeDecode(ptr3, chars[28], chars[29]);
				ptr[8] = (byte)num;
				int num10 = num9 | num;
				num = UnsafeDecode(ptr3, chars[30], chars[31]);
				ptr[9] = (byte)num;
				int num11 = num10 | num;
				num = UnsafeDecode(ptr3, chars[33], chars[34]);
				ptr[10] = (byte)num;
				int num12 = num11 | num;
				num = UnsafeDecode(ptr3, chars[35], chars[36]);
				ptr[11] = (byte)num;
				int num13 = num12 | num;
				num = UnsafeDecode(ptr3, chars[37], chars[38]);
				ptr[12] = (byte)num;
				int num14 = num13 | num;
				num = UnsafeDecode(ptr3, chars[39], chars[40]);
				ptr[13] = (byte)num;
				int num15 = num14 | num;
				num = UnsafeDecode(ptr3, chars[41], chars[42]);
				ptr[14] = (byte)num;
				int num16 = num15 | num;
				num = UnsafeDecode(ptr3, chars[43], chars[44]);
				ptr[15] = (byte)num;
				if ((num16 | num) >= 256)
				{
					return;
				}
				idLow = UnsafeGetInt64(ptr);
				idHigh = UnsafeGetInt64(ptr + 8);
			}
		}

		[SecuritySafeCritical]
		public unsafe int ToCharArray(char[] chars, int offset)
		{
			int charArrayLength = CharArrayLength;
			if (chars == null)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
			}
			if (offset < 0)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative.")));
			}
			if (offset > chars.Length)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", chars.Length)));
			}
			if (charArrayLength > chars.Length - offset)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("chars", System.Runtime.Serialization.SR.GetString("Array too small.  Must be able to hold at least {0}.", charArrayLength)));
			}
			if (s != null)
			{
				s.CopyTo(0, chars, offset, charArrayLength);
			}
			else
			{
				byte* ptr = stackalloc byte[16];
				UnsafeSetInt64(idLow, ptr);
				UnsafeSetInt64(idHigh, ptr + 8);
				fixed (char* ptr2 = &chars[offset])
				{
					*ptr2 = 'u';
					ptr2[1] = 'r';
					ptr2[2] = 'n';
					ptr2[3] = ':';
					ptr2[4] = 'u';
					ptr2[5] = 'u';
					ptr2[6] = 'i';
					ptr2[7] = 'd';
					ptr2[8] = ':';
					ptr2[17] = '-';
					ptr2[22] = '-';
					ptr2[27] = '-';
					ptr2[32] = '-';
					fixed (char* ptr3 = "0123456789abcdef")
					{
						char* ptr4 = ptr3;
						UnsafeEncode(ptr4, *ptr, ptr2 + 15);
						UnsafeEncode(ptr4, ptr[1], ptr2 + 13);
						UnsafeEncode(ptr4, ptr[2], ptr2 + 11);
						UnsafeEncode(ptr4, ptr[3], ptr2 + 9);
						UnsafeEncode(ptr4, ptr[4], ptr2 + 20);
						UnsafeEncode(ptr4, ptr[5], ptr2 + 18);
						UnsafeEncode(ptr4, ptr[6], ptr2 + 25);
						UnsafeEncode(ptr4, ptr[7], ptr2 + 23);
						UnsafeEncode(ptr4, ptr[8], ptr2 + 28);
						UnsafeEncode(ptr4, ptr[9], ptr2 + 30);
						UnsafeEncode(ptr4, ptr[10], ptr2 + 33);
						UnsafeEncode(ptr4, ptr[11], ptr2 + 35);
						UnsafeEncode(ptr4, ptr[12], ptr2 + 37);
						UnsafeEncode(ptr4, ptr[13], ptr2 + 39);
						UnsafeEncode(ptr4, ptr[14], ptr2 + 41);
						UnsafeEncode(ptr4, ptr[15], ptr2 + 43);
					}
				}
			}
			return charArrayLength;
		}

		public bool TryGetGuid(out Guid guid)
		{
			byte[] array = new byte[16];
			if (!TryGetGuid(array, 0))
			{
				guid = Guid.Empty;
				return false;
			}
			guid = new Guid(array);
			return true;
		}

		[SecuritySafeCritical]
		public unsafe bool TryGetGuid(byte[] buffer, int offset)
		{
			if (!IsGuid)
			{
				return false;
			}
			if (buffer == null)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer"));
			}
			if (offset < 0)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative.")));
			}
			if (offset > buffer.Length)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", buffer.Length)));
			}
			if (16 > buffer.Length - offset)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("buffer", System.Runtime.Serialization.SR.GetString("Array too small.  Must be able to hold at least {0}.", 16)));
			}
			fixed (byte* ptr = &buffer[offset])
			{
				UnsafeSetInt64(idLow, ptr);
				UnsafeSetInt64(idHigh, ptr + 8);
			}
			return true;
		}

		[SecuritySafeCritical]
		public override string ToString()
		{
			if (s == null)
			{
				int charArrayLength = CharArrayLength;
				char[] array = new char[charArrayLength];
				ToCharArray(array, 0);
				s = new string(array, 0, charArrayLength);
			}
			return s;
		}

		public static bool operator ==(UniqueId id1, UniqueId id2)
		{
			if ((object)id1 == null && (object)id2 == null)
			{
				return true;
			}
			if ((object)id1 == null || (object)id2 == null)
			{
				return false;
			}
			if (id1.IsGuid && id2.IsGuid)
			{
				if (id1.idLow == id2.idLow)
				{
					return id1.idHigh == id2.idHigh;
				}
				return false;
			}
			return id1.ToString() == id2.ToString();
		}

		public static bool operator !=(UniqueId id1, UniqueId id2)
		{
			return !(id1 == id2);
		}

		public override bool Equals(object obj)
		{
			return this == obj as UniqueId;
		}

		public override int GetHashCode()
		{
			if (IsGuid)
			{
				long num = idLow ^ idHigh;
				return (int)(num >> 32) ^ (int)num;
			}
			return ToString().GetHashCode();
		}

		[SecurityCritical]
		private unsafe long UnsafeGetInt64(byte* pb)
		{
			int num = UnsafeGetInt32(pb);
			return ((long)UnsafeGetInt32(pb + 4) << 32) | (uint)num;
		}

		[SecurityCritical]
		private unsafe int UnsafeGetInt32(byte* pb)
		{
			return (((((pb[3] << 8) | pb[2]) << 8) | pb[1]) << 8) | *pb;
		}

		[SecurityCritical]
		private unsafe void UnsafeSetInt64(long value, byte* pb)
		{
			UnsafeSetInt32((int)value, pb);
			UnsafeSetInt32((int)(value >> 32), pb + 4);
		}

		[SecurityCritical]
		private unsafe void UnsafeSetInt32(int value, byte* pb)
		{
			*pb = (byte)value;
			value >>= 8;
			pb[1] = (byte)value;
			value >>= 8;
			pb[2] = (byte)value;
			value >>= 8;
			pb[3] = (byte)value;
		}
	}
	internal enum ValueHandleConstStringType
	{
		String,
		Number,
		Array,
		Object,
		Boolean,
		Null
	}
	internal static class ValueHandleLength
	{
		public const int Int8 = 1;

		public const int Int16 = 2;

		public const int Int32 = 4;

		public const int Int64 = 8;

		public const int UInt64 = 8;

		public const int Single = 4;

		public const int Double = 8;

		public const int Decimal = 16;

		public const int DateTime = 8;

		public const int TimeSpan = 8;

		public const int Guid = 16;

		public const int UniqueId = 16;
	}
	internal enum ValueHandleType
	{
		Empty,
		True,
		False,
		Zero,
		One,
		Int8,
		Int16,
		Int32,
		Int64,
		UInt64,
		Single,
		Double,
		Decimal,
		DateTime,
		TimeSpan,
		Guid,
		UniqueId,
		UTF8,
		EscapedUTF8,
		Base64,
		Dictionary,
		List,
		Char,
		Unicode,
		QName,
		ConstString
	}
	internal class ValueHandle
	{
		private XmlBufferReader bufferReader;

		private ValueHandleType type;

		private int offset;

		private int length;

		private static Base64Encoding base64Encoding;

		private static string[] constStrings = new string[6] { "string", "number", "array", "object", "boolean", "null" };

		private static Base64Encoding Base64Encoding
		{
			get
			{
				if (base64Encoding == null)
				{
					base64Encoding = new Base64Encoding();
				}
				return base64Encoding;
			}
		}

		public ValueHandle(XmlBufferReader bufferReader)
		{
			this.bufferReader = bufferReader;
			type = ValueHandleType.Empty;
		}

		public void SetConstantValue(ValueHandleConstStringType constStringType)
		{
			type = ValueHandleType.ConstString;
			offset = (int)constStringType;
		}

		public void SetValue(ValueHandleType type)
		{
			this.type = type;
		}

		public void SetDictionaryValue(int key)
		{
			SetValue(ValueHandleType.Dictionary, key, 0);
		}

		public void SetCharValue(int ch)
		{
			SetValue(ValueHandleType.Char, ch, 0);
		}

		public void SetQNameValue(int prefix, int key)
		{
			SetValue(ValueHandleType.QName, key, prefix);
		}

		public void SetValue(ValueHandleType type, int offset, int length)
		{
			this.type = type;
			this.offset = offset;
			this.length = length;
		}

		public bool IsWhitespace()
		{
			switch (type)
			{
			case ValueHandleType.UTF8:
				return bufferReader.IsWhitespaceUTF8(offset, length);
			case ValueHandleType.Dictionary:
				return bufferReader.IsWhitespaceKey(offset);
			case ValueHandleType.Char:
			{
				int @char = GetChar();
				if (@char > 65535)
				{
					return false;
				}
				return XmlConverter.IsWhitespace((char)@char);
			}
			case ValueHandleType.EscapedUTF8:
				return bufferReader.IsWhitespaceUTF8(offset, length);
			case ValueHandleType.Unicode:
				return bufferReader.IsWhitespaceUnicode(offset, length);
			case ValueHandleType.True:
			case ValueHandleType.False:
			case ValueHandleType.Zero:
			case ValueHandleType.One:
				return false;
			case ValueHandleType.ConstString:
				return constStrings[offset].Length == 0;
			default:
				return length == 0;
			}
		}

		public Type ToType()
		{
			switch (type)
			{
			case ValueHandleType.True:
			case ValueHandleType.False:
				return typeof(bool);
			case ValueHandleType.Zero:
			case ValueHandleType.One:
			case ValueHandleType.Int8:
			case ValueHandleType.Int16:
			case ValueHandleType.Int32:
				return typeof(int);
			case ValueHandleType.Int64:
				return typeof(long);
			case ValueHandleType.UInt64:
				return typeof(ulong);
			case ValueHandleType.Single:
				return typeof(float);
			case ValueHandleType.Double:
				return typeof(double);
			case ValueHandleType.Decimal:
				return typeof(decimal);
			case ValueHandleType.DateTime:
				return typeof(DateTime);
			case ValueHandleType.Empty:
			case ValueHandleType.UTF8:
			case ValueHandleType.EscapedUTF8:
			case ValueHandleType.Dictionary:
			case ValueHandleType.Char:
			case ValueHandleType.Unicode:
			case ValueHandleType.QName:
			case ValueHandleType.ConstString:
				return typeof(string);
			case ValueHandleType.Base64:
				return typeof(byte[]);
			case ValueHandleType.List:
				return typeof(object[]);
			case ValueHandleType.UniqueId:
				return typeof(UniqueId);
			case ValueHandleType.Guid:
				return typeof(Guid);
			case ValueHandleType.TimeSpan:
				return typeof(TimeSpan);
			default:
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
			}
		}

		public bool ToBoolean()
		{
			switch (type)
			{
			case ValueHandleType.False:
				return false;
			case ValueHandleType.True:
				return true;
			case ValueHandleType.UTF8:
				return XmlConverter.ToBoolean(bufferReader.Buffer, offset, length);
			case ValueHandleType.Int8:
				switch (GetInt8())
				{
				case 0:
					return false;
				case 1:
					return true;
				}
				break;
			}
			return XmlConverter.ToBoolean(GetString());
		}

		public int ToInt()
		{
			ValueHandleType valueHandleType = type;
			switch (valueHandleType)
			{
			case ValueHandleType.Zero:
				return 0;
			case ValueHandleType.One:
				return 1;
			case ValueHandleType.Int8:
				return GetInt8();
			case ValueHandleType.Int16:
				return GetInt16();
			case ValueHandleType.Int32:
				return GetInt32();
			case ValueHandleType.Int64:
			{
				long @int = GetInt64();
				if (@int >= int.MinValue && @int <= int.MaxValue)
				{
					return (int)@int;
				}
				break;
			}
			}
			if (valueHandleType == ValueHandleType.UInt64)
			{
				ulong uInt = GetUInt64();
				if (uInt <= int.MaxValue)
				{
					return (int)uInt;
				}
			}
			if (valueHandleType == ValueHandleType.UTF8)
			{
				return XmlConverter.ToInt32(bufferReader.Buffer, offset, length);
			}
			return XmlConverter.ToInt32(GetString());
		}

		public long ToLong()
		{
			ValueHandleType valueHandleType = type;
			switch (valueHandleType)
			{
			case ValueHandleType.Zero:
				return 0L;
			case ValueHandleType.One:
				return 1L;
			case ValueHandleType.Int8:
				return GetInt8();
			case ValueHandleType.Int16:
				return GetInt16();
			case ValueHandleType.Int32:
				return GetInt32();
			case ValueHandleType.Int64:
				return GetInt64();
			case ValueHandleType.UInt64:
			{
				ulong uInt = GetUInt64();
				if (uInt <= long.MaxValue)
				{
					return (long)uInt;
				}
				break;
			}
			}
			if (valueHandleType == ValueHandleType.UTF8)
			{
				return XmlConverter.ToInt64(bufferReader.Buffer, offset, length);
			}
			return XmlConverter.ToInt64(GetString());
		}

		public ulong ToULong()
		{
			ValueHandleType valueHandleType = type;
			switch (valueHandleType)
			{
			case ValueHandleType.Zero:
				return 0uL;
			case ValueHandleType.One:
				return 1uL;
			case ValueHandleType.Int8:
			case ValueHandleType.Int16:
			case ValueHandleType.Int32:
			case ValueHandleType.Int64:
			{
				long num = ToLong();
				if (num >= 0)
				{
					return (ulong)num;
				}
				break;
			}
			}
			return valueHandleType switch
			{
				ValueHandleType.UInt64 => GetUInt64(), 
				ValueHandleType.UTF8 => XmlConverter.ToUInt64(bufferReader.Buffer, offset, length), 
				_ => XmlConverter.ToUInt64(GetString()), 
			};
		}

		public float ToSingle()
		{
			ValueHandleType valueHandleType = type;
			switch (valueHandleType)
			{
			case ValueHandleType.Single:
				return GetSingle();
			case ValueHandleType.Double:
			{
				double @double = GetDouble();
				if ((@double >= -3.4028234663852886E+38 && @double <= 3.4028234663852886E+38) || double.IsInfinity(@double) || double.IsNaN(@double))
				{
					return (float)@double;
				}
				break;
			}
			}
			return valueHandleType switch
			{
				ValueHandleType.Zero => 0f, 
				ValueHandleType.One => 1f, 
				ValueHandleType.Int8 => GetInt8(), 
				ValueHandleType.Int16 => GetInt16(), 
				ValueHandleType.UTF8 => XmlConverter.ToSingle(bufferReader.Buffer, offset, length), 
				_ => XmlConverter.ToSingle(GetString()), 
			};
		}

		public double ToDouble()
		{
			return type switch
			{
				ValueHandleType.Double => GetDouble(), 
				ValueHandleType.Single => GetSingle(), 
				ValueHandleType.Zero => 0.0, 
				ValueHandleType.One => 1.0, 
				ValueHandleType.Int8 => GetInt8(), 
				ValueHandleType.Int16 => GetInt16(), 
				ValueHandleType.Int32 => GetInt32(), 
				ValueHandleType.UTF8 => XmlConverter.ToDouble(bufferReader.Buffer, offset, length), 
				_ => XmlConverter.ToDouble(GetString()), 
			};
		}

		public decimal ToDecimal()
		{
			ValueHandleType valueHandleType = type;
			switch (valueHandleType)
			{
			case ValueHandleType.Decimal:
				return GetDecimal();
			case ValueHandleType.Zero:
				return 0m;
			case ValueHandleType.One:
				return 1m;
			case ValueHandleType.Int8:
			case ValueHandleType.Int16:
			case ValueHandleType.Int32:
			case ValueHandleType.Int64:
				return ToLong();
			default:
				return valueHandleType switch
				{
					ValueHandleType.UInt64 => GetUInt64(), 
					ValueHandleType.UTF8 => XmlConverter.ToDecimal(bufferReader.Buffer, offset, length), 
					_ => XmlConverter.ToDecimal(GetString()), 
				};
			}
		}

		public DateTime ToDateTime()
		{
			if (type == ValueHandleType.DateTime)
			{
				return XmlConverter.ToDateTime(GetInt64());
			}
			if (type == ValueHandleType.UTF8)
			{
				return XmlConverter.ToDateTime(bufferReader.Buffer, offset, length);
			}
			return XmlConverter.ToDateTime(GetString());
		}

		public UniqueId ToUniqueId()
		{
			if (type == ValueHandleType.UniqueId)
			{
				return GetUniqueId();
			}
			if (type == ValueHandleType.UTF8)
			{
				return XmlConverter.ToUniqueId(bufferReader.Buffer, offset, length);
			}
			return XmlConverter.ToUniqueId(GetString());
		}

		public TimeSpan ToTimeSpan()
		{
			if (type == ValueHandleType.TimeSpan)
			{
				return new TimeSpan(GetInt64());
			}
			if (type == ValueHandleType.UTF8)
			{
				return XmlConverter.ToTimeSpan(bufferReader.Buffer, offset, length);
			}
			return XmlConverter.ToTimeSpan(GetString());
		}

		public Guid ToGuid()
		{
			if (type == ValueHandleType.Guid)
			{
				return GetGuid();
			}
			if (type == ValueHandleType.UTF8)
			{
				return XmlConverter.ToGuid(bufferReader.Buffer, offset, length);
			}
			return XmlConverter.ToGuid(GetString());
		}

		public override string ToString()
		{
			return GetString();
		}

		public byte[] ToByteArray()
		{
			if (type == ValueHandleType.Base64)
			{
				byte[] array = new byte[length];
				GetBase64(array, 0, length);
				return array;
			}
			if (type == ValueHandleType.UTF8 && length % 4 == 0)
			{
				try
				{
					int num = length / 4 * 3;
					if (length > 0 && bufferReader.Buffer[offset + length - 1] == 61)
					{
						num--;
						if (bufferReader.Buffer[offset + length - 2] == 61)
						{
							num--;
						}
					}
					byte[] array2 = new byte[num];
					int bytes = Base64Encoding.GetBytes(bufferReader.Buffer, offset, length, array2, 0);
					if (bytes != array2.Length)
					{
						byte[] array3 = new byte[bytes];
						Buffer.BlockCopy(array2, 0, array3, 0, bytes);
						array2 = array3;
					}
					return array2;
				}
				catch (FormatException)
				{
				}
			}
			try
			{
				return Base64Encoding.GetBytes(XmlConverter.StripWhitespace(GetString()));
			}
			catch (FormatException ex2)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(ex2.Message, ex2.InnerException));
			}
		}

		public string GetString()
		{
			ValueHandleType valueHandleType = type;
			if (valueHandleType == ValueHandleType.UTF8)
			{
				return GetCharsText();
			}
			switch (valueHandleType)
			{
			case ValueHandleType.False:
				return "false";
			case ValueHandleType.True:
				return "true";
			case ValueHandleType.Zero:
				return "0";
			case ValueHandleType.One:
				return "1";
			case ValueHandleType.Int8:
			case ValueHandleType.Int16:
			case ValueHandleType.Int32:
				return XmlConverter.ToString(ToInt());
			case ValueHandleType.Int64:
				return XmlConverter.ToString(GetInt64());
			case ValueHandleType.UInt64:
				return XmlConverter.ToString(GetUInt64());
			case ValueHandleType.Single:
				return XmlConverter.ToString(GetSingle());
			case ValueHandleType.Double:
				return XmlConverter.ToString(GetDouble());
			case ValueHandleType.Decimal:
				return XmlConverter.ToString(GetDecimal());
			case ValueHandleType.DateTime:
				return XmlConverter.ToString(ToDateTime());
			case ValueHandleType.Empty:
				return string.Empty;
			case ValueHandleType.UTF8:
				return GetCharsText();
			case ValueHandleType.Unicode:
				return GetUnicodeCharsText();
			case ValueHandleType.EscapedUTF8:
				return GetEscapedCharsText();
			case ValueHandleType.Char:
				return GetCharText();
			case ValueHandleType.Dictionary:
				return GetDictionaryString().Value;
			case ValueHandleType.Base64:
				return Base64Encoding.GetString(ToByteArray());
			case ValueHandleType.List:
				return XmlConverter.ToString(ToList());
			case ValueHandleType.UniqueId:
				return XmlConverter.ToString(ToUniqueId());
			case ValueHandleType.Guid:
				return XmlConverter.ToString(ToGuid());
			case ValueHandleType.TimeSpan:
				return XmlConverter.ToString(ToTimeSpan());
			case ValueHandleType.QName:
				return GetQNameDictionaryText();
			case ValueHandleType.ConstString:
				return constStrings[offset];
			default:
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
			}
		}

		public bool Equals2(string str, bool checkLower)
		{
			if (type != ValueHandleType.UTF8)
			{
				return GetString() == str;
			}
			if (length != str.Length)
			{
				return false;
			}
			byte[] buffer = bufferReader.Buffer;
			for (int i = 0; i < length; i++)
			{
				byte b = buffer[i + offset];
				if (b != str[i] && (!checkLower || char.ToLowerInvariant((char)b) != str[i]))
				{
					return false;
				}
			}
			return true;
		}

		public void Sign(XmlSigningNodeWriter writer)
		{
			switch (type)
			{
			case ValueHandleType.Int8:
			case ValueHandleType.Int16:
			case ValueHandleType.Int32:
				writer.WriteInt32Text(ToInt());
				break;
			case ValueHandleType.Int64:
				writer.WriteInt64Text(GetInt64());
				break;
			case ValueHandleType.UInt64:
				writer.WriteUInt64Text(GetUInt64());
				break;
			case ValueHandleType.Single:
				writer.WriteFloatText(GetSingle());
				break;
			case ValueHandleType.Double:
				writer.WriteDoubleText(GetDouble());
				break;
			case ValueHandleType.Decimal:
				writer.WriteDecimalText(GetDecimal());
				break;
			case ValueHandleType.DateTime:
				writer.WriteDateTimeText(ToDateTime());
				break;
			case ValueHandleType.UTF8:
				writer.WriteEscapedText(bufferReader.Buffer, offset, length);
				break;
			case ValueHandleType.Base64:
				writer.WriteBase64Text(bufferReader.Buffer, 0, bufferReader.Buffer, offset, length);
				break;
			case ValueHandleType.UniqueId:
				writer.WriteUniqueIdText(ToUniqueId());
				break;
			case ValueHandleType.Guid:
				writer.WriteGuidText(ToGuid());
				break;
			case ValueHandleType.TimeSpan:
				writer.WriteTimeSpanText(ToTimeSpan());
				break;
			default:
				writer.WriteEscapedText(GetString());
				break;
			case ValueHandleType.Empty:
				break;
			}
		}

		public object[] ToList()
		{
			return bufferReader.GetList(offset, length);
		}

		public object ToObject()
		{
			switch (type)
			{
			case ValueHandleType.True:
			case ValueHandleType.False:
				return ToBoolean();
			case ValueHandleType.Zero:
			case ValueHandleType.One:
			case ValueHandleType.Int8:
			case ValueHandleType.Int16:
			case ValueHandleType.Int32:
				return ToInt();
			case ValueHandleType.Int64:
				return ToLong();
			case ValueHandleType.UInt64:
				return GetUInt64();
			case ValueHandleType.Single:
				return ToSingle();
			case ValueHandleType.Double:
				return ToDouble();
			case ValueHandleType.Decimal:
				return ToDecimal();
			case ValueHandleType.DateTime:
				return ToDateTime();
			case ValueHandleType.Empty:
			case ValueHandleType.UTF8:
			case ValueHandleType.EscapedUTF8:
			case ValueHandleType.Dictionary:
			case ValueHandleType.Char:
			case ValueHandleType.Unicode:
			case ValueHandleType.ConstString:
				return ToString();
			case ValueHandleType.Base64:
				return ToByteArray();
			case ValueHandleType.List:
				return ToList();
			case ValueHandleType.UniqueId:
				return ToUniqueId();
			case ValueHandleType.Guid:
				return ToGuid();
			case ValueHandleType.TimeSpan:
				return ToTimeSpan();
			default:
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
			}
		}

		public bool TryReadBase64(byte[] buffer, int offset, int count, out int actual)
		{
			if (type == ValueHandleType.Base64)
			{
				actual = Math.Min(length, count);
				GetBase64(buffer, offset, actual);
				this.offset += actual;
				length -= actual;
				return true;
			}
			if (type == ValueHandleType.UTF8 && count >= 3 && length % 4 == 0)
			{
				try
				{
					int num = Math.Min(count / 3 * 4, length);
					actual = Base64Encoding.GetBytes(bufferReader.Buffer, this.offset, num, buffer, offset);
					this.offset += num;
					length -= num;
					return true;
				}
				catch (FormatException)
				{
				}
			}
			actual = 0;
			return false;
		}

		public bool TryReadChars(char[] chars, int offset, int count, out int actual)
		{
			if (type == ValueHandleType.Unicode)
			{
				return TryReadUnicodeChars(chars, offset, count, out actual);
			}
			if (type != ValueHandleType.UTF8)
			{
				actual = 0;
				return false;
			}
			int num = offset;
			int num2 = count;
			byte[] buffer = bufferReader.Buffer;
			int num3 = this.offset;
			int num4 = length;
			bool flag = false;
			while (true)
			{
				if (num2 > 0 && num4 > 0)
				{
					byte b = buffer[num3];
					if (b < 128)
					{
						chars[num] = (char)b;
						num3++;
						num4--;
						num++;
						num2--;
						continue;
					}
				}
				if (num2 == 0 || num4 == 0 || flag)
				{
					break;
				}
				UTF8Encoding uTF8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
				int chars2;
				int num5;
				try
				{
					if (num2 >= uTF8Encoding.GetMaxCharCount(num4) || num2 >= uTF8Encoding.GetCharCount(buffer, num3, num4))
					{
						chars2 = uTF8Encoding.GetChars(buffer, num3, num4, chars, num);
						num5 = num4;
					}
					else
					{
						Decoder decoder = uTF8Encoding.GetDecoder();
						num5 = Math.Min(num2, num4);
						chars2 = decoder.GetChars(buffer, num3, num5, chars, num);
						while (chars2 == 0)
						{
							if (num5 >= 3 && num2 < 2)
							{
								flag = true;
								break;
							}
							chars2 = decoder.GetChars(buffer, num3 + num5, 1, chars, num);
							num5++;
						}
						num5 = uTF8Encoding.GetByteCount(chars, num, chars2);
					}
				}
				catch (FormatException exception)
				{
					throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, num3, num4, exception));
				}
				num3 += num5;
				num4 -= num5;
				num += chars2;
				num2 -= chars2;
			}
			this.offset = num3;
			length = num4;
			actual = count - num2;
			return true;
		}

		private bool TryReadUnicodeChars(char[] chars, int offset, int count, out int actual)
		{
			int num = Math.Min(count, length / 2);
			for (int i = 0; i < num; i++)
			{
				chars[offset + i] = (char)bufferReader.GetInt16(this.offset + i * 2);
			}
			this.offset += num * 2;
			length -= num * 2;
			actual = num;
			return true;
		}

		public bool TryGetDictionaryString(out XmlDictionaryString value)
		{
			if (type == ValueHandleType.Dictionary)
			{
				value = GetDictionaryString();
				return true;
			}
			value = null;
			return false;
		}

		public bool TryGetByteArrayLength(out int length)
		{
			if (type == ValueHandleType.Base64)
			{
				length = this.length;
				return true;
			}
			length = 0;
			return false;
		}

		private string GetCharsText()
		{
			if (length == 1 && bufferReader.GetByte(offset) == 49)
			{
				return "1";
			}
			return bufferReader.GetString(offset, length);
		}

		private string GetUnicodeCharsText()
		{
			return bufferReader.GetUnicodeString(offset, length);
		}

		private string GetEscapedCharsText()
		{
			return bufferReader.GetEscapedString(offset, length);
		}

		private string GetCharText()
		{
			int @char = GetChar();
			if (@char > 65535)
			{
				SurrogateChar surrogateChar = new SurrogateChar(@char);
				return new string(new char[2] { surrogateChar.HighChar, surrogateChar.LowChar }, 0, 2);
			}
			return ((char)@char).ToString();
		}

		private int GetChar()
		{
			return offset;
		}

		private int GetInt8()
		{
			return bufferReader.GetInt8(offset);
		}

		private int GetInt16()
		{
			return bufferReader.GetInt16(offset);
		}

		private int GetInt32()
		{
			return bufferReader.GetInt32(offset);
		}

		private long GetInt64()
		{
			return bufferReader.GetInt64(offset);
		}

		private ulong GetUInt64()
		{
			return bufferReader.GetUInt64(offset);
		}

		private float GetSingle()
		{
			return bufferReader.GetSingle(offset);
		}

		private double GetDouble()
		{
			return bufferReader.GetDouble(offset);
		}

		private decimal GetDecimal()
		{
			return bufferReader.GetDecimal(offset);
		}

		private UniqueId GetUniqueId()
		{
			return bufferReader.GetUniqueId(offset);
		}

		private Guid GetGuid()
		{
			return bufferReader.GetGuid(offset);
		}

		private void GetBase64(byte[] buffer, int offset, int count)
		{
			bufferReader.GetBase64(this.offset, buffer, offset, count);
		}

		private XmlDictionaryString GetDictionaryString()
		{
			return bufferReader.GetDictionaryString(offset);
		}

		private string GetQNameDictionaryText()
		{
			return PrefixHandle.GetString(PrefixHandle.GetAlphaPrefix(length)) + ":" + bufferReader.GetDictionaryString(offset);
		}
	}
	internal abstract class XmlBaseReader : XmlDictionaryReader
	{
		protected enum QNameType
		{
			Normal,
			Xmlns
		}

		protected class XmlNode
		{
			protected enum XmlNodeFlags
			{
				None = 0,
				CanGetAttribute = 1,
				CanMoveToElement = 2,
				HasValue = 4,
				AtomicValue = 8,
				SkipValue = 0x10,
				HasContent = 0x20
			}

			private XmlNodeType nodeType;

			private PrefixHandle prefix;

			private StringHandle localName;

			private ValueHandle value;

			private Namespace ns;

			private bool hasValue;

			private bool canGetAttribute;

			private bool canMoveToElement;

			private ReadState readState;

			private XmlAttributeTextNode attributeTextNode;

			private bool exitScope;

			private int depthDelta;

			private bool isAtomicValue;

			private bool skipValue;

			private QNameType qnameType;

			private bool hasContent;

			private bool isEmptyElement;

			private char quoteChar;

			public bool HasValue => hasValue;

			public ReadState ReadState => readState;

			public StringHandle LocalName => localName;

			public PrefixHandle Prefix => prefix;

			public bool CanGetAttribute => canGetAttribute;

			public bool CanMoveToElement => canMoveToElement;

			public XmlAttributeTextNode AttributeText => attributeTextNode;

			public bool SkipValue => skipValue;

			public ValueHandle Value => value;

			public int DepthDelta => depthDelta;

			public bool HasContent => hasContent;

			public XmlNodeType NodeType
			{
				get
				{
					return nodeType;
				}
				set
				{
					nodeType = value;
				}
			}

			public QNameType QNameType
			{
				get
				{
					return qnameType;
				}
				set
				{
					qnameType = value;
				}
			}

			public Namespace Namespace
			{
				get
				{
					return ns;
				}
				set
				{
					ns = value;
				}
			}

			public bool IsAtomicValue
			{
				get
				{
					return isAtomicValue;
				}
				set
				{
					isAtomicValue = value;
				}
			}

			public bool ExitScope
			{
				get
				{
					return exitScope;
				}
				set
				{
					exitScope = value;
				}
			}

			public bool IsEmptyElement
			{
				get
				{
					return isEmptyElement;
				}
				set
				{
					isEmptyElement = value;
				}
			}

			public char QuoteChar
			{
				get
				{
					return quoteChar;
				}
				set
				{
					quoteChar = value;
				}
			}

			public string ValueAsString
			{
				get
				{
					if (qnameType == QNameType.Normal)
					{
						return Value.GetString();
					}
					return Namespace.Uri.GetString();
				}
			}

			protected XmlNode(XmlNodeType nodeType, PrefixHandle prefix, StringHandle localName, ValueHandle value, XmlNodeFlags nodeFlags, ReadState readState, XmlAttributeTextNode attributeTextNode, int depthDelta)
			{
				this.nodeType = nodeType;
				this.prefix = prefix;
				this.localName = localName;
				this.value = value;
				ns = NamespaceManager.EmptyNamespace;
				hasValue = (nodeFlags & XmlNodeFlags.HasValue) != 0;
				canGetAttribute = (nodeFlags & XmlNodeFlags.CanGetAttribute) != 0;
				canMoveToElement = (nodeFlags & XmlNodeFlags.CanMoveToElement) != 0;
				isAtomicValue = (nodeFlags & XmlNodeFlags.AtomicValue) != 0;
				skipValue = (nodeFlags & XmlNodeFlags.SkipValue) != 0;
				hasContent = (nodeFlags & XmlNodeFlags.HasContent) != 0;
				this.readState = readState;
				this.attributeTextNode = attributeTextNode;
				exitScope = nodeType == XmlNodeType.EndElement;
				this.depthDelta = depthDelta;
				isEmptyElement = false;
				quoteChar = '"';
				qnameType = QNameType.Normal;
			}

			public bool IsLocalName(string localName)
			{
				if (qnameType == QNameType.Normal)
				{
					return LocalName == localName;
				}
				return Namespace.Prefix == localName;
			}

			public bool IsLocalName(XmlDictionaryString localName)
			{
				if (qnameType == QNameType.Normal)
				{
					return LocalName == localName;
				}
				return Namespace.Prefix == localName;
			}

			public bool IsNamespaceUri(string ns)
			{
				if (qnameType == QNameType.Normal)
				{
					return Namespace.IsUri(ns);
				}
				return ns == "http://www.w3.org/2000/xmlns/";
			}

			public bool IsNamespaceUri(XmlDictionaryString ns)
			{
				if (qnameType == QNameType.Normal)
				{
					return Namespace.IsUri(ns);
				}
				return ns.Value == "http://www.w3.org/2000/xmlns/";
			}

			public bool IsLocalNameAndNamespaceUri(string localName, string ns)
			{
				if (qnameType == QNameType.Normal)
				{
					if (LocalName == localName)
					{
						return Namespace.IsUri(ns);
					}
					return false;
				}
				if (Namespace.Prefix == localName)
				{
					return ns == "http://www.w3.org/2000/xmlns/";
				}
				return false;
			}

			public bool IsLocalNameAndNamespaceUri(XmlDictionaryString localName, XmlDictionaryString ns)
			{
				if (qnameType == QNameType.Normal)
				{
					if (LocalName == localName)
					{
						return Namespace.IsUri(ns);
					}
					return false;
				}
				if (Namespace.Prefix == localName)
				{
					return ns.Value == "http://www.w3.org/2000/xmlns/";
				}
				return false;
			}

			public bool IsPrefixAndLocalName(string prefix, string localName)
			{
				if (qnameType == QNameType.Normal)
				{
					if (Prefix == prefix)
					{
						return LocalName == localName;
					}
					return false;
				}
				if (prefix == "xmlns")
				{
					return Namespace.Prefix == localName;
				}
				return false;
			}

			public bool TryGetLocalNameAsDictionaryString(out XmlDictionaryString localName)
			{
				if (qnameType == QNameType.Normal)
				{
					return LocalName.TryGetDictionaryString(out localName);
				}
				localName = null;
				return false;
			}

			public bool TryGetNamespaceUriAsDictionaryString(out XmlDictionaryString ns)
			{
				if (qnameType == QNameType.Normal)
				{
					return Namespace.Uri.TryGetDictionaryString(out ns);
				}
				ns = null;
				return false;
			}

			public bool TryGetValueAsDictionaryString(out XmlDictionaryString value)
			{
				if (qnameType == QNameType.Normal)
				{
					return Value.TryGetDictionaryString(out value);
				}
				value = null;
				return false;
			}
		}

		protected class XmlElementNode : XmlNode
		{
			private XmlEndElementNode endElementNode;

			private int bufferOffset;

			public int NameOffset;

			public int NameLength;

			public XmlEndElementNode EndElement => endElementNode;

			public int BufferOffset
			{
				get
				{
					return bufferOffset;
				}
				set
				{
					bufferOffset = value;
				}
			}

			public XmlElementNode(XmlBufferReader bufferReader)
				: this(new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader))
			{
			}

			private XmlElementNode(PrefixHandle prefix, StringHandle localName, ValueHandle value)
				: base(XmlNodeType.Element, prefix, localName, value, (XmlNodeFlags)33, ReadState.Interactive, null, -1)
			{
				endElementNode = new XmlEndElementNode(prefix, localName, value);
			}
		}

		protected class XmlAttributeNode : XmlNode
		{
			public XmlAttributeNode(XmlBufferReader bufferReader)
				: this(new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader))
			{
			}

			private XmlAttributeNode(PrefixHandle prefix, StringHandle localName, ValueHandle value)
				: base(XmlNodeType.Attribute, prefix, localName, value, (XmlNodeFlags)15, ReadState.Interactive, new XmlAttributeTextNode(prefix, localName, value), 0)
			{
			}
		}

		protected class XmlEndElementNode : XmlNode
		{
			public XmlEndElementNode(PrefixHandle prefix, StringHandle localName, ValueHandle value)
				: base(XmlNodeType.EndElement, prefix, localName, value, XmlNodeFlags.HasContent, ReadState.Interactive, null, -1)
			{
			}
		}

		protected class XmlTextNode : XmlNode
		{
			protected XmlTextNode(XmlNodeType nodeType, PrefixHandle prefix, StringHandle localName, ValueHandle value, XmlNodeFlags nodeFlags, ReadState readState, XmlAttributeTextNode attributeTextNode, int depthDelta)
				: base(nodeType, prefix, localName, value, nodeFlags, readState, attributeTextNode, depthDelta)
			{
			}
		}

		protected class XmlAtomicTextNode : XmlTextNode
		{
			public XmlAtomicTextNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.Text, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), (XmlNodeFlags)60, ReadState.Interactive, null, 0)
			{
			}
		}

		protected class XmlComplexTextNode : XmlTextNode
		{
			public XmlComplexTextNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.Text, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), (XmlNodeFlags)36, ReadState.Interactive, null, 0)
			{
			}
		}

		protected class XmlWhitespaceTextNode : XmlTextNode
		{
			public XmlWhitespaceTextNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.Whitespace, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.HasValue, ReadState.Interactive, null, 0)
			{
			}
		}

		protected class XmlCDataNode : XmlTextNode
		{
			public XmlCDataNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.CDATA, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), (XmlNodeFlags)36, ReadState.Interactive, null, 0)
			{
			}
		}

		protected class XmlAttributeTextNode : XmlTextNode
		{
			public XmlAttributeTextNode(PrefixHandle prefix, StringHandle localName, ValueHandle value)
				: base(XmlNodeType.Text, prefix, localName, value, (XmlNodeFlags)47, ReadState.Interactive, null, 1)
			{
			}
		}

		protected class XmlInitialNode : XmlNode
		{
			public XmlInitialNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.None, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.None, ReadState.Initial, null, 0)
			{
			}
		}

		protected class XmlDeclarationNode : XmlNode
		{
			public XmlDeclarationNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.XmlDeclaration, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.CanGetAttribute, ReadState.Interactive, null, 0)
			{
			}
		}

		protected class XmlCommentNode : XmlNode
		{
			public XmlCommentNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.Comment, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.HasValue, ReadState.Interactive, null, 0)
			{
			}
		}

		protected class XmlEndOfFileNode : XmlNode
		{
			public XmlEndOfFileNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.None, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.None, ReadState.EndOfFile, null, 0)
			{
			}
		}

		protected class XmlClosedNode : XmlNode
		{
			public XmlClosedNode(XmlBufferReader bufferReader)
				: base(XmlNodeType.None, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.None, ReadState.Closed, null, 0)
			{
			}
		}

		private class AttributeSorter : IComparer
		{
			private object[] indeces;

			private XmlAttributeNode[] attributeNodes;

			private int attributeCount;

			private int attributeIndex1;

			private int attributeIndex2;

			public bool Sort(XmlAttributeNode[] attributeNodes, int attributeCount)
			{
				attributeIndex1 = -1;
				attributeIndex2 = -1;
				this.attributeNodes = attributeNodes;
				this.attributeCount = attributeCount;
				bool result = Sort();
				this.attributeNodes = null;
				this.attributeCount = 0;
				return result;
			}

			public void GetIndeces(out int attributeIndex1, out int attributeIndex2)
			{
				attributeIndex1 = this.attributeIndex1;
				attributeIndex2 = this.attributeIndex2;
			}

			public void Close()
			{
				if (indeces != null && indeces.Length > 32)
				{
					indeces = null;
				}
			}

			private bool Sort()
			{
				if (indeces != null && indeces.Length == attributeCount && IsSorted())
				{
					return true;
				}
				object[] array = new object[attributeCount];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = i;
				}
				indeces = array;
				Array.Sort(indeces, 0, attributeCount, this);
				return IsSorted();
			}

			private bool IsSorted()
			{
				for (int i = 0; i < indeces.Length - 1; i++)
				{
					if (Compare(indeces[i], indeces[i + 1]) >= 0)
					{
						attributeIndex1 = (int)indeces[i];
						attributeIndex2 = (int)indeces[i + 1];
						return false;
					}
				}
				return true;
			}

			public int Compare(object obj1, object obj2)
			{
				int num = (int)obj1;
				int num2 = (int)obj2;
				XmlAttributeNode xmlAttributeNode = attributeNodes[num];
				XmlAttributeNode xmlAttributeNode2 = attributeNodes[num2];
				int num3 = CompareQNameType(xmlAttributeNode.QNameType, xmlAttributeNode2.QNameType);
				if (num3 == 0)
				{
					if (xmlAttributeNode.QNameType == QNameType.Normal)
					{
						num3 = xmlAttributeNode.LocalName.CompareTo(xmlAttributeNode2.LocalName);
						if (num3 == 0)
						{
							num3 = xmlAttributeNode.Namespace.Uri.CompareTo(xmlAttributeNode2.Namespace.Uri);
						}
					}
					else
					{
						num3 = xmlAttributeNode.Namespace.Prefix.CompareTo(xmlAttributeNode2.Namespace.Prefix);
					}
				}
				return num3;
			}

			public int CompareQNameType(QNameType type1, QNameType type2)
			{
				return type1 - type2;
			}
		}

		private class NamespaceManager
		{
			private class XmlAttribute
			{
				private XmlSpace space;

				private string lang;

				private int depth;

				public int Depth
				{
					get
					{
						return depth;
					}
					set
					{
						depth = value;
					}
				}

				public string XmlLang
				{
					get
					{
						return lang;