Decompiled source of Custom Car Mod v1.1.3

Distance.CustomCar.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Distance.CustomCar.Data.Car;
using Distance.CustomCar.Data.Errors;
using Distance.CustomCar.Data.Materials;
using Events;
using Events.Car;
using Events.MainMenu;
using HarmonyLib;
using JsonFx.Json;
using JsonFx.Model;
using JsonFx.Serialization;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Distance.ModTemplate")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Distance.ModTemplate")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7bcb2908-b003-45d9-be68-50cba5217603")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
public static class DictionaryExtensions
{
	public static bool ContainsKey<T>(this Dictionary<string, object> obj, string key)
	{
		try
		{
			obj.GetItem<T>(key);
			return true;
		}
		catch
		{
			return false;
		}
	}

	public static T GetItem<T>(this Dictionary<string, object> obj, string key)
	{
		if (!obj.ContainsKey(key))
		{
			throw new KeyNotFoundException("The key requested doesn't exist in store: '" + key + "'.");
		}
		try
		{
			return (T)Convert.ChangeType(obj[key], typeof(T));
		}
		catch (Exception innerException)
		{
			throw new Exception("Failed type conversion exception has been thrown.", innerException);
		}
	}

	public static T GetOrCreate<T>(this Dictionary<string, object> obj, string key) where T : new()
	{
		if (!obj.ContainsKey(key))
		{
			obj[key] = new T();
		}
		return obj.GetItem<T>(key);
	}

	public static T GetOrCreate<T>(this Dictionary<string, object> obj, string key, T defaultValue)
	{
		if (!obj.ContainsKey<T>(key))
		{
			obj[key] = defaultValue;
		}
		return obj.GetItem<T>(key);
	}
}
public static class GameObjectExtensions
{
	public static string FullName(this GameObject obj)
	{
		if (!Object.op_Implicit((Object)(object)obj.transform.parent))
		{
			return ((Object)obj).name;
		}
		return ((Component)obj.transform.parent).gameObject.FullName() + "/" + ((Object)obj).name;
	}
}
namespace Distance.CustomCar
{
	public class Assets
	{
		private string _filePath = null;

		private string RootDirectory { get; }

		private string FileName { get; set; }

		private string FilePath => _filePath ?? Path.Combine(Path.Combine(RootDirectory, "Assets"), FileName);

		public object Bundle { get; private set; }

		private Assets()
		{
		}

		public Assets(string fileName)
		{
			RootDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
			FileName = fileName;
			if (!File.Exists(FilePath))
			{
				Mod.Log.LogError((object)("Couldn't find requested asset bundle at " + FilePath));
			}
			else
			{
				Bundle = Load();
			}
		}

		public static Assets FromUnsafePath(string filePath)
		{
			if (!File.Exists(filePath))
			{
				Mod.Log.LogError((object)("Could not find requested asset bundle at " + filePath));
				return null;
			}
			Assets assets = new Assets
			{
				_filePath = filePath,
				FileName = Path.GetFileName(filePath)
			};
			assets.Bundle = assets.Load();
			if (assets.Bundle == null)
			{
				return null;
			}
			return assets;
		}

		private object Load()
		{
			try
			{
				object result = AssetBundleBridge.LoadFrom(FilePath);
				Mod.Log.LogInfo((object)("Loaded asset bundle " + FilePath));
				return result;
			}
			catch (Exception ex)
			{
				Mod.Log.LogInfo((object)ex);
				return null;
			}
		}
	}
	internal static class AssetBundleBridge
	{
		public static Type AssetBundleType => Kernel.FindTypeByFullName("UnityEngine.AssetBundle", "UnityEngine");

		private static MethodInfo LoadFromFile => AssetBundleType.GetMethod("LoadFromFile", new Type[1] { typeof(string) });

		public static object LoadFrom(string path)
		{
			MethodInfo loadFromFile = LoadFromFile;
			object[] parameters = new string[1] { path };
			return loadFromFile.Invoke(null, parameters);
		}
	}
	internal static class Kernel
	{
		internal static Type FindTypeByFullName(string fullName, string assemblyFilter)
		{
			IEnumerable<Assembly> enumerable = from a in AppDomain.CurrentDomain.GetAssemblies()
				where a.GetName().Name.Contains(assemblyFilter)
				select a;
			foreach (Assembly item in enumerable)
			{
				Type type = item.GetTypes().FirstOrDefault((Type t) => t.FullName == fullName);
				if ((object)type == null)
				{
					continue;
				}
				return type;
			}
			Mod.Log.LogError((object)("Type " + fullName + " wasn't found in the main AppDomain at this moment."));
			throw new Exception("Type " + fullName + " wasn't found in the main AppDomain at this moment.");
		}
	}
	public class FileSystem
	{
		public string RootDirectory { get; }

		public string VirtualFileSystemRoot => Path.Combine(RootDirectory, "Data");

		public FileSystem()
		{
			RootDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
			if (!Directory.Exists(VirtualFileSystemRoot))
			{
				Directory.CreateDirectory(VirtualFileSystemRoot);
			}
		}

		public bool FileExists(string path)
		{
			string path2 = Path.Combine(VirtualFileSystemRoot, path);
			return File.Exists(path2);
		}

		public bool DirectoryExists(string path)
		{
			string path2 = Path.Combine(VirtualFileSystemRoot, path);
			return Directory.Exists(path2);
		}

		public bool PathExists(string path)
		{
			return FileExists(path) || DirectoryExists(path);
		}

		public byte[] ReadAllBytes(string filePath)
		{
			string text = Path.Combine(VirtualFileSystemRoot, filePath);
			if (!File.Exists(text))
			{
				Mod.Log.LogInfo((object)("Couldn't read a file for path '" + text + "'. File does not exist."));
				return null;
			}
			return File.ReadAllBytes(text);
		}

		public FileStream CreateFile(string filePath, bool overwrite = false)
		{
			string text = Path.Combine(VirtualFileSystemRoot, filePath);
			if (File.Exists(text))
			{
				if (!overwrite)
				{
					Mod.Log.LogInfo((object)("Couldn't create a mod VFS file for path '" + text + "'. The file already exists."));
					return null;
				}
				Mod.Log.LogInfo((object)("Couldn't delete a mod VFS file for path '" + text + "'. File does not exist."));
				RemoveFile(filePath);
			}
			try
			{
				return File.Create(text);
			}
			catch (Exception ex)
			{
				Mod.Log.LogInfo((object)("Couldn't create a mod VFS file for path '" + text + "'."));
				Mod.Log.LogInfo((object)ex);
				return null;
			}
		}

		public void RemoveFile(string filePath)
		{
			string text = Path.Combine(VirtualFileSystemRoot, filePath);
			if (!File.Exists(text))
			{
				Mod.Log.LogInfo((object)("Couldn't delete a mod VFS file for path '" + text + "'. File does not exist."));
				return;
			}
			try
			{
				File.Delete(text);
			}
			catch (Exception ex)
			{
				Mod.Log.LogInfo((object)("Couldn't delete a mod VFS file for path '" + text + "'."));
				Mod.Log.LogInfo((object)ex);
			}
		}

		public void IterateOver(string directoryPath, Action<string, bool> action, bool sort = true)
		{
			string text = Path.Combine(VirtualFileSystemRoot, directoryPath);
			if (!Directory.Exists(text))
			{
				Mod.Log.LogInfo((object)("Cannot iterate over directory at '" + text + "'. It doesn't exist."));
				return;
			}
			List<string> list = Directory.GetFiles(text).ToList();
			list.AddRange(Directory.GetDirectories(text));
			if (sort)
			{
				list = list.OrderBy((string x) => x).ToList();
			}
			foreach (string item in list)
			{
				try
				{
					bool arg = Directory.Exists(item);
					action(item, arg);
				}
				catch (Exception ex)
				{
					Mod.Log.LogInfo((object)("Action for the element at path '" + item + "' failed. See file system exception log for details."));
					Mod.Log.LogInfo((object)ex);
					break;
				}
			}
		}

		public List<string> GetDirectories(string directoryPath, string searchPattern)
		{
			string text = Path.Combine(VirtualFileSystemRoot, directoryPath);
			if (!Directory.Exists(text))
			{
				Mod.Log.LogInfo((object)("Cannot get directories in directory at '" + text + "'. It doesn't exist."));
				return null;
			}
			return Directory.GetDirectories(text, searchPattern).ToList();
		}

		public List<string> GetDirectories(string directoryPath)
		{
			return GetDirectories(directoryPath, "*");
		}

		public List<string> GetFiles(string directoryPath, string searchPattern)
		{
			string text = Path.Combine(VirtualFileSystemRoot, directoryPath);
			if (!Directory.Exists(text))
			{
				Mod.Log.LogInfo((object)("Cannot get files in directory at '" + text + "'. It doesn't exist."));
				return null;
			}
			return Directory.GetFiles(text, searchPattern).ToList();
		}

		public List<string> GetFiles(string directoryPath)
		{
			return GetFiles(directoryPath, "*");
		}

		public FileStream OpenFile(string filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
		{
			string text = Path.Combine(VirtualFileSystemRoot, filePath);
			if (!File.Exists(text))
			{
				Mod.Log.LogInfo((object)("Couldn't open a VFS file. The requested file: '" + text + "' does not exist."));
				return null;
			}
			try
			{
				return File.Open(text, fileMode, fileAccess, fileShare);
			}
			catch (Exception ex)
			{
				Mod.Log.LogInfo((object)("Couldn't open a VFS file for path '" + text + "'."));
				Mod.Log.LogInfo((object)ex);
				return null;
			}
		}

		public FileStream OpenFile(string filePath)
		{
			return OpenFile(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
		}

		public string CreateDirectory(string directoryName)
		{
			string text = Path.Combine(VirtualFileSystemRoot, directoryName);
			try
			{
				Directory.CreateDirectory(text);
				return text;
			}
			catch (Exception ex)
			{
				Mod.Log.LogInfo((object)("Couldn't create a VFS directory for path '" + text + "'."));
				Mod.Log.LogInfo((object)ex);
				return string.Empty;
			}
		}

		public void RemoveDirectory(string directoryPath)
		{
			string text = Path.Combine(VirtualFileSystemRoot, directoryPath);
			if (!Directory.Exists(text))
			{
				Mod.Log.LogInfo((object)("Couldn't remove a VFS directory for path '" + text + "'. Directory does not exist."));
				return;
			}
			try
			{
				Directory.Delete(text, recursive: true);
			}
			catch (Exception ex)
			{
				Mod.Log.LogInfo((object)("Couldn't remove a VFS directory for path '" + text + "'."));
				Mod.Log.LogInfo((object)ex);
			}
		}

		public static string GetValidFileName(string dirtyFileName, string replaceInvalidCharsWith = "_")
		{
			return Regex.Replace(dirtyFileName, "[^\\w\\s\\.]", replaceInvalidCharsWith, RegexOptions.None);
		}

		public static string GetValidFileNameToLower(string dirtyFileName, string replaceInvalidCharsWith = "_")
		{
			return GetValidFileName(dirtyFileName, replaceInvalidCharsWith).ToLower();
		}
	}
	public sealed class MessageBox
	{
		private readonly string Message = "";

		private readonly string Title = "";

		private float Time = 0f;

		private ButtonType Buttons = (ButtonType)0;

		private Action Confirm;

		private Action Cancel;

		private MessageBox(string message, string title)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Message = message;
			Title = title;
			Confirm = EmptyAction;
			Cancel = EmptyAction;
		}

		public static MessageBox Create(string content, string title = "")
		{
			return new MessageBox(content, title);
		}

		public MessageBox SetButtons(MessageButtons buttons)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Buttons = (ButtonType)buttons;
			return this;
		}

		public MessageBox SetTimeout(float delay)
		{
			Time = delay;
			return this;
		}

		public MessageBox OnConfirm(Action action)
		{
			Confirm = action;
			return this;
		}

		public MessageBox OnCancel(Action action)
		{
			Cancel = action;
			return this;
		}

		public void Show()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0042: Expected O, but got Unknown
			G.Sys.MenuPanelManager_.ShowMessage(Message, Title, (OnButtonClicked)delegate
			{
				Confirm();
			}, (OnButtonClicked)delegate
			{
				Cancel();
			}, Buttons, false, (Pivot)4, Time);
		}

		private void EmptyAction()
		{
		}
	}
	[Flags]
	public enum MessageButtons
	{
		Ok = 0,
		OkCancel = 1,
		YesNo = 2
	}
	[BepInPlugin("Distance.CustomCar", "Custom Car", "1.1.3")]
	public sealed class Mod : BaseUnityPlugin
	{
		private const string modGUID = "Distance.CustomCar";

		private const string modName = "Custom Car";

		private const string modVersion = "1.1.3";

		public static string UseTrumpetKey = "Use Trumpet Horn";

		private static readonly Harmony harmony = new Harmony("Distance.CustomCar");

		public static ManualLogSource Log = new ManualLogSource("Custom Car");

		public static Mod Instance;

		private bool displayErrors_ = true;

		public static ConfigEntry<bool> UseTrumpetHorn { get; set; }

		public static int DefaultCarCount { get; private set; }

		public static int ModdedCarCount => TotalCarCount - DefaultCarCount;

		public static int TotalCarCount { get; private set; }

		public ErrorList Errors { get; set; }

		public ProfileCarColors CarColors { get; set; }

		private void Awake()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			Log = Logger.CreateLogSource("Distance.CustomCar");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Thanks for using Custom Cars!");
			Errors = new ErrorList(((BaseUnityPlugin)this).Logger);
			CarColors = ((Component)this).gameObject.AddComponent<ProfileCarColors>();
			UseTrumpetHorn = ((BaseUnityPlugin)this).Config.Bind<bool>("General", UseTrumpetKey, false, new ConfigDescription("Custom car models will use the encryptor horn (the \"doot!\" trumpet).", (AcceptableValueBase)null, new object[0]));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading...");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded!");
		}

		public void Start()
		{
			ProfileManager profileManager_ = G.Sys.ProfileManager_;
			DefaultCarCount = profileManager_.CarInfos_.Length;
			CarInfos carInfos = new CarInfos();
			carInfos.CollectInfos();
			CarBuilder carBuilder = new CarBuilder();
			carBuilder.CreateCars(carInfos);
			TotalCarCount = profileManager_.CarInfos_.Length;
			CarColors.LoadAll();
			Errors.Show();
		}

		private void OnEnable()
		{
			StaticEvent<Data>.Subscribe((Delegate<Data>)OnMainMenuLoaded);
		}

		private void OnDisable()
		{
			StaticEvent<Data>.Unsubscribe((Delegate<Data>)OnMainMenuLoaded);
		}

		private void OnMainMenuLoaded(Data _)
		{
			if (displayErrors_)
			{
				Errors.Show();
				displayErrors_ = false;
			}
		}

		private void OnConfigChanged(object sender, EventArgs e)
		{
			SettingChangedEventArgs val = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null);
			if (val != null)
			{
			}
		}
	}
	public class ProfileCarColors : MonoBehaviour
	{
		internal Settings Config;

		public event Action<ProfileCarColors> OnChanged;

		protected void Load()
		{
			Config = new Settings("CustomCars");
		}

		protected void Awake()
		{
			Load();
			Save();
		}

		protected Dictionary<string, object> Profile(string profileName)
		{
			Mod.Log.LogInfo((object)"Assigning Profile Name...");
			return Config.GetOrCreate(profileName, new Dictionary<string, object>());
		}

		protected Dictionary<string, object> Vehicle(string profileName, string vehicleName)
		{
			Mod.Log.LogInfo((object)"Assigning Vehicle Name...");
			return Profile(profileName).GetOrCreate(vehicleName, new Dictionary<string, object>());
		}

		protected CarColors GetCarColors(string profileName, string vehicleName)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, object> vehicle = Vehicle(profileName, vehicleName);
			CarColors val = default(CarColors);
			val.primary_ = GetColor(vehicle, "primary", Colors.whiteSmoke);
			val.secondary_ = GetColor(vehicle, "secondary", Colors.darkGray);
			val.glow_ = GetColor(vehicle, "glow", Colors.cyan);
			val.sparkle_ = GetColor(vehicle, "sparkle", Colors.lightSlateGray);
			CarColors val2 = val;
			SetCarColors(profileName, vehicleName, val2);
			return val2;
		}

		protected Color GetColor(Dictionary<string, object> vehicle, string category, Color defaultColor)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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)
			Dictionary<string, object> orCreate = vehicle.GetOrCreate(category, new Dictionary<string, object>());
			float orCreate2 = orCreate.GetOrCreate("r", defaultColor.r);
			float orCreate3 = orCreate.GetOrCreate("g", defaultColor.g);
			float orCreate4 = orCreate.GetOrCreate("b", defaultColor.b);
			float orCreate5 = orCreate.GetOrCreate("a", defaultColor.a);
			return new Color(orCreate2, orCreate3, orCreate4, orCreate5);
		}

		protected void SetCarColors(string profileName, string vehicleName, CarColors colors)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, object> dictionary = Vehicle(profileName, vehicleName);
			dictionary["primary"] = ToSection(colors.primary_);
			dictionary["secondary"] = ToSection(colors.secondary_);
			dictionary["glow"] = ToSection(colors.glow_);
			dictionary["sparkle"] = ToSection(colors.sparkle_);
			Dictionary<string, object> dictionary2 = Profile(profileName);
			dictionary2[vehicleName] = dictionary;
			Config[profileName] = dictionary2;
		}

		protected Section ToSection(Color color)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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)
			return new Section
			{
				["r"] = color.r,
				["g"] = color.g,
				["b"] = color.b,
				["a"] = color.a
			};
		}

		protected void Save()
		{
			Config.Save();
			this.OnChanged?.Invoke(this);
		}

		public void LoadAll()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			ProfileManager profileManager_ = G.Sys.ProfileManager_;
			List<Profile> profiles_ = profileManager_.profiles_;
			foreach (Profile item in profiles_)
			{
				CarColors[] array = (CarColors[])(object)new CarColors[Mod.TotalCarCount];
				for (int i = 0; i < profileManager_.CarInfos_.Length; i++)
				{
					if (i < Mod.DefaultCarCount)
					{
						array[i] = item.carColorsList_[i];
						continue;
					}
					CarInfo val = profileManager_.CarInfos_[i];
					Mod.Log.LogInfo((object)("Getting car color in " + item.FileName_ + "'s profile for the " + val.name_ + " car"));
					CarColors carColors = GetCarColors(item.FileName_, val.name_);
					array[i] = carColors;
				}
				item.carColorsList_ = array;
			}
		}

		public void SaveAll()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			ProfileManager profileManager_ = G.Sys.ProfileManager_;
			List<Profile> profiles_ = profileManager_.profiles_;
			foreach (Profile item in profiles_)
			{
				for (int i = 0; i < profileManager_.CarInfos_.Length; i++)
				{
					if (i >= Mod.DefaultCarCount)
					{
						CarInfo val = profileManager_.CarInfos_[i];
						CarColors colors = item.carColorsList_[i];
						SetCarColors(item.FileName_, val.name_, colors);
					}
				}
			}
			Save();
		}
	}
	public class Section : Dictionary<string, object>
	{
		public new object this[string key]
		{
			get
			{
				if (!ContainsKey(key))
				{
					return null;
				}
				return base[key];
			}
			set
			{
				if (!ContainsKey(key))
				{
					Add(key, value);
					this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, null, base[key]));
				}
				else
				{
					object oldValue = base[key];
					base[key] = value;
					this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, oldValue, base[key]));
				}
			}
		}

		public event EventHandler<SettingsChangedEventArgs> ValueChanged;

		public T GetItem<T>(string key)
		{
			if (!ContainsKey(key))
			{
				Mod.Log.LogError((object)("The key requested doesn't exist in store: '" + key + "'."));
				throw new KeyNotFoundException("The key requested doesn't exist in store: '" + key + "'.");
			}
			try
			{
				return (T)Convert.ChangeType(this[key], typeof(T));
			}
			catch (Exception ex)
			{
				Mod.Log.LogWarning((object)$"Failed type conversion exception has been thrown. String: {key} \n{ex}");
				throw new SettingsException("Failed type conversion exception has been thrown.", key, isJsonFailure: false, ex);
			}
		}

		public T GetOrCreate<T>(string key) where T : new()
		{
			if (!ContainsKey(key))
			{
				this[key] = new T();
				this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, null, this[key]));
			}
			return GetItem<T>(key);
		}

		public T GetOrCreate<T>(string key, T defaultValue)
		{
			if (!ContainsKey<T>(key))
			{
				this[key] = defaultValue;
				this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, null, this[key]));
			}
			return GetItem<T>(key);
		}

		public bool ContainsKey<T>(string key)
		{
			try
			{
				GetItem<T>(key);
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	public class Settings : Section
	{
		private string FileName { get; }

		private string RootDirectory { get; }

		private string SettingsDirectory => Path.Combine(RootDirectory, "Settings");

		private string FilePath => Path.Combine(SettingsDirectory, FileName);

		public Settings(string fileName)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			RootDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
			FileName = fileName + ".json";
			Mod.Log.LogInfo((object)("Settings instance for '" + FilePath + "' initializing..."));
			if (!File.Exists(FilePath))
			{
				return;
			}
			bool flag = false;
			using (StreamReader streamReader = new StreamReader(FilePath))
			{
				string text = streamReader.ReadToEnd();
				JsonReader val = new JsonReader();
				Section section = null;
				try
				{
					section = ((DataReader<ModelTokenType>)(object)val).Read<Section>(text);
				}
				catch (Exception ex)
				{
					Mod.Log.LogWarning((object)ex);
					flag = true;
				}
				if (section != null)
				{
					foreach (string key in section.Keys)
					{
						Add(key, section[key]);
					}
				}
			}
			if (flag)
			{
				Save();
			}
		}

		public void Save(bool formatJson = true)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			if (!Directory.Exists(SettingsDirectory))
			{
				Directory.CreateDirectory(SettingsDirectory);
			}
			DataWriterSettings val = new DataWriterSettings
			{
				PrettyPrint = formatJson
			};
			JsonWriter val2 = new JsonWriter(val);
			try
			{
				using StreamWriter streamWriter = new StreamWriter(FilePath, append: false);
				streamWriter.WriteLine(((DataWriter<ModelTokenType>)(object)val2).Write((object)this));
			}
			catch (Exception ex)
			{
				Mod.Log.LogWarning((object)ex);
			}
		}
	}
	public class SettingsChangedEventArgs : EventArgs
	{
		public string Key { get; }

		public object OldValue { get; }

		public object NewValue { get; }

		public SettingsChangedEventArgs(string key, object oldValue = null, object newValue = null)
		{
			Key = key;
			OldValue = oldValue;
			NewValue = newValue;
		}
	}
	public class SettingsException : Exception
	{
		public string Key { get; }

		public bool IsJsonFailure { get; }

		public SettingsException(string message, string key, bool isJsonFailure, Exception innerException)
			: base(message, innerException)
		{
			Key = key;
			IsJsonFailure = isJsonFailure;
		}

		public SettingsException(string message, string key, bool isJsonFailure)
			: this(message, key, isJsonFailure, null)
		{
		}
	}
}
namespace Distance.CustomCar.Patches
{
	[HarmonyPatch(typeof(CarAudio), "OnCarHornEvent")]
	internal static class OnCarHornEvent
	{
		[HarmonyPrefix]
		internal static bool Prefix(CarAudio __instance, Data data)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			int num = G.Sys.ProfileManager_.knownCars_[__instance.carLogic_.PlayerData_.CarName_];
			if (num >= Mod.DefaultCarCount && Mod.UseTrumpetHorn.Value)
			{
				__instance.phantom_.SetRTPCValue("Horn_volume", Mathf.Clamp01(data.hornPercent_ + 0.5f));
				__instance.phantom_.Play("SpookyHorn", 0f, true);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(GadgetWithAnimation), "SetAnimationStateValues")]
	internal static class GadgetWithAnimation__SetAnimationStateValues
	{
		[HarmonyPrefix]
		internal static bool Prefix(GadgetWithAnimation __instance)
		{
			Animation componentInChildren = ((Component)__instance).GetComponentInChildren<Animation>(true);
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				return PatchAnimations(componentInChildren, __instance.animationName_);
			}
			return false;
		}

		private static bool PatchAnimations(Animation animation, string name)
		{
			if (Object.op_Implicit((Object)(object)animation))
			{
				if (!ChangeBlendModeToBlend(((Component)animation).transform, name))
				{
					return true;
				}
				AnimationState val = animation[name];
				if (TrackedReference.op_Implicit((TrackedReference)(object)val))
				{
					val.layer = 3;
					val.blendMode = (AnimationBlendMode)0;
					val.wrapMode = (WrapMode)8;
					val.enabled = true;
					val.weight = 1f;
					val.speed = 0f;
				}
			}
			return false;
		}

		private static bool ChangeBlendModeToBlend(Transform obj, string animationName)
		{
			for (int i = 0; i < obj.childCount; i++)
			{
				string text = ((Object)((Component)obj.GetChild(i)).gameObject).name.ToLower();
				if (!text.StartsWith("#"))
				{
					continue;
				}
				text = text.Remove(0, 1);
				string[] array = text.Split(new char[1] { ';' });
				if (array.Length == 1)
				{
					if (array[0] == "additive")
					{
						return false;
					}
					if (array[0] == "blend")
					{
						return true;
					}
				}
				if (array[1] == animationName.ToLower())
				{
					if (array[0] == "additive")
					{
						return false;
					}
					if (array[0] == "blend")
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Profile), "Awake")]
	internal static class Profile__Awake
	{
		[HarmonyPostfix]
		internal static void Postfix(Profile __instance)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			CarColors[] array = (CarColors[])(object)new CarColors[G.Sys.ProfileManager_.carInfos_.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = G.Sys.ProfileManager_.carInfos_[i].colors_;
			}
			__instance.carColorsList_ = array;
		}
	}
	[HarmonyPatch(typeof(Profile), "Save")]
	internal static class Profile__Save
	{
		[HarmonyPostfix]
		internal static void Postfix()
		{
			Mod.Instance.CarColors.SaveAll();
		}
	}
	[HarmonyPatch(typeof(Profile), "SetColorsForAllCars", new Type[] { typeof(CarColors) })]
	internal static class Profile__SetColorsForAllCars
	{
		[HarmonyPrefix]
		internal static bool Prefix(Profile __instance, CarColors cc)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			CarColors[] array = (CarColors[])(object)new CarColors[G.Sys.ProfileManager_.carInfos_.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = cc;
			}
			__instance.carColorsList_ = array;
			__instance.dataModified_ = true;
			return false;
		}
	}
}
namespace Distance.CustomCar.Data.Materials
{
	public class MaterialInfos
	{
		public Material material;

		public int diffuseIndex = -1;

		public int normalIndex = -1;

		public int emitIndex = -1;

		public void ReplaceMaterialInRenderer(Renderer renderer, int materialIndex)
		{
			if (!((Object)(object)material == (Object)null) && !((Object)(object)renderer == (Object)null) && materialIndex < renderer.materials.Length)
			{
				ref Material reference = ref renderer.materials[materialIndex];
				Material val = Object.Instantiate<Material>(material);
				if (diffuseIndex >= 0)
				{
					val.SetTexture(diffuseIndex, reference.GetTexture("_MainTex"));
				}
				if (emitIndex >= 0)
				{
					val.SetTexture(emitIndex, reference.GetTexture("_EmissionMap"));
				}
				if (normalIndex >= 0)
				{
					val.SetTexture(normalIndex, reference.GetTexture("_BumpMap"));
				}
				renderer.materials[materialIndex] = val;
			}
		}
	}
	public class MaterialPropertyExport
	{
		public string fromName;

		public string toName;

		public int fromID = -1;

		public int toID = -1;

		public PropertyType type;
	}
	public class MaterialPropertyInfo
	{
		public string shaderName;

		public string name;

		public int diffuseIndex = -1;

		public int normalIndex = -1;

		public int emitIndex = -1;

		public MaterialPropertyInfo(string _shaderName, string _name, int _diffuseIndex, int _normalIndex, int _emitIndex)
		{
			shaderName = _shaderName;
			name = _name;
			diffuseIndex = _diffuseIndex;
			normalIndex = _normalIndex;
			emitIndex = _emitIndex;
		}
	}
	public enum PropertyType
	{
		Color,
		ColorArray,
		Float,
		FloatArray,
		Int,
		Matrix,
		MatrixArray,
		Texture,
		Vector,
		VectorArray
	}
}
namespace Distance.CustomCar.Data.Errors
{
	public class ErrorList : List<string>
	{
		private readonly ManualLogSource logger_;

		public ErrorList(ManualLogSource logger)
		{
			logger_ = logger;
		}

		public new void Add(string value)
		{
			base.Add(value);
			logger_.LogInfo((object)value);
		}

		public void Add(Exception value)
		{
			base.Add(value.ToString());
			logger_.LogInfo((object)value);
		}

		public void Show()
		{
			if (this.Any())
			{
				string arg = ((base.Count < 15) ? string.Join(Environment.NewLine, ToArray()) : "There were too many errors when loading custom cars to be displayed here, please check the logs in your mod installation directory.");
				MessageBox.Create($"Can't load the cars correctly: {base.Count} error(s)\n{arg}", "CUSTOM CARS - ERRORS").SetButtons(MessageButtons.Ok).Show();
			}
		}
	}
}
namespace Distance.CustomCar.Data.Car
{
	public class CarBuilder
	{
		private CarInfos infos_;

		public void CreateCars(CarInfos infos)
		{
			infos_ = infos;
			Dictionary<string, GameObject> dictionary = LoadAssetsBundles();
			List<CreateCarReturnInfos> list = new List<CreateCarReturnInfos>();
			foreach (KeyValuePair<string, GameObject> item in dictionary)
			{
				try
				{
					Mod.Log.LogInfo((object)("Creating car prefab for " + item.Key + " ..."));
					CreateCarReturnInfos createCarReturnInfos = CreateCar(item.Value);
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item.Key.Substring(0, item.Key.LastIndexOf('(') - 1));
					((Object)createCarReturnInfos.car).name = fileNameWithoutExtension;
					list.Add(createCarReturnInfos);
				}
				catch (Exception value)
				{
					Mod.Log.LogError((object)("Could not load car prefab: " + item.Key));
					Mod.Instance.Errors.Add("Could not load car prefab: " + item.Key);
					Mod.Instance.Errors.Add(value);
				}
			}
			RegisterCars(list);
		}

		private void RegisterCars(List<CreateCarReturnInfos> carsInfos)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			Mod.Log.LogInfo((object)$"Registering {carsInfos.Count} car(s)...");
			ProfileManager profileManager_ = G.Sys.ProfileManager_;
			CarInfo[] array = ICollectionEx.ToArray<CarInfo>((ICollection<CarInfo>)profileManager_.carInfos_);
			profileManager_.carInfos_ = (CarInfo[])(object)new CarInfo[array.Length + carsInfos.Count];
			ref Dictionary<string, int> unlockedCars_ = ref profileManager_.unlockedCars_;
			ref Dictionary<string, int> knownCars_ = ref profileManager_.knownCars_;
			for (int i = 0; i < profileManager_.carInfos_.Length; i++)
			{
				if (i < array.Length)
				{
					profileManager_.carInfos_[i] = array[i];
					continue;
				}
				int index = i - array.Length;
				CarInfo val = new CarInfo
				{
					name_ = ((Object)carsInfos[index].car).name,
					prefabs_ = new CarPrefabs
					{
						carPrefab_ = carsInfos[index].car
					},
					colors_ = carsInfos[index].colors
				};
				if (!knownCars_.ContainsKey(val.name_) && !unlockedCars_.ContainsKey(val.name_))
				{
					unlockedCars_.Add(val.name_, i);
					knownCars_.Add(val.name_, i);
				}
				else
				{
					Mod.Instance.Errors.Add("A car with the name " + val.name_ + " is already registered, rename the car file if they're the same.");
					Mod.Log.LogInfo((object)("Generating unique name for car " + val.name_));
					string text = $"#{Guid.NewGuid():B}";
					Mod.Log.LogInfo((object)("Using GUID: " + text));
					val.name_ = "[FFFF00]![-] " + val.name_ + " " + text;
					unlockedCars_.Add(val.name_, i);
					knownCars_.Add(val.name_, i);
				}
				profileManager_.carInfos_[i] = val;
			}
			CarColors[] array2 = (CarColors[])(object)new CarColors[array.Length + carsInfos.Count];
			for (int j = 0; j < array2.Length; j++)
			{
				array2[j] = G.Sys.ProfileManager_.carInfos_[j].colors_;
			}
			for (int k = 0; k < profileManager_.ProfileCount_; k++)
			{
				Profile profile = profileManager_.GetProfile(k);
				CarColors[] carColorsList_ = profile.carColorsList_;
				for (int l = 0; l < carColorsList_.Length && l < array2.Length; l++)
				{
					array2[l] = carColorsList_[l];
				}
				profile.carColorsList_ = array2;
			}
		}

		private Dictionary<string, GameObject> LoadAssetsBundles()
		{
			Dictionary<string, GameObject> dictionary = new Dictionary<string, GameObject>();
			DirectoryInfo localFolder = GetLocalFolder("Assets");
			DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Resource.personalDistanceDirPath_, "CustomCars"));
			if (!directoryInfo.Exists)
			{
				try
				{
					directoryInfo.Create();
				}
				catch (Exception ex)
				{
					Mod.Instance.Errors.Add("Could not create the following folder: " + directoryInfo.FullName);
					Mod.Log.LogError((object)("Could not create the following folder: " + directoryInfo.FullName));
					Mod.Instance.Errors.Add(ex);
					Mod.Log.LogError((object)ex);
				}
			}
			DirectoryInfo directoryInfo2 = new DirectoryInfo(Directory.GetParent(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location)).ToString());
			foreach (FileInfo item in from x in ArrayEx.Concat<FileInfo>(directoryInfo2.GetFiles("*", SearchOption.AllDirectories), directoryInfo.GetFiles("*", SearchOption.AllDirectories))
				orderby x.Name
				select x)
			{
				if (!(item.Extension == ""))
				{
					continue;
				}
				try
				{
					Assets assets = Assets.FromUnsafePath(item.FullName);
					object bundle = assets.Bundle;
					AssetBundle val = (AssetBundle)((bundle is AssetBundle) ? bundle : null);
					int num = 0;
					foreach (string item2 in from name in val.GetAllAssetNames()
						where name.EndsWith(".prefab", StringComparison.InvariantCultureIgnoreCase)
						select name)
					{
						GameObject value = val.LoadAsset<GameObject>(item2);
						string key = item.FullName + " (" + item2 + ")";
						if (!dictionary.ContainsKey(key))
						{
							dictionary.Add(key, value);
							num++;
						}
					}
					if (num == 0)
					{
						Mod.Instance.Errors.Add("Can't find a prefab in the asset bundle: " + item.FullName);
						Mod.Log.LogError((object)("Can't find a prefab in the asset bundle: " + item.FullName));
					}
				}
				catch (Exception ex2)
				{
					Mod.Instance.Errors.Add("Could not load assets file: " + item.FullName);
					Mod.Log.LogError((object)("Could not load assets file: " + item.FullName));
					Mod.Instance.Errors.Add(ex2);
					Mod.Log.LogError((object)ex2);
				}
			}
			return dictionary;
		}

		public DirectoryInfo GetLocalFolder(string dir)
		{
			FileSystem fileSystem = new FileSystem();
			return new DirectoryInfo(Path.GetDirectoryName(Path.Combine(fileSystem.RootDirectory, dir + (dir.EndsWith($"{Path.DirectorySeparatorChar}") ? string.Empty : $"{Path.DirectorySeparatorChar}"))));
		}

		private CreateCarReturnInfos CreateCar(GameObject car)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			CreateCarReturnInfos createCarReturnInfos = new CreateCarReturnInfos();
			GameObject val = Object.Instantiate<GameObject>(infos_.baseCar);
			((Object)val).name = ((Object)car).name;
			Object.DontDestroyOnLoad((Object)(object)val);
			val.SetActive(false);
			RemoveOldCar(val);
			GameObject car2 = AddNewCarOnPrefab(val, car);
			SetCarDatas(val, car2);
			createCarReturnInfos.car = val;
			createCarReturnInfos.colors = LoadDefaultColors(car2);
			return createCarReturnInfos;
		}

		private void RemoveOldCar(GameObject obj)
		{
			List<GameObject> list = new List<GameObject>();
			for (int i = 0; i < obj.transform.childCount; i++)
			{
				GameObject gameObject = ((Component)obj.transform.GetChild(i)).gameObject;
				if (((Object)gameObject).name.IndexOf("wheel", StringComparison.InvariantCultureIgnoreCase) >= 0)
				{
					list.Add(gameObject);
				}
			}
			if (list.Count != 4)
			{
				Mod.Instance.Errors.Add($"Found {list.Count} wheels on base prefabs, expected 4");
				Mod.Log.LogError((object)$"Found {list.Count} wheels on base prefabs, expected 4");
			}
			Transform val = obj.transform.Find("Refractor");
			if ((Object)(object)val == (Object)null)
			{
				Mod.Instance.Errors.Add("Can't find the Refractor object on the base car prefab");
				Mod.Log.LogError((object)"Can't find the Refractor object on the base car prefab");
				return;
			}
			Object.Destroy((Object)(object)((Component)val).gameObject);
			foreach (GameObject item in list)
			{
				Object.Destroy((Object)(object)item);
			}
		}

		private GameObject AddNewCarOnPrefab(GameObject obj, GameObject car)
		{
			return Object.Instantiate<GameObject>(car, obj.transform);
		}

		private void SetCarDatas(GameObject obj, GameObject car)
		{
			SetColorChanger(obj.GetComponent<ColorChanger>(), car);
			SetCarVisuals(obj.GetComponent<CarVisuals>(), car);
		}

		private void SetColorChanger(ColorChanger colorChanger, GameObject car)
		{
			if ((Object)(object)colorChanger == (Object)null)
			{
				Mod.Instance.Errors.Add("Can't find the ColorChanger component on the base car");
				Mod.Log.LogError((object)"Can't find the ColorChanger component on the base car");
				return;
			}
			colorChanger.rendererChangers_ = (RendererChanger[])(object)new RendererChanger[0];
			Renderer[] componentsInChildren = car.GetComponentsInChildren<Renderer>();
			foreach (Renderer val in componentsInChildren)
			{
				ReplaceMaterials(val);
				if ((Object)(object)colorChanger != (Object)null)
				{
					AddMaterialColorChanger(colorChanger, ((Component)val).transform);
				}
			}
		}

		private void ReplaceMaterials(Renderer renderer)
		{
			string[] array = new string[renderer.materials.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = "wheel";
			}
			List<MaterialPropertyExport>[] array2 = new List<MaterialPropertyExport>[renderer.materials.Length];
			for (int j = 0; j < array2.Length; j++)
			{
				array2[j] = new List<MaterialPropertyExport>();
			}
			FillMaterialInfos(renderer, array, array2);
			Material[] array3 = ICollectionEx.ToArray<Material>((ICollection<Material>)renderer.materials);
			for (int k = 0; k < renderer.materials.Length; k++)
			{
				if (!infos_.materials.TryGetValue(array[k], out var value))
				{
					Mod.Instance.Errors.Add("Can't find the material " + array[k] + " on " + ((Component)renderer).gameObject.FullName());
					Mod.Log.LogError((object)("Can't find the material " + array[k] + " on " + ((Component)renderer).gameObject.FullName()));
				}
				else
				{
					if (value == null || (Object)(object)value.material == (Object)null)
					{
						continue;
					}
					Material val = Object.Instantiate<Material>(value.material);
					if (value.diffuseIndex >= 0)
					{
						val.SetTexture(value.diffuseIndex, renderer.materials[k].GetTexture("_MainTex"));
					}
					if (value.normalIndex >= 0)
					{
						val.SetTexture(value.normalIndex, renderer.materials[k].GetTexture("_BumpMap"));
					}
					if (value.emitIndex >= 0)
					{
						val.SetTexture(value.emitIndex, renderer.materials[k].GetTexture("_EmissionMap"));
					}
					foreach (MaterialPropertyExport item in array2[k])
					{
						CopyMaterialProperty(renderer.materials[k], val, item);
					}
					array3[k] = val;
				}
			}
			renderer.materials = array3;
		}

		private void FillMaterialInfos(Renderer renderer, string[] matNames, List<MaterialPropertyExport>[] materialProperties)
		{
			int childCount = ((Component)renderer).transform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				string text = ((Object)((Component)renderer).transform.GetChild(i)).name.ToLower();
				if (!text.StartsWith("#"))
				{
					continue;
				}
				text = text.Remove(0, 1);
				string[] array = text.Split(new char[1] { ';' });
				if (array.Length == 0)
				{
					continue;
				}
				if (array[0].Contains("mat"))
				{
					int result;
					if (array.Length != 3)
					{
						Mod.Instance.Errors.Add(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 2 arguments");
						Mod.Log.LogError((object)(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 2 arguments"));
					}
					else if (!int.TryParse(array[1], out result))
					{
						Mod.Instance.Errors.Add("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number");
						Mod.Log.LogError((object)("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number"));
					}
					else if (result < matNames.Length)
					{
						matNames[result] = array[2];
					}
				}
				else
				{
					if (!array[0].Contains("export"))
					{
						continue;
					}
					int result2;
					if (array.Length != 5)
					{
						Mod.Instance.Errors.Add(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 4 arguments");
						Mod.Log.LogError((object)(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 4 arguments"));
					}
					else if (!int.TryParse(array[1], out result2))
					{
						Mod.Instance.Errors.Add("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number");
						Mod.Log.LogError((object)("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number"));
					}
					else
					{
						if (result2 >= matNames.Length)
						{
							continue;
						}
						MaterialPropertyExport materialPropertyExport = new MaterialPropertyExport();
						bool flag = false;
						foreach (PropertyType value in Enum.GetValues(typeof(PropertyType)))
						{
							if (array[2] == value.ToString().ToLower())
							{
								flag = true;
								materialPropertyExport.type = value;
								break;
							}
						}
						if (!flag)
						{
							Mod.Instance.Errors.Add("The property " + array[2] + " on " + ((Component)renderer).gameObject.FullName() + " is not valid");
							Mod.Log.LogError((object)("The property " + array[2] + " on " + ((Component)renderer).gameObject.FullName() + " is not valid"));
						}
						else
						{
							if (!int.TryParse(array[3], out materialPropertyExport.fromID))
							{
								materialPropertyExport.fromName = array[3];
							}
							if (!int.TryParse(array[4], out materialPropertyExport.toID))
							{
								materialPropertyExport.toName = array[4];
							}
							materialProperties[result2].Add(materialPropertyExport);
						}
					}
				}
			}
		}

		private void CopyMaterialProperty(Material from, Material to, MaterialPropertyExport property)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			int num = property.fromID;
			if (num == -1)
			{
				num = Shader.PropertyToID(property.fromName);
			}
			int num2 = property.toID;
			if (num2 == -1)
			{
				num2 = Shader.PropertyToID(property.toName);
			}
			switch (property.type)
			{
			case PropertyType.Color:
				to.SetColor(num2, from.GetColor(num));
				break;
			case PropertyType.ColorArray:
				to.SetColorArray(num2, from.GetColorArray(num));
				break;
			case PropertyType.Float:
				to.SetFloat(num2, from.GetFloat(num));
				break;
			case PropertyType.FloatArray:
				to.SetFloatArray(num2, from.GetFloatArray(num));
				break;
			case PropertyType.Int:
				to.SetInt(num2, from.GetInt(num));
				break;
			case PropertyType.Matrix:
				to.SetMatrix(num2, from.GetMatrix(num));
				break;
			case PropertyType.MatrixArray:
				to.SetMatrixArray(num2, from.GetMatrixArray(num));
				break;
			case PropertyType.Texture:
				to.SetTexture(num2, from.GetTexture(num));
				break;
			case PropertyType.Vector:
				to.SetVector(num2, from.GetVector(num));
				break;
			case PropertyType.VectorArray:
				to.SetVectorArray(num2, from.GetVectorArray(num));
				break;
			}
		}

		private void AddMaterialColorChanger(ColorChanger colorChanger, Transform transform)
		{
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			Renderer component = ((Component)transform).GetComponent<Renderer>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			List<UniformChanger> list = new List<UniformChanger>();
			for (int i = 0; i < transform.childCount; i++)
			{
				GameObject gameObject = ((Component)transform.GetChild(i)).gameObject;
				string text = ((Object)gameObject).name.ToLower();
				if (!text.StartsWith("#"))
				{
					continue;
				}
				text = text.Remove(0, 1);
				string[] array = text.Split(new char[1] { ';' });
				if (array.Length != 0 && array[0].Contains("color"))
				{
					if (array.Length != 6)
					{
						Mod.Instance.Errors.Add(array[0] + " property on " + ((Component)transform).gameObject.FullName() + " must have 5 arguments");
						Mod.Log.LogError((object)(array[0] + " property on " + ((Component)transform).gameObject.FullName() + " must have 5 arguments"));
						continue;
					}
					UniformChanger val = new UniformChanger();
					int.TryParse(array[1], out var result);
					val.materialIndex_ = result;
					val.colorType_ = ColorType(array[2]);
					val.name_ = UniformName(array[3]);
					float.TryParse(array[4], out var result2);
					val.mul_ = result2;
					val.alpha_ = string.Equals(array[5], "true", StringComparison.InvariantCultureIgnoreCase);
					list.Add(val);
				}
			}
			if (list.Count != 0)
			{
				RendererChanger item = new RendererChanger
				{
					renderer_ = component,
					uniformChangers_ = list.ToArray()
				};
				List<RendererChanger> list2 = colorChanger.rendererChangers_.ToList();
				list2.Add(item);
				colorChanger.rendererChangers_ = list2.ToArray();
			}
		}

		private ColorType ColorType(string name)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			name = name.ToLower();
			return (ColorType)(name switch
			{
				"primary" => 0, 
				"secondary" => 1, 
				"glow" => 2, 
				"sparkle" => 3, 
				_ => 0, 
			});
		}

		private SupportedUniform UniformName(string name)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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)
			name = name.ToLower();
			return (SupportedUniform)(name switch
			{
				"color" => 0, 
				"color2" => 1, 
				"emitcolor" => 2, 
				"reflectcolor" => 4, 
				"speccolor" => 5, 
				_ => 0, 
			});
		}

		private void SetCarVisuals(CarVisuals visuals, GameObject car)
		{
			if ((Object)(object)visuals == (Object)null)
			{
				Mod.Instance.Errors.Add("Can't find the CarVisuals component on the base car");
				Mod.Log.LogInfo((object)"Can't find the CarVisuals component on the base car");
				return;
			}
			SkinnedMeshRenderer componentInChildren = car.GetComponentInChildren<SkinnedMeshRenderer>();
			MakeMeshSkinned(componentInChildren);
			visuals.carBodyRenderer_ = componentInChildren;
			List<JetFlame> list = new List<JetFlame>();
			List<JetFlame> list2 = new List<JetFlame>();
			List<JetFlame> list3 = new List<JetFlame>();
			PlaceJets(car, list, list2, list3);
			visuals.boostJetFlames_ = list.ToArray();
			visuals.wingJetFlames_ = list2.ToArray();
			visuals.rotationJetFlames_ = list3.ToArray();
			visuals.driverPosition_ = FindCarDriver(car.transform);
			PlaceCarWheelsVisuals(visuals, car);
		}

		private void MakeMeshSkinned(SkinnedMeshRenderer renderer)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			Mesh sharedMesh = renderer.sharedMesh;
			if ((Object)(object)sharedMesh == (Object)null)
			{
				Mod.Instance.Errors.Add("The mesh on " + ((Component)renderer).gameObject.FullName() + " is null");
				Mod.Log.LogError((object)("The mesh on " + ((Component)renderer).gameObject.FullName() + " is null"));
			}
			else if (!sharedMesh.isReadable)
			{
				Mod.Instance.Errors.Add("Can't read the car mesh " + ((Object)sharedMesh).name + " on " + ((Component)renderer).gameObject.FullName() + "You must allow reading on it's unity inspector !");
				Mod.Log.LogError((object)("Can't read the car mesh " + ((Object)sharedMesh).name + " on " + ((Component)renderer).gameObject.FullName() + "You must allow reading on it's unity inspector !"));
			}
			else if (sharedMesh.vertices.Length != sharedMesh.boneWeights.Length)
			{
				BoneWeight[] array = (BoneWeight[])(object)new BoneWeight[sharedMesh.vertices.Length];
				for (int i = 0; i < array.Length; i++)
				{
					((BoneWeight)(ref array[i])).weight0 = 1f;
				}
				sharedMesh.boneWeights = array;
				Transform transform = ((Component)renderer).transform;
				sharedMesh.bindposes = (Matrix4x4[])(object)new Matrix4x4[1] { transform.worldToLocalMatrix * ((Component)renderer).transform.localToWorldMatrix };
				renderer.bones = (Transform[])(object)new Transform[1] { transform };
			}
		}

		private void PlaceJets(GameObject obj, List<JetFlame> boostJets, List<JetFlame> wingJets, List<JetFlame> rotationJets)
		{
			//IL_0075: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			int childCount = obj.transform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				GameObject gameObject = GameObjectEx.GetChild(obj, i).gameObject;
				string text = ((Object)gameObject).name.ToLower();
				if ((Object)(object)infos_.boostJet != (Object)null && text.Contains("boostjet"))
				{
					GameObject val = Object.Instantiate<GameObject>(infos_.boostJet, gameObject.transform);
					val.transform.localPosition = Vector3.zero;
					val.transform.localRotation = Quaternion.identity;
					boostJets.Add(val.GetComponentInChildren<JetFlame>());
				}
				else if ((Object)(object)infos_.wingJet != (Object)null && text.Contains("wingjet"))
				{
					GameObject val2 = Object.Instantiate<GameObject>(infos_.wingJet, gameObject.transform);
					val2.transform.localPosition = Vector3.zero;
					val2.transform.localRotation = Quaternion.identity;
					wingJets.Add(val2.GetComponentInChildren<JetFlame>());
					ListEx.Last<JetFlame>(wingJets).rotationAxis_ = JetDirection(gameObject.transform);
				}
				else if ((Object)(object)infos_.rotationJet != (Object)null && text.Contains("rotationjet"))
				{
					GameObject val3 = Object.Instantiate<GameObject>(infos_.rotationJet, gameObject.transform);
					val3.transform.localPosition = Vector3.zero;
					val3.transform.localRotation = Quaternion.identity;
					rotationJets.Add(val3.GetComponentInChildren<JetFlame>());
					ListEx.Last<JetFlame>(rotationJets).rotationAxis_ = JetDirection(gameObject.transform);
				}
				else if ((Object)(object)infos_.wingTrail != (Object)null && text.Contains("wingtrail"))
				{
					GameObject val4 = Object.Instantiate<GameObject>(infos_.wingTrail, gameObject.transform);
					val4.transform.localPosition = Vector3.zero;
					val4.transform.localRotation = Quaternion.identity;
				}
				else
				{
					PlaceJets(gameObject, boostJets, wingJets, rotationJets);
				}
			}
		}

		private Vector3 JetDirection(Transform transform)
		{
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			int childCount = transform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				string text = ((Object)((Component)transform.GetChild(i)).gameObject).name.ToLower();
				if (!text.StartsWith("#"))
				{
					continue;
				}
				text = text.Remove(0, 1);
				string[] array = text.Split(new char[1] { ';' });
				if (array.Length != 0 && array[0].Contains("dir") && array.Length >= 2)
				{
					if (array[1] == "front")
					{
						return new Vector3(-1f, 0f, 0f);
					}
					if (array[1] == "back")
					{
						return new Vector3(1f, 0f, 0f);
					}
					if (array[1] == "left")
					{
						return new Vector3(0f, 1f, -1f);
					}
					if (array[1] == "right")
					{
						return new Vector3(0f, -1f, 1f);
					}
					if (array.Length == 4 && array[0].Contains("dir"))
					{
						Vector3 zero = Vector3.zero;
						float.TryParse(array[1], out zero.x);
						float.TryParse(array[2], out zero.y);
						float.TryParse(array[3], out zero.z);
						return zero;
					}
				}
			}
			return Vector3.zero;
		}

		private Transform FindCarDriver(Transform parent)
		{
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				Transform val = ((((Object)((Component)child).gameObject).name.IndexOf("driverposition", StringComparison.InvariantCultureIgnoreCase) >= 0) ? child : FindCarDriver(child));
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private void PlaceCarWheelsVisuals(CarVisuals visual, GameObject car)
		{
			for (int i = 0; i < car.transform.childCount; i++)
			{
				GameObject gameObject = ((Component)car.transform.GetChild(i)).gameObject;
				string text = ((Object)gameObject).name.ToLower();
				if (!text.Contains("wheel"))
				{
					continue;
				}
				CarWheelVisuals val = gameObject.AddComponent<CarWheelVisuals>();
				MeshRenderer[] componentsInChildren = gameObject.GetComponentsInChildren<MeshRenderer>();
				foreach (MeshRenderer val2 in componentsInChildren)
				{
					if (((Object)((Component)val2).gameObject).name.IndexOf("tire", StringComparison.InvariantCultureIgnoreCase) >= 0)
					{
						val.tire_ = val2;
						break;
					}
				}
				if (text.Contains("front"))
				{
					if (text.Contains("left"))
					{
						visual.wheelFL_ = val;
					}
					else if (text.Contains("right"))
					{
						visual.wheelFR_ = val;
					}
				}
				else if (text.Contains("back"))
				{
					if (text.Contains("left"))
					{
						visual.wheelBL_ = val;
					}
					else if (text.Contains("right"))
					{
						visual.wheelBR_ = val;
					}
				}
			}
		}

		private CarColors LoadDefaultColors(GameObject car)
		{
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			CarColors val2 = default(CarColors);
			for (int i = 0; i < car.transform.childCount; i++)
			{
				GameObject gameObject = ((Component)car.transform.GetChild(i)).gameObject;
				string text = ((Object)gameObject).name.ToLower();
				if (!text.Contains("defaultcolor"))
				{
					continue;
				}
				for (int j = 0; j < gameObject.transform.childCount; j++)
				{
					GameObject gameObject2 = ((Component)gameObject.transform.GetChild(j)).gameObject;
					string text2 = ((Object)gameObject2).name.ToLower();
					if (!text2.StartsWith("#"))
					{
						continue;
					}
					text2 = text2.Remove(0, 1);
					string[] array = text2.Split(new char[1] { ';' });
					if (array.Length == 2)
					{
						Color val = ColorEx.HexToColor(array[1], byte.MaxValue);
						val.a = 1f;
						if (array[0] == "primary")
						{
							val2.primary_ = val;
						}
						else if (array[0] == "secondary")
						{
							val2.secondary_ = val;
						}
						else if (array[0] == "glow")
						{
							val2.glow_ = val;
						}
						else if (array[0] == "sparkle")
						{
							val2.sparkle_ = val;
						}
					}
				}
			}
			return infos_.defaultColors;
		}
	}
	public class CarInfos
	{
		public Dictionary<string, MaterialInfos> materials = new Dictionary<string, MaterialInfos>();

		public GameObject boostJet = null;

		public GameObject wingJet = null;

		public GameObject rotationJet = null;

		public GameObject wingTrail = null;

		public GameObject baseCar = null;

		public CarColors defaultColors;

		public void CollectInfos()
		{
			GetBaseCar();
			GetJetsAndTrail();
			GetMaterials();
		}

		private void GetBaseCar()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			GameObject carPrefab_ = G.Sys.ProfileManager_.carInfos_[0].prefabs_.carPrefab_;
			if ((Object)(object)carPrefab_ == (Object)null)
			{
				Mod.Instance.Errors.Add("Can't find the refractor base car prefab");
				return;
			}
			baseCar = carPrefab_;
			defaultColors = G.Sys.ProfileManager_.carInfos_[0].colors_;
		}

		private void GetJetsAndTrail()
		{
			if ((Object)(object)baseCar == (Object)null)
			{
				return;
			}
			JetFlame[] componentsInChildren = baseCar.GetComponentsInChildren<JetFlame>();
			foreach (JetFlame val in componentsInChildren)
			{
				switch (((Object)((Component)val).gameObject).name)
				{
				case "BoostJetFlameCenter":
					boostJet = ((Component)val).gameObject;
					break;
				case "JetFlameBackLeft":
					rotationJet = ((Component)val).gameObject;
					break;
				case "WingJetFlameLeft1":
					wingJet = ((Component)val).gameObject;
					break;
				}
			}
			wingTrail = ((Component)baseCar.GetComponentInChildren<WingTrail>()).gameObject;
			if ((Object)(object)boostJet == (Object)null)
			{
				Mod.Instance.Errors.Add("No valid BoostJet found on Refractor");
			}
			if ((Object)(object)rotationJet == (Object)null)
			{
				Mod.Instance.Errors.Add("No valid RotationJet found on Refractor");
			}
			if ((Object)(object)wingJet == (Object)null)
			{
				Mod.Instance.Errors.Add("No valid WingJet found on Refractor");
			}
			if ((Object)(object)wingTrail == (Object)null)
			{
				Mod.Instance.Errors.Add("No valid WingTrail found on Refractor");
			}
		}

		private void GetMaterials()
		{
			List<MaterialPropertyInfo> list = new List<MaterialPropertyInfo>
			{
				new MaterialPropertyInfo("Custom/LaserCut/CarPaint", "carpaint", 5, -1, -1),
				new MaterialPropertyInfo("Custom/LaserCut/CarWindow", "carwindow", -1, 218, 219),
				new MaterialPropertyInfo("Custom/Reflective/Bump Glow LaserCut", "wheel", 5, 218, 255),
				new MaterialPropertyInfo("Custom/LaserCut/CarPaintBump", "carpaintbump", 5, 218, -1),
				new MaterialPropertyInfo("Custom/Reflective/Bump Glow Interceptor Special", "interceptor", 5, 218, 255),
				new MaterialPropertyInfo("Custom/LaserCut/CarWindowTrans2Sided", "transparentglow", -1, 218, 219)
			};
			CarInfo[] carInfos_ = G.Sys.ProfileManager_.carInfos_;
			foreach (CarInfo val in carInfos_)
			{
				GameObject carPrefab_ = val.prefabs_.carPrefab_;
				Renderer[] componentsInChildren = carPrefab_.GetComponentsInChildren<Renderer>();
				foreach (Renderer val2 in componentsInChildren)
				{
					Material[] array = val2.materials;
					foreach (Material val3 in array)
					{
						foreach (MaterialPropertyInfo item in list)
						{
							if (!materials.ContainsKey(item.name) && ((Object)val3.shader).name == item.shaderName)
							{
								MaterialInfos value = new MaterialInfos
								{
									material = val3,
									diffuseIndex = item.diffuseIndex,
									normalIndex = item.normalIndex,
									emitIndex = item.emitIndex
								};
								materials.Add(item.name, value);
							}
						}
					}
				}
			}
			foreach (MaterialPropertyInfo item2 in list)
			{
				if (!materials.ContainsKey(item2.name))
				{
					Mod.Instance.Errors.Add("Can't find the material: " + item2.name + " - shader: " + item2.shaderName);
				}
			}
			materials.Add("donotreplace", new MaterialInfos());
		}
	}
	public class CreateCarReturnInfos
	{
		public GameObject car;

		public CarColors colors;
	}
}

JsonFx.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using JsonFx.CodeGen;
using JsonFx.IO;
using JsonFx.Json;
using JsonFx.Linq;
using JsonFx.Markup;
using JsonFx.Model;
using JsonFx.Model.Filters;
using JsonFx.Serialization;
using JsonFx.Serialization.Filters;
using JsonFx.Serialization.GraphCycles;
using JsonFx.Serialization.Resolvers;
using JsonFx.Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyCopyright("Copyright © 2006-2010 Stephen M. McKamey. All rights reserved.")]
[assembly: AssemblyCompany("http://jsonfx.net")]
[assembly: AllowPartiallyTrustedCallers]
[assembly: AssemblyDescription("JsonFx Serialization Framework")]
[assembly: AssemblyProduct("JsonFx v2")]
[assembly: AssemblyTitle("JsonFx")]
[assembly: AssemblyConfiguration(".NET 3.5 Signed")]
[assembly: Guid("D98A5EF8-4709-4FF8-B162-8EA04B281400")]
[assembly: AssemblyFileVersion("2.0.1209.2802")]
[assembly: AssemblyVersion("2.0.1209.2802")]
namespace JsonFx
{
	public sealed class About
	{
		public static readonly About Fx = new About(typeof(About).Assembly);

		public readonly Version Version;

		public readonly string FullName;

		public readonly string Name;

		public readonly string Configuration;

		public readonly string Copyright;

		public readonly string Title;

		public readonly string Description;

		public readonly string Company;

		public About(Assembly assembly)
		{
			if ((object)assembly == null)
			{
				throw new ArgumentNullException("assembly");
			}
			AssemblyName name = assembly.GetName();
			FullName = assembly.FullName;
			Version = name.Version;
			Name = name.Name;
			AssemblyCopyrightAttribute assemblyCopyrightAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyCopyrightAttribute)) as AssemblyCopyrightAttribute;
			Copyright = ((assemblyCopyrightAttribute != null) ? assemblyCopyrightAttribute.Copyright : string.Empty);
			AssemblyDescriptionAttribute assemblyDescriptionAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyDescriptionAttribute)) as AssemblyDescriptionAttribute;
			Description = ((assemblyDescriptionAttribute != null) ? assemblyDescriptionAttribute.Description : string.Empty);
			AssemblyTitleAttribute assemblyTitleAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyTitleAttribute)) as AssemblyTitleAttribute;
			Title = ((assemblyTitleAttribute != null) ? assemblyTitleAttribute.Title : string.Empty);
			AssemblyCompanyAttribute assemblyCompanyAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute;
			Company = ((assemblyCompanyAttribute != null) ? assemblyCompanyAttribute.Company : string.Empty);
			AssemblyConfigurationAttribute assemblyConfigurationAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyConfigurationAttribute)) as AssemblyConfigurationAttribute;
			Configuration = ((assemblyConfigurationAttribute != null) ? assemblyConfigurationAttribute.Configuration : string.Empty);
		}
	}
}
namespace JsonFx.Bson
{
	public enum BsonElementType : byte
	{
		None = 0,
		Double = 1,
		String = 2,
		Document = 3,
		Array = 4,
		Binary = 5,
		[Obsolete]
		Undefined = 6,
		ObjectID = 7,
		Boolean = 8,
		DateTimeUtc = 9,
		Null = 10,
		RegExp = 11,
		[Obsolete]
		DBPointer = 12,
		JavaScriptCode = 13,
		Symbol = 14,
		CodeWithScope = 15,
		Int32 = 16,
		TimeStamp = 17,
		Int64 = 18,
		MinKey = byte.MaxValue,
		MaxKey = 127
	}
	public enum BsonBinarySubtype : byte
	{
		Generic = 0,
		Function = 1,
		[Obsolete]
		BinaryOld = 2,
		UUID = 3,
		MD5 = 5,
		UserDefined = 128
	}
	public class BsonWriter
	{
		public class BsonFormatter : IBinaryFormatter<ModelTokenType>
		{
			public byte[] Format(IEnumerable<Token<ModelTokenType>> tokens)
			{
				if (tokens == null)
				{
					throw new ArgumentNullException("tokens");
				}
				using MemoryStream memoryStream = new MemoryStream();
				Format(tokens, memoryStream);
				return memoryStream.ToArray();
			}

			public void Format(IEnumerable<Token<ModelTokenType>> tokens, Stream stream)
			{
				if (stream == null)
				{
					throw new ArgumentNullException("stream");
				}
				if (tokens == null)
				{
					throw new ArgumentNullException("tokens");
				}
				using BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8);
				IStream<Token<ModelTokenType>> stream2 = Stream<Token<ModelTokenType>>.Create(tokens);
				if (!stream2.IsCompleted)
				{
					WriteDocument(writer, stream2);
				}
			}

			private int WriteDocument(BinaryWriter writer, IStream<Token<ModelTokenType>> tokens)
			{
				Token<ModelTokenType> token = tokens.Peek();
				if (tokens.IsCompleted || token == null)
				{
					throw new TokenException<ModelTokenType>(token, "Unterminated document");
				}
				bool flag;
				if (token.TokenType == ModelTokenType.ArrayBegin)
				{
					flag = true;
				}
				else
				{
					if (token.TokenType != ModelTokenType.ObjectBegin)
					{
						throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})");
					}
					flag = false;
				}
				tokens.Pop();
				long position = writer.BaseStream.Position;
				int num = 5;
				writer.Seek(4, SeekOrigin.Current);
				token = tokens.Peek();
				int num2 = 0;
				while (!tokens.IsCompleted && token != null)
				{
					if (flag)
					{
						if (token.TokenType == ModelTokenType.ArrayEnd)
						{
							tokens.Pop();
							break;
						}
					}
					else if (token.TokenType == ModelTokenType.ObjectEnd)
					{
						tokens.Pop();
						break;
					}
					string ename;
					if (flag)
					{
						ename = num2.ToString(CultureInfo.InvariantCulture);
					}
					else
					{
						if (token.TokenType != ModelTokenType.Property)
						{
							throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})");
						}
						ename = token.Name.LocalName;
						tokens.Pop();
					}
					num += WriteElement(writer, tokens, ename);
					token = tokens.Peek();
					num2++;
				}
				writer.Write((byte)0);
				long position2 = writer.BaseStream.Position;
				writer.Seek((int)(position - position2), SeekOrigin.Current);
				writer.Write(num);
				writer.Seek((int)(position2 - position - 4), SeekOrigin.Current);
				return num;
			}

			private int WriteElement(BinaryWriter writer, IStream<Token<ModelTokenType>> tokens, string ename)
			{
				Token<ModelTokenType> token = tokens.Peek();
				if (tokens.IsCompleted || token == null)
				{
					throw new TokenException<ModelTokenType>(token, "Unterminated document");
				}
				BsonElementType bsonElementType = token.TokenType switch
				{
					ModelTokenType.ArrayBegin => BsonElementType.Array, 
					ModelTokenType.ObjectBegin => BsonElementType.Document, 
					ModelTokenType.Primitive => GetElementType(token.Value), 
					_ => throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})"), 
				};
				writer.Write((byte)bsonElementType);
				int num = 1;
				num += WriteString(writer, ename, asCString: true);
				if (token.Value is IBsonFormattable bsonFormattable)
				{
					num += bsonFormattable.Format(this, writer);
				}
				else
				{
					switch (bsonElementType)
					{
					case BsonElementType.Double:
						tokens.Pop();
						writer.Write((double)token.Value);
						num += 8;
						break;
					case BsonElementType.String:
					case BsonElementType.JavaScriptCode:
					case BsonElementType.Symbol:
						tokens.Pop();
						num += WriteString(writer, token.ValueAsString(), asCString: false);
						break;
					case BsonElementType.Document:
					case BsonElementType.Array:
						num += WriteDocument(writer, tokens);
						break;
					case BsonElementType.Binary:
						tokens.Pop();
						num += WriteBinary(writer, token);
						break;
					case BsonElementType.ObjectID:
						tokens.Pop();
						writer.Write((byte[])token.Value);
						num += 12;
						break;
					case BsonElementType.Boolean:
					{
						tokens.Pop();
						bool flag = true.Equals(token.Value);
						writer.Write((byte)(flag ? 1 : 0));
						num++;
						break;
					}
					case BsonElementType.DateTimeUtc:
					{
						tokens.Pop();
						DateTime dateTime = (DateTime)token.Value;
						if (dateTime.Kind == DateTimeKind.Local)
						{
							dateTime = dateTime.ToUniversalTime();
						}
						long value2 = (long)dateTime.Subtract(UnixEpoch).TotalMilliseconds;
						writer.Write(value2);
						num += 8;
						break;
					}
					case BsonElementType.RegExp:
						tokens.Pop();
						if (token.Value is Regex regex)
						{
							string value3 = regex.ToString();
							num += WriteString(writer, value3, asCString: true);
							string text = (false ? "g" : "");
							switch (regex.Options & (RegexOptions.IgnoreCase | RegexOptions.Multiline))
							{
							case RegexOptions.IgnoreCase:
								text += "i";
								break;
							case RegexOptions.Multiline:
								text += "m";
								break;
							case RegexOptions.IgnoreCase | RegexOptions.Multiline:
								text += "im";
								break;
							}
							num += WriteString(writer, text, asCString: true);
							break;
						}
						goto default;
					case BsonElementType.DBPointer:
						tokens.Pop();
						if (token.Value is BsonDBPointer bsonDBPointer)
						{
							num += WriteString(writer, bsonDBPointer.Namespace, asCString: false);
							writer.Write((byte[])bsonDBPointer.ObjectID);
							num += 12;
							break;
						}
						goto default;
					case BsonElementType.CodeWithScope:
						tokens.Pop();
						if (token.Value is BsonCodeWithScope value)
						{
							num += WriteCodeWithScope(writer, value);
							break;
						}
						goto default;
					case BsonElementType.Int32:
						tokens.Pop();
						writer.Write((int)token.Value);
						num += 4;
						break;
					case BsonElementType.TimeStamp:
					case BsonElementType.Int64:
						tokens.Pop();
						writer.Write((long)token.Value);
						num += 8;
						break;
					case BsonElementType.Undefined:
					case BsonElementType.Null:
					case BsonElementType.MaxKey:
					case BsonElementType.MinKey:
						tokens.Pop();
						break;
					default:
						throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})");
					}
				}
				return num;
			}

			private static int WriteString(BinaryWriter writer, string value, bool asCString)
			{
				int num = 1;
				byte[] bytes = Encoding.UTF8.GetBytes(value);
				if (!asCString)
				{
					writer.Write(bytes.Length + 1);
					num += 4;
				}
				writer.Write(bytes);
				num += bytes.Length;
				writer.Write((byte)0);
				return num;
			}

			private static int WriteBinary(BinaryWriter writer, Token<ModelTokenType> token)
			{
				BsonBinary bsonBinary = GetBsonBinary(token.Value);
				writer.Write(bsonBinary.Count);
				writer.Write((byte)bsonBinary.Type);
				writer.Write(bsonBinary.Data);
				return 9 + bsonBinary.Count;
			}

			private int WriteCodeWithScope(BinaryWriter writer, BsonCodeWithScope value)
			{
				long position = writer.BaseStream.Position;
				int num = 4;
				writer.Seek(4, SeekOrigin.Current);
				num += WriteString(writer, (string)value.Code, asCString: false);
				num += WriteDocument(writer, value.Scope);
				long position2 = writer.BaseStream.Position;
				writer.Seek((int)(position - position2), SeekOrigin.Current);
				writer.Write(num);
				writer.Seek((int)(position2 - position - 4), SeekOrigin.Current);
				return num;
			}

			private static BsonElementType GetElementType(object value)
			{
				Type type = value?.GetType();
				switch (Type.GetTypeCode(type))
				{
				case TypeCode.Boolean:
					return BsonElementType.Boolean;
				case TypeCode.SByte:
				case TypeCode.Byte:
				case TypeCode.Int16:
				case TypeCode.UInt16:
				case TypeCode.Int32:
					return BsonElementType.Int32;
				case TypeCode.Char:
				case TypeCode.String:
					return BsonElementType.String;
				case TypeCode.DateTime:
					return BsonElementType.DateTimeUtc;
				case TypeCode.Empty:
				case TypeCode.DBNull:
					return BsonElementType.Null;
				case TypeCode.Single:
				case TypeCode.Double:
				case TypeCode.Decimal:
					return BsonElementType.Double;
				case TypeCode.UInt32:
				case TypeCode.Int64:
				case TypeCode.UInt64:
					return BsonElementType.Int32;
				default:
					if (value is IBsonFormattable)
					{
						return ((IBsonFormattable)value).GetElementType();
					}
					if (value is TimeSpan)
					{
						return BsonElementType.TimeStamp;
					}
					if (value is Regex)
					{
						return BsonElementType.RegExp;
					}
					if (value is Guid || value is byte[] || value is BsonBinary || value is BsonMD5)
					{
						return BsonElementType.Binary;
					}
					if (value is BsonObjectID)
					{
						return BsonElementType.ObjectID;
					}
					if (value is BsonSymbol)
					{
						return BsonElementType.Symbol;
					}
					if (value is BsonJavaScriptCode)
					{
						return BsonElementType.JavaScriptCode;
					}
					if (value is BsonCodeWithScope)
					{
						return BsonElementType.CodeWithScope;
					}
					if (value is BsonDBPointer)
					{
						return BsonElementType.DBPointer;
					}
					throw new NotSupportedException("Unknown BSON element data type");
				}
			}

			private static BsonBinary GetBsonBinary(object value)
			{
				if (value is BsonBinary result)
				{
					return result;
				}
				if (value is BsonMD5)
				{
					return new BsonBinary(BsonBinarySubtype.MD5, ((Guid)value).ToByteArray());
				}
				if (value is Guid)
				{
					return new BsonBinary(BsonBinarySubtype.UUID, ((Guid)value).ToByteArray());
				}
				if (value is byte[])
				{
					return new BsonBinary(BsonBinarySubtype.Generic, (byte[])value);
				}
				throw new NotSupportedException("Unknown BSON binary data type");
			}
		}

		internal const string ErrorUnterminated = "Unterminated document";

		private const string ErrorUnexpectedToken = "Unexpected token ({0})";

		private const string ErrorExpectedObjectValueDelim = "Expected value delimiter or end of document ({0})";

		internal const int SizeOfByte = 1;

		internal const int SizeOfInt32 = 4;

		internal const int SizeOfInt64 = 8;

		internal const int SizeOfDouble = 8;

		internal const int SizeOfObjectID = 12;

		internal const byte NullByte = 0;

		internal const byte FalseByte = 0;

		internal const byte TrueByte = 1;

		internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
	}
}
namespace JsonFx.Serialization
{
	public interface IBinaryFormatter<T>
	{
		void Format(IEnumerable<Token<T>> tokens, Stream stream);

		byte[] Format(IEnumerable<Token<T>> tokens);
	}
}
namespace JsonFx.Bson
{
	public class BsonReader
	{
		public class BsonTokenizer : IBinaryTokenizer<ModelTokenType>, IDisposable
		{
			private const string ErrorUnexpectedElementType = "Unexpected element type ({0})";

			private static readonly BinaryReader NullBinaryReader = new BinaryReader(Stream.Null, Encoding.UTF8);

			private BinaryReader Reader = NullBinaryReader;

			public long Index => Reader.BaseStream.Position;

			private static void ReadDocument(List<Token<ModelTokenType>> tokens, BinaryReader reader, bool isArray)
			{
				if (reader.PeekChar() >= 0)
				{
					long position = reader.BaseStream.Position;
					int num = reader.ReadInt32();
					tokens.Add(isArray ? ModelGrammar.TokenArrayBeginUnnamed : ModelGrammar.TokenObjectBeginUnnamed);
					while (reader.BaseStream.Position - position < num - 1)
					{
						ReadElement(tokens, reader, isArray);
					}
					if (reader.ReadByte() != 0)
					{
						throw new DeserializationException("Unterminated document", position);
					}
					tokens.Add(isArray ? ModelGrammar.TokenArrayEnd : ModelGrammar.TokenObjectEnd);
				}
			}

			private static void ReadElement(List<Token<ModelTokenType>> tokens, BinaryReader reader, bool isArrayItem)
			{
				BsonElementType bsonElementType = (BsonElementType)reader.ReadByte();
				string localName = ReadCString(reader);
				if (!isArrayItem)
				{
					tokens.Add(ModelGrammar.TokenProperty(localName));
				}
				switch (bsonElementType)
				{
				case BsonElementType.Double:
				{
					double num5 = reader.ReadDouble();
					tokens.Add(ModelGrammar.TokenPrimitive(num5));
					break;
				}
				case BsonElementType.String:
				{
					string value4 = ReadString(reader);
					tokens.Add(ModelGrammar.TokenPrimitive(value4));
					break;
				}
				case BsonElementType.JavaScriptCode:
				{
					BsonJavaScriptCode bsonJavaScriptCode = (BsonJavaScriptCode)ReadString(reader);
					tokens.Add(ModelGrammar.TokenPrimitive(bsonJavaScriptCode));
					break;
				}
				case BsonElementType.Symbol:
				{
					BsonSymbol bsonSymbol = (BsonSymbol)ReadString(reader);
					tokens.Add(ModelGrammar.TokenPrimitive(bsonSymbol));
					break;
				}
				case BsonElementType.Document:
					ReadDocument(tokens, reader, isArray: false);
					break;
				case BsonElementType.Array:
					ReadDocument(tokens, reader, isArray: true);
					break;
				case BsonElementType.Binary:
					ReadBinary(tokens, reader);
					break;
				case BsonElementType.ObjectID:
				{
					byte[] bytes2 = reader.ReadBytes(12);
					tokens.Add(ModelGrammar.TokenPrimitive(new BsonObjectID(bytes2)));
					break;
				}
				case BsonElementType.Boolean:
				{
					bool flag = reader.ReadByte() != 0;
					tokens.Add(flag ? ModelGrammar.TokenTrue : ModelGrammar.TokenFalse);
					break;
				}
				case BsonElementType.DateTimeUtc:
				{
					DateTime unixEpoch = BsonWriter.UnixEpoch;
					DateTime dateTime = unixEpoch.AddMilliseconds(reader.ReadInt64());
					tokens.Add(ModelGrammar.TokenPrimitive(dateTime));
					break;
				}
				case BsonElementType.RegExp:
				{
					string pattern = ReadCString(reader);
					string text = ReadCString(reader);
					RegexOptions regexOptions = RegexOptions.ECMAScript;
					for (int num4 = text.Length - 1; num4 >= 0; num4--)
					{
						switch (text[num4])
						{
						case 'i':
							regexOptions |= RegexOptions.IgnoreCase;
							break;
						case 'm':
							regexOptions |= RegexOptions.Multiline;
							break;
						}
					}
					Regex value3 = new Regex(pattern, regexOptions);
					tokens.Add(ModelGrammar.TokenPrimitive(value3));
					break;
				}
				case BsonElementType.DBPointer:
				{
					string @namespace = ReadString(reader);
					byte[] bytes = reader.ReadBytes(12);
					BsonDBPointer bsonDBPointer = new BsonDBPointer();
					bsonDBPointer.Namespace = @namespace;
					bsonDBPointer.ObjectID = new BsonObjectID(bytes);
					BsonDBPointer value2 = bsonDBPointer;
					tokens.Add(ModelGrammar.TokenPrimitive(value2));
					break;
				}
				case BsonElementType.CodeWithScope:
				{
					reader.ReadInt32();
					string value = ReadString(reader);
					tokens.Add(ModelGrammar.TokenPrimitive(value));
					ReadDocument(tokens, reader, isArray: false);
					break;
				}
				case BsonElementType.Int32:
				{
					int num3 = reader.ReadInt32();
					tokens.Add(ModelGrammar.TokenPrimitive(num3));
					break;
				}
				case BsonElementType.TimeStamp:
				{
					long num2 = reader.ReadInt64();
					tokens.Add(ModelGrammar.TokenPrimitive(num2));
					break;
				}
				case BsonElementType.Int64:
				{
					long num = reader.ReadInt64();
					tokens.Add(ModelGrammar.TokenPrimitive(num));
					break;
				}
				default:
					throw new DeserializationException($"Unexpected element type ({bsonElementType})", reader.BaseStream.Position);
				case BsonElementType.Undefined:
				case BsonElementType.Null:
				case BsonElementType.MaxKey:
				case BsonElementType.MinKey:
					break;
				}
			}

			private static void ReadBinary(List<Token<ModelTokenType>> tokens, BinaryReader reader)
			{
				int num = reader.ReadInt32();
				BsonBinarySubtype bsonBinarySubtype = (BsonBinarySubtype)reader.ReadByte();
				byte[] array = reader.ReadBytes(num);
				object value;
				switch (bsonBinarySubtype)
				{
				case BsonBinarySubtype.MD5:
					if (num == 16)
					{
						value = new BsonMD5(array);
						break;
					}
					goto default;
				case BsonBinarySubtype.UUID:
					if (num == 16)
					{
						value = new Guid(array);
						break;
					}
					goto default;
				case BsonBinarySubtype.BinaryOld:
				{
					num = BitConverter.ToInt32(array, 0);
					byte[] array2 = new byte[num];
					Buffer.BlockCopy(array, 4, array2, 0, num);
					value = new BsonBinary(BsonBinarySubtype.Generic, array2);
					break;
				}
				default:
					value = new BsonBinary(bsonBinarySubtype, array);
					break;
				}
				tokens.Add(ModelGrammar.TokenPrimitive(value));
			}

			private static string ReadString(BinaryReader reader)
			{
				int num = reader.ReadInt32();
				char[] value = reader.ReadChars(num);
				return new string(value, 0, num - 1);
			}

			private static string ReadCString(BinaryReader reader)
			{
				StringBuilder stringBuilder = new StringBuilder();
				char value;
				while ((value = reader.ReadChar()) != 0)
				{
					stringBuilder.Append(value);
				}
				return stringBuilder.ToString();
			}

			public IEnumerable<Token<ModelTokenType>> GetTokens(Stream stream)
			{
				if (stream == null)
				{
					throw new ArgumentNullException("stream");
				}
				return GetTokens(new BinaryReader(stream, Encoding.UTF8));
			}

			public IEnumerable<Token<ModelTokenType>> GetTokens(byte[] bytes)
			{
				if (bytes == null)
				{
					throw new ArgumentNullException("bytes");
				}
				return GetTokens(new MemoryStream(bytes, writable: false));
			}

			protected IEnumerable<Token<ModelTokenType>> GetTokens(BinaryReader reader)
			{
				if (reader == null)
				{
					throw new ArgumentNullException("reader");
				}
				Reader = reader;
				using (reader)
				{
					List<Token<ModelTokenType>> list = new List<Token<ModelTokenType>>();
					ReadDocument(list, reader, isArray: false);
					Reader = NullBinaryReader;
					return list;
				}
			}

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

			protected virtual void Dispose(bool disposing)
			{
				if (disposing)
				{
					((IDisposable)Reader).Dispose();
				}
			}
		}
	}
}
namespace JsonFx.Serialization
{
	public interface IBinaryTokenizer<T> : IDisposable
	{
		long Index { get; }

		IEnumerable<Token<T>> GetTokens(Stream stream);

		IEnumerable<Token<T>> GetTokens(byte[] bytes);
	}
}
namespace JsonFx.Bson
{
	public struct BsonMD5
	{
		public readonly Guid Hash;

		public BsonMD5(string hash)
		{
			Hash = new Guid(hash);
		}

		public BsonMD5(byte[] hash)
		{
			Hash = new Guid(hash);
		}

		public BsonMD5(Guid hash)
		{
			Hash = hash;
		}

		public static explicit operator Guid(BsonMD5 value)
		{
			return value.Hash;
		}

		public static explicit operator BsonMD5(Guid value)
		{
			return new BsonMD5(value);
		}

		public override string ToString()
		{
			return Hash.ToString();
		}

		public override int GetHashCode()
		{
			return EqualityComparer<Guid>.Default.GetHashCode(Hash);
		}
	}
	public class BsonCodeWithScope
	{
		public BsonJavaScriptCode Code { get; set; }

		public IStream<Token<ModelTokenType>> Scope { get; set; }
	}
	public struct BsonJavaScriptCode
	{
		public readonly string Code;

		public BsonJavaScriptCode(string code)
		{
			Code = code;
		}

		public static explicit operator string(BsonJavaScriptCode value)
		{
			return value.Code;
		}

		public static explicit operator BsonJavaScriptCode(string value)
		{
			return new BsonJavaScriptCode(value);
		}

		public override string ToString()
		{
			return Code;
		}

		public override int GetHashCode()
		{
			return EqualityComparer<string>.Default.GetHashCode(Code);
		}
	}
	public struct BsonSymbol
	{
		public readonly string Code;

		public BsonSymbol(string code)
		{
			Code = code;
		}

		public static explicit operator string(BsonSymbol value)
		{
			return value.Code;
		}

		public static explicit operator BsonSymbol(string value)
		{
			return new BsonSymbol(value);
		}

		public override string ToString()
		{
			return Code;
		}

		public override int GetHashCode()
		{
			return EqualityComparer<string>.Default.GetHashCode(Code);
		}
	}
	[Obsolete]
	public class BsonDBPointer
	{
		public string Namespace { get; set; }

		public BsonObjectID ObjectID { get; set; }
	}
	public struct BsonObjectID
	{
		public static readonly BsonObjectID Empty = new BsonObjectID(new byte[0]);

		private readonly byte[] Bytes;

		public DateTime Time
		{
			get
			{
				int num = (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | Bytes[3];
				DateTime unixEpoch = BsonWriter.UnixEpoch;
				return unixEpoch.AddSeconds(num);
			}
		}

		public int Machine => Bytes[4] | (Bytes[5] << 8) | (Bytes[6] << 16);

		public int Pid => Bytes[7] | (Bytes[8] << 8);

		public int Inc => (Bytes[9] << 16) | (Bytes[10] << 8) | Bytes[11];

		public BsonObjectID(byte[] bytes)
		{
			if (bytes == null)
			{
				throw new ArgumentNullException("bytes");
			}
			if (bytes.Length != 12)
			{
				throw new ArgumentException("ObjectID is exact 12 bytes", "bytes");
			}
			Bytes = bytes;
		}

		public BsonObjectID(DateTime time, int machine, int pid, int inc)
		{
			Bytes = new byte[12];
			int num = (int)time.Subtract(BsonWriter.UnixEpoch).TotalSeconds;
			if (num < 0 || num > 65535)
			{
				throw new ArgumentOutOfRangeException("ObjectID only supports a limited range of dates (" + ushort.MaxValue + " seconds since Unix epoch).");
			}
			Bytes[0] = (byte)((num >> 24) % 255);
			Bytes[1] = (byte)((num >> 16) % 255);
			Bytes[2] = (byte)((num >> 8) % 255);
			Bytes[3] = (byte)(num % 255);
		}

		public static explicit operator string(BsonObjectID value)
		{
			return value.ToString();
		}

		public static explicit operator BsonObjectID(string value)
		{
			return Parse(value);
		}

		public static explicit operator byte[](BsonObjectID value)
		{
			return value.Bytes ?? Empty.Bytes;
		}

		public static explicit operator BsonObjectID(byte[] value)
		{
			return new BsonObjectID(value);
		}

		public override string ToString()
		{
			byte[] bytes = Bytes;
			if (bytes == null)
			{
				bytes = Empty.Bytes;
			}
			char[] array = new char[24];
			int num = 0;
			int num2 = 0;
			while (num < 24)
			{
				array[num] = CharUtility.GetHexDigit(bytes[num2] / 16);
				array[num] = CharUtility.GetHexDigit(bytes[num2] % 16);
				num += 2;
				num2++;
			}
			return new string(array);
		}

		public byte[] ToByteArray()
		{
			byte[] array = new byte[12];
			Buffer.BlockCopy(Bytes, 0, array, 0, 12);
			return array;
		}

		public static BsonObjectID Parse(string value)
		{
			if (TryParse(value, out var result))
			{
				return result;
			}
			throw new InvalidCastException("String must be exactly 24 hex digits");
		}

		public static bool TryParse(string value, out BsonObjectID result)
		{
			if (string.IsNullOrEmpty(value) || value.Length != 24)
			{
				result = Empty;
				return false;
			}
			byte[] array = new byte[12];
			for (int i = 0; i < 24; i += 2)
			{
				if (!byte.TryParse(value.Substring(i, 2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out var result2))
				{
					result = Empty;
					return false;
				}
				array[i] = result2;
			}
			result = new BsonObjectID(array);
			return true;
		}

		public override int GetHashCode()
		{
			return EqualityComparer<byte[]>.Default.GetHashCode(Bytes);
		}
	}
	public class BsonBinary : IEnumerable<byte>, IEnumerable
	{
		public static readonly BsonBinary Empty = new BsonBinary(BsonBinarySubtype.Generic, new byte[0]);

		private readonly BsonBinarySubtype Subtype;

		private readonly byte[] Bytes;

		internal byte[] Data => Bytes;

		public BsonBinarySubtype Type => Subtype;

		public byte this[int index] => Bytes[index];

		public int Count => Bytes.Length;

		public BsonBinary(BsonBinarySubtype subtype, byte[] bytes)
		{
			if (bytes == null)
			{
				throw new ArgumentNullException("bytes");
			}
			Subtype = subtype;
			Bytes = bytes;
		}

		public static explicit operator string(BsonBinary value)
		{
			return value.ToString();
		}

		public static explicit operator BsonBinary(string value)
		{
			return Parse(value);
		}

		public static explicit operator byte[](BsonBinary value)
		{
			return value.Bytes;
		}

		public static explicit operator BsonBinary(byte[] value)
		{
			return new BsonBinary(BsonBinarySubtype.Generic, value);
		}

		public override string ToString()
		{
			byte[] bytes = Bytes;
			char[] array = new char[24];
			int num = 0;
			int num2 = 0;
			while (num < 24)
			{
				array[num] = GetHexDigit(bytes[num2] / 16);
				array[num] = GetHexDigit(bytes[num2] % 16);
				num += 2;
				num2++;
			}
			return new string(array);
		}

		public byte[] ToByteArray()
		{
			byte[] array = new byte[12];
			Buffer.BlockCopy(Bytes, 0, array, 0, 12);
			return array;
		}

		public static BsonBinary Parse(string value)
		{
			if (TryParse(value, out var result))
			{
				return result;
			}
			throw new InvalidCastException("String must be only hex digits");
		}

		public static bool TryParse(string value, out BsonBinary result)
		{
			if (string.IsNullOrEmpty(value))
			{
				result = Empty;
				return true;
			}
			byte[] array = new byte[value.Length / 2];
			for (int i = 0; i < value.Length; i += 2)
			{
				if (!byte.TryParse(value.Substring(i, 2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out var result2))
				{
					result = Empty;
					return false;
				}
				array[i] = result2;
			}
			result = new BsonBinary(BsonBinarySubtype.Generic, array);
			return true;
		}

		public override int GetHashCode()
		{
			return EqualityComparer<byte[]>.Default.GetHashCode(Bytes);
		}

		private static char GetHexDigit(int i)
		{
			if (i < 10)
			{
				return (char)(i + 48);
			}
			return (char)(i - 10 + 97);
		}

		public IEnumerator<byte> GetEnumerator()
		{
			return ((IEnumerable<byte>)Bytes).GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return Bytes.GetEnumerator();
		}
	}
}
namespace JsonFx.Serialization
{
	public interface IBinaryFormattable<T>
	{
		int Format(IBinaryFormatter<T> formatter, BinaryWriter writer);
	}
}
namespace JsonFx.Bson
{
	public interface IBsonFormattable : IBinaryFormattable<ModelTokenType>
	{
		BsonElementType GetElementType();
	}
}
namespace JsonFx.CodeGen
{
	public delegate object FactoryDelegate(params object[] args);
	public delegate object ProxyDelegate(object target, params object[] args);
	public delegate object GetterDelegate(object target);
	public delegate void SetterDelegate(object target, object value);
}
namespace JsonFx.Serialization
{
	public interface ITokenAnalyzer<T>
	{
		DataReaderSettings Settings { get; }

		IEnumerable Analyze(IEnumerable<Token<T>> tokens);

		IEnumerable Analyze(IEnumerable<Token<T>> tokens, Type targetType);

		IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<T>> tokens);

		IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<T>> tokens, TResult ignored);
	}
}
namespace JsonFx.Model
{
	public class ModelAnalyzer : ITokenAnalyzer<ModelTokenType>
	{
		private const string ErrorUnexpectedToken = "Unexpected token ({0})";

		private const string ErrorExpectedArray = "Expected array start ({0})";

		private const string ErrorExpectedArrayItem = "Expected array item or end of array ({0})";

		private const string ErrorExpectedArrayItemDelim = "Expected array item delimiter or end of array ({0})";

		private const string ErrorMissingArrayItem = "Missing array item";

		private const string ErrorUnterminatedArray = "Unterminated array";

		private const string ErrorExpectedObject = "Expected object start ({0})";

		private const string ErrorExpectedPropertyName = "Expected object property name or end of object ({0})";

		private const string ErrorExpectedObjectValueDelim = "Expected value delimiter or end of object ({0})";

		private const string ErrorMissingObjectProperty = "Missing object property";

		private const string ErrorUnterminatedObject = "Unterminated object";

		private readonly DataReaderSettings Settings;

		private readonly TypeCoercionUtility Coercion;

		private readonly IEnumerable<IDataFilter<ModelTokenType>> Filters;

		DataReaderSettings ITokenAnalyzer<ModelTokenType>.Settings => Settings;

		public ModelAnalyzer(DataReaderSettings settings)
		{
			if (settings == null)
			{
				throw new ArgumentNullException("settings");
			}
			Settings = settings;
			List<IDataFilter<ModelTokenType>> list = new List<IDataFilter<ModelTokenType>>();
			if (settings.Filters != null)
			{
				foreach (IDataFilter<ModelTokenType> filter in settings.Filters)
				{
					if (filter != null)
					{
						list.Add(filter);
					}
				}
			}
			Filters = list;
			Coercion = new TypeCoercionUtility(settings, settings.AllowNullValueTypes);
		}

		public IEnumerable Analyze(IEnumerable<Token<ModelTokenType>> tokens)
		{
			return Analyze(tokens, null);
		}

		public IEnumerable Analyze(IEnumerable<Token<ModelTokenType>> tokens, Type targetType)
		{
			if (tokens == null)
			{
				throw new ArgumentNullException("tokens");
			}
			IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(tokens);
			while (!stream.IsCompleted)
			{
				yield return ConsumeValue(stream, targetType);
			}
		}

		public IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<ModelTokenType>> tokens)
		{
			if (tokens == null)
			{
				throw new ArgumentNullException("tokens");
			}
			Type resultType = typeof(TResult);
			IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(tokens);
			while (!stream.IsCompleted)
			{
				yield return (TResult)ConsumeValue(stream, resultType);
			}
		}

		public IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<ModelTokenType>> tokens, TResult ignored)
		{
			return Analyze<TResult>(tokens);
		}

		private object ConsumeValue(IStream<Token<ModelTokenType>> tokens, Type targetType)
		{
			if (TryReadFilters(tokens, out var result))
			{
				return result;
			}
			Token<ModelTokenType> token = tokens.Peek();
			switch (token.TokenType)
			{
			case ModelTokenType.ArrayBegin:
				return ConsumeArray(tokens, targetType);
			case ModelTokenType.ObjectBegin:
				return ConsumeObject(tokens, targetType);
			case ModelTokenType.Primitive:
				tokens.Pop();
				return Coercion.CoerceType(targetType, token.Value);
			default:
				tokens.Pop();
				throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})");
			}
		}

		private object ConsumeObject(IStream<Token<ModelTokenType>> tokens, Type targetType)
		{
			Token<ModelTokenType> token = tokens.Pop();
			if (token.TokenType != ModelTokenType.ObjectBegin)
			{
				throw new TokenException<ModelTokenType>(token, $"Expected object start ({token.TokenType})");
			}
			IDictionary<string, MemberMap> dictionary = Settings.Resolver.LoadMaps(targetType);
			Type dictionaryItemType = TypeCoercionUtility.GetDictionaryItemType(targetType);
			object obj = Coercion.InstantiateObjectDefaultCtor(targetType);
			while (!tokens.IsCompleted)
			{
				token = tokens.Peek();
				string localName;
				MemberMap value;
				Type targetType2;
				switch (token.TokenType)
				{
				case ModelTokenType.Property:
					tokens.Pop();
					localName = token.Name.LocalName;
					if ((object)dictionaryItemType != null)
					{
						value = null;
						targetType2 = dictionaryItemType;
					}
					else if (dictionary != null && dictionary.TryGetValue(localName, out value))
					{
						targetType2 = value?.Type;
					}
					else
					{
						value = null;
						targetType2 = null;
					}
					break;
				case ModelTokenType.ObjectEnd:
					tokens.Pop();
					return Coercion.CoerceType(targetType, obj);
				default:
					tokens.Pop();
					throw new TokenException<ModelTokenType>(token, $"Expected object property name or end of object ({token.TokenType})");
				}
				object memberValue = ConsumeValue(tokens, targetType2);
				Coercion.SetMemberValue(obj, targetType, value, localName, memberValue);
			}
			throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unterminated object");
		}

		private object ConsumeArray(IStream<Token<ModelTokenType>> tokens, Type arrayType)
		{
			Token<ModelTokenType> token = tokens.Pop();
			if (token.TokenType != ModelTokenType.ArrayBegin)
			{
				throw new TokenException<ModelTokenType>(token, $"Expected array start ({token.TokenType})");
			}
			Type type = TypeCoercionUtility.GetElementType(arrayType);
			bool flag = (object)type == null;
			IList list = new List<object>();
			while (!tokens.IsCompleted)
			{
				token = tokens.Peek();
				object result;
				switch (token.TokenType)
				{
				case ModelTokenType.ArrayBegin:
					result = ConsumeArray(tokens, flag ? null : type);
					break;
				case ModelTokenType.ArrayEnd:
					tokens.Pop();
					return Coercion.CoerceCollection(arrayType, type, list);
				case ModelTokenType.ObjectBegin:
					result = ConsumeObject(tokens, flag ? null : type);
					break;
				case ModelTokenType.Primitive:
					if (!TryReadFilters(tokens, out result))
					{
						token = tokens.Pop();
						result = ((token != null) ? token.Value : null);
					}
					if (!flag)
					{
						result = Coercion.CoerceType(type, result);
					}
					break;
				default:
					tokens.Pop();
					throw new TokenException<ModelTokenType>(token, $"Expected array item or end of array ({token.TokenType})");
				}
				type = TypeCoercionUtility.FindCommonType(type, result);
				list.Add(result);
			}
			throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unterminated array");
		}

		private bool TryReadFilters(IStream<Token<ModelTokenType>> tokens, out object result)
		{
			if (!tokens.IsCompleted)
			{
				foreach (IDataFilter<ModelTokenType> filter in Filters)
				{
					if (filter.TryRead(Settings, tokens, out result))
					{
						return true;
					}
				}
			}
			result = null;
			return false;
		}
	}
	public static class ModelGrammar
	{
		public static readonly Token<ModelTokenType> TokenNone = new Token<ModelTokenType>(ModelTokenType.None);

		public static readonly Token<ModelTokenType> TokenArrayEnd = new Token<ModelTokenType>(ModelTokenType.ArrayEnd);

		public static readonly Token<ModelTokenType> TokenObjectEnd = new Token<ModelTokenType>(ModelTokenType.ObjectEnd);

		public static readonly Token<ModelTokenType> TokenNull = new Token<ModelTokenType>(ModelTokenType.Primitive);

		public static readonly Token<ModelTokenType> TokenFalse = new Token<ModelTokenType>(ModelTokenType.Primitive, false);

		public static readonly Token<ModelTokenType> TokenTrue = new Token<ModelTokenType>(ModelTokenType.Primitive, true);

		public static readonly Token<ModelTokenType> TokenArrayBeginUnnamed = new Token<ModelTokenType>(ModelTokenType.ArrayBegin);

		public static readonly Token<ModelTokenType> TokenObjectBeginUnnamed = new Token<ModelTokenType>(ModelTokenType.ObjectBegin);

		internal static readonly Token<ModelTokenType> TokenNaN = new Token<ModelTokenType>(ModelTokenType.Primitive, double.NaN);

		internal static readonly Token<ModelTokenType> TokenPositiveInfinity = new Token<ModelTokenType>(ModelTokenType.Primitive, double.PositiveInfinity);

		internal static readonly Token<ModelTokenType> TokenNegativeInfinity = new Token<ModelTokenType>(ModelTokenType.Primitive, double.NegativeInfinity);

		public static Token<ModelTokenType> TokenArrayBegin(string name)
		{
			return new Token<ModelTokenType>(ModelTokenType.ArrayBegin, new DataName(name));
		}

		public static Token<ModelTokenType> TokenArrayBegin(string name, string prefix, string namespaceUri)
		{
			return new Token<ModelTokenType>(ModelTokenType.ArrayBegin, new DataName(name, prefix, namespaceUri));
		}

		public static Token<ModelTokenType> TokenArrayBegin(DataName name)
		{
			return new Token<ModelTokenType>(ModelTokenType.ArrayBegin, name);
		}

		public static Token<ModelTokenType> TokenObjectBegin(string name)
		{
			return new Token<ModelTokenType>(ModelTokenType.ObjectBegin, new DataName(name));
		}

		public static Token<ModelTokenType> TokenObjectBegin(DataName name)
		{
			return new Token<ModelTokenType>(ModelTokenType.ObjectBegin, name);
		}

		internal static Token<ModelTokenType> TokenProperty(object localName)
		{
			string localName2 = Token<ModelTokenType>.ToString(localName);
			return new Token<ModelTokenType>(ModelTokenType.Property, new DataName(localName2));
		}

		public static Token<ModelTokenType> TokenProperty(string localName)
		{
			return new Token<ModelTokenType>(ModelTokenType.Property, new DataName(localName));
		}

		public static Token<ModelTokenType> TokenProperty(DataName name)
		{
			return new Token<ModelTokenType>(ModelTokenType.Property, name);
		}

		public static Token<ModelTokenType> TokenPrimitive(object value)
		{
			return new Token<ModelTokenType>(ModelTokenType.Primitive, value);
		}
	}
}
namespace JsonFx.Serialization
{
	public interface IDataReader
	{
		IEnumerable<string> ContentType { get; }

		DataReaderSettings Settings { get; }

		TResult Read<TResult>(TextReader input, TResult ignored);

		TResult Read<TResult>(TextReader input);

		object Read(TextReader input);

		object Read(TextReader input, Type targetType);

		TResult Read<TResult>(string input, TResult ignored);

		TResult Read<TResult>(string input);

		object Read(string input);

		object Read(string input, Type targetType);

		IEnumerable ReadMany(TextReader input);
	}
	public abstract class DataReader<T> : IDataReader
	{
		private readonly DataReaderSettings settings;

		public abstract IEnumerable<string> ContentType { get; }

		public DataReaderSettings Settings => settings;

		protected DataReader(DataReaderSettings settings)
		{
			if (settings == null)
			{
				throw new NullReferenceException("settings");
			}
			this.settings = settings;
		}

		public virtual TResult Read<TResult>(TextReader input, TResult ignored)
		{
			return Read<TResult>(input);
		}

		public virtual TResult Read<TResult>(TextReader input)
		{
			object obj = Read(input, typeof(TResult));
			if (!(obj is TResult))
			{
				return default(TResult);
			}
			return (TResult)obj;
		}

		public virtual object Read(TextReader input)
		{
			return Read(input, null);
		}

		public virtual object Read(TextReader input, Type targetType)
		{
			ITextTokenizer<T> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new InvalidOperationException("Tokenizer is invalid");
			}
			return ReadSingle(tokenizer, tokenizer.GetTokens(input), targetType);
		}

		public virtual TResult Read<TResult>(string input, TResult ignored)
		{
			return Read<TResult>(input);
		}

		public virtual TResult Read<TResult>(string input)
		{
			object obj = Read(input, typeof(TResult));
			if (!(obj is TResult))
			{
				return default(TResult);
			}
			return (TResult)obj;
		}

		public virtual object Read(string input)
		{
			return Read(input, null);
		}

		public virtual object Read(string input, Type targetType)
		{
			ITextTokenizer<T> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new ArgumentNullException("tokenizer");
			}
			return ReadSingle(tokenizer, tokenizer.GetTokens(input), targetType);
		}

		public IEnumerable ReadMany(TextReader input)
		{
			ITextTokenizer<T> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new ArgumentNullException("tokenizer");
			}
			ITokenAnalyzer<T> analyzer = GetAnalyzer();
			if (analyzer == null)
			{
				throw new ArgumentNullException("analyzer");
			}
			try
			{
				return analyzer.Analyze(tokenizer.GetTokens(input));
			}
			catch (DeserializationException)
			{
				throw;
			}
			catch (Exception ex2)
			{
				throw new DeserializationException(ex2.Message, tokenizer.Index, tokenizer.Line, tokenizer.Column, ex2);
			}
		}

		private object ReadSingle(ITextTokenizer<T> tokenizer, IEnumerable<Token<T>> tokens, Type targetType)
		{
			ITokenAnalyzer<T> analyzer = GetAnalyzer();
			if (analyzer == null)
			{
				throw new ArgumentNullException("analyzer");
			}
			try
			{
				IEnumerator enumerator = analyzer.Analyze(tokens, targetType).GetEnumerator();
				if (!enumerator.MoveNext())
				{
					return null;
				}
				object current = enumerator.Current;
				if (!Settings.AllowTrailingContent && enumerator.MoveNext())
				{
					throw new DeserializationException("Invalid trailing content", tokenizer.Index, tokenizer.Line, tokenizer.Column);
				}
				return current;
			}
			catch (DeserializationException)
			{
				throw;
			}
			catch (Exception ex2)
			{
				throw new DeserializationException(ex2.Message, tokenizer.Index, tokenizer.Line, tokenizer.Column, ex2);
			}
		}

		protected abstract ITextTokenizer<T> GetTokenizer();

		protected abstract ITokenAnalyzer<T> GetAnalyzer();
	}
}
namespace JsonFx.Linq
{
	public interface IQueryableReader : IDataReader
	{
		IQueryable<TResult> Query<TResult>(TextReader input, TResult ignored);

		IQueryable<TResult> Query<TResult>(TextReader input);

		IQueryable Query(TextReader input);

		IQueryable Query(TextReader input, Type targetType);

		IQueryable<TResult> Query<TResult>(string input, TResult ignored);

		IQueryable<TResult> Query<TResult>(string input);

		IQueryable Query(string input);

		IQueryable Query(string input, Type targetType);
	}
}
namespace JsonFx.Model
{
	public abstract class ModelReader : DataReader<ModelTokenType>, IQueryableReader, IDataReader
	{
		protected ModelReader(DataReaderSettings settings)
			: base(settings)
		{
		}

		protected override ITokenAnalyzer<ModelTokenType> GetAnalyzer()
		{
			return new ModelAnalyzer(base.Settings);
		}

		IQueryable<T> IQueryableReader.Query<T>(TextReader input, T ignored)
		{
			return Query<T>(input);
		}

		IQueryable<T> IQueryableReader.Query<T>(TextReader input)
		{
			return Query<T>(input);
		}

		IQueryable<T> IQueryableReader.Query<T>(string input, T ignored)
		{
			return Query<T>(input);
		}

		IQueryable<T> IQueryableReader.Query<T>(string input)
		{
			return Query<T>(input);
		}

		public Query<T> Query<T>(TextReader input, T ignored)
		{
			return Query<T>(input);
		}

		public Query<T> Query<T>(TextReader input)
		{
			ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new InvalidOperationException("Tokenizer is invalid");
			}
			IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input);
			return new Query<T>(GetAnalyzer(), tokens);
		}

		public IQueryable Query(TextReader input)
		{
			ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new InvalidOperationException("Tokenizer is invalid");
			}
			IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input);
			return new Query<object>(GetAnalyzer(), tokens);
		}

		public IQueryable Query(TextReader input, Type targetType)
		{
			ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new InvalidOperationException("Tokenizer is invalid");
			}
			IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input);
			try
			{
				return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(targetType), GetAnalyzer(), tokens);
			}
			catch (TargetInvocationException ex)
			{
				throw ex.InnerException;
			}
		}

		public Query<T> Query<T>(string input, T ignored)
		{
			return Query<T>(input);
		}

		public Query<T> Query<T>(string input)
		{
			ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new InvalidOperationException("Tokenizer is invalid");
			}
			IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input);
			return new Query<T>(GetAnalyzer(), tokens);
		}

		public IQueryable Query(string input)
		{
			ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new InvalidOperationException("Tokenizer is invalid");
			}
			IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input);
			return new Query<object>(GetAnalyzer(), tokens);
		}

		public IQueryable Query(string input, Type targetType)
		{
			ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer();
			if (tokenizer == null)
			{
				throw new InvalidOperationException("Tokenizer is invalid");
			}
			IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input);
			try
			{
				return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(targetType), GetAnalyzer(), tokens);
			}
			catch (TargetInvocationException ex)
			{
				throw ex.InnerException;
			}
		}
	}
	public static class ModelSubsequencer
	{
		private const string ErrorUnexpectedEndOfInput = "Unexpected end of token stream";

		private const string ErrorInvalidPropertyValue = "Invalid property value token ({0})";

		private static readonly IEnumerable<Token<ModelTokenType>> EmptySequence = new Token<ModelTokenType>[0];

		public static bool IsPrimitive(this IEnumerable<Token<ModelTokenType>> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (source is IList<Token<ModelTokenType>> list)
			{
				if (list.Count > 0)
				{
					return list[0].TokenType == ModelTokenType.Primitive;
				}
				return false;
			}
			using (IEnumerator<Token<ModelTokenType>> enumerator = source.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					Token<ModelTokenType> current = enumerator.Current;
					return current.TokenType == ModelTokenType.Primitive;
				}
			}
			return false;
		}

		public static bool IsObject(this IEnumerable<Token<ModelTokenType>> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (source is IList<Token<ModelTokenType>> list)
			{
				if (list.Count > 0)
				{
					return list[0].TokenType == ModelTokenType.ObjectBegin;
				}
				return false;
			}
			using (IEnumerator<Token<ModelTokenType>> enumerator = source.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					Token<ModelTokenType> current = enumerator.Current;
					return current.TokenType == ModelTokenType.ObjectBegin;
				}
			}
			return false;
		}

		public static bool HasProperty(this IEnumerable<Token<ModelTokenType>> source, Func<DataName, bool> predicate)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source);
			if (stream.IsCompleted || stream.Pop().TokenType != ModelTokenType.ObjectBegin)
			{
				return false;
			}
			int num = 0;
			while (!stream.IsCompleted)
			{
				Token<ModelTokenType> token = stream.Peek();
				switch (token.TokenType)
				{
				case ModelTokenType.ObjectBegin:
				case ModelTokenType.ArrayBegin:
					num++;
					stream.Pop();
					break;
				case ModelTokenType.ArrayEnd:
					num--;
					stream.Pop();
					break;
				case ModelTokenType.ObjectEnd:
					if (num != 0)
					{
						num--;
						stream.Pop();
						break;
					}
					return false;
				case ModelTokenType.Property:
					stream.Pop();
					if (num == 0 && (predicate == null || predicate(token.Name)))
					{
						return true;
					}
					break;
				default:
					stream.Pop();
					break;
				}
			}
			return false;
		}

		public static IEnumerable<Token<ModelTokenType>> Property(this IEnumerable<Token<ModelTokenType>> source, DataName propertyName)
		{
			Func<DataName, bool> predicate = (DataName name) => name == propertyName;
			using IEnumerator<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> enumerator = source.Properties(predicate).GetEnumerator();
			return enumerator.MoveNext() ? enumerator.Current.Value : null;
		}

		public static IEnumerable<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> Properties(this IEnumerable<Token<ModelTokenType>> source)
		{
			return source.Properties(null);
		}

		public static IEnumerable<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> Properties(this IEnumerable<Token<ModelTokenType>> source, Func<DataName, bool> predicate)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (!(source is IList<Token<ModelTokenType>>))
			{
				source = new SequenceBuffer<Token<ModelTokenType>>(source);
			}
			return PropertiesIterator(source, predicate);
		}

		private static IEnumerable<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> PropertiesIterator(IEnumerable<Token<ModelTokenType>> source, Func<DataName, bool> predicate)
		{
			IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source);
			if (stream.IsCompleted || stream.Pop().TokenType != ModelTokenType.ObjectBegin)
			{
				yield break;
			}
			int depth = 0;
			while (!stream.IsCompleted)
			{
				Token<ModelTokenType> token = stream.Peek();
				switch (token.TokenType)
				{
				case ModelTokenType.ObjectBegin:
				case ModelTokenType.ArrayBegin:
					depth++;
					stream.Pop();
					break;
				case ModelTokenType.ArrayEnd:
					depth--;
					stream.Pop();
					break;
				case ModelTokenType.ObjectEnd:
					if (depth != 0)
					{
						depth--;
						stream.Pop();
						break;
					}
					yield break;
				case ModelTokenType.Property:
					stream.Pop();
					if (depth == 0 && (predicate == null || predicate(token.Name)))
					{
						yield return new KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>(token.Name, SpliceNextValue(stream));
					}
					break;
				default:
					stream.Pop();
					break;
				}
			}
		}

		public static bool IsArray(this IEnumerable<Token<ModelTokenType>> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (source is IList<Token<ModelTokenType>> list)
			{
				if (list.Count > 0)
				{
					return list[0].TokenType == ModelTokenType.ArrayBegin;
				}
				return false;
			}
			using (IEnumerator<Token<ModelTokenType>> enumerator = source.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					Token<ModelTokenType> current = enumerator.Current;
					return current.TokenType == ModelTokenType.ArrayBegin;
				}
			}
			return false;
		}

		public static IEnumerable<IEnumerable<Token<ModelTokenType>>> ArrayItems(this IEnumerable<Token<ModelTokenType>> source)
		{
			return source.ArrayItems(null);
		}

		public static IEnumerable<IEnumerable<Token<ModelTokenType>>> ArrayItems(this IEnumerable<Token<ModelTokenType>> source, Func<int, bool> predicate)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (!(source is IList<Token<ModelTokenType>>))
			{
				source = new SequenceBuffer<Token<ModelTokenType>>(source);
			}
			return ArrayItemsIterator(source, predicate);
		}

		private static IEnumerable<IEnumerable<Token<ModelTokenType>>> ArrayItemsIterator(IEnumerable<Token<ModelTokenType>> source, Func<int, bool> predicate)
		{
			IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source);
			if (stream.IsCompleted)
			{
				yield break;
			}
			if (stream.Pop().TokenType != ModelTokenType.ArrayBegin)
			{
				yield return source;
				yield break;
			}
			int index = 0;
			while (!stream.IsCompleted)
			{
				Token<ModelTokenType> token = stream.Peek();
				if (token.TokenType != ModelTokenType.ArrayEnd)
				{
					if (predicate == null || predicate(index))
					{
						yield return SpliceNextValue(stream);
					}
					else
					{
						SkipNextValue(stream);
					}
					index++;
					continue;
				}
				break;
			}
		}

		public static IEnumerable<IEnumerable<Token<ModelTokenType>>> Descendants(this IEnumerable<Token<ModelTokenType>> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (!(source is IList<Token<ModelTokenType>>))
			{
				source = new SequenceBuffer<Token<ModelTokenType>>(source);
			}
			return DescendantsIterator(source);
		}

		private static IEnumerable<IEnumerable<Token<ModelTokenType>>> DescendantsIterator(IEnumerable<Token<ModelTokenType>> source)
		{
			if (source.IsPrimitive())
			{
				yield break;
			}
			if (source.IsObject())
			{
				foreach (KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>> property in source.Properties(null))
				{
					KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>> keyValuePair = property;
					yield return keyValuePair.Value;
					KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>> keyValuePair2 = property;
					foreach (IEnumerable<Token<ModelTokenType>> item2 in keyValuePair2.Value.Descendants())
					{
						yield return item2;
					}
				}
				yield break;
			}
			if (!source.IsArray())
			{
				yield break;
			}
			foreach (IEnumerable<Token<ModelTokenType>> item in source.ArrayItems(null))
			{
				yield return item;
				foreach (IEnumerable<Token<ModelTokenType>> item3 in item.Descendants())
				{
					yield return item3;
				}
			}
		}

		public static IEnumerable<IEnumerable<Token<ModelTokenType>>> DescendantsAndSelf(this IEnumerable<Token<ModelTokenType>> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (!(source is IList<Token<ModelTokenType>>))
			{
				source = new SequenceBuffer<Token<ModelTokenType>>(source);
			}
			return DescendantsAndSelfIterator(source);
		}

		private static IEnumerable<IEnumerable<Token<ModelTokenType>>> DescendantsAndSelfIterator(IEnumerable<Token<ModelTokenType>> source)
		{
			yield return source;
			foreach (IEnumerable<Token<ModelTokenType>> item in DescendantsIterator(source))
			{
				yield return item;
			}
		}

		internal static IEnumerable<IEnumerable<Token<ModelTokenType>>> SplitValues(this IEnumerable<Token<ModelTokenType>> source)
		{
			if (source == null)
			{
				return new IEnumerable<Token<ModelTokenType>>[0];
			}
			if (!(source is IList<Token<ModelTokenType>>))
			{
				source = new SequenceBuffer<Token<ModelTokenType>>(source);
			}
			return SplitValuesIterator(source);
		}

		private static IEnumerable<IEnumerable<Token<ModelTokenType>>> SplitValuesIterator(IEnumerable<Token<ModelTokenType>> source)
		{
			using IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source);
			while (!stream.IsCompleted)
			{
				yield return SpliceNextValue(stream);
			}
		}

		[Obsolete("TODO: Lazy does not mix well with shared IStream<T>.", true)]
		private static IEnumerable<Token<ModelTokenType>> SpliceNextValueLazy(IStream<Token<ModelTokenType>> stream)
		{
			if (stream.IsCompleted)
			{
				yield break;
			}
			int depth2 = 0;
			Token<ModelTokenType> token2 = stream.Pop();
			switch (token2.TokenType)
			{
			case ModelTokenType.Primitive:
				yield return token2;
				break;
			case ModelTokenType.ObjectBegin:
			case ModelTokenType.ArrayBegin:
				depth2++;
				yield return token2;
				while (!stream.IsCompleted && depth2 > 0)
				{
					token2 = stream.Pop();
					switch (token2.TokenType)
					{
					case ModelTokenType.ObjectBegin:
					case ModelTokenType.ArrayBegin:
						depth2++;
						yield return token2;
						break;
					case ModelTokenType.ObjectEnd:
					case ModelTokenType.ArrayEnd:
						depth2--;
						yield return token2;
						break;
					default:
						yield return token2;
						break;
					}
				}
				if (depth2 > 0)
				{
					throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream");
				}
				break;
			default:
				throw new TokenException<ModelTokenType>(token2, $"Invalid property value token ({token2.TokenType})");
			}
		}

		private static IEnumerable<Token<ModelTokenType>> SpliceNextValue(IStream<Token<ModelTokenType>> stream)
		{
			if (stream.IsCompleted)
			{
				throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream");
			}
			stream.BeginChunk();
			int num = 0;
			Token<ModelTokenType> token = stream.Pop();
			switch (token.TokenType)
			{
			case ModelTokenType.Primitive:
				return stream.EndChunk();
			case ModelTokenType.ObjectBegin:
			case ModelTokenType.ArrayBegin:
				num++;
				while (!stream.IsCompleted && num > 0)
				{
					switch (stream.Pop().TokenType)
					{
					case ModelTokenType.ObjectBegin:
					case ModelTokenType.ArrayBegin:
						num++;
						break;
					case ModelTokenType.ObjectEnd:
					case ModelTokenType.ArrayEnd:
						num--;
						break;
					}
				}
				if (num > 0)
				{
					throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream");
				}
				return stream.EndChunk();
			default:
				throw new TokenException<ModelTokenType>(token, $"Invalid property value token ({token.TokenType})");
			}
		}

		private static void SkipNextValue(IStream<Token<ModelTokenType>> stream)
		{
			if (stream.IsCompleted)
			{
				return;
			}
			int num = 0;
			Token<ModelTokenType> token = stream.Pop();
			switch (token.TokenType)
			{
			case ModelTokenType.Primitive:
				break;
			case ModelTokenType.ObjectBegin:
			case ModelTokenType.ArrayBegin:
				num++;
				while (!stream.IsCompleted && num > 0)
				{
					switch (stream.Pop().TokenType)
					{
					case ModelTokenType.ObjectBegin:
					case ModelTokenType.ArrayBegin:
						num++;
						break;
					case ModelTokenType.ObjectEnd:
					case ModelTokenType.ArrayEnd:
						num--;
						break;
					}
				}
				if (num > 0)
				{
					throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream");
				}
				break;
			default:
				throw new TokenException<ModelTokenType>(token, $"Invalid property value token ({token.TokenType})");
			}
		}
	}
	public enum ModelTokenType
	{
		None,
		ObjectBegin,
		ObjectEnd,
		ArrayBegin,
		ArrayEnd,
		Property,
		Primitive
	}
}
namespace JsonFx.Serialization
{
	public interface IObjectWalker<T>
	{
		IEnumerable<Token<T>> GetTokens(object value);
	}
}
namespace JsonFx.Model
{
	public class ModelWalker : IObjectWalker<ModelTokenType>
	{
		private readonly DataWriterSettings Settings;

		private readonly IEnumerable<IDataFilter<ModelTokenType>> Filters;

		public ModelWalker(DataWriterSettings settings)
		{
			if (settings == null)
			{
				throw new ArgumentNullException("settings");
			}
			Settings = settings;
			List<IDataFilter<ModelTokenType>> list = new List<IDataFilter<ModelTokenType>>();
			if (settings.Filters != null)
			{
				foreach (IDataFilter<ModelTokenType> filter in settings.Filters)
				{
					if (filter != null)
					{
						list.Add(filter);
					}
				}
			}
			Filters = list;
		}

		public IEnumerable<Token<ModelTokenType>> GetTokens(object value)
		{
			GraphCycleType graphCycles = Settings.GraphCycles;
			ICycleDetector detector = ((graphCycles != GraphCycleType.MaxDepth) ? ((ICycleDetector)new ReferenceSet()) : ((ICycleDetector)new DepthCounter(Settings.MaxDepth)));
			List<Token<ModelTokenType>> list = new List<Token<ModelTokenType>>();
			GetTokens(list, detector, value);
			return list;
		}

		private void GetTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, object value)
		{
			if (value == null)
			{
				tokens.Add(ModelGrammar.TokenNull);
				return;
			}
			if (detector.Add(value))
			{
				switch (Settings.GraphCycles)
				{
				case GraphCycleType.Reference:
					throw new GraphCycleException(GraphCycleType.Reference, "Graph cycle detected: repeated references");
				case GraphCycleType.MaxDepth:
					throw new GraphCycleException(GraphCycleType.MaxDepth, "Graph cycle potentially detected: maximum depth exceeded");
				}
				tokens.Add(ModelGrammar.TokenNull);
				return;
			}
			try
			{
				foreach (IDataFilter<ModelTokenType> filter in Filters)
				{
					if (filter.TryWrite(Settings, value, out var tokens2))
					{
						tokens.AddRange(tokens2);
						return;
					}
				}
				Type type = value.GetType();
				if (type.IsEnum)
				{
					tokens.Add(ModelGrammar.TokenPrimitive((Enum)value));
					return;
				}
				switch (Type.GetTypeCode(type))
				{
				case TypeCode.Boolean:
					tokens.Add(true.Equals(value) ? ModelGrammar.TokenTrue : ModelGrammar.TokenFalse);
					break;
				case TypeCode.SByte:
				case TypeCode.Byte:
				case TypeCode.Int16:
				case TypeCode.UInt16:
				case TypeCode.Int32:
				case TypeCode.UInt32:
				case TypeCode.Int64:
				case TypeCode.UInt64:
				case TypeCode.Decimal:
					tokens.Add(ModelGrammar.TokenPrimitive((ValueType)value));
					break;
				case TypeCode.Double:
				{
					double num2 = (double)value;
					if (double.IsNaN(num2))
					{
						tokens.Add(ModelGrammar.TokenNaN);
					}
					else if (double.IsPositiveInfinity(num2))
					{
						tokens.Add(ModelGrammar.TokenPositiveInfinity);
					}
					else if (double.IsNegativeInfinity(num2))
					{
						tokens.Add(ModelGrammar.TokenNegativeInfinity);
					}
					else
					{
						tokens.Add(ModelGrammar.TokenPrimitive(num2));
					}
					break;
				}
				case TypeCode.Single:
				{
					float num = (float)value;
					if (float.IsNaN(num))
					{
						tokens.Add(ModelGrammar.TokenNaN);
					}
					else if (float.IsPositiveInfinity(num))
					{
						tokens.Add(ModelGrammar.TokenPositiveInfinity);
					}
					else if (float.IsNegativeInfinity(num))
					{
						tokens.Add(ModelGrammar.TokenNegativeInfinity);
					}
					else
					{
						tokens.Add(ModelGrammar.TokenPrimitive(num));
					}
					break;
				}
				case TypeCode.Char:
				case TypeCode.DateTime:
				case TypeCode.String:
					tokens.Add(ModelGrammar.TokenPrimitive(value));
					break;
				case TypeCode.Empty:
				case TypeCode.DBNull:
					tokens.Add(ModelGrammar.TokenNull);
					break;
				default:
					if (value is IEnumerable)
					{
						GetArrayTokens(tokens, detector, (IEnumerable)value);
					}
					else if (value is Guid || value is Uri || value is Version)
					{
						tokens.Add(ModelGrammar.TokenPrimitive(value));
					}
					else if (value is TimeSpan)
					{
						tokens.Add(ModelGrammar.TokenPrimitive((TimeSpan)value));
					}
					else
					{
						GetObjectTokens(tokens, detector, type, value);
					}
					break;
				}
			}
			finally
			{
				detector.Remove(value);
			}
		}

		private void GetArrayTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, IEnumerable value)
		{
			DataName typeName = GetTypeName(value);
			IEnumerator enumerator = value.GetEnumerator();
			if (enumerator is IEnumerator<KeyValuePair<string, object>>)
			{
				GetObjectTokens(tokens, detector, typeName, (IEnumerator<KeyValuePair<string, object>>)enumerator);
				return;
			}
			if (enumerator is IDictionaryEnumerator)
			{
				GetObjectTokens(tokens, detector, typeName, (IDictionaryEnumerator)enumerator);
				return;
			}
			tokens.Add(ModelGrammar.TokenArrayBegin(typeName));
			while (enumerator.MoveNext())
			{
				GetTokens(tokens, detector, enumerator.Current);
			}
			tokens.Add(ModelGrammar.TokenArrayEnd);
		}

		private void GetObjectTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, DataName typeName, IDictionaryEnumerator enumerator)
		{
			tokens.Add(ModelGrammar.TokenObjectBegin(typeName));
			while (enumerator.MoveNext())
			{
				tokens.Add(ModelGrammar.TokenProperty(enumerator.Key));
				GetTokens(tokens, detector, enumerator.Value);
			}
			tokens.Add(ModelGrammar.TokenObjectEnd);
		}

		private void GetObjectTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, DataName typeName, IEnumerator<KeyValuePair<string, object>> enumerator)
		{
			tokens.Add(ModelGrammar.TokenObjectBegin(typeName));
			while (enumerator.MoveNext())
			{
				KeyValuePair<string, object> current = enumerator.Current;
				tokens.Add(ModelGrammar.TokenProperty(current.Key));
				GetTokens(tokens, detector, current.Value);
			}
			tokens.Add(ModelGrammar.TokenObjectEnd);
		}

		private void GetObjectTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, Type type, object value)
		{
			DataName typeName = GetTypeName(value);
			tokens.Add(ModelGrammar.TokenObjectBegin(typeName));
			IDictionary<string, MemberMap> dictionary = Settings.Resolver.LoadMaps(type);
			if (dictionary == null)
			{
				tokens.Add(ModelGrammar.TokenObjectEnd);
				return;
			}
			IEnumerable<MemberMap> enumerable = Settings.Resolver.SortMembers(dictionary.Values);
			foreach (MemberMap item in enumerable)
			{
				if (!item.IsAlternate && item.Getter != null)
				{
					object obj = item.Getter(value);
					if (item.IsIgnored == null || !item.IsIgnored(value, obj))
					{
						tokens.Add(ModelGrammar.TokenProperty(item.DataName));
						GetTokens(tokens, detector, obj);
					}
				}
			}
			tokens.Add(ModelGrammar.TokenObjectEnd);
		}

		private DataName GetTypeName(object value)
		{
			IEnumerable<DataName> enumerable = Settings.Resolver.LoadTypeName(value?.GetType());
			if (enumerable != null)
			{
				foreach (DataName item in enumerable)
				{
					if (!item.IsEmpty)
					{
						return item;
					}
				}
			}
			return DataName.Empty;
		}
	}
}
namespace JsonFx.Serialization.Filters
{
	public interface IDataFilter<TTokenType>
	{
		bool TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out object value);

		bool TryWrite(DataWriterSettings settings, object value, out IEnumerable<Token<TTokenType>> tokens);
	}
	public interface IDataFilter<TTokenType, TResult> : IDataFilter<TTokenType>
	{
		bool TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out TResult value);

		bool TryWrite(DataWriterSettings settings, TResult value, out IEnumerable<Token<TTokenType>> tokens);
	}
	public abstract class DataFilter<TTokenType, TResult> : IDataFilter<TTokenType, TResult>, IDataFilter<TTokenType>
	{
		public abstract bool TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out TResult value);

		public abstract bool TryWrite(DataWriterSettings settings, TResult value, out IEnumerable<Token<TTokenType>> tokens);

		bool IDataFilter<TTokenType>.TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out object value)
		{
			TResult value2;
			bool result = TryRead(settings, tokens, out value2);
			value = value2;
			return result;
		}

		bool IDataFilter<TTokenType>.TryWrite(DataWriterSettings settings, object value, out IEnumerable<Token<TTokenType>> tokens)
		{
			tokens = null;
			if (value is TResult)
			{
				return TryWrite(settings, (TResult)value, out tokens);
			}
			return false;
		}
	}
}
namespace JsonFx.Model.Filters
{
	public abstract class ModelFilter<T> : DataFilter<ModelTokenType, T>
	{
	}
	public class Iso8601DateFilter : ModelFilter<DateTime>
	{
		public enum Precision
		{
			Seconds,
			Milliseconds,
			Ticks
		}

		private const string ShortFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK";

		private const string LongFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK";

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

		private string iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK";

		public Precision Format
		{
			get
			{
				return iso8601Format switch
				{
					"yyyy'-'MM'-'dd'T'HH':'mm':'ssK" => Precision.Seconds, 
					"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK" => Precision.Milliseconds, 
					_ => Precision.Ticks, 
				};
			}
			set
			{
				switch (value)
				{
				case Precision.Seconds:
					iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK";
					break;
				case Precision.Milliseconds:
					iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK";
					break;
				default:
					iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFK";
					break;
				}
			}
		}

		public override bool TryRead(DataReaderSettings settings, IStream<Token<ModelTokenType>> tokens, out DateTime value)
		{
			Token<ModelTokenType> token = tokens.Peek();
			if (token == null || token.TokenType != ModelTokenType.Primitive || !(token.Value is string))
			{
				value = default(DateTime);
				return false;
			}
			if (!TryParseIso8601(token.ValueAsString(), out value))
			{
				value = default(DateTime);
				return false;
			}
			tokens.Pop();
			return true;
		}

		public override bool TryWrite(DataWriterSettings settings, DateTime value, out IEnumerable<Token<ModelTokenType>> tokens)
		{
			tokens = new Token<ModelTokenType>[1] { ModelGrammar.TokenPrimitive(FormatIso8601(value)) };
			return true;
		}

		private static bool TryParseIso8601(string date, out DateTime value)
		{
			try
			{
				value = DateTime.ParseExact(date, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFK", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.RoundtripKind);
			}
			catch (Exception)
			{
				value = default(DateTime);
				return false;
			}
			if (value.Kind == DateTimeKind.Local)
			{
				value = value.ToUniversalTime();
			}
			return true;
		}

		private string FormatIso8601(DateTime value)
		{
			if (value.Kind == DateTimeKind.Local)
			{
				value = value.ToUniversalTime();
			}
			return value.ToString(iso8601Format);
		}
	}
	public class MSAjaxDateFilter : ModelFilter<DateTime>
	{
		private const long MinValueMilliseconds = -62135596800000L;

		private const long MaxValueMilliseconds = 253402300800000L;

		private const string MSAjaxDatePattern = "^/Date\\(([+\\-]?\\d+?)([+\\-]\\d{4})?\\)/$";

		private const string MSAjaxDatePrefix = "/Date(";

		private const string MSAjaxDateSuffix = ")/";

		private static readonly DateTime EcmaScriptEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

		private static readonly Regex MSAjaxDateRegex = new Regex("^/Date\\(([+\\-]?\\d+?)([+\\-]\\d{4})?\\)/$", RegexOptions.Compiled | RegexOptions.ECMAScript | RegexOptions.CultureInvariant);

		public override bool TryRead(DataReaderSettings settings, IStream<Token<ModelTokenType>> tokens, out DateTime value)
		{
			Token<ModelTokenType> token = tokens.Peek();
			if (token == null || token.TokenType != ModelTokenType.Primitive || !(token.Value is string))
			{
				value = default(DateTime);
				return false;
			}
			if (!TryParseMSAjaxDate(token.ValueAsString(), out value))
			{
				value = default(DateTime);
				return false;
			}
			tokens.Pop();
			return true;
		}

		public override bool TryWrite(DataWriterSettings settings, DateTime value, out IEnumerable<Token<ModelTokenType>> tokens)
		{
			tokens = new Token<ModelTokenType>[1] { ModelGrammar.TokenPrimitive(FormatMSAjaxDate(value)) };
			return true;
		}

		internal static bool TryParseMSAjaxDate(string date, out DateTime value)
		{
			if (string.IsNullOrEmpty(date))
			{
				value = default(DateTime);
				return false;
			}
			Match match = MSAjaxDateRegex.Match(date);
			if (!match.Success || !long.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				value = default(DateTime);
				return false;
			}
			if (result <= -62135596800000L)
			{
				value = DateTime.MinValue;
			}
			else if (result >= 253402300800000L)
			{
				value = DateTime.MaxValue;
			}
			else
			{
				DateTime ecmaScriptEpoch = EcmaScriptEpoch;
				value = ecmaScriptEpoch.AddMilliseconds(result);
			}
			return true;
		}

		private string FormatMSAjaxDate(DateTime value)
		{
			if (value.Kind == DateTimeKind.Local)
			{
				value = value.ToUniversalTime();
			}
			long num = (long)value.Subtract(EcmaScriptEpoch).TotalMilliseconds;
			return "/Date(" + num + ")/";
		}
	}
}
namespace JsonFx.Serialization
{
	public interface IDataWriter
	{
		Encoding ContentEncoding { get; }

		IEnumerable<string> ContentType { get; }

		IEnumerable<string> FileExtension { get; }

		DataWriterSettings Settings { get; }

		void Write(object data, TextWriter output);

		string Write(object data);
	}
	public abstract class DataWriter<T> : IDataWriter
	{
		private readonly DataWriterSettings settings;

		public abstract Encoding ContentEncoding { get; }

		public abstract IEnumerable<string> ContentType { get; }

		public abstract IEnumerable<string> FileExtension { get; }

		public DataWriterSettings Settings => settings;

		protected DataWriter(DataWriterSettings settings)
		{
			if (settings == null)
			{
				throw new NullReferenceException("settings");
			}
			this.settings = settings;
		}

		public virtual void Write(object data, TextWriter output)
		{
			IObjectWalker<T> walker = GetWalker();
			if (walker == null)
			{
				throw new ArgumentNullException("walker");
			}
			ITextFormatter<T> formatter = GetFormatter();
			if (formatter == null)
			{
				throw new ArgumentNullException("formatter");
			}
			try
			{
				formatter.Format(walker.GetTokens(data), output);
			}
			catch (SerializationException)
			{
				throw;
			}
			catch (Exception ex2)
			{
				throw new SerializationException(ex2.Message, ex2);
			}
		}

		public virtual string Write(object data)
		{
			IObjectWalker<T> walker = GetWalker();
			if (walker == null)
			{
				throw new ArgumentNullException("walker");
			}
			ITextFormatter<T> formatter = GetFormatter();
			if (formatter == null)
			{
				throw new ArgumentNullException("formatter");
			}
			try
			{
				return formatter.Format(walker.GetTokens(data));
			}
			catch (SerializationException)
			{
				throw;
			}
			catch (Exception ex2)
			{
				throw new SerializationException(ex2.Message, ex2);
			}
		}

		protected abstract IObjectWalker<T> GetWalker();

		protected abstract ITextFormatter<T> GetFormatter();
	}
}
namespace JsonFx.Model
{
	public abstract class ModelWriter : DataWriter<ModelTokenType>
	{
		public override Encoding ContentEncoding => Encoding.UTF8;

		protected ModelWriter(DataWriterSettings settings)
			: base(settings)
		{
		}

		protected override IObjectWalker<ModelTokenType> GetWalker()
		{
			return new ModelWalker(base.Settings);
		}
	}
}
namespace JsonFx.Serialization
{
	public interface ITextFormattable<T>
	{
		void Format(ITextFormatter<T> formatter, TextWriter writer);
	}
}
namespace JsonFx.EcmaScript
{
	public class EcmaScriptIdentifier : ITextFormattable<ModelTokenType>
	{
		private readonly string identifier;

		public string Identifier => identifier;

		public EcmaScriptIdentifier()
			: this(null)
		{
		}

		public EcmaScriptIdentifier(string ident)
		{
			identifier = (string.IsNullOrEmpty(ident) ? string.Empty : VerifyIdentifier(ident, nested: true));
		}

		public static string VerifyIdentifier(string ident, bool nested)
		{
			return VerifyIdentifier(ident, nested, throwOnEmpty: true);
		}

		public static string VerifyIdentifier(string ident, bool nested, bool throwOnEmpty)
		{
			if (string.IsNullOrEmpty(ident))
			{
				if (throwOnEmpty)
				{
					throw new ArgumentException("Identifier is empty.");
				}
				return string.Empty;
			}
			ident = ident.Replace(" ", "");
			if (!IsValidIdentifier(ident, nested))
			{
				throw new ArgumentException("Identifier \"" + ident + "\" is not supported.");
			}
			return ident;
		}

		public static bool IsValidIdentifier(string ident, bool nested)
		{
			if (string.IsNullOrEmpty(ident))
			{
				return false;
			}
			if (nested)
			{
				string[] array = ident.Split(new char[1] { '.' });
				string[] array2 = array;
				foreach (string ident2 in array2)
				{
					if (!IsValidIdentifier(ident2, nested: false))
					{
						return false;
					}
				}
				return true;
			}
			if (IsReservedWord(ident))
			{
				return false;
			}
			bool flag = false;
			int j = 0;
			for (int length = ident.Length; j < length; j++)
			{
				char c = ident[j];
				if (!flag || c < '0' || c > '9')
				{
					if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_' && c != '$')
					{
						return false;
					}
					flag = true;
				}
			}
			return true;
		}

		private static bool IsReservedWord(string ident)
		{
			switch (ident)
			{
			case "null":
			case "false":
			case "true":
			case "break":
			case "case":
			case "catch":
			case "continue":
			case "debugger":
			case "default":
			case "delete":
			case "do":
			case "else":
			case "finally":
			case "for":
			case "function":
			case "if":
			case "in":
			case "instanceof":
			case "new":
			case "return":
			case "switch":
			case "this":
			case "throw":
			case "try":
			case "typeof":
			case "var":
			case "void":
			case "while":
			case "with":
			case "abstract":
			case "boolean":
			case "byte":
			case "char":
			case "class":
			case "const":
			case "double":
			case "enum":
			case "export":
			case "extends":
			case "final":
			case "float":
			case "goto":
			case "implements":
			case "import":
			case "int":
			case "interface":
			case "long":
			case "native":
			case "package":
			case "private":
			case "protected":
			case "public":
			case "short":
			case "static":
			case "super":
			case "synchronized":
			case "throws":
			case "transient":
			case "volatile":
			case "let":
			case "yield":
				return true;
			default:
				return false;
			}
		}

		public static EcmaScriptIdentifier Parse(string value)
		{
			return new EcmaScriptIdentifier(value);
		}

		public static implicit operator string(EcmaScriptIdentifier ident)
		{
			if (ident == null)
			{
				return string.Empty;
			}
			return ident.identifier;
		}

		public static implicit operator EcmaScriptIdentifier(string ident)
		{
			return new EcmaScriptIdentifier(ident);
		}

		void ITextFormattable<ModelTokenType>.Format(ITextFormatter<ModelTokenType> formatter, TextWriter writer)
		{
			if (string.IsNullOrEmpty(identifier))
			{
				writer.Write("null");
			}
			else
			{
				writer.Write(identifier);
			}
		}

		public override string ToString()
		{
			return identifier;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is EcmaScriptIdentifier ecmaScriptIdentifier))
			{
				return base.Equals(obj);
			}
			if (string.IsNullOrEmpty(identifier) && string.IsNullOrEmpty(ecmaScriptIdentifier.identifier))
			{
				return true;
			}
			return StringComparer.Ordinal.Equals(identifier, ecmaScriptIdentifier.identifier);
		}

		public override int GetHashCode()
		{
			return StringComparer.Ordinal.GetHashCode(identifier);
		}
	}
}
namespace JsonFx.Serialization
{
	public interface ITextFormatter<T>
	{
		void Format(IEnumerable<Token<T>> tokens, TextWriter writer);

		string Format(IEnumerable<Token<T>> tokens);
	}
}
namespace JsonFx.Json
{
	public class JsonWriter : ModelWriter
	{
		public class JsonFormatter : ITextFormatter<ModelTokenType>
		{
			private readonly DataWriterSettings Settings;

			private bool encodeLessThan;

			public bool EncodeLessThan
			{
				get
				{
					return encodeLessThan;
				}
				set
				{
					encodeLessThan = value;
				}
			}

			public JsonFormatter(DataWriterSettings settings)
			{
				if (settings == null)
				{
					throw new ArgumentNullException("settings");
				}
				Settings = settings;
			}

			public string Format(IEnumerable<Token<ModelTokenType>> tokens)
			{
				using StringWriter stringWriter = new StringWriter();
				Format(tokens, stringWriter);
				return stringWriter.GetStringBuilder().ToString();
			}

			public void Format(IEnumerable<Token<ModelTokenType>> tokens, TextWriter writer)
			{
				if (tokens == null)
				{
					throw new ArgumentNullException("tokens");
				}
				bool prettyPrint = Settings.PrettyPrint;
				bool flag = false;
				bool flag2 = false;
				int num = 0;
				foreach (Token<ModelTokenType> token in tokens)
				{
					switch (token.TokenType)
					{
					case ModelTokenType.ArrayBegin:
						if (flag2)
						{
							writer.Write(',');
							if (prettyPrint)
							{
								WriteLine(writer, num);
							}
						}
						if (flag)
						{
							if (prettyPrint)
							{
								WriteLine(writer, ++num);
							}
							flag = false;
						}
						writer.Write('[');
						flag = true;
						flag2 = false;
						break;
					case ModelTokenType.ArrayEnd:
						if (flag)
						{
							flag = false;
						}
						else if (prettyPrint)
						{
							WriteLine(writer, --num);
						}
						writer.Write(']');
						flag2 = true;
						break;
					case ModelTokenType.Primitive:
					{
						if (flag2)
						{
							writer.Write(',');
							if (prettyPrint)
							{
								WriteLine(writer, num);
							}
						}
						if (flag)
						{
							if (prettyPrint)
							{
								WriteLine(writer, ++num);
							}
							flag = false;
						}
						Type type = ((token.Value == null) ? null : token.Value.GetType());
						TypeCode typeCode = Type.GetTypeCode(type);
						switch (typeCode)
						{
						case TypeCode.Boolean:
							writer.Write(true.Equals(token.Value) ? "true" : "false");
							break;
						case TypeCode.SByte:
						case TypeCode.Byte:
						case TypeCode.Int16:
						case TypeCode.UInt16:
						case TypeCode.Int32:
						case TypeCode.UInt32:
						case TypeCode.Int64:
						case TypeCode.UInt64:
						case TypeCode.Single:
						case TypeCode.Double:
						case TypeCode.Decimal:
							if (!type.IsEnum)
							{
								WriteNumber(writer, token.Value, typeCode);
								break;
							}
							goto default;
						case TypeCode.Empty:
						case TypeCode.DBNull:
							writer.Write("null");
							break;
						default:
							if (token.Value is ITextFormattable<ModelTokenType> textFormattable)
							{
								textFormattable.Format(this, writer);
							}
							else
							{
								WritePrimitive(writer, token.Value);
							}
							break;
						}
						flag2 = true;
						break;
					}
					case ModelTokenType.ObjectBegin:
						if (flag2)
						{
							writer.Write(',');
							if (prettyPrint)
							{
								WriteLine(writer, num);
							}
						}
						if (flag)
						{
							if (prettyPrint)
							{
								WriteLine(writer, ++num);
							}
							flag = false;
						}
						writer.Write('{');
						flag = true;
						flag2 = false;
						break;
					case ModelTokenType.ObjectEnd:
						if (flag)
						{
							flag = false;
						}
						else if (prettyPrint)
						{
							WriteLine(writer, --num);
						}
						writer.Write('}');
						flag2 = true;
						break;
					case ModelTokenType.Property:
						if (flag2)
						{
							writer.Write(',');
							if (prettyPrint)
							{
								WriteLine(writer, num);
							}
						}
						if (flag)
						{
							if (prettyPrint)
							{
								WriteLine(writer, ++num);
							}
							flag = false;
						}
						WritePropertyName(writer, token.Name.LocalName);
						if (prettyPrint)
						{
							writer.Write(" ");
							writer.Write(':');
							writer.Write(" ");
						}
						else
						{
							writer.Write(':');
						}
						flag2 = false;
						break;
					default:
						throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})");
					}
				}
			}

			protected virtual void WritePrimitive(TextWriter writer, object value)
			{
				if (value is TimeSpan)
				{
					WriteNumber(writer, ((TimeSpan)value).Ticks, TypeCode.Int64);
				}
				else
				{
					WriteString(writer, FormatString(value));
				}
			}

			protected virtual void WritePropertyName(TextWriter writer, string propertyName)
			{
				WriteString(writer, FormatString(propertyName));
			}

			protected virtual void WriteNumber(TextWriter writer, object value, TypeCode typeCode)
			{
				bool flag = false;
				string value2;
				switch (typeCode)
				{
				case TypeCode.Byte:
					value2 = ((byte)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.Boolean:
					value2 = (true.Equals(value) ? "1" : "0");
					break;
				case TypeCode.Decimal:
					flag = true;
					value2 = ((decimal)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.Double:
				{
					double d = (double)value;
					if (double.IsNaN(d))
					{
						WriteNaN(writer);
						return;
					}
					if (double.IsInfinity(d))
					{
						if (double.IsNegativeInfinity(d))
						{
							WriteNegativeInfinity(writer);
						}
						else
						{
							WritePositiveInfinity(writer);
						}
						return;
					}
					value2 = d.ToString("r", CultureInfo.InvariantCulture);
					break;
				}
				case TypeCode.Int16:
					value2 = ((short)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.Int32:
					value2 = ((int)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.Int64:
					flag = true;
					value2 = ((long)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.SByte:
					value2 = ((sbyte)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.Single:
				{
					float f = (float)value;
					if (float.IsNaN(f))
					{
						WriteNaN(writer);
						return;
					}
					if (float.IsInfinity(f))
					{
						if (float.IsNegativeInfinity(f))
						{
							WriteNegativeInfinity(writer);
						}
						else
						{
							WritePositiveInfinity(writer);
						}
						return;
					}
					value2 = f.ToString("r", CultureInfo.InvariantCulture);
					break;
				}
				case TypeCode.UInt16:
					value2 = ((ushort)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.UInt32:
					flag = true;
					value2 = ((uint)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				case TypeCode.UInt64:
					flag = true;
					value2 = ((ulong)value).ToString("g", CultureInfo.InvariantCulture);
					break;
				default:
					throw new TokenException<ModelTokenType>(ModelGrammar.TokenPrimitive(value), "Invalid number token");
				}
				if (flag && InvalidIEEE754(Convert.ToDecimal(value)))
				{
					WriteString(writer, value2);
				}
				else
				{
					writer.Write(value2);
				}
			}

			protected virtual void WriteNegativeInfinity(TextWriter writer)
			{
				writer.Write("null");
			}

			protected virtual void WritePositiveInfinity(TextWriter writer)
			{
				writer.Write("null");
			}

			protected virtual void WriteNaN(TextWriter writer)
			{
				writer.Write("null");
			}

			protected virtual void WriteString(TextWriter writer, string value)
			{
				int num = 0;
				int length = value.Length;
				writer.Write('"');
				for (int i = num; i < length; i++)
				{
					char c = value[i];
					if (c <= '\u001f' || c >= '\u007f' || (encodeLessThan && c == '<') || c == '"' || c == '\\')
					{
						if (i > num)
						{
							writer.Write(value.Substring(num, i - num));
						}
						num = i + 1;
						switch (c)
						{
						case '"':
						case '\\':
							writer.Write('\\');
							writer.Write(c);
							break;
						case '\b':
							writer.Write("\\b");
							break;
						case '\f':
							writer.Write("\\f");
							break;
						case '\n':
							writer.Write("\\n");
							break;
						case '\r':
							writer.Write("\\r");
							break;
						case '\t':
							writer.Write("\\t");
							break;
						default:
							writer.Write("\\u");
							writer.Write(CharUtility.ConvertToUtf32(value, i).ToString("X4"));
							break;
						}
					}
				}
				if (length > num)
				{
					writer.Write(value.Substring(num, length - num));
				}
				writer.Write('"');
			}

			private void WriteLine(TextWriter writer, int depth)
			{
				writer.Write(Settings.NewLine);
				for (int i = 0; i < depth; i++)
				{
					writer.Write(Settings.Tab);
				}
			}

			protected virtual string FormatString(object value)
			{
				if (value is Enum)
				{
					return FormatEnum((Enum)value);
				}
				return Token<ModelTokenType>.ToString(value);
			}

			private string FormatEnum(Enum value)
			{
				Type type = value.GetType();
				IDictionary<Enum, string> dictionary = Settings.Resolver.LoadEnumMaps(type);
				if (type.IsDefined(typeof(FlagsAttribute), inherit: true) && !Enum.IsDefined(type, value))
				{
					Enum[] flagList = GetFlagList(type, value);
					string[] array = new string[flagList.Length];
					for (int i = 0; i < flagList.Length; i++)
					{
						if (!dictionary.TryGetValue(flagList[i], out array[i]) || string.IsNullOrEmpty(array[i]))
						{
							array[i] = flagList[i].ToString("f");
						}
					}
					return string.Join(", ", array);
				}
				if (!dictionary.TryGetValue(value, out var value2) || string.IsNullOrEmpty(value2))
				{
					return value.ToString("f");
				}
				return value2;
			}

			private static Enum[] GetFlagList(Type enumType, object value)
			{
				ulong num = Convert.ToUInt64(value);
				Array values = Enum.GetValues(enumType);
				List<Enum> list = new List<Enum>(values.Length);
				if (num == 0)
				{
					list.Add((Enum)Convert.ChangeType(value, enumType, CultureInfo.InvariantCulture));
					return list.ToArray();
				}
				for (int num2 = values.Length - 1; num2 >= 0; num2--)
				{
					ulong num3 = Convert.ToUInt64(values.GetValue(num2));
					if ((num2 != 0 || num3 != 0) && (num & num3) == num3)
					{
						num -= num3;
						list.Add(values.GetValue(num2) as Enum);
					}
				}
				if (num != 0)
				{
					list.Add(Enum.ToObject(enumType, num) as Enum);
				}
				return list.ToArray();
			}

			protected virtual bool InvalidIEEE754(decimal value)
			{
				try
				{
					return (decimal)decimal.ToDouble(value) != value;
				}
				catch
				{
					return true;
				}
			}
		}

		private const string ErrorUnexpectedToken = "Unexpected token ({0})";

		private readonly string[] ContentTypes;

		public override IEnumerable<string> ContentType
		{
			get
			{
				if (ContentTypes != null)
				{
					try
					{
						string[] contentTypes = ContentTypes;
						for (int i = 0; i < contentTypes.Length; i++)
						{
							yield return contentTypes[i];
						}
						yield break;
					}
					finally
					{
					}
				}
				yield return "application/json";
				yield return "text/json";
				yield return "text/x-json";
			}
		}

		public override IEnumerable<string> FileExtension
		{
			get
			{
				yield return ".json";
			}
		}

		public JsonWriter()
			: base(new DataWriterSettings())
		{
		}

		public JsonWriter(DataWriterSettings settings)
			: base((settings != null) ? settings : new DataWriterSettings())
		{
		}

		public JsonWriter(DataWriterSettings settings, params string[] contentTypes)
			: base((settings != null) ? settings : new DataWriterSettings())
		{
			if (contentTypes == null)
			{
				throw new NullReferenceException("contentTypes");
			}
			ContentTypes = new string[contentTypes.Length];
			Array.Copy(contentTypes, ContentTypes, contentTypes.Length);
		}

		protected override ITextFormatter<ModelTokenType> GetFormatter()
		{
			return new JsonFormatter(base.Settings);
		}
	}
}
namespace JsonFx.EcmaScript
{
	public class EcmaScriptFormatter : JsonWriter.JsonFormatter
	{
		private const string EcmaScriptDateCtor1 = "new Date({0})";

		private const string EcmaScriptDateCtor7 = "new Date({0:0000},{1},{2},{3},{4},{5},{6})";

		private const string EmptyRegExpLiteral = "(?:)";

		private const char RegExpLiteralDelim = '/';

		private const char OperatorCharEscape = '\\';

		private const string NamespaceDelim = ".";

		private const string RootDeclarationDebug = "\r\n/* namespace {1} */\r\nvar {0};";

		private const string RootDeclaration = "var {0};";

		private const string NamespaceCheck = "if(\"undefined\"===typeof {0}){{{0}={{}};}}";

		private const string NamespaceCheckDebug = "\r\nif (\"undefined\" === typeof {0}) {{\r\n\t{0} = {{}};\r\n}}";

		private static readonly DateTime EcmaScriptEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

		private static readonly char[] NamespaceDelims = new char[1] { '.' };

		private static readonly IList<string> BrowserObjects = new List<string>(new string[10] { "console", "document", "event", "frames", "history", "location", "navigator", "opera", "screen", "window" });

		public EcmaScriptFormatter(DataWriterSettings settings)
			: base(settings)
		{
		}

		public static bool WriteNamespaceDeclaration(TextWriter writer, string ident, List<string> namespaces, bool prettyPrint)
		{
			if (string.IsNullOrEmpty(ident))
			{
				return false;
			}
			if (namespaces == null)
			{
				namespaces = new List<string>();
			}
			string[] array = ident.Split(NamespaceDelims, StringSplitOptions.RemoveEmptyEntries);
			string text = array[0];
			bool flag = false;
			for (int i = 0; i < array.Length - 1; i++)
			{
				flag = true;
				if (i > 0)
				{
					text += ".";
					text += array[i];
				}
				if (namespaces.Contains(text) || BrowserObjects.Contains(text))
				{
					continue;
				}
				namespaces.Add(text);
				if (i == 0)
				{
					if (prettyPrint)
					{
						writer.Write("\r\n/* namespace {1} */\r\nvar {0};", text, string.Join(".", array, 0, array.Length - 1));
					}
					else
					{
						writer.Write("var {0};", text);
					}
				}
				if (prettyPrint)
				{
					writer.WriteLine("\r\nif (\"undefined\" === typeof {0}) {{\r\n\t{0} = {{}};\r\n}}", text);
				}
				else
				{
					writer.Write("if(\"undefined\"===typeof {0}){{{0}={{}};}}", text);
				}
			}
			if (prettyPrint && flag)
			{
				writer.WriteLine();
			}
			return flag;
		}

		protected override void WriteNaN(TextWriter writer)
		{
			writer.Write("NaN");
		}

		protected override void WriteNegativeInfinity(TextWriter writer)
		{
			writer.Write('-');
			writer.Write("Infinity");
		}

		protected override void WritePositiveInfinity(TextWriter writer)
		{
			writer.Write("Infinity");
		}

		protected override void WritePrimitive(TextWriter writer, object value)
		{
			if (value is DateTime)
			{
				WriteEcmaScriptDate(writer, (DateTime)value);
			}
			else if (value is Regex)
			{
				WriteEcmaScriptRegExp(writer, (Regex)value);
			}
			else
			{
				base.WritePrimitive(writer, value);
			}
		}

		protected override void WritePropertyName(TextWriter writer, string propertyName)
		{
			if (EcmaScriptIdentifier.IsValidIdentifier(propertyName, nested: false))
			{
				writer.Write(propertyName);
			}
			else
			{
				base.WritePropertyName(writer, propertyName);
			}
		}

		public static void WriteEcmaScriptDate(TextWriter writer, DateTime value)
		{
			if (value.Kind == DateTimeKind.Unspecified)
			{
				writer.Write("new Date({0:0000},{1},{2},{3},{4},{5},{6})", value.Year, value.Month - 1, value.Day, value.Hour, value.Minute, value.Second, value.Millisecond);
			}
			else
			{
				if (value.Kind == DateTimeKind.Local)
				{
					value = value.ToUniversalTime();
				}
				long num = (long)value.Subtract(EcmaScriptEpoch).TotalMilliseconds;
				writer.Write("new Date({0})", num);
			}
		}

		public static void WriteEcmaScriptRegExp(TextWriter writer, Regex regex)
		{
			WriteEcmaScriptRegExp(writer, regex, isGlobal: false);
		}

		public static void WriteEcmaScriptRegExp(TextWriter writer, Regex regex, bool isGlobal)
		{
			if (regex == null)
			{
				writer.Write("null");
				return;
			}
			string text = regex.ToString();
			if (string.IsNullOrEmpty(text))
			{
				text = "(?:)";
			}
			string text2 = (isGlobal ? "g" : "");
			switch (regex.Options & (RegexOptions.IgnoreCase | RegexOptions.Multiline))
			{
			case RegexOptions.IgnoreCase:
				text2 += "i";
				break;
			case RegexOptions.Multiline:
				text2 += "m";
				break;
			case RegexOptions.IgnoreCase | RegexOptions.Multiline:
				text2 += "im";
				break;
			}
			writer.Write('/');
			int length = text.Length;
			int num = 0;
			for (int i = num; i < length; i++)
			{
				char c = text[i];
				if (c == '/')
				{
					writer.Write(text.Substring(num, i - num));
					num = i + 1;
					writer.Write('\\');
					writer.Write(text[i]);
				}
			}
			writer.Write(text.Substring(num, length - num));
			writer.Write('/');
			writer.Write(text2);
		}
	}
}
namespace JsonFx.Html
{
	public interface IHtmlFilterStrategy
	{
		bool FilterTag(DataName tag, MarkupTokenType type, HtmlTaxonomy taxonomy);

		bool FilterAttribute(DataName tag, DataName attribute, ref object value);

		bool FilterStyle(DataName tag, string style, ref object value);

		bool FilterLiteral(ref object value);
	}
	public class HtmlFilter
	{
		private static bool VoidTagRequired(string tag)
		{
			switch (tag)
			{
			case "area":
			case "base":
			case "basefont":
			case "br":
			case "col":
			case "frame":
			case "hr":
			case "img":
			case "input":
			case "isindex":
			case "keygen":
			case "link":
			case "meta":
			case "param":
			case "source":
			case "wbr":
				return true;
			default:
				return false;
			}
		}

		private static bool CloseTagOptional(string tag)
		{
			switch (tag)
			{
			case "body":
			case "colgroup":
			case "dd":
			case "dt":
			case "embed":
			case "head":
			case "html":
			case "li":
			case "option":
			case "p":
			case "tbody":
			case "td":
			case "tfoot":
			case "th":
			case "thead":
			case "tr":
				return true;
			default:
				return false;
			}
		}

		private static HtmlTaxonomy GetTaxonomy(string tag)
		{
			switch (tag)
			{
			case "a":
			case "abbr":
			case "acronym":
			case "area":
			case "bdo":
			case "cite":
			case "code":
			case "dfn":
			case "em":
			case "isindex":
			case "kbd":
			case "map":
			case "q":
			case "samp":
			case "span":
			case "strong":
			case "time":
			case "var":
			case "wbr":
				return HtmlTaxonomy.Inline;
			case "audio":
			case "bgsound":
			case "img":
			case "sound":
			case "source":
				return HtmlTaxonomy.Inline | HtmlTaxonomy.Media;
			case "canvas":
			case "math":
			case "svg":
			case "video":
				return HtmlTaxonomy.Block | HtmlTaxonomy.Media;
			case "b":
			case "big":
			case "blink":
			case "figcaption":
			case "font":
			case "i":
			case "marquee":
			case "mark":
			case "rp":
			case "rt":
			case "ruby":
			case "s":
			case "small":
			case "strike":
			case "sub":
			case "sup":
			case "tt":
			case "u":
				return HtmlTaxonomy.Inline | HtmlTaxonomy.Style;
			case "address":
			case "article":
			case "asside":
			case "blockquote":
			case "bq":
			case "br":
			case "center":
			case "del":
			case "details":
			case "div":
			case "figure":
			case "footer":
			case "h1":
			case "h2":
			case "h3":
			case "h4":
			case "h5":
			case "h6":
			case "header":
			case "hgroup":
			case "hr":
			case "ins":
			case "nav":
			case "nobr":
			case "p":
			case "pre":
			case "section":
			case "summary":
				return HtmlTaxonomy.Block;
			case "command":
			case "dl":
			case "dd":
			case "dir":
			case "dt":
			case "lh":
			case "li":
			case "menu":
			case "ol":
			case "ul":
				return HtmlTaxonomy.List;
			case "caption":
			case "col":
			case "colgroup":
			case "table":
			case "tbody":
			case "td":
			case "th":
			case "the