Decompiled source of LethalCompanyDe v1.0.4

BepInEx/core/Kuriki-LethalCompanyDe/XUnity.Common.dll

Decompiled a year ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Utils;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using XUnity.Common.Constants;
using XUnity.Common.Extensions;
using XUnity.Common.Logging;
using XUnity.Common.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("XUnity.AutoTranslator.Plugin.Core")]
[assembly: AssemblyCompany("gravydevsupreme")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Common dependencies shared between XUnity Auto Translator and Resource Redirector.")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("XUnity.Common")]
[assembly: AssemblyTitle("XUnity.Common")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
namespace XUnity.Common.Utilities
{
	public static class ArrayHelper
	{
		public static T[] Null<T>()
		{
			return null;
		}
	}
	public static class CabHelper
	{
		private static string CreateRandomCab()
		{
			return "CAB-" + Guid.NewGuid().ToString("N");
		}

		public static void RandomizeCab(byte[] assetBundleData)
		{
			string @string = Encoding.ASCII.GetString(assetBundleData, 0, Math.Min(1024, assetBundleData.Length - 4));
			int num = @string.IndexOf("CAB-", StringComparison.Ordinal);
			if (num >= 0)
			{
				int num2 = @string.Substring(num).IndexOf('\0');
				if (num2 >= 0 && num2 <= 36)
				{
					string s = CreateRandomCab();
					Buffer.BlockCopy(Encoding.ASCII.GetBytes(s), 36 - num2, assetBundleData, num, num2);
				}
			}
		}

		public static void RandomizeCabWithAnyLength(byte[] assetBundleData)
		{
			FindAndReplaceCab("CAB-", 0, assetBundleData, 2048);
		}

		private static void FindAndReplaceCab(string ansiStringToStartWith, byte byteToEndWith, byte[] data, int maxIterations = -1)
		{
			int num = Math.Min(data.Length, maxIterations);
			if (num == -1)
			{
				num = data.Length;
			}
			int num2 = 0;
			int length = ansiStringToStartWith.Length;
			string text = Guid.NewGuid().ToString("N");
			int num3 = 0;
			for (int i = 0; i < num; i++)
			{
				char c = (char)data[i];
				if (num2 == length)
				{
					while (data[i] != byteToEndWith && i < num)
					{
						if (num3 >= text.Length)
						{
							num3 = 0;
							text = Guid.NewGuid().ToString("N");
						}
						data[i++] = (byte)text[num3++];
					}
					break;
				}
				num2 = ((c == ansiStringToStartWith[num2]) ? (num2 + 1) : 0);
			}
		}
	}
	internal static class CecilFastReflectionHelper
	{
		private static readonly Type[] DynamicMethodDelegateArgs = new Type[2]
		{
			typeof(object),
			typeof(object[])
		};

		public static FastReflectionDelegate CreateFastDelegate(MethodBase method, bool directBoxValueAccess, bool forceNonVirtcall)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: 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_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: 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_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + method.DeclaringType.FullName + "." + method.Name + ">", typeof(object), DynamicMethodDelegateArgs);
			ILProcessor iLProcessor = val.GetILProcessor();
			ParameterInfo[] parameters = method.GetParameters();
			bool flag = true;
			if (!method.IsStatic)
			{
				iLProcessor.Emit(OpCodes.Ldarg_0);
				if (method.DeclaringType.IsValueType)
				{
					Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, method.DeclaringType);
				}
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				Type type = parameters[i].ParameterType;
				bool isByRef = type.IsByRef;
				if (isByRef)
				{
					type = type.GetElementType();
				}
				bool isValueType = type.IsValueType;
				if (isByRef && isValueType && !directBoxValueAccess)
				{
					iLProcessor.Emit(OpCodes.Ldarg_1);
					iLProcessor.Emit(OpCodes.Ldc_I4, i);
				}
				iLProcessor.Emit(OpCodes.Ldarg_1);
				iLProcessor.Emit(OpCodes.Ldc_I4, i);
				if (isByRef && !isValueType)
				{
					Extensions.Emit(iLProcessor, OpCodes.Ldelema, typeof(object));
					continue;
				}
				iLProcessor.Emit(OpCodes.Ldelem_Ref);
				if (!isValueType)
				{
					continue;
				}
				if (!isByRef || !directBoxValueAccess)
				{
					Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, type);
					if (isByRef)
					{
						Extensions.Emit(iLProcessor, OpCodes.Box, type);
						iLProcessor.Emit(OpCodes.Dup);
						Extensions.Emit(iLProcessor, OpCodes.Unbox, type);
						if (flag)
						{
							flag = false;
							val.Definition.Body.Variables.Add(new VariableDefinition((TypeReference)new PinnedType((TypeReference)new PointerType(((MemberReference)val.Definition).Module.TypeSystem.Void))));
						}
						iLProcessor.Emit(OpCodes.Stloc_0);
						iLProcessor.Emit(OpCodes.Stelem_Ref);
						iLProcessor.Emit(OpCodes.Ldloc_0);
					}
				}
				else
				{
					Extensions.Emit(iLProcessor, OpCodes.Unbox, type);
				}
			}
			if (method.IsConstructor)
			{
				Extensions.Emit(iLProcessor, OpCodes.Newobj, (MethodBase)(method as ConstructorInfo));
			}
			else if (method.IsFinal || !method.IsVirtual || forceNonVirtcall)
			{
				Extensions.Emit(iLProcessor, OpCodes.Call, (MethodBase)(method as MethodInfo));
			}
			else
			{
				Extensions.Emit(iLProcessor, OpCodes.Callvirt, (MethodBase)(method as MethodInfo));
			}
			Type type2 = (method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType);
			if ((object)type2 != typeof(void))
			{
				if (type2.IsValueType)
				{
					Extensions.Emit(iLProcessor, OpCodes.Box, type2);
				}
			}
			else
			{
				iLProcessor.Emit(OpCodes.Ldnull);
			}
			iLProcessor.Emit(OpCodes.Ret);
			return (FastReflectionDelegate)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(FastReflectionDelegate));
		}

		public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match return type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + typeof(T).FullName + ".Get_" + fieldInfo.Name + ">", typeof(F), new Type[1] { typeof(T) });
			ILProcessor iLProcessor = val.GetILProcessor();
			if (!fieldInfo.IsStatic)
			{
				iLProcessor.Emit(OpCodes.Ldarg_0);
				Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			Extensions.Emit(iLProcessor, fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
			if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
			{
				Extensions.Emit(iLProcessor, OpCodes.Box, fieldInfo.FieldType);
			}
			iLProcessor.Emit(OpCodes.Ret);
			return (Func<T, F>)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(Func<T, F>));
		}

		public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: 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_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match argument type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + typeof(T).FullName + ".Set_" + fieldInfo.Name + ">", (Type)null, new Type[2]
			{
				typeof(T),
				typeof(F)
			});
			ILProcessor iLProcessor = val.GetILProcessor();
			if (!fieldInfo.IsStatic)
			{
				iLProcessor.Emit(OpCodes.Ldarg_0);
				Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			iLProcessor.Emit(OpCodes.Ldarg_1);
			if ((object)fieldInfo.FieldType != typeof(F))
			{
				if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
				{
					if (fieldInfo.FieldType.IsValueType)
					{
						Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, fieldInfo.FieldType);
					}
					else
					{
						Extensions.Emit(iLProcessor, OpCodes.Box, fieldInfo.FieldType);
					}
				}
				else
				{
					Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.FieldType);
				}
			}
			Extensions.Emit(iLProcessor, fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
			iLProcessor.Emit(OpCodes.Ret);
			return (Action<T, F>)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(Action<T, F>));
		}
	}
	public static class CustomFastReflectionHelper
	{
		private struct FastReflectionDelegateKey
		{
			public MethodBase Method { get; }

			public bool DirectBoxValueAccess { get; }

			public bool ForceNonVirtCall { get; }

			public FastReflectionDelegateKey(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
			{
				Method = method;
				DirectBoxValueAccess = directBoxValueAccess;
				ForceNonVirtCall = forceNonVirtCall;
			}

			public override bool Equals(object obj)
			{
				if (obj is FastReflectionDelegateKey fastReflectionDelegateKey && EqualityComparer<MethodBase>.Default.Equals(Method, fastReflectionDelegateKey.Method) && DirectBoxValueAccess == fastReflectionDelegateKey.DirectBoxValueAccess)
				{
					return ForceNonVirtCall == fastReflectionDelegateKey.ForceNonVirtCall;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return ((1017116076 * -1521134295 + EqualityComparer<MethodBase>.Default.GetHashCode(Method)) * -1521134295 + DirectBoxValueAccess.GetHashCode()) * -1521134295 + ForceNonVirtCall.GetHashCode();
			}
		}

		private static readonly Dictionary<FastReflectionDelegateKey, FastReflectionDelegate> MethodCache = new Dictionary<FastReflectionDelegateKey, FastReflectionDelegate>();

		public static FastReflectionDelegate CreateFastDelegate(this MethodBase method, bool directBoxValueAccess = true, bool forceNonVirtCall = false)
		{
			FastReflectionDelegateKey key = new FastReflectionDelegateKey(method, directBoxValueAccess, forceNonVirtCall);
			if (MethodCache.TryGetValue(key, out var value))
			{
				return value;
			}
			value = (((object)ClrTypes.DynamicMethodDefinition == null) ? GetFastDelegateForSRE(method, directBoxValueAccess, forceNonVirtCall) : GetFastDelegateForCecil(method, directBoxValueAccess, forceNonVirtCall));
			MethodCache.Add(key, value);
			return value;
		}

		public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)ClrTypes.DynamicMethodDefinition != null)
			{
				return CreateFastFieldGetterForCecil<T, F>(fieldInfo);
			}
			return CreateFastFieldGetterForSRE<T, F>(fieldInfo);
		}

		public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)ClrTypes.DynamicMethodDefinition != null)
			{
				return CreateFastFieldSetterForCecil<T, F>(fieldInfo);
			}
			return CreateFastFieldSetterForSRE<T, F>(fieldInfo);
		}

		private static FastReflectionDelegate GetFastDelegateForCecil(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
		{
			try
			{
				return CecilFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
			}
			catch (Exception e)
			{
				try
				{
					XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
					return ReflectionEmitFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
				}
				catch (Exception e2)
				{
					XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
					return (object target, object[] args) => method.Invoke(target, args);
				}
			}
		}

		private static Func<T, F> CreateFastFieldGetterForCecil<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return CecilFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				try
				{
					XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
					return ReflectionEmitFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
				}
				catch (Exception e2)
				{
					XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
					return (T target) => (F)fieldInfo.GetValue(target);
				}
			}
		}

		private static Action<T, F> CreateFastFieldSetterForCecil<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return CecilFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				try
				{
					XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
					return ReflectionEmitFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
				}
				catch (Exception e2)
				{
					XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
					return delegate(T target, F value)
					{
						fieldInfo.SetValue(target, value);
					};
				}
			}
		}

		private static FastReflectionDelegate GetFastDelegateForSRE(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
		{
			try
			{
				return ReflectionEmitFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
			}
			catch (Exception e)
			{
				XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
				return (object target, object[] args) => method.Invoke(target, args);
			}
		}

		private static Func<T, F> CreateFastFieldGetterForSRE<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return ReflectionEmitFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
				return (T target) => (F)fieldInfo.GetValue(target);
			}
		}

		private static Action<T, F> CreateFastFieldSetterForSRE<T, F>(FieldInfo fieldInfo)
		{
			try
			{
				return ReflectionEmitFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
			}
			catch (Exception e)
			{
				XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
				return delegate(T target, F value)
				{
					fieldInfo.SetValue(target, value);
				};
			}
		}
	}
	public static class DiacriticHelper
	{
		public static string RemoveAllDiacritics(this string input)
		{
			return new string((from c in input.SafeNormalize(NormalizationForm.FormD)
				where CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark
				select c).ToArray()).SafeNormalize();
		}

		private static string SafeNormalize(this string input, NormalizationForm normalizationForm = NormalizationForm.FormC)
		{
			return ReplaceNonCharacters(input, '?').Normalize(normalizationForm);
		}

		private static string ReplaceNonCharacters(string input, char replacement)
		{
			StringBuilder stringBuilder = new StringBuilder(input.Length);
			for (int i = 0; i < input.Length; i++)
			{
				if (char.IsSurrogatePair(input, i))
				{
					int num = char.ConvertToUtf32(input, i);
					i++;
					if (IsValidCodePoint(num))
					{
						stringBuilder.Append(char.ConvertFromUtf32(num));
					}
					else
					{
						stringBuilder.Append(replacement);
					}
				}
				else
				{
					char c = input[i];
					if (IsValidCodePoint(c))
					{
						stringBuilder.Append(c);
					}
					else
					{
						stringBuilder.Append(replacement);
					}
				}
			}
			return stringBuilder.ToString();
		}

		private static bool IsValidCodePoint(int point)
		{
			if (point >= 64976)
			{
				if (point >= 65008 && (point & 0xFFFF) != 65535 && (point & 0xFFFE) != 65534)
				{
					return point <= 1114111;
				}
				return false;
			}
			return true;
		}
	}
	public static class ExpressionHelper
	{
		public static Delegate CreateTypedFastInvoke(MethodBase method)
		{
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			return CreateTypedFastInvokeUnchecked(method);
		}

		public static Delegate CreateTypedFastInvokeUnchecked(MethodBase method)
		{
			if ((object)method == null)
			{
				return null;
			}
			if (method.IsGenericMethod)
			{
				throw new ArgumentException("The provided method must not be generic.", "method");
			}
			if (method is MethodInfo methodInfo)
			{
				Expression[] arguments;
				if (method.IsStatic)
				{
					ParameterExpression[] array = (from p in methodInfo.GetParameters()
						select Expression.Parameter(p.ParameterType, p.Name)).ToArray();
					arguments = array;
					return Expression.Lambda(Expression.Call(null, methodInfo, arguments), array).Compile();
				}
				List<ParameterExpression> list = (from p in methodInfo.GetParameters()
					select Expression.Parameter(p.ParameterType, p.Name)).ToList();
				list.Insert(0, Expression.Parameter(methodInfo.DeclaringType, "instance"));
				ParameterExpression instance = list[0];
				arguments = list.Skip(1).ToArray();
				return Expression.Lambda(Expression.Call(instance, methodInfo, arguments), list.ToArray()).Compile();
			}
			if (method is ConstructorInfo constructorInfo)
			{
				ParameterExpression[] array2 = (from p in constructorInfo.GetParameters()
					select Expression.Parameter(p.ParameterType, p.Name)).ToArray();
				Expression[] arguments = array2;
				return Expression.Lambda(Expression.New(constructorInfo, arguments), array2).Compile();
			}
			throw new ArgumentException("method", "This method only supports MethodInfo and ConstructorInfo.");
		}
	}
	public static class ExtensionDataHelper
	{
		private static readonly object Sync;

		private static readonly WeakDictionary<object, object> WeakDynamicFields;

		public static int WeakReferenceCount
		{
			get
			{
				lock (Sync)
				{
					return WeakDynamicFields.Count;
				}
			}
		}

		static ExtensionDataHelper()
		{
			Sync = new object();
			WeakDynamicFields = new WeakDictionary<object, object>();
			MaintenanceHelper.AddMaintenanceFunction(Cull, 12);
		}

		public static void SetExtensionData<T>(this object obj, T t)
		{
			lock (Sync)
			{
				if (WeakDynamicFields.TryGetValue(obj, out var value))
				{
					if (value is Dictionary<Type, object> dictionary)
					{
						dictionary[typeof(T)] = t;
						return;
					}
					Dictionary<Type, object> dictionary2 = new Dictionary<Type, object>();
					dictionary2.Add(value.GetType(), value);
					dictionary2[typeof(T)] = t;
					WeakDynamicFields[obj] = dictionary2;
				}
				else
				{
					WeakDynamicFields[obj] = t;
				}
			}
		}

		public static T GetOrCreateExtensionData<T>(this object obj) where T : new()
		{
			if (obj == null)
			{
				return default(T);
			}
			lock (Sync)
			{
				if (WeakDynamicFields.TryGetValue(obj, out var value))
				{
					if (value is Dictionary<Type, object> dictionary)
					{
						if (dictionary.TryGetValue(typeof(T), out value))
						{
							return (T)value;
						}
						T val = new T();
						dictionary[typeof(T)] = val;
						return val;
					}
					if (!(value is T result))
					{
						Dictionary<Type, object> dictionary2 = new Dictionary<Type, object>();
						dictionary2.Add(value.GetType(), value);
						T val2 = new T();
						dictionary2[typeof(T)] = val2;
						WeakDynamicFields[obj] = dictionary2;
						return val2;
					}
					return result;
				}
				T val3 = new T();
				WeakDynamicFields[obj] = val3;
				return val3;
			}
		}

		public static T GetExtensionData<T>(this object obj)
		{
			if (obj == null)
			{
				return default(T);
			}
			lock (Sync)
			{
				if (WeakDynamicFields.TryGetValue(obj, out var value))
				{
					if (value is Dictionary<Type, object> dictionary && dictionary.TryGetValue(typeof(T), out value))
					{
						if (!(value is T result))
						{
							return default(T);
						}
						return result;
					}
					if (!(value is T result2))
					{
						return default(T);
					}
					return result2;
				}
			}
			return default(T);
		}

		public static void Cull()
		{
			lock (Sync)
			{
				WeakDynamicFields.RemoveCollectedEntries();
			}
		}

		public static List<KeyValuePair<object, object>> GetAllRegisteredObjects()
		{
			lock (Sync)
			{
				return IterateAllPairs().ToList();
			}
		}

		public static void Remove(object obj)
		{
			lock (Sync)
			{
				WeakDynamicFields.Remove(obj);
			}
		}

		private static IEnumerable<KeyValuePair<object, object>> IterateAllPairs()
		{
			foreach (KeyValuePair<object, object> kvp in WeakDynamicFields)
			{
				if (kvp.Value is Dictionary<Type, object> dictionary)
				{
					foreach (KeyValuePair<Type, object> item in dictionary)
					{
						yield return new KeyValuePair<object, object>(kvp.Key, item.Value);
					}
				}
				else
				{
					yield return kvp;
				}
			}
		}
	}
	public delegate object FastReflectionDelegate(object target, params object[] args);
	public static class HookingHelper
	{
		private static readonly MethodInfo PatchMethod12;

		private static readonly MethodInfo PatchMethod20;

		private static readonly object Harmony;

		private static bool _loggedHarmonyError;

		static HookingHelper()
		{
			PatchMethod12 = ClrTypes.HarmonyInstance?.GetMethod("Patch", new Type[4]
			{
				ClrTypes.MethodBase,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod
			});
			PatchMethod20 = ClrTypes.Harmony?.GetMethod("Patch", new Type[5]
			{
				ClrTypes.MethodBase,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod,
				ClrTypes.HarmonyMethod
			});
			_loggedHarmonyError = false;
			try
			{
				if ((object)ClrTypes.HarmonyInstance != null)
				{
					Harmony = ClrTypes.HarmonyInstance.GetMethod("Create", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[1] { "xunity.common.hookinghelper" });
				}
				else if ((object)ClrTypes.Harmony != null)
				{
					Harmony = ClrTypes.Harmony.GetConstructor(new Type[1] { typeof(string) }).Invoke(new object[1] { "xunity.common.hookinghelper" });
				}
				else
				{
					XuaLogger.Common.Error("An unexpected exception occurred during harmony initialization, likely caused by unknown Harmony version. Harmony hooks will be unavailable!");
				}
			}
			catch (Exception e)
			{
				XuaLogger.Common.Error(e, "An unexpected exception occurred during harmony initialization. Harmony hooks will be unavailable!");
			}
		}

		public static void PatchAll(IEnumerable<Type> types, bool forceExternHooks)
		{
			foreach (Type type in types)
			{
				PatchType(type, forceExternHooks);
			}
		}

		public static void PatchAll(IEnumerable<Type[]> types, bool forceMonoModHooks)
		{
			foreach (Type[] type in types)
			{
				for (int i = 0; i < type.Length && !PatchType(type[i], forceMonoModHooks); i++)
				{
				}
			}
		}

		public static bool PatchType(Type type, bool forceExternHooks)
		{
			MethodBase methodBase = null;
			IntPtr intPtr = IntPtr.Zero;
			try
			{
				if (Harmony == null && !_loggedHarmonyError)
				{
					_loggedHarmonyError = true;
					XuaLogger.Common.Warn("Harmony is not loaded or could not be initialized. Using fallback hooks instead.");
				}
				BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
				MethodInfo method = type.GetMethod("Prepare", bindingAttr);
				if ((object)method == null || (bool)method.Invoke(null, new object[1] { Harmony }))
				{
					try
					{
						methodBase = (MethodBase)(type.GetMethod("TargetMethod", bindingAttr)?.Invoke(null, new object[1] { Harmony }));
					}
					catch
					{
					}
					try
					{
						intPtr = ((IntPtr?)type.GetMethod("TargetMethodPointer", bindingAttr)?.Invoke(null, null)) ?? IntPtr.Zero;
					}
					catch
					{
					}
					if ((object)methodBase == null && intPtr == IntPtr.Zero)
					{
						if ((object)methodBase != null)
						{
							XuaLogger.Common.Warn("Could not hook '" + methodBase.DeclaringType.FullName + "." + methodBase.Name + "'. Likely due differences between different versions of the engine or text framework.");
						}
						else
						{
							XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
						}
						return false;
					}
					MethodInfo method2 = type.GetMethod("Prefix", bindingAttr);
					MethodInfo method3 = type.GetMethod("Postfix", bindingAttr);
					MethodInfo method4 = type.GetMethod("Finalizer", bindingAttr);
					if ((object)methodBase == null || forceExternHooks || Harmony == null || ((object)method2 == null && (object)method3 == null && (object)method4 == null))
					{
						return PatchWithExternHooks(type, methodBase, intPtr, forced: true);
					}
					if ((object)methodBase != null)
					{
						try
						{
							int? priority = type.GetCustomAttributes(typeof(HookingHelperPriorityAttribute), inherit: false).OfType<HookingHelperPriorityAttribute>().FirstOrDefault()?.priority;
							object obj3 = (((object)method2 != null) ? CreateHarmonyMethod(method2, priority) : null);
							object obj4 = (((object)method3 != null) ? CreateHarmonyMethod(method3, priority) : null);
							object obj5 = (((object)method4 != null) ? CreateHarmonyMethod(method4, priority) : null);
							if ((object)PatchMethod12 != null)
							{
								PatchMethod12.Invoke(Harmony, new object[4] { methodBase, obj3, obj4, null });
							}
							else
							{
								PatchMethod20.Invoke(Harmony, new object[5] { methodBase, obj3, obj4, null, obj5 });
							}
							XuaLogger.Common.Debug("Hooked " + methodBase.DeclaringType.FullName + "." + methodBase.Name + " through Harmony hooks.");
							return true;
						}
						catch (Exception e) when (((Func<bool>)delegate
						{
							// Could not convert BlockContainer to single expression
							System.Runtime.CompilerServices.Unsafe.SkipInit(out int num);
							if (e.FirstInnerExceptionOfType<PlatformNotSupportedException>() == null)
							{
								ArgumentException ex = e.FirstInnerExceptionOfType<ArgumentException>();
								num = ((ex != null && ex.Message?.Contains("no body") == true) ? 1 : 0);
							}
							else
							{
								num = 1;
							}
							return num != 0;
						}).Invoke())
						{
							return PatchWithExternHooks(type, methodBase, intPtr, forced: false);
						}
					}
					XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
				}
			}
			catch (Exception e2)
			{
				if ((object)methodBase != null)
				{
					XuaLogger.Common.Warn(e2, "An error occurred while patching property/method '" + methodBase.DeclaringType.FullName + "." + methodBase.Name + "'. Failing hook: '" + type.Name + "'.");
				}
				else
				{
					XuaLogger.Common.Warn(e2, "An error occurred while patching property/method. Failing hook: '" + type.Name + "'.");
				}
			}
			return false;
		}

		private static bool PatchWithExternHooks(Type type, MethodBase original, IntPtr originalPtr, bool forced)
		{
			BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			if ((object)ClrTypes.Imports != null)
			{
				if (originalPtr == IntPtr.Zero)
				{
					XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
					return false;
				}
				IntPtr? intPtr = type.GetMethod("ML_Detour", bindingAttr)?.MethodHandle.GetFunctionPointer();
				if (intPtr.HasValue && intPtr.Value != IntPtr.Zero)
				{
					ClrTypes.Imports.GetMethod("Hook", bindingAttr).Invoke(null, new object[2] { originalPtr, intPtr.Value });
					XuaLogger.Common.Debug("Hooked " + type.Name + " through MelonMod Imports.Hook method.");
					return true;
				}
				XuaLogger.Common.Warn("Could not hook '" + type.Name + "' because no detour method was found.");
			}
			else
			{
				if ((object)original == null)
				{
					XuaLogger.Common.Warn("Cannot hook '" + type.Name + "'. Could not locate the original method. Failing hook: '" + type.Name + "'.");
					return false;
				}
				if ((object)ClrTypes.Hook == null || (object)ClrTypes.NativeDetour == null)
				{
					XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. MonoMod hooks is not supported in this runtime as MonoMod is not loaded. Failing hook: '" + type.Name + "'.");
					return false;
				}
				object obj = type.GetMethod("Get_MM_Detour", bindingAttr)?.Invoke(null, null) ?? type.GetMethod("MM_Detour", bindingAttr);
				if (obj != null)
				{
					string text = "(managed)";
					object obj2;
					try
					{
						obj2 = ClrTypes.Hook.GetConstructor(new Type[2]
						{
							typeof(MethodBase),
							typeof(MethodInfo)
						}).Invoke(new object[2] { original, obj });
						obj2.GetType().GetMethod("Apply").Invoke(obj2, null);
					}
					catch (Exception e) when (((Func<bool>)delegate
					{
						// Could not convert BlockContainer to single expression
						System.Runtime.CompilerServices.Unsafe.SkipInit(out int num);
						if (e.FirstInnerExceptionOfType<NullReferenceException>() == null)
						{
							NotSupportedException ex = e.FirstInnerExceptionOfType<NotSupportedException>();
							num = ((ex != null && ex.Message?.Contains("Body-less") == true) ? 1 : 0);
						}
						else
						{
							num = 1;
						}
						return num != 0;
					}).Invoke())
					{
						text = "(native)";
						obj2 = ClrTypes.NativeDetour.GetConstructor(new Type[2]
						{
							typeof(MethodBase),
							typeof(MethodBase)
						}).Invoke(new object[2] { original, obj });
						obj2.GetType().GetMethod("Apply").Invoke(obj2, null);
					}
					type.GetMethod("MM_Init", bindingAttr)?.Invoke(null, new object[1] { obj2 });
					if (forced)
					{
						XuaLogger.Common.Debug("Hooked " + original.DeclaringType.FullName + "." + original.Name + " through forced MonoMod hooks. " + text);
					}
					else
					{
						XuaLogger.Common.Debug("Hooked " + original.DeclaringType.FullName + "." + original.Name + " through MonoMod hooks. " + text);
					}
					return true;
				}
				if (forced)
				{
					XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. Harmony is not supported in this runtime and no alternate MonoMod hook has been implemented. Failing hook: '" + type.Name + "'.");
				}
				else
				{
					XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. Harmony is not supported in this runtime and no alternate MonoMod hook has been implemented. Failing hook: '" + type.Name + "'.");
				}
			}
			return false;
		}

		private static object CreateHarmonyMethod(MethodInfo method, int? priority)
		{
			object obj = ClrTypes.HarmonyMethod.GetConstructor(new Type[1] { typeof(MethodInfo) }).Invoke(new object[1] { method });
			if (priority.HasValue)
			{
				(ClrTypes.HarmonyMethod.GetField("priority", BindingFlags.Instance | BindingFlags.Public) ?? ClrTypes.HarmonyMethod.GetField("prioritiy", BindingFlags.Instance | BindingFlags.Public)).SetValue(obj, priority.Value);
			}
			return obj;
		}
	}
	public class HookingHelperPriorityAttribute : Attribute
	{
		public int priority;

		public HookingHelperPriorityAttribute(int priority)
		{
			this.priority = priority;
		}
	}
	public static class HookPriority
	{
		public const int Last = 0;

		public const int VeryLow = 100;

		public const int Low = 200;

		public const int LowerThanNormal = 300;

		public const int Normal = 400;

		public const int HigherThanNormal = 500;

		public const int High = 600;

		public const int VeryHigh = 700;

		public const int First = 800;
	}
	public static class ListExtensions
	{
		public static void BinarySearchInsert<T>(this List<T> items, T item) where T : IComparable<T>
		{
			int num = items.BinarySearch(item);
			if (num < 0)
			{
				items.Insert(~num, item);
			}
			else
			{
				items.Insert(num, item);
			}
		}
	}
	public static class MaintenanceHelper
	{
		private class ActionRegistration
		{
			public Action Action { get; }

			public int Filter { get; }

			public ActionRegistration(Action action, int filter)
			{
				Action = action;
				Filter = filter;
			}
		}

		private static readonly object Sync = new object();

		private static readonly List<ActionRegistration> RegisteredActions = new List<ActionRegistration>();

		private static bool _initialized;

		public static void AddMaintenanceFunction(Action action, int filter)
		{
			lock (Sync)
			{
				if (!_initialized)
				{
					_initialized = true;
					StartMaintenance();
				}
				ActionRegistration item = new ActionRegistration(action, filter);
				RegisteredActions.Add(item);
			}
		}

		private static void StartMaintenance()
		{
			Thread thread = new Thread(MaintenanceLoop);
			thread.IsBackground = true;
			thread.Start();
		}

		private static void MaintenanceLoop(object state)
		{
			int num = 0;
			while (true)
			{
				lock (Sync)
				{
					foreach (ActionRegistration registeredAction in RegisteredActions)
					{
						if (num % registeredAction.Filter == 0)
						{
							try
							{
								registeredAction.Action();
							}
							catch (Exception e)
							{
								XuaLogger.Common.Error(e, "An unexpected error occurred during maintenance.");
							}
						}
					}
				}
				num++;
				Thread.Sleep(5000);
			}
		}
	}
	public static class Paths
	{
		private static string _gameRoot;

		public static string GameRoot
		{
			get
			{
				return _gameRoot ?? GetAndSetGameRoot();
			}
			set
			{
				_gameRoot = value;
			}
		}

		public static void Initialize()
		{
			GetAndSetGameRoot();
		}

		private static string GetAndSetGameRoot()
		{
			return _gameRoot = new DirectoryInfo(Application.dataPath).Parent.FullName;
		}
	}
	public static class ReflectionCache
	{
		private struct MemberLookupKey
		{
			public Type Type { get; set; }

			public string MemberName { get; set; }

			public MemberLookupKey(Type type, string memberName)
			{
				Type = type;
				MemberName = memberName;
			}

			public override bool Equals(object obj)
			{
				if (obj is MemberLookupKey memberLookupKey)
				{
					if ((object)Type == memberLookupKey.Type)
					{
						return MemberName == memberLookupKey.MemberName;
					}
					return false;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return Type.GetHashCode() + MemberName.GetHashCode();
			}
		}

		private static Dictionary<MemberLookupKey, CachedMethod> Methods = new Dictionary<MemberLookupKey, CachedMethod>();

		private static Dictionary<MemberLookupKey, CachedProperty> Properties = new Dictionary<MemberLookupKey, CachedProperty>();

		private static Dictionary<MemberLookupKey, CachedField> Fields = new Dictionary<MemberLookupKey, CachedField>();

		public static CachedMethod CachedMethod(this Type type, string name)
		{
			return type.CachedMethod(name, (Type[])null);
		}

		public static CachedMethod CachedMethod(this Type type, string name, params Type[] types)
		{
			MemberLookupKey key = new MemberLookupKey(type, name);
			if (!Methods.TryGetValue(key, out var value))
			{
				Type type2 = type;
				MethodInfo methodInfo = null;
				while ((object)methodInfo == null && (object)type2 != null)
				{
					methodInfo = ((types != null && types.Length != 0) ? type2.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, types, null) : type2.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
					type2 = type2.BaseType;
				}
				if ((object)methodInfo != null)
				{
					value = new CachedMethod(methodInfo);
				}
				Methods[key] = value;
			}
			return value;
		}

		public static CachedProperty CachedProperty(this Type type, string name)
		{
			MemberLookupKey key = new MemberLookupKey(type, name);
			if (!Properties.TryGetValue(key, out var value))
			{
				Type type2 = type;
				PropertyInfo propertyInfo = null;
				while ((object)propertyInfo == null && (object)type2 != null)
				{
					propertyInfo = type2.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					type2 = type2.BaseType;
				}
				if ((object)propertyInfo != null)
				{
					value = new CachedProperty(propertyInfo);
				}
				Properties[key] = value;
			}
			return value;
		}

		public static CachedField CachedField(this Type type, string name)
		{
			MemberLookupKey key = new MemberLookupKey(type, name);
			if (!Fields.TryGetValue(key, out var value))
			{
				Type type2 = type;
				FieldInfo fieldInfo = null;
				while ((object)fieldInfo == null && (object)type2 != null)
				{
					fieldInfo = type2.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					type2 = type2.BaseType;
				}
				if ((object)fieldInfo != null)
				{
					value = new CachedField(fieldInfo);
				}
				Fields[key] = value;
			}
			return value;
		}

		public static CachedField CachedFieldByIndex(this Type type, int index, Type fieldType, BindingFlags flags)
		{
			FieldInfo[] array = (from x in type.GetFields(flags)
				where (object)x.FieldType == fieldType
				select x).ToArray();
			if (index < array.Length)
			{
				return new CachedField(array[index]);
			}
			return null;
		}
	}
	public class CachedMethod
	{
		private static readonly object[] Args0 = new object[0];

		private static readonly object[] Args1 = new object[1];

		private static readonly object[] Args2 = new object[2];

		private FastReflectionDelegate _invoke;

		internal CachedMethod(MethodInfo method)
		{
			_invoke = method.CreateFastDelegate();
		}

		public object Invoke(object instance, object[] arguments)
		{
			return _invoke(instance, arguments);
		}

		public object Invoke(object instance)
		{
			return _invoke(instance, Args0);
		}

		public object Invoke(object instance, object arg1)
		{
			try
			{
				Args1[0] = arg1;
				return _invoke(instance, Args1);
			}
			finally
			{
				Args1[0] = null;
			}
		}

		public object Invoke(object instance, object arg1, object arg2)
		{
			try
			{
				Args2[0] = arg1;
				Args2[1] = arg2;
				return _invoke(instance, Args2);
			}
			finally
			{
				Args2[0] = null;
				Args2[1] = null;
			}
		}
	}
	public class CachedProperty
	{
		private static readonly object[] Args0 = new object[0];

		private static readonly object[] Args1 = new object[1];

		private FastReflectionDelegate _set;

		private FastReflectionDelegate _get;

		public Type PropertyType { get; }

		internal CachedProperty(PropertyInfo propertyInfo)
		{
			if (propertyInfo.CanRead)
			{
				_get = propertyInfo.GetGetMethod(nonPublic: true).CreateFastDelegate();
			}
			if (propertyInfo.CanWrite)
			{
				_set = propertyInfo.GetSetMethod(nonPublic: true).CreateFastDelegate();
			}
			PropertyType = propertyInfo.PropertyType;
		}

		public void Set(object instance, object[] arguments)
		{
			if (_set != null)
			{
				_set(instance, arguments);
			}
		}

		public void Set(object instance, object arg1)
		{
			if (_set == null)
			{
				return;
			}
			try
			{
				Args1[0] = arg1;
				_set(instance, Args1);
			}
			finally
			{
				Args1[0] = null;
			}
		}

		public object Get(object instance, object[] arguments)
		{
			if (_get == null)
			{
				return null;
			}
			return _get(instance, arguments);
		}

		public object Get(object instance)
		{
			if (_get == null)
			{
				return null;
			}
			return _get(instance, Args0);
		}
	}
	public class CachedField
	{
		private Func<object, object> _get;

		private Action<object, object> _set;

		public Type FieldType { get; }

		internal CachedField(FieldInfo fieldInfo)
		{
			_get = CustomFastReflectionHelper.CreateFastFieldGetter<object, object>(fieldInfo);
			_set = CustomFastReflectionHelper.CreateFastFieldSetter<object, object>(fieldInfo);
			FieldType = fieldInfo.FieldType;
		}

		public void Set(object instance, object value)
		{
			if (_set != null)
			{
				_set(instance, value);
			}
		}

		public object Get(object instance)
		{
			if (_get == null)
			{
				return null;
			}
			return _get(instance);
		}
	}
	internal static class ReflectionEmitFastReflectionHelper
	{
		private static readonly Type[] DynamicMethodDelegateArgs = new Type[2]
		{
			typeof(object),
			typeof(object[])
		};

		public static FastReflectionDelegate CreateFastDelegate(MethodBase method, bool directBoxValueAccess, bool forceNonVirtcall)
		{
			DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + method.DeclaringType.FullName + "." + method.Name + ">", typeof(object), DynamicMethodDelegateArgs, method.DeclaringType.Module, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			ParameterInfo[] parameters = method.GetParameters();
			bool flag = true;
			if (!method.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				if (method.DeclaringType.IsValueType)
				{
					iLGenerator.Emit(OpCodes.Unbox_Any, method.DeclaringType);
				}
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				Type type = parameters[i].ParameterType;
				bool isByRef = type.IsByRef;
				if (isByRef)
				{
					type = type.GetElementType();
				}
				bool isValueType = type.IsValueType;
				if (isByRef && isValueType && !directBoxValueAccess)
				{
					iLGenerator.Emit(OpCodes.Ldarg_1);
					iLGenerator.Emit(OpCodes.Ldc_I4, i);
				}
				iLGenerator.Emit(OpCodes.Ldarg_1);
				iLGenerator.Emit(OpCodes.Ldc_I4, i);
				if (isByRef && !isValueType)
				{
					iLGenerator.Emit(OpCodes.Ldelema, typeof(object));
					continue;
				}
				iLGenerator.Emit(OpCodes.Ldelem_Ref);
				if (!isValueType)
				{
					continue;
				}
				if (!isByRef || !directBoxValueAccess)
				{
					iLGenerator.Emit(OpCodes.Unbox_Any, type);
					if (isByRef)
					{
						iLGenerator.Emit(OpCodes.Box, type);
						iLGenerator.Emit(OpCodes.Dup);
						iLGenerator.Emit(OpCodes.Unbox, type);
						if (flag)
						{
							flag = false;
							throw new NotImplementedException("No idea how to implement this...");
						}
						iLGenerator.Emit(OpCodes.Stloc_0);
						iLGenerator.Emit(OpCodes.Stelem_Ref);
						iLGenerator.Emit(OpCodes.Ldloc_0);
					}
				}
				else
				{
					iLGenerator.Emit(OpCodes.Unbox, type);
				}
			}
			if (method.IsConstructor)
			{
				iLGenerator.Emit(OpCodes.Newobj, method as ConstructorInfo);
			}
			else if (method.IsFinal || !method.IsVirtual || forceNonVirtcall)
			{
				iLGenerator.Emit(OpCodes.Call, method as MethodInfo);
			}
			else
			{
				iLGenerator.Emit(OpCodes.Callvirt, method as MethodInfo);
			}
			Type type2 = (method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType);
			if ((object)type2 != typeof(void))
			{
				if (type2.IsValueType)
				{
					iLGenerator.Emit(OpCodes.Box, type2);
				}
			}
			else
			{
				iLGenerator.Emit(OpCodes.Ldnull);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (FastReflectionDelegate)dynamicMethod.CreateDelegate(typeof(FastReflectionDelegate));
		}

		public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match return type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + typeof(T).FullName + ".Get_" + fieldInfo.Name + ">", typeof(F), new Type[1] { typeof(T) }, fieldInfo.DeclaringType.Module, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!fieldInfo.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			iLGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
			if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
			{
				iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (Func<T, F>)dynamicMethod.CreateDelegate(typeof(Func<T, F>));
		}

		public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
		{
			if ((object)fieldInfo == null)
			{
				throw new ArgumentNullException("fieldInfo");
			}
			if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new ArgumentException("FieldInfo type does not match argument type.");
			}
			if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
			{
				throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
			}
			DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + typeof(T).FullName + ".Set_" + fieldInfo.Name + ">", null, new Type[2]
			{
				typeof(T),
				typeof(F)
			}, fieldInfo.DeclaringType.Module, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!fieldInfo.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
			}
			iLGenerator.Emit(OpCodes.Ldarg_1);
			if ((object)fieldInfo.FieldType != typeof(F))
			{
				if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
				{
					if (fieldInfo.FieldType.IsValueType)
					{
						iLGenerator.Emit(OpCodes.Unbox, fieldInfo.FieldType);
					}
					else
					{
						iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType);
					}
				}
				else
				{
					iLGenerator.Emit(OpCodes.Castclass, fieldInfo.FieldType);
				}
			}
			iLGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
			iLGenerator.Emit(OpCodes.Ret);
			return (Action<T, F>)dynamicMethod.CreateDelegate(typeof(Action<T, F>));
		}
	}
	public static class TimeHelper
	{
		public static float realtimeSinceStartup => Time.realtimeSinceStartup;
	}
	public class UnityObjectReferenceComparer : IEqualityComparer<object>
	{
		public static readonly UnityObjectReferenceComparer Default = new UnityObjectReferenceComparer();

		public new bool Equals(object x, object y)
		{
			return x == y;
		}

		public int GetHashCode(object obj)
		{
			return obj.GetHashCode();
		}
	}
	public class WeakReference<T> : WeakReference where T : class
	{
		public new T Target => (T)base.Target;

		public static WeakReference<T> Create(T target)
		{
			if (target == null)
			{
				return WeakNullReference<T>.Singleton;
			}
			return new WeakReference<T>(target);
		}

		protected WeakReference(T target)
			: base(target, trackResurrection: false)
		{
		}
	}
	internal class WeakNullReference<T> : WeakReference<T> where T : class
	{
		public static readonly WeakNullReference<T> Singleton = new WeakNullReference<T>();

		public override bool IsAlive => true;

		private WeakNullReference()
			: base((T)null)
		{
		}
	}
	internal sealed class WeakKeyReference<T> : WeakReference<T> where T : class
	{
		public readonly int HashCode;

		public WeakKeyReference(T key, WeakKeyComparer<T> comparer)
			: base(key)
		{
			HashCode = comparer.GetHashCode(key);
		}
	}
	internal sealed class WeakKeyComparer<T> : IEqualityComparer<object> where T : class
	{
		private IEqualityComparer<T> comparer;

		internal WeakKeyComparer(IEqualityComparer<T> comparer)
		{
			if (comparer == null)
			{
				comparer = EqualityComparer<T>.Default;
			}
			this.comparer = comparer;
		}

		public int GetHashCode(object obj)
		{
			if (obj is WeakKeyReference<T> weakKeyReference)
			{
				return weakKeyReference.HashCode;
			}
			return comparer.GetHashCode((T)obj);
		}

		public new bool Equals(object x, object y)
		{
			bool isDead;
			T target = GetTarget(x, out isDead);
			bool isDead2;
			T target2 = GetTarget(y, out isDead2);
			if (isDead)
			{
				if (!isDead2)
				{
					return false;
				}
				return x == y;
			}
			if (isDead2)
			{
				return false;
			}
			return comparer.Equals(target, target2);
		}

		private static T GetTarget(object obj, out bool isDead)
		{
			T result;
			if (obj is WeakKeyReference<T> weakKeyReference)
			{
				result = weakKeyReference.Target;
				isDead = !weakKeyReference.IsAlive;
			}
			else
			{
				result = (T)obj;
				isDead = false;
			}
			return result;
		}
	}
	public sealed class WeakDictionary<TKey, TValue> : BaseDictionary<TKey, TValue> where TKey : class
	{
		private Dictionary<object, TValue> dictionary;

		private WeakKeyComparer<TKey> comparer;

		public override int Count => dictionary.Count;

		public WeakDictionary()
			: this(0, (IEqualityComparer<TKey>)null)
		{
		}

		public WeakDictionary(int capacity)
			: this(capacity, (IEqualityComparer<TKey>)null)
		{
		}

		public WeakDictionary(IEqualityComparer<TKey> comparer)
			: this(0, comparer)
		{
		}

		public WeakDictionary(int capacity, IEqualityComparer<TKey> comparer)
		{
			this.comparer = new WeakKeyComparer<TKey>(comparer);
			dictionary = new Dictionary<object, TValue>(capacity, this.comparer);
		}

		public override void Add(TKey key, TValue value)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			WeakReference<TKey> key2 = new WeakKeyReference<TKey>(key, comparer);
			dictionary.Add(key2, value);
		}

		public override bool ContainsKey(TKey key)
		{
			return dictionary.ContainsKey(key);
		}

		public override bool Remove(TKey key)
		{
			return dictionary.Remove(key);
		}

		public override bool TryGetValue(TKey key, out TValue value)
		{
			if (dictionary.TryGetValue(key, out value))
			{
				return true;
			}
			value = default(TValue);
			return false;
		}

		protected override void SetValue(TKey key, TValue value)
		{
			WeakReference<TKey> key2 = new WeakKeyReference<TKey>(key, comparer);
			dictionary[key2] = value;
		}

		public override void Clear()
		{
			dictionary.Clear();
		}

		public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
		{
			foreach (KeyValuePair<object, TValue> item in dictionary)
			{
				WeakReference<TKey> obj = (WeakReference<TKey>)item.Key;
				TValue value = item.Value;
				TKey target = obj.Target;
				if (obj.IsAlive)
				{
					yield return new KeyValuePair<TKey, TValue>(target, value);
				}
			}
		}

		public void RemoveCollectedEntries()
		{
			List<object> list = null;
			foreach (KeyValuePair<object, TValue> item in dictionary)
			{
				WeakReference<TKey> weakReference = (WeakReference<TKey>)item.Key;
				if (!weakReference.IsAlive)
				{
					if (list == null)
					{
						list = new List<object>();
					}
					list.Add(weakReference);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (object item2 in list)
			{
				dictionary.Remove(item2);
			}
		}
	}
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
	public abstract class BaseDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
	{
		private abstract class Collection<T> : ICollection<T>, IEnumerable<T>, IEnumerable
		{
			protected readonly IDictionary<TKey, TValue> dictionary;

			public int Count => dictionary.Count;

			public bool IsReadOnly => true;

			protected Collection(IDictionary<TKey, TValue> dictionary)
			{
				this.dictionary = dictionary;
			}

			public void CopyTo(T[] array, int arrayIndex)
			{
				BaseDictionary<TKey, TValue>.Copy((ICollection<T>)this, array, arrayIndex);
			}

			public virtual bool Contains(T item)
			{
				using (IEnumerator<T> enumerator = GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						T current = enumerator.Current;
						if (EqualityComparer<T>.Default.Equals(current, item))
						{
							return true;
						}
					}
				}
				return false;
			}

			public IEnumerator<T> GetEnumerator()
			{
				foreach (KeyValuePair<TKey, TValue> item in dictionary)
				{
					yield return GetItem(item);
				}
			}

			protected abstract T GetItem(KeyValuePair<TKey, TValue> pair);

			public bool Remove(T item)
			{
				throw new NotSupportedException("Collection is read-only.");
			}

			public void Add(T item)
			{
				throw new NotSupportedException("Collection is read-only.");
			}

			public void Clear()
			{
				throw new NotSupportedException("Collection is read-only.");
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}
		}

		[DebuggerDisplay("Count = {Count}")]
		[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryKeyCollectionDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
		private class KeyCollection : Collection<TKey>
		{
			public KeyCollection(IDictionary<TKey, TValue> dictionary)
				: base(dictionary)
			{
			}

			protected override TKey GetItem(KeyValuePair<TKey, TValue> pair)
			{
				return pair.Key;
			}

			public override bool Contains(TKey item)
			{
				return dictionary.ContainsKey(item);
			}
		}

		[DebuggerDisplay("Count = {Count}")]
		[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryValueCollectionDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
		private class ValueCollection : Collection<TValue>
		{
			public ValueCollection(IDictionary<TKey, TValue> dictionary)
				: base(dictionary)
			{
			}

			protected override TValue GetItem(KeyValuePair<TKey, TValue> pair)
			{
				return pair.Value;
			}
		}

		private const string PREFIX = "System.Collections.Generic.Mscorlib_";

		private const string SUFFIX = ",mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089";

		private KeyCollection keys;

		private ValueCollection values;

		public abstract int Count { get; }

		public bool IsReadOnly => false;

		public ICollection<TKey> Keys
		{
			get
			{
				if (keys == null)
				{
					keys = new KeyCollection(this);
				}
				return keys;
			}
		}

		public ICollection<TValue> Values
		{
			get
			{
				if (values == null)
				{
					values = new ValueCollection(this);
				}
				return values;
			}
		}

		public TValue this[TKey key]
		{
			get
			{
				if (!TryGetValue(key, out var value))
				{
					throw new KeyNotFoundException();
				}
				return value;
			}
			set
			{
				SetValue(key, value);
			}
		}

		public abstract void Clear();

		public abstract void Add(TKey key, TValue value);

		public abstract bool ContainsKey(TKey key);

		public abstract bool Remove(TKey key);

		public abstract bool TryGetValue(TKey key, out TValue value);

		public abstract IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();

		protected abstract void SetValue(TKey key, TValue value);

		public void Add(KeyValuePair<TKey, TValue> item)
		{
			Add(item.Key, item.Value);
		}

		public bool Contains(KeyValuePair<TKey, TValue> item)
		{
			if (!TryGetValue(item.Key, out var value))
			{
				return false;
			}
			return EqualityComparer<TValue>.Default.Equals(value, item.Value);
		}

		public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
		{
			Copy(this, array, arrayIndex);
		}

		public bool Remove(KeyValuePair<TKey, TValue> item)
		{
			if (!Contains(item))
			{
				return false;
			}
			return Remove(item.Key);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		private static void Copy<T>(ICollection<T> source, T[] array, int arrayIndex)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			if (arrayIndex < 0 || arrayIndex > array.Length)
			{
				throw new ArgumentOutOfRangeException("arrayIndex");
			}
			if (array.Length - arrayIndex < source.Count)
			{
				throw new ArgumentException("Destination array is not large enough. Check array.Length and arrayIndex.");
			}
			foreach (T item in source)
			{
				array[arrayIndex++] = item;
			}
		}
	}
}
namespace XUnity.Common.MonoMod
{
	public static class DetourExtensions
	{
		public static T GenerateTrampolineEx<T>(this object detour)
		{
			return (T)(from x in detour.GetType().GetMethods()
				where x.Name == "GenerateTrampoline" && x.IsGenericMethod
				select x).FirstOrDefault().MakeGenericMethod(typeof(T)).Invoke(detour, null);
		}
	}
}
namespace XUnity.Common.Logging
{
	internal class ConsoleLogger : XuaLogger
	{
		public ConsoleLogger(string source)
			: base(source)
		{
		}

		protected override void Log(LogLevel level, string message)
		{
			Console.WriteLine(GetDefaultPrefix(level) + " " + message);
		}
	}
	public enum LogLevel
	{
		Debug,
		Info,
		Warn,
		Error
	}
	internal class ModLoaderSpecificLogger : XuaLogger
	{
		public static class BepInExLogLevel
		{
			public const int None = 0;

			public const int Fatal = 1;

			public const int Error = 2;

			public const int Warning = 4;

			public const int Message = 8;

			public const int Info = 16;

			public const int Debug = 32;

			public const int All = 63;
		}

		private static Action<LogLevel, string> _logMethod;

		public ModLoaderSpecificLogger(string source)
			: base(source)
		{
			if (_logMethod != null)
			{
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public;
			BindingFlags bindingAttr2 = BindingFlags.Instance | BindingFlags.Public;
			Type type = Type.GetType("BepInEx.Logging.LogLevel, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.LogLevel, BepInEx.Core", throwOnError: false);
			if ((object)type != null)
			{
				if ((object)(Type.GetType("BepInEx.Logging.ManualLogSource, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.ManualLogSource, BepInEx.Core", throwOnError: false)) != null)
				{
					MethodInfo method = (Type.GetType("BepInEx.Logging.Logger, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.Logger, BepInEx.Core", throwOnError: false)).GetMethod("CreateLogSource", bindingAttr, null, new Type[1] { typeof(string) }, null);
					object logInstance2 = method.Invoke(null, new object[1] { base.Source });
					MethodInfo method2 = logInstance2.GetType().GetMethod("Log", bindingAttr2, null, new Type[2]
					{
						type,
						typeof(object)
					}, null);
					FastReflectionDelegate log2 = method2.CreateFastDelegate();
					_logMethod = delegate(LogLevel level, string msg)
					{
						int num2 = Convert(level);
						log2(logInstance2, num2, msg);
					};
				}
				else
				{
					Type type2 = Type.GetType("BepInEx.Logger, BepInEx", throwOnError: false);
					object logInstance = type2.GetProperty("CurrentLogger", bindingAttr).GetValue(null, null);
					MethodInfo method3 = logInstance.GetType().GetMethod("Log", bindingAttr2, null, new Type[2]
					{
						type,
						typeof(object)
					}, null);
					FastReflectionDelegate log = method3.CreateFastDelegate();
					_logMethod = delegate(LogLevel level, string msg)
					{
						int num = Convert(level);
						log(logInstance, num, msg);
					};
				}
			}
			else
			{
				Type type3 = Type.GetType("MelonLoader.MelonLogger, MelonLoader.ModHandler", throwOnError: false);
				if ((object)type3 != null)
				{
					MethodInfo method4 = type3.GetMethod("Log", bindingAttr, null, new Type[2]
					{
						typeof(ConsoleColor),
						typeof(string)
					}, null);
					MethodInfo method5 = type3.GetMethod("Log", bindingAttr, null, new Type[1] { typeof(string) }, null);
					MethodInfo method6 = type3.GetMethod("LogWarning", bindingAttr, null, new Type[1] { typeof(string) }, null);
					MethodInfo method7 = type3.GetMethod("LogError", bindingAttr, null, new Type[1] { typeof(string) }, null);
					FastReflectionDelegate logDebug = method4.CreateFastDelegate();
					FastReflectionDelegate logInfo = method5.CreateFastDelegate();
					FastReflectionDelegate logWarning = method6.CreateFastDelegate();
					FastReflectionDelegate logError = method7.CreateFastDelegate();
					_logMethod = delegate(LogLevel level, string msg)
					{
						switch (level)
						{
						case LogLevel.Debug:
							logDebug(null, ConsoleColor.Gray, msg);
							break;
						case LogLevel.Info:
							logInfo(null, msg);
							break;
						case LogLevel.Warn:
							logWarning(null, msg);
							break;
						case LogLevel.Error:
							logError(null, msg);
							break;
						default:
							throw new ArgumentException("level");
						}
					};
				}
			}
			if (_logMethod != null)
			{
				return;
			}
			throw new Exception("Did not recognize any mod loader!");
		}

		protected override void Log(LogLevel level, string message)
		{
			_logMethod(level, message);
		}

		public static int Convert(LogLevel level)
		{
			return level switch
			{
				LogLevel.Debug => 32, 
				LogLevel.Info => 16, 
				LogLevel.Warn => 4, 
				LogLevel.Error => 2, 
				_ => 0, 
			};
		}
	}
	public abstract class XuaLogger
	{
		private static XuaLogger _default;

		private static XuaLogger _common;

		private static XuaLogger _resourceRedirector;

		public static XuaLogger AutoTranslator
		{
			get
			{
				if (_default == null)
				{
					_default = CreateLogger("XUnity.AutoTranslator");
				}
				return _default;
			}
			set
			{
				_default = value ?? throw new ArgumentNullException("value");
			}
		}

		public static XuaLogger Common
		{
			get
			{
				if (_common == null)
				{
					_common = CreateLogger("XUnity.Common");
				}
				return _common;
			}
			set
			{
				_common = value ?? throw new ArgumentNullException("value");
			}
		}

		public static XuaLogger ResourceRedirector
		{
			get
			{
				if (_resourceRedirector == null)
				{
					_resourceRedirector = CreateLogger("XUnity.ResourceRedirector");
				}
				return _resourceRedirector;
			}
			set
			{
				_resourceRedirector = value ?? throw new ArgumentNullException("value");
			}
		}

		public string Source { get; set; }

		internal static XuaLogger CreateLogger(string source)
		{
			try
			{
				return new ModLoaderSpecificLogger(source);
			}
			catch (Exception)
			{
				return new ConsoleLogger(source);
			}
		}

		public XuaLogger(string source)
		{
			Source = source;
		}

		public void Error(Exception e, string message)
		{
			Log(LogLevel.Error, message + Environment.NewLine + e);
		}

		public void Error(string message)
		{
			Log(LogLevel.Error, message);
		}

		public void Warn(Exception e, string message)
		{
			Log(LogLevel.Warn, message + Environment.NewLine + e);
		}

		public void Warn(string message)
		{
			Log(LogLevel.Warn, message);
		}

		public void Info(Exception e, string message)
		{
			Log(LogLevel.Info, message + Environment.NewLine + e);
		}

		public void Info(string message)
		{
			Log(LogLevel.Info, message);
		}

		public void Debug(Exception e, string message)
		{
			Log(LogLevel.Debug, message + Environment.NewLine + e);
		}

		public void Debug(string message)
		{
			Log(LogLevel.Debug, message);
		}

		protected abstract void Log(LogLevel level, string message);

		protected string GetDefaultPrefix(LogLevel level)
		{
			return level switch
			{
				LogLevel.Debug => "[DEBUG][" + Source + "]: ", 
				LogLevel.Info => "[INFO][" + Source + "]: ", 
				LogLevel.Warn => "[WARN][" + Source + "]: ", 
				LogLevel.Error => "[ERROR][" + Source + "]: ", 
				_ => "[UNKNOW][" + Source + "]: ", 
			};
		}
	}
}
namespace XUnity.Common.Harmony
{
	public static class AccessToolsShim
	{
		private static readonly BindingFlags All;

		private static readonly Func<Type, string, Type[], Type[], MethodInfo> AccessTools_Method;

		private static readonly Func<Type, string, PropertyInfo> AccessTools_Property;

		static AccessToolsShim()
		{
			All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			MethodInfo method = ClrTypes.AccessTools.GetMethod("Method", All, null, new Type[4]
			{
				typeof(Type),
				typeof(string),
				typeof(Type[]),
				typeof(Type[])
			}, null);
			MethodInfo? method2 = ClrTypes.AccessTools.GetMethod("Property", All, null, new Type[2]
			{
				typeof(Type),
				typeof(string)
			}, null);
			AccessTools_Method = (Func<Type, string, Type[], Type[], MethodInfo>)ExpressionHelper.CreateTypedFastInvoke(method);
			AccessTools_Property = (Func<Type, string, PropertyInfo>)ExpressionHelper.CreateTypedFastInvoke(method2);
		}

		public static MethodInfo Method(Type type, string name, params Type[] parameters)
		{
			return AccessTools_Method(type, name, parameters, null);
		}

		public static PropertyInfo Property(Type type, string name)
		{
			return AccessTools_Property(type, name);
		}
	}
}
namespace XUnity.Common.Extensions
{
	public static class ExceptionExtensions
	{
		public static TException FirstInnerExceptionOfType<TException>(this Exception e) where TException : Exception
		{
			for (Exception ex = e; ex != null; ex = ex.InnerException)
			{
				if (ex is TException)
				{
					return (TException)ex;
				}
			}
			return null;
		}
	}
	public static class ObjectExtensions
	{
		public static Type GetUnityType(this object obj)
		{
			return obj.GetType();
		}

		public static bool TryCastTo<TObject>(this object obj, out TObject castedObject)
		{
			if (obj is TObject val)
			{
				castedObject = val;
				return true;
			}
			castedObject = default(TObject);
			return false;
		}
	}
	public static class StreamExtensions
	{
		public static byte[] ReadFully(this Stream stream, int initialLength)
		{
			if (initialLength < 1)
			{
				initialLength = 32768;
			}
			byte[] array = new byte[initialLength];
			int num = 0;
			int num2;
			while ((num2 = stream.Read(array, num, array.Length - num)) > 0)
			{
				num += num2;
				if (num == array.Length)
				{
					int num3 = stream.ReadByte();
					if (num3 == -1)
					{
						return array;
					}
					byte[] array2 = new byte[array.Length * 2];
					Array.Copy(array, array2, array.Length);
					array2[num] = (byte)num3;
					array = array2;
					num++;
				}
			}
			byte[] array3 = new byte[num];
			Array.Copy(array, array3, num);
			return array3;
		}
	}
	public static class StringExtensions
	{
		private static readonly HashSet<char> InvalidFileNameChars = new HashSet<char>(Path.GetInvalidFileNameChars());

		public static string UseCorrectDirectorySeparators(this string path)
		{
			if (Path.DirectorySeparatorChar == '\\')
			{
				return path.Replace('/', Path.DirectorySeparatorChar);
			}
			if (Path.DirectorySeparatorChar == '/')
			{
				return path.Replace('\\', Path.DirectorySeparatorChar);
			}
			return path;
		}

		public static bool IsNullOrWhiteSpace(this string value)
		{
			if (value == null)
			{
				return true;
			}
			for (int i = 0; i < value.Length; i++)
			{
				if (!char.IsWhiteSpace(value[i]))
				{
					return false;
				}
			}
			return true;
		}

		public static string MakeRelativePath(this string fullOrRelativePath, string basePath)
		{
			StringBuilder stringBuilder = new StringBuilder();
			int i = 0;
			bool flag = false;
			string[] array = basePath.Split(':', '\\', '/');
			List<string> list = fullOrRelativePath.Split(':', '\\', '/').ToList();
			if (array.Length == 0 || list.Count <= 0 || array[0] != list[0])
			{
				flag = true;
			}
			bool flag2 = false;
			for (int j = 0; j < list.Count; j++)
			{
				if (list[j] == "..")
				{
					if (flag2)
					{
						int num = j - 1;
						if (num >= 0)
						{
							list.RemoveAt(j);
							list.RemoveAt(num);
							j -= 2;
						}
					}
				}
				else
				{
					flag2 = true;
				}
			}
			if (!flag)
			{
				for (i = 1; i < array.Length && !(array[i] != list[i]); i++)
				{
				}
				for (int k = 0; k < array.Length - i; k++)
				{
					char directorySeparatorChar = Path.DirectorySeparatorChar;
					stringBuilder.Append(".." + directorySeparatorChar);
				}
			}
			for (int l = i; l < list.Count - 1; l++)
			{
				string value = list[l];
				stringBuilder.Append(value).Append(Path.DirectorySeparatorChar);
			}
			string value2 = list[^1];
			stringBuilder.Append(value2);
			return stringBuilder.ToString();
		}

		public static string SanitizeForFileSystem(this string path)
		{
			StringBuilder stringBuilder = new StringBuilder(path.Length);
			foreach (char c in path)
			{
				if (!InvalidFileNameChars.Contains(c))
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		public static string SplitToLines(this string text, int maxStringLength, params char[] splitOnCharacters)
		{
			StringBuilder stringBuilder = new StringBuilder();
			int num;
			for (int i = 0; text.Length > i; i += num)
			{
				if (i != 0)
				{
					stringBuilder.Append('\n');
				}
				num = ((i + maxStringLength <= text.Length) ? text.Substring(i, maxStringLength).LastIndexOfAny(splitOnCharacters) : (text.Length - i));
				num = ((num == -1) ? maxStringLength : num);
				stringBuilder.Append(text.Substring(i, num).Trim());
			}
			return stringBuilder.ToString();
		}

		public static bool StartsWithStrict(this string str, string prefix)
		{
			int num = Math.Min(str.Length, prefix.Length);
			if (num < prefix.Length)
			{
				return false;
			}
			for (int i = 0; i < num; i++)
			{
				if (str[i] != prefix[i])
				{
					return false;
				}
			}
			return true;
		}

		public static string GetBetween(this string strSource, string strStart, string strEnd)
		{
			int num = strSource.IndexOf(strStart);
			if (num != -1)
			{
				num += strStart.Length;
				int num2 = strSource.IndexOf(strEnd, num);
				if (num2 > num)
				{
					return strSource.Substring(num, num2 - num);
				}
			}
			return string.Empty;
		}

		public static bool RemindsOf(this string that, string other)
		{
			if (!that.StartsWith(other) && !other.StartsWith(that) && !that.EndsWith(other))
			{
				return other.EndsWith(that);
			}
			return true;
		}
	}
}
namespace XUnity.Common.Constants
{
	public static class ClrTypes
	{
		public static readonly Type AccessTools = FindTypeStrict("Harmony.AccessTools, 0Harmony") ?? FindTypeStrict("HarmonyLib.AccessTools, 0Harmony") ?? FindTypeStrict("Harmony.AccessTools, MelonLoader.ModHandler") ?? FindTypeStrict("HarmonyLib.AccessTools, MelonLoader.ModHandler");

		public static readonly Type HarmonyMethod = FindTypeStrict("Harmony.HarmonyMethod, 0Harmony") ?? FindTypeStrict("HarmonyLib.HarmonyMethod, 0Harmony") ?? FindTypeStrict("Harmony.HarmonyMethod, MelonLoader.ModHandler") ?? FindTypeStrict("HarmonyLib.HarmonyMethod, MelonLoader.ModHandler");

		public static readonly Type HarmonyInstance = FindTypeStrict("Harmony.HarmonyInstance, 0Harmony") ?? FindTypeStrict("Harmony.HarmonyInstance, MelonLoader.ModHandler");

		public static readonly Type Harmony = FindTypeStrict("HarmonyLib.Harmony, 0Harmony") ?? FindTypeStrict("HarmonyLib.Harmony, MelonLoader.ModHandler");

		public static readonly Type Hook = FindTypeStrict("MonoMod.RuntimeDetour.Hook, MonoMod.RuntimeDetour");

		public static readonly Type Detour = FindTypeStrict("MonoMod.RuntimeDetour.Detour, MonoMod.RuntimeDetour");

		public static readonly Type NativeDetour = FindTypeStrict("MonoMod.RuntimeDetour.NativeDetour, MonoMod.RuntimeDetour");

		public static readonly Type DynamicMethodDefinition = FindTypeStrict("MonoMod.Utils.DynamicMethodDefinition, MonoMod.Utils");

		public static readonly Type Imports = FindTypeStrict("MelonLoader.Imports, MelonLoader.ModHandler");

		public static readonly Type MethodBase = FindType("System.Reflection.MethodBase");

		public static readonly Type Task = FindType("System.Threading.Tasks.Task");

		private static Type FindType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if ((object)type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static Type FindTypeStrict(string name)
		{
			return Type.GetType(name, throwOnError: false);
		}
	}
	public class TypeContainer
	{
		public Type ClrType { get; }

		public Type UnityType { get; }

		public TypeContainer(Type type)
		{
			UnityType = type;
			ClrType = type;
		}

		public bool IsAssignableFrom(Type unityType)
		{
			if ((object)UnityType != null)
			{
				return UnityType.IsAssignableFrom(unityType);
			}
			return false;
		}
	}
	public static class UnityFeatures
	{
		private static readonly BindingFlags All;

		public static bool SupportsMouseScrollDelta { get; }

		public static bool SupportsClipboard { get; }

		public static bool SupportsCustomYieldInstruction { get; }

		public static bool SupportsSceneManager { get; }

		public static bool SupportsWaitForSecondsRealtime { get; set; }

		static UnityFeatures()
		{
			All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			SupportsMouseScrollDelta = false;
			SupportsClipboard = false;
			SupportsCustomYieldInstruction = false;
			SupportsSceneManager = false;
			SupportsWaitForSecondsRealtime = false;
			try
			{
				SupportsClipboard = (object)UnityTypes.TextEditor?.ClrType.GetProperty("text")?.GetSetMethod() != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsCustomYieldInstruction = UnityTypes.CustomYieldInstruction != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsSceneManager = UnityTypes.Scene != null && UnityTypes.SceneManager != null && (object)UnityTypes.SceneManager.ClrType.GetMethod("add_sceneLoaded", All) != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsMouseScrollDelta = (object)UnityTypes.Input?.ClrType.GetProperty("mouseScrollDelta") != null;
			}
			catch (Exception)
			{
			}
			try
			{
				SupportsWaitForSecondsRealtime = UnityTypes.WaitForSecondsRealtime != null;
			}
			catch (Exception)
			{
			}
		}
	}
	public static class UnityTypes
	{
		public static class TMP_Settings_Properties
		{
			public static CachedProperty Version = TMP_Settings?.ClrType.CachedProperty("version");

			public static CachedProperty FallbackFontAssets = TMP_Settings?.ClrType.CachedProperty("fallbackFontAssets");
		}

		public static class TMP_FontAsset_Properties
		{
			public static CachedProperty Version = TMP_FontAsset?.ClrType.CachedProperty("version");
		}

		public static class AdvScenarioData_Properties
		{
			public static CachedProperty ScenarioLabels = AdvScenarioData?.ClrType.CachedProperty("ScenarioLabels");
		}

		public static class UguiNovelText_Properties
		{
			public static CachedProperty TextGenerator = UguiNovelText?.ClrType.CachedProperty("TextGenerator");
		}

		public static class UguiNovelText_Methods
		{
			public static CachedMethod SetAllDirty = UguiNovelText?.ClrType.CachedMethod("SetAllDirty");
		}

		public static class UguiNovelTextGenerator_Methods
		{
			public static CachedMethod Refresh = UguiNovelTextGenerator?.ClrType.CachedMethod("Refresh");
		}

		public static class AdvUguiMessageWindow_Properties
		{
			public static CachedProperty Text = AdvUguiMessageWindow?.ClrType.CachedProperty("Text");

			public static CachedProperty Engine = AdvUguiMessageWindow?.ClrType.CachedProperty("Engine");
		}

		public static class AdvUiMessageWindow_Fields
		{
			public static CachedField text = AdvUiMessageWindow?.ClrType.CachedField("text");

			public static CachedField nameText = AdvUiMessageWindow?.ClrType.CachedField("nameText");
		}

		public static class AdvUguiMessageWindow_Fields
		{
			public static FieldInfo text = AdvUguiMessageWindow?.ClrType.GetField("text", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

			public static FieldInfo nameText = AdvUguiMessageWindow?.ClrType.GetField("nameText", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

			public static FieldInfo engine = AdvUguiMessageWindow?.ClrType.GetField("engine", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		}

		public static class AdvEngine_Properties
		{
			public static CachedProperty Page = AdvEngine?.ClrType.CachedProperty("Page");
		}

		public static class AdvPage_Methods
		{
			public static CachedMethod RemakeTextData = AdvPage?.ClrType.CachedMethod("RemakeTextData");

			public static CachedMethod RemakeText = AdvPage?.ClrType.CachedMethod("RemakeText");

			public static CachedMethod ChangeMessageWindowText = AdvPage?.ClrType.CachedMethod("ChangeMessageWindowText", typeof(string), typeof(string), typeof(string), typeof(string));
		}

		public static class UILabel_Properties
		{
			public static CachedProperty MultiLine = UILabel?.ClrType.CachedProperty("multiLine");

			public static CachedProperty OverflowMethod = UILabel?.ClrType.CachedProperty("overflowMethod");

			public static CachedProperty SpacingX = UILabel?.ClrType.CachedProperty("spacingX");

			public static CachedProperty UseFloatSpacing = UILabel?.ClrType.CachedProperty("useFloatSpacing");
		}

		public static class Text_Properties
		{
			public static CachedProperty Font = Text?.ClrType.CachedProperty("font");

			public static CachedProperty FontSize = Text?.ClrType.CachedProperty("fontSize");

			public static CachedProperty HorizontalOverflow = Text?.ClrType.CachedProperty("horizontalOverflow");

			public static CachedProperty VerticalOverflow = Text?.ClrType.CachedProperty("verticalOverflow");

			public static CachedProperty LineSpacing = Text?.ClrType.CachedProperty("lineSpacing");

			public static CachedProperty ResizeTextForBestFit = Text?.ClrType.CachedProperty("resizeTextForBestFit");

			public static CachedProperty ResizeTextMinSize = Text?.ClrType.CachedProperty("resizeTextMinSize");

			public static CachedProperty ResizeTextMaxSize = Text?.ClrType.CachedProperty("resizeTextMaxSize");
		}

		public static class InputField_Properties
		{
			public static CachedProperty Placeholder = InputField?.ClrType.CachedProperty("placeholder");
		}

		public static class TMP_InputField_Properties
		{
			public static CachedProperty Placeholder = TMP_InputField?.ClrType.CachedProperty("placeholder");
		}

		public static class Font_Properties
		{
			public static CachedProperty FontSize = Font?.ClrType.CachedProperty("fontSize");
		}

		public static class AssetBundle_Methods
		{
			public static CachedMethod LoadAll = AssetBundle?.ClrType.CachedMethod("LoadAll", typeof(Type));

			public static CachedMethod LoadAllAssets = AssetBundle?.ClrType.CachedMethod("LoadAllAssets", typeof(Type));

			public static CachedMethod LoadFromFile = AssetBundle?.ClrType.CachedMethod("LoadFromFile", typeof(string));

			public static CachedMethod CreateFromFile = AssetBundle?.ClrType.CachedMethod("CreateFromFile", typeof(string));
		}

		public static class TextExpansion_Methods
		{
			public static CachedMethod SetMessageType = TextExpansion?.ClrType.CachedMethod("SetMessageType");

			public static CachedMethod SkipTypeWriter = TextExpansion?.ClrType.CachedMethod("SkipTypeWriter");
		}

		public static class GameObject_Methods
		{
		}

		public static class TextMesh_Methods
		{
		}

		public static class Text_Methods
		{
		}

		public static class InputField_Methods
		{
		}

		public static class TMP_Text_Methods
		{
		}

		public static class TMP_InputField_Methods
		{
		}

		public static class TextMeshPro_Methods
		{
		}

		public static class TextMeshProUGUI_Methods
		{
		}

		public static class UILabel_Methods
		{
		}

		public static class UIRect_Methods
		{
		}

		public static class SceneManager_Methods
		{
			public static readonly Action<UnityAction<Scene, LoadSceneMode>> add_sceneLoaded = (Action<UnityAction<Scene, LoadSceneMode>>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(SceneManager).GetMethod("add_sceneLoaded", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(UnityAction<Scene, LoadSceneMode>) }, null));
		}

		public static class Texture2D_Methods
		{
			public static readonly Func<Texture2D, byte[], bool> LoadImage = (Func<Texture2D, byte[], bool>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(Texture2D).GetMethod("LoadImage", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(byte[]) }, null));

			public static readonly Func<Texture2D, byte[]> EncodeToPNG = (Func<Texture2D, byte[]>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(Texture2D).GetMethod("EncodeToPNG", BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null));
		}

		public static class ImageConversion_Methods
		{
			public static readonly Func<Texture2D, byte[], bool, bool> LoadImage = (Func<Texture2D, byte[], bool, bool>)ExpressionHelper.CreateTypedFastInvokeUnchecked(ImageConversion?.ClrType.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
			{
				typeof(Texture2D),
				typeof(byte[]),
				typeof(bool)
			}, null));

			public static readonly Func<Texture2D, byte[]> EncodeToPNG = (Func<Texture2D, byte[]>)ExpressionHelper.CreateTypedFastInvokeUnchecked(ImageConversion?.ClrType.GetMethod("EncodeToPNG", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Texture2D) }, null));
		}

		public static readonly TypeContainer UILabel = FindType("UILabel");

		public static readonly TypeContainer UIWidget = FindType("UIWidget");

		public static readonly TypeContainer UIAtlas = FindType("UIAtlas");

		public static readonly TypeContainer UISprite = FindType("UISprite");

		public static readonly TypeContainer UITexture = FindType("UITexture");

		public static readonly TypeContainer UI2DSprite = FindType("UI2DSprite");

		public static readonly TypeContainer UIFont = FindType("UIFont");

		public static readonly TypeContainer UIPanel = FindType("UIPanel");

		public static readonly TypeContainer UIRect = FindType("UIRect");

		public static readonly TypeContainer UIInput = FindType("UIInput");

		public static readonly TypeContainer TextField = FindType("FairyGUI.TextField");

		public static readonly TypeContainer TMP_InputField = FindType("TMPro.TMP_InputField");

		public static readonly TypeContainer TMP_Text = FindType("TMPro.TMP_Text");

		public static readonly TypeContainer TextMeshProUGUI = FindType("TMPro.TextMeshProUGUI");

		public static readonly TypeContainer TextMeshPro = FindType("TMPro.TextMeshPro");

		public static readonly TypeContainer TMP_FontAsset = FindType("TMPro.TMP_FontAsset");

		public static readonly TypeContainer TMP_Settings = FindType("TMPro.TMP_Settings");

		public static readonly TypeContainer GameObject = FindType("UnityEngine.GameObject");

		public static readonly TypeContainer Transform = FindType("UnityEngine.Transform");

		public static readonly TypeContainer TextMesh = FindType("UnityEngine.TextMesh");

		public static readonly TypeContainer Text = FindType("UnityEngine.UI.Text");

		public static readonly TypeContainer Image = FindType("UnityEngine.UI.Image");

		public static readonly TypeContainer RawImage = FindType("UnityEngine.UI.RawImage");

		public static readonly TypeContainer MaskableGraphic = FindType("UnityEngine.UI.MaskableGraphic");

		public static readonly TypeContainer Graphic = FindType("UnityEngine.UI.Graphic");

		public static readonly TypeContainer GUIContent = FindType("UnityEngine.GUIContent");

		public static readonly TypeContainer WWW = FindType("UnityEngine.WWW");

		public static readonly TypeContainer InputField = FindType("UnityEngine.UI.InputField");

		public static readonly TypeContainer GUI = FindType("UnityEngine.GUI");

		public static readonly TypeContainer GUI_ToolbarButtonSize = FindType("UnityEngine.GUI+ToolbarButtonSize");

		public static readonly TypeContainer GUIStyle = FindType("UnityEngine.GUIStyle");

		public static readonly TypeContainer ImageConversion = FindType("UnityEngine.ImageConversion");

		public static readonly TypeContainer Texture2D = FindType("UnityEngine.Texture2D");

		public static readonly TypeContainer Texture = FindType("UnityEngine.Texture");

		public static readonly TypeContainer SpriteRenderer = FindType("UnityEngine.SpriteRenderer");

		public static readonly TypeContainer Sprite = FindType("UnityEngine.Sprite");

		public static readonly TypeContainer Object = FindType("UnityEngine.Object");

		public static readonly TypeContainer TextEditor = FindType("UnityEngine.TextEditor");

		public static readonly TypeContainer CustomYieldInstruction = FindType("UnityEngine.CustomYieldInstruction");

		public static readonly TypeContainer SceneManager = FindType("UnityEngine.SceneManagement.SceneManager");

		public static readonly TypeContainer Scene = FindType("UnityEngine.SceneManagement.Scene");

		public static readonly TypeContainer UnityEventBase = FindType("UnityEngine.Events.UnityEventBase");

		public static readonly TypeContainer BaseInvokableCall = FindType("UnityEngine.Events.BaseInvokableCall");

		public static readonly TypeContainer Font = FindType("UnityEngine.Font");

		public static readonly TypeContainer WaitForSecondsRealtime = FindType("UnityEngine.WaitForSecondsRealtime");

		public static readonly TypeContainer Input = FindType("UnityEngine.Input");

		public static readonly TypeContainer AssetBundleCreateRequest = FindType("UnityEngine.AssetBundleCreateRequest");

		public static readonly TypeContainer AssetBundle = FindType("UnityEngine.AssetBundle");

		public static readonly TypeContainer AssetBundleRequest = FindType("UnityEngine.AssetBundleRequest");

		public static readonly TypeContainer Resources = FindType("UnityEngine.Resources");

		public static readonly TypeContainer AsyncOperation = FindType("UnityEngine.AsyncOperation");

		public static readonly TypeContainer TextAsset = FindType("UnityEngine.TextAsset");

		public static readonly Type HorizontalWrapMode = FindClrType("UnityEngine.HorizontalWrapMode");

		public static readonly Type TextOverflowModes = FindClrType("TMPro.TextOverflowModes");

		public static readonly Type TextAlignmentOptions = FindClrType("TMPro.TextAlignmentOptions");

		public static readonly Type VerticalWrapMode = FindClrType("UnityEngine.VerticalWrapMode");

		public static readonly TypeContainer TextExpansion = FindType("UnityEngine.UI.TextExpansion");

		public static readonly TypeContainer Typewriter = FindType("Typewriter");

		public static readonly TypeContainer UguiNovelText = FindType("Utage.UguiNovelText");

		public static readonly TypeContainer UguiNovelTextGenerator = FindType("Utage.UguiNovelTextGenerator");

		public static readonly TypeContainer AdvEngine = FindType("Utage.AdvEngine");

		public static readonly TypeContainer AdvPage = FindType("Utage.AdvPage");

		public static readonly TypeContainer TextData = FindType("Utage.TextData");

		public static readonly TypeContainer AdvUguiMessageWindow = FindType("Utage.AdvUguiMessageWindow") ?? FindType("AdvUguiMessageWindow");

		public static readonly TypeContainer AdvUiMessageWindow = FindType("AdvUiMessageWindow");

		public static readonly TypeContainer AdvDataManager = FindType("Utage.AdvDataManager");

		public static readonly TypeContainer AdvScenarioData = FindType("Utage.AdvScenarioData");

		public static readonly TypeContainer AdvScenarioLabelData = FindType("Utage.AdvScenarioLabelData");

		public static readonly TypeContainer DicingTextures = FindType("Utage.DicingTextures");

		public static readonly TypeContainer DicingImage = FindType("Utage.DicingImage");

		public static readonly TypeContainer TextArea2D = FindType("Utage.TextArea2D");

		public static readonly TypeContainer CubismRenderer = FindType("Live2D.Cubism.Rendering.CubismRenderer");

		public static readonly TypeContainer TextWindow = FindType("Assets.System.Text.TextWindow");

		private static Type FindClrType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if ((object)type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static TypeContainer FindType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if ((object)type != null)
					{
						return new TypeContainer(type);
					}
				}
				catch
				{
				}
			}
			return null;
		}
	}
}

BepInEx/plugins/Kuriki-LethalCompanyDe/ExIni.dll

Decompiled a year 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.Text;
using System.Text.RegularExpressions;
using Microsoft.Win32;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyInformationalVersion("GIT master [cf85ca6f3fc361cf48bf56107e4cec9102b7f5eb] ")]
[assembly: AssemblyTitle("ExIni")]
[assembly: Guid("b8adf1ac-aade-485a-8997-14c4b42e0a8b")]
[assembly: AssemblyDescription("Extended INI File Handler")]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyFileVersion("1.0.2.1")]
[assembly: AssemblyCompany("Usagirei")]
[assembly: AssemblyProduct("ExIni")]
[assembly: ComVisible(false)]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCopyright("Copyright © Usagirei 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("1.0.2.1")]
namespace ExIni;

public class IniComment
{
	public List<string> Comments { get; set; }

	public IniComment()
	{
		Comments = new List<string>();
	}

	public override string ToString()
	{
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < Comments.Count; i++)
		{
			string text = Comments[i];
			string value = ((i < Comments.Count - 1) ? (";" + text + Environment.NewLine) : (";" + text));
			stringBuilder.Append(value);
		}
		return stringBuilder.ToString();
	}

	public void Append(params string[] comments)
	{
		Comments.AddRange(comments);
	}
}
public class IniFile
{
	private readonly IniComment _comments;

	private readonly List<IniSection> _sections;

	public IniSection this[string sec] => CreateSection(sec);

	public IniComment Comments => _comments;

	public List<IniSection> Sections => _sections;

	public IniFile()
	{
		_comments = new IniComment();
		_sections = new List<IniSection>();
	}

	public override string ToString()
	{
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < Sections.Count; i++)
		{
			IniSection iniSection = Sections[i];
			if (iniSection.Comments.Comments.Any())
			{
				stringBuilder.AppendLine(iniSection.Comments.ToString());
			}
			stringBuilder.AppendLine(iniSection.ToString());
			foreach (IniKey key in iniSection.Keys)
			{
				if (key.Comments.Comments.Any())
				{
					stringBuilder.AppendLine(key.Comments.ToString());
				}
				stringBuilder.AppendLine(key.ToString());
			}
			if (i < Sections.Count - 1)
			{
				stringBuilder.AppendLine();
			}
		}
		if (Comments.Comments.Any())
		{
			stringBuilder.AppendLine();
			stringBuilder.AppendLine(Comments.ToString());
		}
		return stringBuilder.ToString();
	}

	public IniSection CreateSection(string section)
	{
		IniSection section2 = GetSection(section);
		if (section2 != null)
		{
			return section2;
		}
		IniSection iniSection = new IniSection(section);
		_sections.Add(iniSection);
		return iniSection;
	}

	public bool DeleteSection(string section)
	{
		if (!HasSection(section))
		{
			return false;
		}
		Sections.Remove(GetSection(section));
		return true;
	}

	public IniSection GetSection(string section)
	{
		if (!HasSection(section))
		{
			return null;
		}
		return _sections.FirstOrDefault((IniSection iniSection) => iniSection.Section == section);
	}

	public bool HasSection(string section)
	{
		return _sections.Any((IniSection iniSection) => iniSection.Section == section);
	}

	public void Merge(IniFile ini)
	{
		Comments.Append(ini.Comments.Comments.ToArray());
		foreach (IniSection section in ini.Sections)
		{
			IniSection iniSection = this[section.Section];
			iniSection.Comments.Append(section.Comments.Comments.ToArray());
			foreach (IniKey key in section.Keys)
			{
				IniKey iniKey = iniSection[key.Key];
				iniKey.Comments.Append(key.Comments.Comments.ToArray());
				iniKey.Value = key.Value;
			}
		}
	}

	public void Save(string filePath)
	{
		string directoryName = Path.GetDirectoryName(filePath);
		if (!string.IsNullOrEmpty(directoryName))
		{
			Directory.CreateDirectory(directoryName);
		}
		File.WriteAllText(filePath, ToString(), Encoding.UTF8);
	}

	public static IniFile FromFile(string iniString)
	{
		return IniParser.Parse(File.ReadAllText(iniString));
	}

	public static IniFile FromString(string iniString)
	{
		return IniParser.Parse(iniString);
	}
}
public class IniKey
{
	private readonly IniComment _comments;

	public IniComment Comments => _comments;

	public string Key { get; set; }

	public string RawValue { get; set; }

	public string Value
	{
		get
		{
			return Resolve(RawValue);
		}
		set
		{
			RawValue = value;
		}
	}

	public IniKey(string key, string value = null)
	{
		Key = key;
		Value = value;
		_comments = new IniComment();
	}

	public override string ToString()
	{
		return $"{Key}={RawValue}";
	}

	private static string GetEnvironment(string env)
	{
		return Environment.ExpandEnvironmentVariables(env);
	}

	private static string GetRegistry(string path)
	{
		string directoryName = Path.GetDirectoryName(path);
		string fileName = Path.GetFileName(path);
		if (string.IsNullOrEmpty(directoryName))
		{
			return null;
		}
		return Registry.GetValue(directoryName, fileName, string.Empty)?.ToString();
	}

	private static string Resolve(string value)
	{
		if (value == null)
		{
			return null;
		}
		Regex regex = new Regex("\\$\\((?<reg>.*)\\)");
		Regex regex2 = new Regex("%.*%");
		while (regex.IsMatch(value) || regex2.IsMatch(value))
		{
			value = regex.Replace(value, (Match match) => GetRegistry(match.Groups["reg"].Value));
			value = GetEnvironment(value);
		}
		return value;
	}
}
internal class IniParser
{
	private static readonly Regex CommentRegex = new Regex("^;(?<com>.*)");

	private static readonly Regex KeyRegex = new Regex("^(?<key>[\\w\\s]+)=(?<val>.*)$");

	private static readonly Regex SectionRegex = new Regex("^\\[(?<sec>[\\w\\s]+)\\]$");

	private static readonly Regex VarRegex = new Regex("^\\@(?<key>[\\w\\s]+)=(?<val>.*)$");

	public static IniFile Parse(string iniString)
	{
		IniFile iniFile = new IniFile();
		string[] array = (from line in iniString.Split(new char[1] { '\n' })
			let trimmed = line.Trim()
			select trimmed.TrimEnd(new char[1] { '\r' })).ToArray();
		List<string> list = new List<string>();
		IniSection iniSection = null;
		bool flag = false;
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i];
			if (string.IsNullOrEmpty(text))
			{
				continue;
			}
			if (IsComment(text))
			{
				string comment = GetComment(text);
				list.Add(comment);
				if (IsVariable(comment))
				{
					string[] variable = GetVariable(comment);
					string variable2 = variable[0];
					string value = variable[1];
					Environment.SetEnvironmentVariable(variable2, value);
				}
				flag = true;
			}
			else if (IsSection(text))
			{
				iniSection = iniFile[GetSection(text)];
				if (flag)
				{
					iniSection.Comments.Append(list.ToArray());
					list.Clear();
					flag = false;
				}
			}
			else if (IsKey(text))
			{
				if (iniSection == null)
				{
					throw new Exception($"{i}: Sectionless Key Value Pair");
				}
				string[] key = GetKey(text);
				string key2 = key[0];
				string value2 = key[1];
				if (flag)
				{
					iniSection[key2].Comments.Append(list.ToArray());
					list.Clear();
					flag = false;
				}
				iniSection[key2].Value = value2;
			}
		}
		if (flag)
		{
			iniFile.Comments.Append(list.ToArray());
		}
		return iniFile;
	}

	private static string GetComment(string line)
	{
		return CommentRegex.Match(line).Groups["com"].Value;
	}

	private static string[] GetKey(string line)
	{
		Match match = KeyRegex.Match(line);
		return new string[2]
		{
			match.Groups["key"].Value,
			match.Groups["val"].Value
		};
	}

	private static string GetSection(string line)
	{
		return SectionRegex.Match(line).Groups["sec"].Value;
	}

	private static string[] GetVariable(string line)
	{
		Match match = VarRegex.Match(line);
		return new string[2]
		{
			match.Groups["key"].Value,
			match.Groups["val"].Value
		};
	}

	private static bool IsComment(string line)
	{
		return CommentRegex.IsMatch(line);
	}

	private static bool IsKey(string line)
	{
		return KeyRegex.IsMatch(line);
	}

	private static bool IsSection(string line)
	{
		return SectionRegex.IsMatch(line);
	}

	private static bool IsVariable(string line)
	{
		return VarRegex.IsMatch(line);
	}
}
public class IniSection
{
	private readonly IniComment _comments;

	private readonly List<IniKey> _keys;

	public IniKey this[string key] => CreateKey(key);

	public IniComment Comments => _comments;

	public List<IniKey> Keys => _keys;

	public string Section { get; set; }

	public IniSection(string section)
	{
		Section = section;
		_comments = new IniComment();
		_keys = new List<IniKey>();
	}

	public override string ToString()
	{
		return $"[{Section}]";
	}

	public IniKey CreateKey(string key)
	{
		IniKey key2 = GetKey(key);
		if (key2 != null)
		{
			return key2;
		}
		IniKey iniKey = new IniKey(key);
		_keys.Add(iniKey);
		return iniKey;
	}

	public IniKey GetKey(string key)
	{
		if (!HasKey(key))
		{
			return null;
		}
		return _keys.FirstOrDefault((IniKey iniKey) => iniKey.Key == key);
	}

	public bool HasKey(string key)
	{
		return _keys.Any((IniKey iniKey) => iniKey.Key == key);
	}

	public bool DeleteKey(string key)
	{
		if (!HasKey(key))
		{
			return false;
		}
		Keys.Remove(GetKey(key));
		return true;
	}
}

BepInEx/plugins/Kuriki-LethalCompanyDe/XUnity.AutoTranslator.Plugin.BepInEx.dll

Decompiled a year ago
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using ExIni;
using XUnity.AutoTranslator.Plugin.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("XUnity.AutoTranslator.Plugin.BepInEx")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("5.3.0.0")]
[assembly: AssemblyInformationalVersion("5.3.0")]
[assembly: AssemblyProduct("XUnity.AutoTranslator.Plugin.BepInEx")]
[assembly: AssemblyTitle("XUnity.AutoTranslator.Plugin.BepInEx")]
[assembly: AssemblyVersion("5.3.0.0")]
namespace XUnity.AutoTranslator.Plugin.BepInEx;

[BepInPlugin("gravydevsupreme.xunity.autotranslator", "XUnity Auto Translator", "5.3.0")]
public class AutoTranslatorPlugin : BaseUnityPlugin, IPluginEnvironment
{
	private IniFile _file;

	private string _configPath;

	public IniFile Preferences => _file ?? (_file = ReloadConfig());

	public string ConfigPath { get; }

	public string TranslationPath { get; }

	public bool AllowDefaultInitializeHarmonyDetourBridge => false;

	public AutoTranslatorPlugin()
	{
		ConfigPath = Paths.ConfigPath;
		TranslationPath = Paths.BepInExRootPath;
		_configPath = Path.Combine(ConfigPath, "AutoTranslatorConfig.ini");
	}

	public IniFile ReloadConfig()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		if (!File.Exists(_configPath))
		{
			return (IniFile)(((object)_file) ?? ((object)new IniFile()));
		}
		IniFile val = IniFile.FromFile(_configPath);
		if (_file == null)
		{
			return _file = val;
		}
		_file.Merge(val);
		return _file;
	}

	public void SaveConfig()
	{
		_file.Save(_configPath);
	}

	private void Awake()
	{
		PluginLoader.LoadWithConfig((IPluginEnvironment)(object)this);
	}
}

BepInEx/plugins/Kuriki-LethalCompanyDe/XUnity.AutoTranslator.Plugin.Core.dll

Decompiled a year ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Cache;
using System.Net.Security;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using DynamicLinq;
using ExIni;
using Harmony;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Encryption;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using Microsoft.CodeAnalysis;
using MonoMod.RuntimeDetour;
using UnityEngine;
using UnityEngine.SceneManagement;
using XUnity.AutoTranslator.Plugin.Core.AssetRedirection;
using XUnity.AutoTranslator.Plugin.Core.Configuration;
using XUnity.AutoTranslator.Plugin.Core.Debugging;
using XUnity.AutoTranslator.Plugin.Core.Endpoints;
using XUnity.AutoTranslator.Plugin.Core.Extensions;
using XUnity.AutoTranslator.Plugin.Core.Fonts;
using XUnity.AutoTranslator.Plugin.Core.Hooks;
using XUnity.AutoTranslator.Plugin.Core.Hooks.NGUI;
using XUnity.AutoTranslator.Plugin.Core.Hooks.TextMeshPro;
using XUnity.AutoTranslator.Plugin.Core.Hooks.UGUI;
using XUnity.AutoTranslator.Plugin.Core.Managed.Textures;
using XUnity.AutoTranslator.Plugin.Core.Parsing;
using XUnity.AutoTranslator.Plugin.Core.Properties;
using XUnity.AutoTranslator.Plugin.Core.Shims;
using XUnity.AutoTranslator.Plugin.Core.Text;
using XUnity.AutoTranslator.Plugin.Core.Textures;
using XUnity.AutoTranslator.Plugin.Core.UI;
using XUnity.AutoTranslator.Plugin.Core.UIResize;
using XUnity.AutoTranslator.Plugin.Core.Utilities;
using XUnity.AutoTranslator.Plugin.Core.Web;
using XUnity.AutoTranslator.Plugin.Core.Web.Internal;
using XUnity.AutoTranslator.Plugin.ExtProtocol;
using XUnity.AutoTranslator.Plugin.Utilities;
using XUnity.Common.Constants;
using XUnity.Common.Extensions;
using XUnity.Common.Harmony;
using XUnity.Common.Logging;
using XUnity.Common.MonoMod;
using XUnity.Common.Utilities;
using XUnity.ResourceRedirector;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("XUnity.AutoTranslator.Plugin.Core")]
[assembly: AssemblyProduct("XUnity.AutoTranslator.Plugin.Core")]
[assembly: AssemblyInformationalVersion("5.3.0")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyDescription("Main development dependency for XUnity Auto Translator.")]
[assembly: AssemblyFileVersion("5.3.0.0")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCompany("gravydevsupreme")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: InternalsVisibleTo("XUnity.AutoTranslator.Plugin.Core.Tests")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("5.3.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DynamicLinq
{
	internal static class DynamicQueryable
	{
		public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
		{
			return (IQueryable<T>)((IQueryable)source).Where(predicate, values);
		}

		public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			LambdaExpression expression = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);
			return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Where", new Type[1] { source.ElementType }, source.Expression, Expression.Quote(expression)));
		}

		public static IQueryable Select(this IQueryable source, string selector, params object[] values)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (selector == null)
			{
				throw new ArgumentNullException("selector");
			}
			LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);
			return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Select", new Type[2]
			{
				source.ElementType,
				lambdaExpression.Body.Type
			}, source.Expression, Expression.Quote(lambdaExpression)));
		}

		public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
		{
			return (IQueryable<T>)((IQueryable)source).OrderBy(ordering, values);
		}

		public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (ordering == null)
			{
				throw new ArgumentNullException("ordering");
			}
			ParameterExpression[] parameters = new ParameterExpression[1] { Expression.Parameter(source.ElementType, "") };
			IEnumerable<DynamicOrdering> enumerable = new ExpressionParser(parameters, ordering, values).ParseOrdering();
			Expression expression = source.Expression;
			string text = "OrderBy";
			string text2 = "OrderByDescending";
			foreach (DynamicOrdering item in enumerable)
			{
				expression = Expression.Call(typeof(Queryable), item.Ascending ? text : text2, new Type[2]
				{
					source.ElementType,
					item.Selector.Type
				}, expression, Expression.Quote(Expression.Lambda(item.Selector, parameters)));
				text = "ThenBy";
				text2 = "ThenByDescending";
			}
			return source.Provider.CreateQuery(expression);
		}

		public static IQueryable Take(this IQueryable source, int count)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Take", new Type[1] { source.ElementType }, source.Expression, Expression.Constant(count)));
		}

		public static IQueryable Skip(this IQueryable source, int count)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Skip", new Type[1] { source.ElementType }, source.Expression, Expression.Constant(count)));
		}

		public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			if (elementSelector == null)
			{
				throw new ArgumentNullException("elementSelector");
			}
			LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values);
			LambdaExpression lambdaExpression2 = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values);
			return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "GroupBy", new Type[3]
			{
				source.ElementType,
				lambdaExpression.Body.Type,
				lambdaExpression2.Body.Type
			}, source.Expression, Expression.Quote(lambdaExpression), Expression.Quote(lambdaExpression2)));
		}

		public static bool Any(this IQueryable source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return (bool)source.Provider.Execute(Expression.Call(typeof(Queryable), "Any", new Type[1] { source.ElementType }, source.Expression));
		}

		public static int Count(this IQueryable source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return (int)source.Provider.Execute(Expression.Call(typeof(Queryable), "Count", new Type[1] { source.ElementType }, source.Expression));
		}
	}
	internal abstract class DynamicClass
	{
		public override string ToString()
		{
			PropertyInfo[] properties = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("{");
			for (int i = 0; i < properties.Length; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(", ");
				}
				stringBuilder.Append(properties[i].Name);
				stringBuilder.Append("=");
				stringBuilder.Append(properties[i].GetValue(this, null));
			}
			stringBuilder.Append("}");
			return stringBuilder.ToString();
		}
	}
	internal class DynamicProperty
	{
		private string name;

		private Type type;

		public string Name => name;

		public Type Type => type;

		public DynamicProperty(string name, Type type)
		{
			if (name == null)
			{
				throw new ArgumentNullException("name");
			}
			if ((object)type == null)
			{
				throw new ArgumentNullException("type");
			}
			this.name = name;
			this.type = type;
		}
	}
	internal static class DynamicExpression
	{
		public static Expression Parse(Type resultType, string expression, params object[] values)
		{
			return new ExpressionParser(null, expression, values).Parse(resultType);
		}

		public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values)
		{
			return ParseLambda(new ParameterExpression[1] { Expression.Parameter(itType, "") }, resultType, expression, values);
		}

		public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
		{
			return Expression.Lambda(new ExpressionParser(parameters, expression, values).Parse(resultType), parameters);
		}

		public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values)
		{
			return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values);
		}

		public static Type CreateClass(params DynamicProperty[] properties)
		{
			throw new NotImplementedException();
		}

		public static Type CreateClass(IEnumerable<DynamicProperty> properties)
		{
			throw new NotImplementedException();
		}
	}
	internal class DynamicOrdering
	{
		public Expression Selector;

		public bool Ascending;
	}
	internal class Signature : IEquatable<Signature>
	{
		public DynamicProperty[] properties;

		public int hashCode;

		public Signature(IEnumerable<DynamicProperty> properties)
		{
			this.properties = properties.ToArray();
			hashCode = 0;
			foreach (DynamicProperty property in properties)
			{
				hashCode ^= property.Name.GetHashCode() ^ property.Type.GetHashCode();
			}
		}

		public override int GetHashCode()
		{
			return hashCode;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is Signature))
			{
				return false;
			}
			return Equals((Signature)obj);
		}

		public bool Equals(Signature other)
		{
			if (properties.Length != other.properties.Length)
			{
				return false;
			}
			for (int i = 0; i < properties.Length; i++)
			{
				if (properties[i].Name != other.properties[i].Name || (object)properties[i].Type != other.properties[i].Type)
				{
					return false;
				}
			}
			return true;
		}
	}
	internal sealed class ParseException : Exception
	{
		private int position;

		public int Position => position;

		public ParseException(string message, int position)
			: base(message)
		{
			this.position = position;
		}

		public override string ToString()
		{
			return $"{Message} (at index {position})";
		}
	}
	internal class ExpressionParser
	{
		private struct Token
		{
			public TokenId id;

			public string text;

			public int pos;
		}

		private enum TokenId
		{
			Unknown,
			End,
			Identifier,
			StringLiteral,
			IntegerLiteral,
			RealLiteral,
			Exclamation,
			Percent,
			Amphersand,
			OpenParen,
			CloseParen,
			Asterisk,
			Plus,
			Comma,
			Minus,
			Dot,
			Slash,
			Colon,
			LessThan,
			Equal,
			GreaterThan,
			Question,
			OpenBracket,
			CloseBracket,
			Bar,
			ExclamationEqual,
			DoubleAmphersand,
			LessThanEqual,
			LessGreater,
			DoubleEqual,
			GreaterThanEqual,
			DoubleBar
		}

		private interface ILogicalSignatures
		{
			void F(bool x, bool y);

			void F(bool? x, bool? y);
		}

		private interface IArithmeticSignatures
		{
			void F(int x, int y);

			void F(uint x, uint y);

			void F(long x, long y);

			void F(ulong x, ulong y);

			void F(float x, float y);

			void F(double x, double y);

			void F(decimal x, decimal y);

			void F(int? x, int? y);

			void F(uint? x, uint? y);

			void F(long? x, long? y);

			void F(ulong? x, ulong? y);

			void F(float? x, float? y);

			void F(double? x, double? y);

			void F(decimal? x, decimal? y);
		}

		private interface IRelationalSignatures : IArithmeticSignatures
		{
			void F(string x, string y);

			void F(char x, char y);

			void F(DateTime x, DateTime y);

			void F(TimeSpan x, TimeSpan y);

			void F(char? x, char? y);

			void F(DateTime? x, DateTime? y);

			void F(TimeSpan? x, TimeSpan? y);
		}

		private interface IEqualitySignatures : IRelationalSignatures, IArithmeticSignatures
		{
			void F(bool x, bool y);

			void F(bool? x, bool? y);
		}

		private interface IAddSignatures : IArithmeticSignatures
		{
			void F(DateTime x, TimeSpan y);

			void F(TimeSpan x, TimeSpan y);

			void F(DateTime? x, TimeSpan? y);

			void F(TimeSpan? x, TimeSpan? y);
		}

		private interface ISubtractSignatures : IAddSignatures, IArithmeticSignatures
		{
			void F(DateTime x, DateTime y);

			void F(DateTime? x, DateTime? y);
		}

		private interface INegationSignatures
		{
			void F(int x);

			void F(long x);

			void F(float x);

			void F(double x);

			void F(decimal x);

			void F(int? x);

			void F(long? x);

			void F(float? x);

			void F(double? x);

			void F(decimal? x);
		}

		private interface INotSignatures
		{
			void F(bool x);

			void F(bool? x);
		}

		private interface IEnumerableSignatures
		{
			void Where(bool predicate);

			void Any();

			void Any(bool predicate);

			void All(bool predicate);

			void Count();

			void Count(bool predicate);

			void Min(object selector);

			void Max(object selector);

			void Sum(int selector);

			void Sum(int? selector);

			void Sum(long selector);

			void Sum(long? selector);

			void Sum(float selector);

			void Sum(float? selector);

			void Sum(double selector);

			void Sum(double? selector);

			void Sum(decimal selector);

			void Sum(decimal? selector);

			void Average(int selector);

			void Average(int? selector);

			void Average(long selector);

			void Average(long? selector);

			void Average(float selector);

			void Average(float? selector);

			void Average(double selector);

			void Average(double? selector);

			void Average(decimal selector);

			void Average(decimal? selector);
		}

		private class MethodData
		{
			public MethodBase MethodBase;

			public ParameterInfo[] Parameters;

			public Expression[] Args;
		}

		private static readonly Type[] predefinedTypes = new Type[20]
		{
			typeof(object),
			typeof(bool),
			typeof(char),
			typeof(string),
			typeof(sbyte),
			typeof(byte),
			typeof(short),
			typeof(ushort),
			typeof(int),
			typeof(uint),
			typeof(long),
			typeof(ulong),
			typeof(float),
			typeof(double),
			typeof(decimal),
			typeof(DateTime),
			typeof(TimeSpan),
			typeof(Guid),
			typeof(Math),
			typeof(Convert)
		};

		private static readonly Expression trueLiteral = Expression.Constant(true);

		private static readonly Expression falseLiteral = Expression.Constant(false);

		private static readonly Expression nullLiteral = Expression.Constant(null);

		private static readonly string keywordIt = "it";

		private static readonly string keywordIif = "iif";

		private static readonly string keywordNew = "new";

		private static Dictionary<string, object> keywords;

		private Dictionary<string, object> symbols;

		private IDictionary<string, object> externals;

		private Dictionary<Expression, string> literals;

		private ParameterExpression it;

		private string text;

		private int textPos;

		private int textLen;

		private char ch;

		private Token token;

		public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			if (keywords == null)
			{
				keywords = CreateKeywords();
			}
			symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
			literals = new Dictionary<Expression, string>();
			if (parameters != null)
			{
				ProcessParameters(parameters);
			}
			if (values != null)
			{
				ProcessValues(values);
			}
			text = expression;
			textLen = text.Length;
			SetTextPos(0);
			NextToken();
		}

		private void ProcessParameters(ParameterExpression[] parameters)
		{
			foreach (ParameterExpression parameterExpression in parameters)
			{
				if (!string.IsNullOrEmpty(parameterExpression.Name))
				{
					AddSymbol(parameterExpression.Name, parameterExpression);
				}
			}
			if (parameters.Length == 1 && string.IsNullOrEmpty(parameters[0].Name))
			{
				it = parameters[0];
			}
		}

		private void ProcessValues(object[] values)
		{
			for (int i = 0; i < values.Length; i++)
			{
				object obj = values[i];
				if (i == values.Length - 1 && obj is IDictionary<string, object>)
				{
					externals = (IDictionary<string, object>)obj;
				}
				else
				{
					AddSymbol("@" + i.ToString(CultureInfo.InvariantCulture), obj);
				}
			}
		}

		private void AddSymbol(string name, object value)
		{
			if (symbols.ContainsKey(name))
			{
				throw ParseError("The identifier '{0}' was defined more than once", name);
			}
			symbols.Add(name, value);
		}

		public Expression Parse(Type resultType)
		{
			int pos = token.pos;
			Expression expression = ParseExpression();
			if ((object)resultType != null && (expression = PromoteExpression(expression, resultType, exact: true)) == null)
			{
				throw ParseError(pos, "Expression of type '{0}' expected", GetTypeName(resultType));
			}
			ValidateToken(TokenId.End, "Syntax error");
			return expression;
		}

		public IEnumerable<DynamicOrdering> ParseOrdering()
		{
			List<DynamicOrdering> list = new List<DynamicOrdering>();
			while (true)
			{
				Expression selector = ParseExpression();
				bool ascending = true;
				if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))
				{
					NextToken();
				}
				else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))
				{
					NextToken();
					ascending = false;
				}
				list.Add(new DynamicOrdering
				{
					Selector = selector,
					Ascending = ascending
				});
				if (token.id != TokenId.Comma)
				{
					break;
				}
				NextToken();
			}
			ValidateToken(TokenId.End, "Syntax error");
			return list;
		}

		private Expression ParseExpression()
		{
			int pos = token.pos;
			Expression expression = ParseLogicalOr();
			if (token.id == TokenId.Question)
			{
				NextToken();
				Expression expr = ParseExpression();
				ValidateToken(TokenId.Colon, "':' expected");
				NextToken();
				Expression expr2 = ParseExpression();
				expression = GenerateConditional(expression, expr, expr2, pos);
			}
			return expression;
		}

		private Expression ParseLogicalOr()
		{
			Expression left = ParseLogicalAnd();
			while (this.token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))
			{
				Token token = this.token;
				NextToken();
				Expression right = ParseLogicalAnd();
				CheckAndPromoteOperands(typeof(ILogicalSignatures), token.text, ref left, ref right, token.pos);
				left = Expression.OrElse(left, right);
			}
			return left;
		}

		private Expression ParseLogicalAnd()
		{
			Expression left = ParseComparison();
			while (this.token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
			{
				Token token = this.token;
				NextToken();
				Expression right = ParseComparison();
				CheckAndPromoteOperands(typeof(ILogicalSignatures), token.text, ref left, ref right, token.pos);
				left = Expression.AndAlso(left, right);
			}
			return left;
		}

		private Expression ParseComparison()
		{
			Expression left = ParseAdditive();
			while (this.token.id == TokenId.Equal || this.token.id == TokenId.DoubleEqual || this.token.id == TokenId.ExclamationEqual || this.token.id == TokenId.LessGreater || this.token.id == TokenId.GreaterThan || this.token.id == TokenId.GreaterThanEqual || this.token.id == TokenId.LessThan || this.token.id == TokenId.LessThanEqual)
			{
				Token token = this.token;
				NextToken();
				Expression right = ParseAdditive();
				bool flag = token.id == TokenId.Equal || token.id == TokenId.DoubleEqual || token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater;
				if (flag && !left.Type.IsValueType && !right.Type.IsValueType)
				{
					if ((object)left.Type != right.Type)
					{
						if (left.Type.IsAssignableFrom(right.Type))
						{
							right = Expression.Convert(right, left.Type);
						}
						else
						{
							if (!right.Type.IsAssignableFrom(left.Type))
							{
								throw IncompatibleOperandsError(token.text, left, right, token.pos);
							}
							left = Expression.Convert(left, right.Type);
						}
					}
				}
				else if (IsEnumType(left.Type) || IsEnumType(right.Type))
				{
					if ((object)left.Type != right.Type)
					{
						Expression expression;
						if ((expression = PromoteExpression(right, left.Type, exact: true)) != null)
						{
							right = expression;
						}
						else
						{
							if ((expression = PromoteExpression(left, right.Type, exact: true)) == null)
							{
								throw IncompatibleOperandsError(token.text, left, right, token.pos);
							}
							left = expression;
						}
					}
				}
				else
				{
					CheckAndPromoteOperands(flag ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), token.text, ref left, ref right, token.pos);
				}
				switch (token.id)
				{
				case TokenId.Equal:
				case TokenId.DoubleEqual:
					left = GenerateEqual(left, right);
					break;
				case TokenId.ExclamationEqual:
				case TokenId.LessGreater:
					left = GenerateNotEqual(left, right);
					break;
				case TokenId.GreaterThan:
					left = GenerateGreaterThan(left, right);
					break;
				case TokenId.GreaterThanEqual:
					left = GenerateGreaterThanEqual(left, right);
					break;
				case TokenId.LessThan:
					left = GenerateLessThan(left, right);
					break;
				case TokenId.LessThanEqual:
					left = GenerateLessThanEqual(left, right);
					break;
				}
			}
			return left;
		}

		private Expression ParseAdditive()
		{
			Expression left = ParseMultiplicative();
			while (this.token.id == TokenId.Plus || this.token.id == TokenId.Minus || this.token.id == TokenId.Amphersand)
			{
				Token token = this.token;
				NextToken();
				Expression right = ParseMultiplicative();
				TokenId id = token.id;
				if (id != TokenId.Amphersand)
				{
					if (id != TokenId.Plus)
					{
						if (id == TokenId.Minus)
						{
							CheckAndPromoteOperands(typeof(ISubtractSignatures), token.text, ref left, ref right, token.pos);
							left = GenerateSubtract(left, right);
						}
						continue;
					}
					if ((object)left.Type != typeof(string) && (object)right.Type != typeof(string))
					{
						CheckAndPromoteOperands(typeof(IAddSignatures), token.text, ref left, ref right, token.pos);
						left = GenerateAdd(left, right);
						continue;
					}
				}
				left = GenerateStringConcat(left, right);
			}
			return left;
		}

		private Expression ParseMultiplicative()
		{
			Expression left = ParseUnary();
			while (this.token.id == TokenId.Asterisk || this.token.id == TokenId.Slash || this.token.id == TokenId.Percent || TokenIdentifierIs("mod"))
			{
				Token token = this.token;
				NextToken();
				Expression right = ParseUnary();
				CheckAndPromoteOperands(typeof(IArithmeticSignatures), token.text, ref left, ref right, token.pos);
				switch (token.id)
				{
				case TokenId.Asterisk:
					left = Expression.Multiply(left, right);
					break;
				case TokenId.Slash:
					left = Expression.Divide(left, right);
					break;
				case TokenId.Identifier:
				case TokenId.Percent:
					left = Expression.Modulo(left, right);
					break;
				}
			}
			return left;
		}

		private Expression ParseUnary()
		{
			if (this.token.id == TokenId.Minus || this.token.id == TokenId.Exclamation || TokenIdentifierIs("not"))
			{
				Token token = this.token;
				NextToken();
				if (token.id == TokenId.Minus && (this.token.id == TokenId.IntegerLiteral || this.token.id == TokenId.RealLiteral))
				{
					this.token.text = "-" + this.token.text;
					this.token.pos = token.pos;
					return ParsePrimary();
				}
				Expression expr = ParseUnary();
				if (token.id == TokenId.Minus)
				{
					CheckAndPromoteOperand(typeof(INegationSignatures), token.text, ref expr, token.pos);
					return Expression.Negate(expr);
				}
				CheckAndPromoteOperand(typeof(INotSignatures), token.text, ref expr, token.pos);
				return Expression.Not(expr);
			}
			return ParsePrimary();
		}

		private Expression ParsePrimary()
		{
			Expression expression = ParsePrimaryStart();
			while (true)
			{
				if (token.id == TokenId.Dot)
				{
					NextToken();
					expression = ParseMemberAccess(null, expression);
					continue;
				}
				if (token.id != TokenId.OpenBracket)
				{
					break;
				}
				expression = ParseElementAccess(expression);
			}
			return expression;
		}

		private Expression ParsePrimaryStart()
		{
			return token.id switch
			{
				TokenId.Identifier => ParseIdentifier(), 
				TokenId.StringLiteral => ParseStringLiteral(), 
				TokenId.IntegerLiteral => ParseIntegerLiteral(), 
				TokenId.RealLiteral => ParseRealLiteral(), 
				TokenId.OpenParen => ParseParenExpression(), 
				_ => throw ParseError("Expression expected"), 
			};
		}

		private Expression ParseStringLiteral()
		{
			ValidateToken(TokenId.StringLiteral);
			char c = token.text[0];
			string text = token.text.Substring(1, token.text.Length - 2);
			int startIndex = 0;
			while (true)
			{
				int num = text.IndexOf(c, startIndex);
				if (num < 0)
				{
					break;
				}
				text = text.Remove(num, 1);
				startIndex = num + 1;
			}
			if (c == '\'')
			{
				if (text.Length != 1)
				{
					throw ParseError("Character literal must contain exactly one character");
				}
				NextToken();
				return CreateLiteral(text[0], text);
			}
			NextToken();
			return CreateLiteral(text, text);
		}

		private Expression ParseIntegerLiteral()
		{
			ValidateToken(TokenId.IntegerLiteral);
			string text = token.text;
			if (text[0] != '-')
			{
				if (!ulong.TryParse(text, out var result))
				{
					throw ParseError("Invalid integer literal '{0}'", text);
				}
				NextToken();
				if (result <= int.MaxValue)
				{
					return CreateLiteral((int)result, text);
				}
				if (result <= uint.MaxValue)
				{
					return CreateLiteral((uint)result, text);
				}
				if (result <= long.MaxValue)
				{
					return CreateLiteral((long)result, text);
				}
				return CreateLiteral(result, text);
			}
			if (!long.TryParse(text, out var result2))
			{
				throw ParseError("Invalid integer literal '{0}'", text);
			}
			NextToken();
			if (result2 >= int.MinValue && result2 <= int.MaxValue)
			{
				return CreateLiteral((int)result2, text);
			}
			return CreateLiteral(result2, text);
		}

		private Expression ParseRealLiteral()
		{
			ValidateToken(TokenId.RealLiteral);
			string text = token.text;
			object obj = null;
			char c = text[text.Length - 1];
			double result2;
			if (c == 'F' || c == 'f')
			{
				if (float.TryParse(text.Substring(0, text.Length - 1), out var result))
				{
					obj = result;
				}
			}
			else if (double.TryParse(text, out result2))
			{
				obj = result2;
			}
			if (obj == null)
			{
				throw ParseError("Invalid real literal '{0}'", text);
			}
			NextToken();
			return CreateLiteral(obj, text);
		}

		private Expression CreateLiteral(object value, string text)
		{
			ConstantExpression constantExpression = Expression.Constant(value);
			literals.Add(constantExpression, text);
			return constantExpression;
		}

		private Expression ParseParenExpression()
		{
			ValidateToken(TokenId.OpenParen, "'(' expected");
			NextToken();
			Expression result = ParseExpression();
			ValidateToken(TokenId.CloseParen, "')' or operator expected");
			NextToken();
			return result;
		}

		private Expression ParseIdentifier()
		{
			ValidateToken(TokenId.Identifier);
			if (keywords.TryGetValue(token.text, out var value))
			{
				if (value is Type)
				{
					return ParseTypeAccess((Type)value);
				}
				if (value == keywordIt)
				{
					return ParseIt();
				}
				if (value == keywordIif)
				{
					return ParseIif();
				}
				if (value == keywordNew)
				{
					return ParseNew();
				}
				NextToken();
				return (Expression)value;
			}
			if (symbols.TryGetValue(token.text, out value) || (externals != null && externals.TryGetValue(token.text, out value)))
			{
				Expression expression = value as Expression;
				if (expression == null)
				{
					expression = Expression.Constant(value);
				}
				else if (expression is LambdaExpression lambda)
				{
					return ParseLambdaInvocation(lambda);
				}
				NextToken();
				return expression;
			}
			if (it != null)
			{
				return ParseMemberAccess(null, it);
			}
			throw ParseError("Unknown identifier '{0}'", token.text);
		}

		private Expression ParseIt()
		{
			if (it == null)
			{
				throw ParseError("No 'it' is in scope");
			}
			NextToken();
			return it;
		}

		private Expression ParseIif()
		{
			int pos = token.pos;
			NextToken();
			Expression[] array = ParseArgumentList();
			if (array.Length != 3)
			{
				throw ParseError(pos, "The 'iif' function requires three arguments");
			}
			return GenerateConditional(array[0], array[1], array[2], pos);
		}

		private Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos)
		{
			if ((object)test.Type != typeof(bool))
			{
				throw ParseError(errorPos, "The first expression must be of type 'Boolean'");
			}
			if ((object)expr1.Type != expr2.Type)
			{
				Expression expression = ((expr2 != nullLiteral) ? PromoteExpression(expr1, expr2.Type, exact: true) : null);
				Expression expression2 = ((expr1 != nullLiteral) ? PromoteExpression(expr2, expr1.Type, exact: true) : null);
				if (expression != null && expression2 == null)
				{
					expr1 = expression;
				}
				else
				{
					if (expression2 == null || expression != null)
					{
						string text = ((expr1 != nullLiteral) ? expr1.Type.Name : "null");
						string text2 = ((expr2 != nullLiteral) ? expr2.Type.Name : "null");
						if (expression != null && expression2 != null)
						{
							throw ParseError(errorPos, "Both of the types '{0}' and '{1}' convert to the other", text, text2);
						}
						throw ParseError(errorPos, "Neither of the types '{0}' and '{1}' converts to the other", text, text2);
					}
					expr2 = expression2;
				}
			}
			return Expression.Condition(test, expr1, expr2);
		}

		private Expression ParseNew()
		{
			NextToken();
			ValidateToken(TokenId.OpenParen, "'(' expected");
			NextToken();
			List<DynamicProperty> list = new List<DynamicProperty>();
			List<Expression> list2 = new List<Expression>();
			while (true)
			{
				int pos = token.pos;
				Expression expression = ParseExpression();
				string name;
				if (TokenIdentifierIs("as"))
				{
					NextToken();
					name = GetIdentifier();
					NextToken();
				}
				else
				{
					if (!(expression is MemberExpression memberExpression))
					{
						throw ParseError(pos, "Expression is missing an 'as' clause");
					}
					name = memberExpression.Member.Name;
				}
				list2.Add(expression);
				list.Add(new DynamicProperty(name, expression.Type));
				if (token.id != TokenId.Comma)
				{
					break;
				}
				NextToken();
			}
			ValidateToken(TokenId.CloseParen, "')' or ',' expected");
			NextToken();
			Type type = DynamicExpression.CreateClass(list);
			MemberBinding[] array = new MemberBinding[list.Count];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = Expression.Bind(type.GetProperty(list[i].Name), list2[i]);
			}
			return Expression.MemberInit(Expression.New(type), array);
		}

		private Expression ParseLambdaInvocation(LambdaExpression lambda)
		{
			int pos = token.pos;
			NextToken();
			Expression[] array = ParseArgumentList();
			if (FindMethod(lambda.Type, "Invoke", staticAccess: false, array, out var _) != 1)
			{
				throw ParseError(pos, "Argument list incompatible with lambda expression");
			}
			return Expression.Invoke(lambda, array);
		}

		private Expression ParseTypeAccess(Type type)
		{
			int pos = token.pos;
			NextToken();
			if (token.id == TokenId.Question)
			{
				if (!type.IsValueType || IsNullableType(type))
				{
					throw ParseError(pos, "Type '{0}' has no nullable form", GetTypeName(type));
				}
				type = typeof(Nullable<>).MakeGenericType(type);
				NextToken();
			}
			if (token.id == TokenId.OpenParen)
			{
				Expression[] array = ParseArgumentList();
				MethodBase method;
				switch (FindBestMethod(type.GetConstructors(), array, out method))
				{
				case 0:
					if (array.Length == 1)
					{
						return GenerateConversion(array[0], type, pos);
					}
					throw ParseError(pos, "No matching constructor in type '{0}'", GetTypeName(type));
				case 1:
					return Expression.New((ConstructorInfo)method, array);
				default:
					throw ParseError(pos, "Ambiguous invocation of '{0}' constructor", GetTypeName(type));
				}
			}
			ValidateToken(TokenId.Dot, "'.' or '(' expected");
			NextToken();
			return ParseMemberAccess(type, null);
		}

		private Expression GenerateConversion(Expression expr, Type type, int errorPos)
		{
			Type type2 = expr.Type;
			if ((object)type2 == type)
			{
				return expr;
			}
			if (type2.IsValueType && type.IsValueType)
			{
				if ((IsNullableType(type2) || IsNullableType(type)) && (object)GetNonNullableType(type2) == GetNonNullableType(type))
				{
					return Expression.Convert(expr, type);
				}
				if (((IsNumericType(type2) || IsEnumType(type2)) && IsNumericType(type)) || IsEnumType(type))
				{
					return Expression.ConvertChecked(expr, type);
				}
			}
			if (type2.IsAssignableFrom(type) || type.IsAssignableFrom(type2) || type2.IsInterface || type.IsInterface)
			{
				return Expression.Convert(expr, type);
			}
			throw ParseError(errorPos, "A value of type '{0}' cannot be converted to type '{1}'", GetTypeName(type2), GetTypeName(type));
		}

		private Expression ParseMemberAccess(Type type, Expression instance)
		{
			if (instance != null)
			{
				type = instance.Type;
			}
			int pos = token.pos;
			string identifier = GetIdentifier();
			NextToken();
			if (token.id == TokenId.OpenParen)
			{
				if (instance != null && (object)type != typeof(string))
				{
					Type type2 = FindGenericType(typeof(IEnumerable<>), type);
					if ((object)type2 != null)
					{
						Type elementType = type2.GetGenericArguments()[0];
						return ParseAggregate(instance, elementType, identifier, pos);
					}
				}
				Expression[] array = ParseArgumentList();
				MethodBase method;
				switch (FindMethod(type, identifier, instance == null, array, out method))
				{
				case 0:
					throw ParseError(pos, "No applicable method '{0}' exists in type '{1}'", identifier, GetTypeName(type));
				case 1:
				{
					MethodInfo methodInfo = (MethodInfo)method;
					if (!IsPredefinedType(methodInfo.DeclaringType))
					{
						throw ParseError(pos, "Methods on type '{0}' are not accessible", GetTypeName(methodInfo.DeclaringType));
					}
					if ((object)methodInfo.ReturnType == typeof(void))
					{
						throw ParseError(pos, "Method '{0}' in type '{1}' does not return a value", identifier, GetTypeName(methodInfo.DeclaringType));
					}
					return Expression.Call(instance, methodInfo, array);
				}
				default:
					throw ParseError(pos, "Ambiguous invocation of method '{0}' in type '{1}'", identifier, GetTypeName(type));
				}
			}
			MemberInfo memberInfo = FindPropertyOrField(type, identifier, instance == null);
			if ((object)memberInfo == null)
			{
				throw ParseError(pos, "No property or field '{0}' exists in type '{1}'", identifier, GetTypeName(type));
			}
			if (!(memberInfo is PropertyInfo))
			{
				return Expression.Field(instance, (FieldInfo)memberInfo);
			}
			return Expression.Property(instance, (PropertyInfo)memberInfo);
		}

		private static Type FindGenericType(Type generic, Type type)
		{
			while ((object)type != null && (object)type != typeof(object))
			{
				if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == generic)
				{
					return type;
				}
				if (generic.IsInterface)
				{
					Type[] interfaces = type.GetInterfaces();
					foreach (Type type2 in interfaces)
					{
						Type type3 = FindGenericType(generic, type2);
						if ((object)type3 != null)
						{
							return type3;
						}
					}
				}
				type = type.BaseType;
			}
			return null;
		}

		private Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
		{
			ParameterExpression parameterExpression = it;
			ParameterExpression parameterExpression2 = (it = Expression.Parameter(elementType, ""));
			Expression[] array = ParseArgumentList();
			it = parameterExpression;
			if (FindMethod(typeof(IEnumerableSignatures), methodName, staticAccess: false, array, out var method) != 1)
			{
				throw ParseError(errorPos, "No applicable aggregate method '{0}' exists", methodName);
			}
			return Expression.Call(typeArguments: (!(method.Name == "Min") && !(method.Name == "Max")) ? new Type[1] { elementType } : new Type[2]
			{
				elementType,
				array[0].Type
			}, arguments: (array.Length != 0) ? new Expression[2]
			{
				instance,
				Expression.Lambda(array[0], parameterExpression2)
			} : new Expression[1] { instance }, type: typeof(Enumerable), methodName: method.Name);
		}

		private Expression[] ParseArgumentList()
		{
			ValidateToken(TokenId.OpenParen, "'(' expected");
			NextToken();
			Expression[] result = ((token.id != TokenId.CloseParen) ? ParseArguments() : new Expression[0]);
			ValidateToken(TokenId.CloseParen, "')' or ',' expected");
			NextToken();
			return result;
		}

		private Expression[] ParseArguments()
		{
			List<Expression> list = new List<Expression>();
			while (true)
			{
				list.Add(ParseExpression());
				if (token.id != TokenId.Comma)
				{
					break;
				}
				NextToken();
			}
			return list.ToArray();
		}

		private Expression ParseElementAccess(Expression expr)
		{
			int pos = token.pos;
			ValidateToken(TokenId.OpenBracket, "'(' expected");
			NextToken();
			Expression[] array = ParseArguments();
			ValidateToken(TokenId.CloseBracket, "']' or ',' expected");
			NextToken();
			if (expr.Type.IsArray)
			{
				if (expr.Type.GetArrayRank() != 1 || array.Length != 1)
				{
					throw ParseError(pos, "Indexing of multi-dimensional arrays is not supported");
				}
				Expression expression = PromoteExpression(array[0], typeof(int), exact: true);
				if (expression == null)
				{
					throw ParseError(pos, "Array index must be an integer expression");
				}
				return Expression.ArrayIndex(expr, expression);
			}
			MethodBase method;
			return FindIndexer(expr.Type, array, out method) switch
			{
				0 => throw ParseError(pos, "No applicable indexer exists in type '{0}'", GetTypeName(expr.Type)), 
				1 => Expression.Call(expr, (MethodInfo)method, array), 
				_ => throw ParseError(pos, "Ambiguous invocation of indexer in type '{0}'", GetTypeName(expr.Type)), 
			};
		}

		private static bool IsPredefinedType(Type type)
		{
			Type[] array = predefinedTypes;
			for (int i = 0; i < array.Length; i++)
			{
				if ((object)array[i] == type)
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsNullableType(Type type)
		{
			if (type.IsGenericType)
			{
				return (object)type.GetGenericTypeDefinition() == typeof(Nullable<>);
			}
			return false;
		}

		private static Type GetNonNullableType(Type type)
		{
			if (!IsNullableType(type))
			{
				return type;
			}
			return type.GetGenericArguments()[0];
		}

		private static string GetTypeName(Type type)
		{
			Type nonNullableType = GetNonNullableType(type);
			string text = nonNullableType.Name;
			if ((object)type != nonNullableType)
			{
				text += "?";
			}
			return text;
		}

		private static bool IsNumericType(Type type)
		{
			return GetNumericTypeKind(type) != 0;
		}

		private static bool IsSignedIntegralType(Type type)
		{
			return GetNumericTypeKind(type) == 2;
		}

		private static bool IsUnsignedIntegralType(Type type)
		{
			return GetNumericTypeKind(type) == 3;
		}

		private static int GetNumericTypeKind(Type type)
		{
			type = GetNonNullableType(type);
			if (type.IsEnum)
			{
				return 0;
			}
			switch (Type.GetTypeCode(type))
			{
			case TypeCode.Char:
			case TypeCode.Single:
			case TypeCode.Double:
			case TypeCode.Decimal:
				return 1;
			case TypeCode.SByte:
			case TypeCode.Int16:
			case TypeCode.Int32:
			case TypeCode.Int64:
				return 2;
			case TypeCode.Byte:
			case TypeCode.UInt16:
			case TypeCode.UInt32:
			case TypeCode.UInt64:
				return 3;
			default:
				return 0;
			}
		}

		private static bool IsEnumType(Type type)
		{
			return GetNonNullableType(type).IsEnum;
		}

		private void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)
		{
			Expression[] array = new Expression[1] { expr };
			if (FindMethod(signatures, "F", staticAccess: false, array, out var _) != 1)
			{
				throw ParseError(errorPos, "Operator '{0}' incompatible with operand type '{1}'", opName, GetTypeName(array[0].Type));
			}
			expr = array[0];
		}

		private void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)
		{
			Expression[] array = new Expression[2] { left, right };
			if (FindMethod(signatures, "F", staticAccess: false, array, out var _) != 1)
			{
				throw IncompatibleOperandsError(opName, left, right, errorPos);
			}
			left = array[0];
			right = array[1];
		}

		private Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)
		{
			return ParseError(pos, "Operator '{0}' incompatible with operand types '{1}' and '{2}'", opName, GetTypeName(left.Type), GetTypeName(right.Type));
		}

		private MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
			foreach (Type item in SelfAndBaseTypes(type))
			{
				MemberInfo[] array = item.FindMembers(MemberTypes.Field | MemberTypes.Property, bindingAttr, Type.FilterNameIgnoreCase, memberName);
				if (array.Length != 0)
				{
					return array[0];
				}
			}
			return null;
		}

		private int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
			foreach (Type item in SelfAndBaseTypes(type))
			{
				MemberInfo[] source = item.FindMembers(MemberTypes.Method, bindingAttr, Type.FilterNameIgnoreCase, methodName);
				int num = FindBestMethod(source.Cast<MethodBase>(), args, out method);
				if (num != 0)
				{
					return num;
				}
			}
			method = null;
			return 0;
		}

		private int FindIndexer(Type type, Expression[] args, out MethodBase method)
		{
			foreach (Type item in SelfAndBaseTypes(type))
			{
				MemberInfo[] defaultMembers = item.GetDefaultMembers();
				if (defaultMembers.Length != 0)
				{
					IEnumerable<MethodBase> methods = from m in defaultMembers.OfType<PropertyInfo>().Select((Func<PropertyInfo, MethodBase>)((PropertyInfo p) => p.GetGetMethod()))
						where (object)m != null
						select m;
					int num = FindBestMethod(methods, args, out method);
					if (num != 0)
					{
						return num;
					}
				}
			}
			method = null;
			return 0;
		}

		private static IEnumerable<Type> SelfAndBaseTypes(Type type)
		{
			if (type.IsInterface)
			{
				List<Type> list = new List<Type>();
				AddInterface(list, type);
				return list;
			}
			return SelfAndBaseClasses(type);
		}

		private static IEnumerable<Type> SelfAndBaseClasses(Type type)
		{
			while ((object)type != null)
			{
				yield return type;
				type = type.BaseType;
			}
		}

		private static void AddInterface(List<Type> types, Type type)
		{
			if (!types.Contains(type))
			{
				types.Add(type);
				Type[] interfaces = type.GetInterfaces();
				foreach (Type type2 in interfaces)
				{
					AddInterface(types, type2);
				}
			}
		}

		private int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method)
		{
			MethodData[] applicable = (from m in methods
				select new MethodData
				{
					MethodBase = m,
					Parameters = m.GetParameters()
				} into m
				where IsApplicable(m, args)
				select m).ToArray();
			if (applicable.Length > 1)
			{
				applicable = applicable.Where((MethodData m) => applicable.All((MethodData n) => m == n || IsBetterThan(args, m, n))).ToArray();
			}
			if (applicable.Length == 1)
			{
				MethodData methodData = applicable[0];
				for (int i = 0; i < args.Length; i++)
				{
					args[i] = methodData.Args[i];
				}
				method = methodData.MethodBase;
			}
			else
			{
				method = null;
			}
			return applicable.Length;
		}

		private bool IsApplicable(MethodData method, Expression[] args)
		{
			if (method.Parameters.Length != args.Length)
			{
				return false;
			}
			Expression[] array = new Expression[args.Length];
			for (int i = 0; i < args.Length; i++)
			{
				ParameterInfo parameterInfo = method.Parameters[i];
				if (parameterInfo.IsOut)
				{
					return false;
				}
				Expression expression = PromoteExpression(args[i], parameterInfo.ParameterType, exact: false);
				if (expression == null)
				{
					return false;
				}
				array[i] = expression;
			}
			method.Args = array;
			return true;
		}

		private Expression PromoteExpression(Expression expr, Type type, bool exact)
		{
			if ((object)expr.Type == type)
			{
				return expr;
			}
			if (expr is ConstantExpression)
			{
				ConstantExpression constantExpression = (ConstantExpression)expr;
				string value;
				if (constantExpression == nullLiteral)
				{
					if (!type.IsValueType || IsNullableType(type))
					{
						return Expression.Constant(null, type);
					}
				}
				else if (literals.TryGetValue(constantExpression, out value))
				{
					Type nonNullableType = GetNonNullableType(type);
					object obj = null;
					switch (Type.GetTypeCode(constantExpression.Type))
					{
					case TypeCode.Int32:
					case TypeCode.UInt32:
					case TypeCode.Int64:
					case TypeCode.UInt64:
						obj = ParseNumber(value, nonNullableType);
						break;
					case TypeCode.Double:
						if ((object)nonNullableType == typeof(decimal))
						{
							obj = ParseNumber(value, nonNullableType);
						}
						break;
					case TypeCode.String:
						obj = ParseEnum(value, nonNullableType);
						break;
					}
					if (obj != null)
					{
						return Expression.Constant(obj, type);
					}
				}
			}
			if (IsCompatibleWith(expr.Type, type))
			{
				if (type.IsValueType || exact)
				{
					return Expression.Convert(expr, type);
				}
				return expr;
			}
			return null;
		}

		private static object ParseNumber(string text, Type type)
		{
			switch (Type.GetTypeCode(GetNonNullableType(type)))
			{
			case TypeCode.SByte:
			{
				if (sbyte.TryParse(text, out var result6))
				{
					return result6;
				}
				break;
			}
			case TypeCode.Byte:
			{
				if (byte.TryParse(text, out var result10))
				{
					return result10;
				}
				break;
			}
			case TypeCode.Int16:
			{
				if (short.TryParse(text, out var result2))
				{
					return result2;
				}
				break;
			}
			case TypeCode.UInt16:
			{
				if (ushort.TryParse(text, out var result8))
				{
					return result8;
				}
				break;
			}
			case TypeCode.Int32:
			{
				if (int.TryParse(text, out var result4))
				{
					return result4;
				}
				break;
			}
			case TypeCode.UInt32:
			{
				if (uint.TryParse(text, out var result11))
				{
					return result11;
				}
				break;
			}
			case TypeCode.Int64:
			{
				if (long.TryParse(text, out var result9))
				{
					return result9;
				}
				break;
			}
			case TypeCode.UInt64:
			{
				if (ulong.TryParse(text, out var result7))
				{
					return result7;
				}
				break;
			}
			case TypeCode.Single:
			{
				if (float.TryParse(text, out var result5))
				{
					return result5;
				}
				break;
			}
			case TypeCode.Double:
			{
				if (double.TryParse(text, out var result3))
				{
					return result3;
				}
				break;
			}
			case TypeCode.Decimal:
			{
				if (decimal.TryParse(text, out var result))
				{
					return result;
				}
				break;
			}
			}
			return null;
		}

		private static object ParseEnum(string name, Type type)
		{
			if (type.IsEnum)
			{
				MemberInfo[] array = type.FindMembers(MemberTypes.Field, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public, Type.FilterNameIgnoreCase, name);
				if (array.Length != 0)
				{
					return ((FieldInfo)array[0]).GetValue(null);
				}
			}
			return null;
		}

		private static bool IsCompatibleWith(Type source, Type target)
		{
			if ((object)source == target)
			{
				return true;
			}
			if (!target.IsValueType)
			{
				return target.IsAssignableFrom(source);
			}
			Type nonNullableType = GetNonNullableType(source);
			Type nonNullableType2 = GetNonNullableType(target);
			if ((object)nonNullableType != source && (object)nonNullableType2 == target)
			{
				return false;
			}
			TypeCode typeCode = (nonNullableType.IsEnum ? TypeCode.Object : Type.GetTypeCode(nonNullableType));
			TypeCode typeCode2 = (nonNullableType2.IsEnum ? TypeCode.Object : Type.GetTypeCode(nonNullableType2));
			switch (typeCode)
			{
			case TypeCode.SByte:
				switch (typeCode2)
				{
				case TypeCode.SByte:
				case TypeCode.Int16:
				case TypeCode.Int32:
				case TypeCode.Int64:
				case TypeCode.Single:
				case TypeCode.Double:
				case TypeCode.Decimal:
					return true;
				}
				break;
			case TypeCode.Byte:
				if ((uint)(typeCode2 - 6) <= 9u)
				{
					return true;
				}
				break;
			case TypeCode.Int16:
				switch (typeCode2)
				{
				case TypeCode.Int16:
				case TypeCode.Int32:
				case TypeCode.Int64:
				case TypeCode.Single:
				case TypeCode.Double:
				case TypeCode.Decimal:
					return true;
				}
				break;
			case TypeCode.UInt16:
				if ((uint)(typeCode2 - 8) <= 7u)
				{
					return true;
				}
				break;
			case TypeCode.Int32:
				switch (typeCode2)
				{
				case TypeCode.Int32:
				case TypeCode.Int64:
				case TypeCode.Single:
				case TypeCode.Double:
				case TypeCode.Decimal:
					return true;
				}
				break;
			case TypeCode.UInt32:
				if ((uint)(typeCode2 - 10) <= 5u)
				{
					return true;
				}
				break;
			case TypeCode.Int64:
				if (typeCode2 == TypeCode.Int64 || (uint)(typeCode2 - 13) <= 2u)
				{
					return true;
				}
				break;
			case TypeCode.UInt64:
				if ((uint)(typeCode2 - 12) <= 3u)
				{
					return true;
				}
				break;
			case TypeCode.Single:
				if ((uint)(typeCode2 - 13) <= 1u)
				{
					return true;
				}
				break;
			default:
				if ((object)nonNullableType == nonNullableType2)
				{
					return true;
				}
				break;
			}
			return false;
		}

		private static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
		{
			bool result = false;
			for (int i = 0; i < args.Length; i++)
			{
				int num = CompareConversions(args[i].Type, m1.Parameters[i].ParameterType, m2.Parameters[i].ParameterType);
				if (num < 0)
				{
					return false;
				}
				if (num > 0)
				{
					result = true;
				}
			}
			return result;
		}

		private static int CompareConversions(Type s, Type t1, Type t2)
		{
			if ((object)t1 == t2)
			{
				return 0;
			}
			if ((object)s == t1)
			{
				return 1;
			}
			if ((object)s == t2)
			{
				return -1;
			}
			bool flag = IsCompatibleWith(t1, t2);
			bool flag2 = IsCompatibleWith(t2, t1);
			if (flag && !flag2)
			{
				return 1;
			}
			if (flag2 && !flag)
			{
				return -1;
			}
			if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2))
			{
				return 1;
			}
			if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1))
			{
				return -1;
			}
			return 0;
		}

		private Expression GenerateEqual(Expression left, Expression right)
		{
			return Expression.Equal(left, right);
		}

		private Expression GenerateNotEqual(Expression left, Expression right)
		{
			return Expression.NotEqual(left, right);
		}

		private Expression GenerateGreaterThan(Expression left, Expression right)
		{
			if ((object)left.Type == typeof(string))
			{
				return Expression.GreaterThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0));
			}
			return Expression.GreaterThan(left, right);
		}

		private Expression GenerateGreaterThanEqual(Expression left, Expression right)
		{
			if ((object)left.Type == typeof(string))
			{
				return Expression.GreaterThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0));
			}
			return Expression.GreaterThanOrEqual(left, right);
		}

		private Expression GenerateLessThan(Expression left, Expression right)
		{
			if ((object)left.Type == typeof(string))
			{
				return Expression.LessThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0));
			}
			return Expression.LessThan(left, right);
		}

		private Expression GenerateLessThanEqual(Expression left, Expression right)
		{
			if ((object)left.Type == typeof(string))
			{
				return Expression.LessThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0));
			}
			return Expression.LessThanOrEqual(left, right);
		}

		private Expression GenerateAdd(Expression left, Expression right)
		{
			if ((object)left.Type == typeof(string) && (object)right.Type == typeof(string))
			{
				return GenerateStaticMethodCall("Concat", left, right);
			}
			return Expression.Add(left, right);
		}

		private Expression GenerateSubtract(Expression left, Expression right)
		{
			return Expression.Subtract(left, right);
		}

		private Expression GenerateStringConcat(Expression left, Expression right)
		{
			return Expression.Call(null, typeof(string).GetMethod("Concat", new Type[2]
			{
				typeof(object),
				typeof(object)
			}), new Expression[2] { left, right });
		}

		private MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
		{
			return left.Type.GetMethod(methodName, new Type[2] { left.Type, right.Type });
		}

		private Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
		{
			return Expression.Call(null, GetStaticMethod(methodName, left, right), new Expression[2] { left, right });
		}

		private void SetTextPos(int pos)
		{
			textPos = pos;
			ch = ((textPos < textLen) ? text[textPos] : '\0');
		}

		private void NextChar()
		{
			if (textPos < textLen)
			{
				textPos++;
			}
			ch = ((textPos < textLen) ? text[textPos] : '\0');
		}

		private void NextToken()
		{
			while (char.IsWhiteSpace(ch))
			{
				NextChar();
			}
			int num = textPos;
			TokenId id;
			switch (ch)
			{
			case '!':
				NextChar();
				if (ch == '=')
				{
					NextChar();
					id = TokenId.ExclamationEqual;
				}
				else
				{
					id = TokenId.Exclamation;
				}
				break;
			case '%':
				NextChar();
				id = TokenId.Percent;
				break;
			case '&':
				NextChar();
				if (ch == '&')
				{
					NextChar();
					id = TokenId.DoubleAmphersand;
				}
				else
				{
					id = TokenId.Amphersand;
				}
				break;
			case '(':
				NextChar();
				id = TokenId.OpenParen;
				break;
			case ')':
				NextChar();
				id = TokenId.CloseParen;
				break;
			case '*':
				NextChar();
				id = TokenId.Asterisk;
				break;
			case '+':
				NextChar();
				id = TokenId.Plus;
				break;
			case ',':
				NextChar();
				id = TokenId.Comma;
				break;
			case '-':
				NextChar();
				id = TokenId.Minus;
				break;
			case '.':
				NextChar();
				id = TokenId.Dot;
				break;
			case '/':
				NextChar();
				id = TokenId.Slash;
				break;
			case ':':
				NextChar();
				id = TokenId.Colon;
				break;
			case '<':
				NextChar();
				if (ch == '=')
				{
					NextChar();
					id = TokenId.LessThanEqual;
				}
				else if (ch == '>')
				{
					NextChar();
					id = TokenId.LessGreater;
				}
				else
				{
					id = TokenId.LessThan;
				}
				break;
			case '=':
				NextChar();
				if (ch == '=')
				{
					NextChar();
					id = TokenId.DoubleEqual;
				}
				else
				{
					id = TokenId.Equal;
				}
				break;
			case '>':
				NextChar();
				if (ch == '=')
				{
					NextChar();
					id = TokenId.GreaterThanEqual;
				}
				else
				{
					id = TokenId.GreaterThan;
				}
				break;
			case '?':
				NextChar();
				id = TokenId.Question;
				break;
			case '[':
				NextChar();
				id = TokenId.OpenBracket;
				break;
			case ']':
				NextChar();
				id = TokenId.CloseBracket;
				break;
			case '|':
				NextChar();
				if (ch == '|')
				{
					NextChar();
					id = TokenId.DoubleBar;
				}
				else
				{
					id = TokenId.Bar;
				}
				break;
			case '"':
			case '\'':
			{
				char c = ch;
				do
				{
					NextChar();
					while (textPos < textLen && ch != c)
					{
						NextChar();
					}
					if (textPos == textLen)
					{
						throw ParseError(textPos, "Unterminated string literal");
					}
					NextChar();
				}
				while (ch == c);
				id = TokenId.StringLiteral;
				break;
			}
			default:
				if (char.IsLetter(ch) || ch == '@' || ch == '_')
				{
					do
					{
						NextChar();
					}
					while (char.IsLetterOrDigit(ch) || ch == '_');
					id = TokenId.Identifier;
				}
				else if (char.IsDigit(ch))
				{
					id = TokenId.IntegerLiteral;
					do
					{
						NextChar();
					}
					while (char.IsDigit(ch));
					if (ch == '.')
					{
						id = TokenId.RealLiteral;
						NextChar();
						ValidateDigit();
						do
						{
							NextChar();
						}
						while (char.IsDigit(ch));
					}
					if (ch == 'E' || ch == 'e')
					{
						id = TokenId.RealLiteral;
						NextChar();
						if (ch == '+' || ch == '-')
						{
							NextChar();
						}
						ValidateDigit();
						do
						{
							NextChar();
						}
						while (char.IsDigit(ch));
					}
					if (ch == 'F' || ch == 'f')
					{
						NextChar();
					}
				}
				else
				{
					if (textPos != textLen)
					{
						throw ParseError(textPos, "Syntax error '{0}'", ch);
					}
					id = TokenId.End;
				}
				break;
			}
			token.id = id;
			token.text = text.Substring(num, textPos - num);
			token.pos = num;
		}

		private bool TokenIdentifierIs(string id)
		{
			if (token.id == TokenId.Identifier)
			{
				return string.Equals(id, token.text, StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		private string GetIdentifier()
		{
			ValidateToken(TokenId.Identifier, "Identifier expected");
			string text = token.text;
			if (text.Length > 1 && text[0] == '@')
			{
				text = text.Substring(1);
			}
			return text;
		}

		private void ValidateDigit()
		{
			if (!char.IsDigit(ch))
			{
				throw ParseError(textPos, "Digit expected");
			}
		}

		private void ValidateToken(TokenId t, string errorMessage)
		{
			if (token.id != t)
			{
				throw ParseError(errorMessage);
			}
		}

		private void ValidateToken(TokenId t)
		{
			if (token.id != t)
			{
				throw ParseError("Syntax error");
			}
		}

		private Exception ParseError(string format, params object[] args)
		{
			return ParseError(token.pos, format, args);
		}

		private Exception ParseError(int pos, string format, params object[] args)
		{
			return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos);
		}

		private static Dictionary<string, object> CreateKeywords()
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
			dictionary.Add("true", trueLiteral);
			dictionary.Add("false", falseLiteral);
			dictionary.Add("null", nullLiteral);
			dictionary.Add(keywordIt, keywordIt);
			dictionary.Add(keywordIif, keywordIif);
			dictionary.Add(keywordNew, keywordNew);
			Type[] array = predefinedTypes;
			foreach (Type type in array)
			{
				dictionary.Add(type.Name, type);
			}
			return dictionary;
		}
	}
	internal static class Res
	{
		public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once";

		public const string ExpressionTypeMismatch = "Expression of type '{0}' expected";

		public const string ExpressionExpected = "Expression expected";

		public const string InvalidCharacterLiteral = "Character literal must contain exactly one character";

		public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'";

		public const string InvalidRealLiteral = "Invalid real literal '{0}'";

		public const string UnknownIdentifier = "Unknown identifier '{0}'";

		public const string NoItInScope = "No 'it' is in scope";

		public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments";

		public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'";

		public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other";

		public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other";

		public const string MissingAsClause = "Expression is missing an 'as' clause";

		public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression";

		public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form";

		public const string NoMatchingConstructor = "No matching constructor in type '{0}'";

		public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor";

		public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'";

		public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'";

		public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible";

		public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value";

		public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'";

		public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'";

		public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists";

		public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported";

		public const string InvalidIndex = "Array index must be an integer expression";

		public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'";

		public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'";

		public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'";

		public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'";

		public const string UnterminatedStringLiteral = "Unterminated string literal";

		public const string InvalidCharacter = "Syntax error '{0}'";

		public const string DigitExpected = "Digit expected";

		public const string SyntaxError = "Syntax error";

		public const string TokenExpected = "{0} expected";

		public const string ParseExceptionFormat = "{0} (at index {1})";

		public const string ColonExpected = "':' expected";

		public const string OpenParenExpected = "'(' expected";

		public const string CloseParenOrOperatorExpected = "')' or operator expected";

		public const string CloseParenOrCommaExpected = "')' or ',' expected";

		public const string DotOrOpenParenExpected = "'.' or '(' expected";

		public const string OpenBracketExpected = "'[' expected";

		public const string CloseBracketOrCommaExpected = "']' or ',' expected";

		public const string IdentifierExpected = "Identifier expected";
	}
}
namespace SimpleJSON
{
	public enum JSONNodeType
	{
		Array = 1,
		Object = 2,
		String = 3,
		Number = 4,
		NullValue = 5,
		Boolean = 6,
		None = 7,
		Custom = 255
	}
	public enum JSONTextMode
	{
		Compact,
		Indent
	}
	public abstract class JSONNode
	{
		public struct Enumerator
		{
			private enum Type
			{
				None,
				Array,
				Object
			}

			private Type type;

			private Dictionary<string, JSONNode>.Enumerator m_Object;

			private List<JSONNode>.Enumerator m_Array;

			public bool IsValid => type != Type.None;

			public KeyValuePair<string, JSONNode> Current
			{
				get
				{
					if (type == Type.Array)
					{
						return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current);
					}
					if (type == Type.Object)
					{
						return m_Object.Current;
					}
					return new KeyValuePair<string, JSONNode>(string.Empty, null);
				}
			}

			public Enumerator(List<JSONNode>.Enumerator aArrayEnum)
			{
				type = Type.Array;
				m_Object = default(Dictionary<string, JSONNode>.Enumerator);
				m_Array = aArrayEnum;
			}

			public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
			{
				type = Type.Object;
				m_Object = aDictEnum;
				m_Array = default(List<JSONNode>.Enumerator);
			}

			public bool MoveNext()
			{
				if (type == Type.Array)
				{
					return m_Array.MoveNext();
				}
				if (type == Type.Object)
				{
					return m_Object.MoveNext();
				}
				return false;
			}
		}

		public struct ValueEnumerator
		{
			private Enumerator m_Enumerator;

			public JSONNode Current => m_Enumerator.Current.Value;

			public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum)
				: this(new Enumerator(aArrayEnum))
			{
			}

			public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
				: this(new Enumerator(aDictEnum))
			{
			}

			public ValueEnumerator(Enumerator aEnumerator)
			{
				m_Enumerator = aEnumerator;
			}

			public bool MoveNext()
			{
				return m_Enumerator.MoveNext();
			}

			public ValueEnumerator GetEnumerator()
			{
				return this;
			}
		}

		public struct KeyEnumerator
		{
			private Enumerator m_Enumerator;

			public JSONNode Current => m_Enumerator.Current.Key;

			public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum)
				: this(new Enumerator(aArrayEnum))
			{
			}

			public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
				: this(new Enumerator(aDictEnum))
			{
			}

			public KeyEnumerator(Enumerator aEnumerator)
			{
				m_Enumerator = aEnumerator;
			}

			public bool MoveNext()
			{
				return m_Enumerator.MoveNext();
			}

			public KeyEnumerator GetEnumerator()
			{
				return this;
			}
		}

		public class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNode>>, IDisposable, IEnumerator, IEnumerable<KeyValuePair<string, JSONNode>>, IEnumerable
		{
			private JSONNode m_Node;

			private Enumerator m_Enumerator;

			public KeyValuePair<string, JSONNode> Current => m_Enumerator.Current;

			object IEnumerator.Current => m_Enumerator.Current;

			internal LinqEnumerator(JSONNode aNode)
			{
				m_Node = aNode;
				if (m_Node != null)
				{
					m_Enumerator = m_Node.GetEnumerator();
				}
			}

			public bool MoveNext()
			{
				return m_Enumerator.MoveNext();
			}

			public void Dispose()
			{
				m_Node = null;
				m_Enumerator = default(Enumerator);
			}

			public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator()
			{
				return new LinqEnumerator(m_Node);
			}

			public void Reset()
			{
				if (m_Node != null)
				{
					m_Enumerator = m_Node.GetEnumerator();
				}
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return new LinqEnumerator(m_Node);
			}
		}

		public static bool forceASCII;

		[ThreadStatic]
		private static StringBuilder m_EscapeBuilder;

		public abstract JSONNodeType Tag { get; }

		public virtual JSONNode this[int aIndex]
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual JSONNode this[string aKey]
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Value
		{
			get
			{
				return "";
			}
			set
			{
			}
		}

		public virtual int Count => 0;

		public virtual bool IsNumber => false;

		public virtual bool IsString => false;

		public virtual bool IsBoolean => false;

		public virtual bool IsNull => false;

		public virtual bool IsArray => false;

		public virtual bool IsObject => false;

		public virtual bool Inline
		{
			get
			{
				return false;
			}
			set
			{
			}
		}

		public virtual IEnumerable<JSONNode> Children
		{
			get
			{
				yield break;
			}
		}

		public IEnumerable<JSONNode> DeepChildren
		{
			get
			{
				foreach (JSONNode child in Children)
				{
					foreach (JSONNode deepChild in child.DeepChildren)
					{
						yield return deepChild;
					}
				}
			}
		}

		public IEnumerable<KeyValuePair<string, JSONNode>> Linq => new LinqEnumerator(this);

		public KeyEnumerator Keys => new KeyEnumerator(GetEnumerator());

		public ValueEnumerator Values => new ValueEnumerator(GetEnumerator());

		public virtual double AsDouble
		{
			get
			{
				double result = 0.0;
				if (double.TryParse(Value, out result))
				{
					return result;
				}
				return 0.0;
			}
			set
			{
				Value = value.ToString();
			}
		}

		public virtual int AsInt
		{
			get
			{
				return (int)AsDouble;
			}
			set
			{
				AsDouble = value;
			}
		}

		public virtual float AsFloat
		{
			get
			{
				return (float)AsDouble;
			}
			set
			{
				AsDouble = value;
			}
		}

		public virtual bool AsBool
		{
			get
			{
				bool result = false;
				if (bool.TryParse(Value, out result))
				{
					return result;
				}
				return !string.IsNullOrEmpty(Value);
			}
			set
			{
				Value = (value ? "true" : "false");
			}
		}

		public virtual JSONArray AsArray => this as JSONArray;

		public virtual JSONObject AsObject => this as JSONObject;

		internal static StringBuilder EscapeBuilder
		{
			get
			{
				if (m_EscapeBuilder == null)
				{
					m_EscapeBuilder = new StringBuilder();
				}
				return m_EscapeBuilder;
			}
		}

		public virtual void Add(string aKey, JSONNode aItem)
		{
		}

		public virtual void Add(JSONNode aItem)
		{
			Add("", aItem);
		}

		public virtual JSONNode Remove(string aKey)
		{
			return null;
		}

		public virtual JSONNode Remove(int aIndex)
		{
			return null;
		}

		public virtual JSONNode Remove(JSONNode aNode)
		{
			return aNode;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			WriteToStringBuilder(stringBuilder, 0, 0, JSONTextMode.Compact);
			return stringBuilder.ToString();
		}

		public virtual string ToString(int aIndent)
		{
			StringBuilder stringBuilder = new StringBuilder();
			WriteToStringBuilder(stringBuilder, 0, aIndent, JSONTextMode.Indent);
			return stringBuilder.ToString();
		}

		internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode);

		public abstract Enumerator GetEnumerator();

		public static implicit operator JSONNode(string s)
		{
			return new JSONString(s);
		}

		public static implicit operator string(JSONNode d)
		{
			if (!(d == null))
			{
				return d.Value;
			}
			return null;
		}

		public static implicit operator JSONNode(double n)
		{
			return new JSONNumber(n);
		}

		public static implicit operator double(JSONNode d)
		{
			if (!(d == null))
			{
				return d.AsDouble;
			}
			return 0.0;
		}

		public static implicit operator JSONNode(float n)
		{
			return new JSONNumber(n);
		}

		public static implicit operator float(JSONNode d)
		{
			if (!(d == null))
			{
				return d.AsFloat;
			}
			return 0f;
		}

		public static implicit operator JSONNode(int n)
		{
			return new JSONNumber(n);
		}

		public static implicit operator int(JSONNode d)
		{
			if (!(d == null))
			{
				return d.AsInt;
			}
			return 0;
		}

		public static implicit operator JSONNode(bool b)
		{
			return new JSONBool(b);
		}

		public static implicit operator bool(JSONNode d)
		{
			if (!(d == null))
			{
				return d.AsBool;
			}
			return false;
		}

		public static implicit operator JSONNode(KeyValuePair<string, JSONNode> aKeyValue)
		{
			return aKeyValue.Value;
		}

		public static bool operator ==(JSONNode a, object b)
		{
			if ((object)a == b)
			{
				return true;
			}
			bool flag = a is JSONNull || (object)a == null || a is JSONLazyCreator;
			bool flag2 = b is JSONNull || b == null || b is JSONLazyCreator;
			if (flag && flag2)
			{
				return true;
			}
			if (!flag)
			{
				return a.Equals(b);
			}
			return false;
		}

		public static bool operator !=(JSONNode a, object b)
		{
			return !(a == b);
		}

		public override bool Equals(object obj)
		{
			return (object)this == obj;
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}

		internal static string Escape(string aText)
		{
			StringBuilder escapeBuilder = EscapeBuilder;
			escapeBuilder.Length = 0;
			if (escapeBuilder.Capacity < aText.Length + aText.Length / 10)
			{
				escapeBuilder.Capacity = aText.Length + aText.Length / 10;
			}
			foreach (char c in aText)
			{
				switch (c)
				{
				case '\\':
					escapeBuilder.Append("\\\\");
					continue;
				case '"':
					escapeBuilder.Append("\\\"");
					continue;
				case '\n':
					escapeBuilder.Append("\\n");
					continue;
				case '\r':
					escapeBuilder.Append("\\r");
					continue;
				case '\t':
					escapeBuilder.Append("\\t");
					continue;
				case '\b':
					escapeBuilder.Append("\\b");
					continue;
				case '\f':
					escapeBuilder.Append("\\f");
					continue;
				}
				if (c < ' ' || (forceASCII && c > '\u007f'))
				{
					ushort num = c;
					escapeBuilder.Append("\\u").Append(num.ToString("X4"));
				}
				else
				{
					escapeBuilder.Append(c);
				}
			}
			string result = escapeBuilder.ToString();
			escapeBuilder.Length = 0;
			return result;
		}

		private static void ParseElement(JSONNode ctx, string token, string tokenName, bool quoted)
		{
			if (quoted)
			{
				ctx.Add(tokenName, token);
				return;
			}
			string text = token.ToLower();
			switch (text)
			{
			case "false":
			case "true":
				ctx.Add(tokenName, text == "true");
				return;
			case "null":
				ctx.Add(tokenName, null);
				return;
			}
			if (double.TryParse(token, out var result))
			{
				ctx.Add(tokenName, result);
			}
			else
			{
				ctx.Add(tokenName, token);
			}
		}

		public static JSONNode Parse(string aJSON)
		{
			Stack<JSONNode> stack = new Stack<JSONNode>();
			JSONNode jSONNode = null;
			int i = 0;
			StringBuilder stringBuilder = new StringBuilder();
			string text = "";
			bool flag = false;
			bool flag2 = false;
			for (; i < aJSON.Length; i++)
			{
				switch (aJSON[i])
				{
				case '{':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					stack.Push(new JSONObject());
					if (jSONNode != null)
					{
						jSONNode.Add(text, stack.Peek());
					}
					text = "";
					stringBuilder.Length = 0;
					jSONNode = stack.Peek();
					break;
				case '[':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					stack.Push(new JSONArray());
					if (jSONNode != null)
					{
						jSONNode.Add(text, stack.Peek());
					}
					text = "";
					stringBuilder.Length = 0;
					jSONNode = stack.Peek();
					break;
				case ']':
				case '}':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					if (stack.Count == 0)
					{
						throw new Exception("JSON Parse: Too many closing brackets");
					}
					stack.Pop();
					if (stringBuilder.Length > 0 || flag2)
					{
						ParseElement(jSONNode, stringBuilder.ToString(), text, flag2);
						flag2 = false;
					}
					text = "";
					stringBuilder.Length = 0;
					if (stack.Count > 0)
					{
						jSONNode = stack.Peek();
					}
					break;
				case ':':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					text = stringBuilder.ToString();
					stringBuilder.Length = 0;
					flag2 = false;
					break;
				case '"':
					flag = !flag;
					flag2 = flag2 || flag;
					break;
				case ',':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					if (stringBuilder.Length > 0 || flag2)
					{
						ParseElement(jSONNode, stringBuilder.ToString(), text, flag2);
						flag2 = false;
					}
					text = "";
					stringBuilder.Length = 0;
					flag2 = false;
					break;
				case '\t':
				case ' ':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
					}
					break;
				case '\\':
					i++;
					if (flag)
					{
						char c = aJSON[i];
						switch (c)
						{
						case 't':
							stringBuilder.Append('\t');
							break;
						case 'r':
							stringBuilder.Append('\r');
							break;
						case 'n':
							stringBuilder.Append('\n');
							break;
						case 'b':
							stringBuilder.Append('\b');
							break;
						case 'f':
							stringBuilder.Append('\f');
							break;
						case 'u':
						{
							string s = aJSON.Substring(i + 1, 4);
							stringBuilder.Append((char)int.Parse(s, NumberStyles.AllowHexSpecifier));
							i += 4;
							break;
						}
						default:
							stringBuilder.Append(c);
							break;
						}
					}
					break;
				default:
					stringBuilder.Append(aJSON[i]);
					break;
				case '\n':
				case '\r':
					break;
				}
			}
			if (flag)
			{
				throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
			}
			return jSONNode;
		}
	}
	public class JSONArray : JSONNode
	{
		private List<JSONNode> m_List = new List<JSONNode>();

		private bool inline;

		public override bool Inline
		{
			get
			{
				return inline;
			}
			set
			{
				inline = value;
			}
		}

		public override JSONNodeType Tag => JSONNodeType.Array;

		public override bool IsArray => true;

		public override JSONNode this[int aIndex]
		{
			get
			{
				if (aIndex < 0 || aIndex >= m_List.Count)
				{
					return new JSONLazyCreator(this);
				}
				return m_List[aIndex];
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				if (aIndex < 0 || aIndex >= m_List.Count)
				{
					m_List.Add(value);
				}
				else
				{
					m_List[aIndex] = value;
				}
			}
		}

		public override JSONNode this[string aKey]
		{
			get
			{
				return new JSONLazyCreator(this);
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				m_List.Add(value);
			}
		}

		public override int Count => m_List.Count;

		public override IEnumerable<JSONNode> Children
		{
			get
			{
				foreach (JSONNode item in m_List)
				{
					yield return item;
				}
			}
		}

		public override Enumerator GetEnumerator()
		{
			return new Enumerator(m_List.GetEnumerator());
		}

		public override void Add(string aKey, JSONNode aItem)
		{
			if (aItem == null)
			{
				aItem = JSONNull.CreateOrGet();
			}
			m_List.Add(aItem);
		}

		public override JSONNode Remove(int aIndex)
		{
			if (aIndex < 0 || aIndex >= m_List.Count)
			{
				return null;
			}
			JSONNode result = m_List[aIndex];
			m_List.RemoveAt(aIndex);
			return result;
		}

		public override JSONNode Remove(JSONNode aNode)
		{
			m_List.Remove(aNode);
			return aNode;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append('[');
			int count = m_List.Count;
			if (inline)
			{
				aMode = JSONTextMode.Compact;
			}
			for (int i = 0; i < count; i++)
			{
				if (i > 0)
				{
					aSB.Append(',');
				}
				if (aMode == JSONTextMode.Indent)
				{
					aSB.AppendLine();
				}
				if (aMode == JSONTextMode.Indent)
				{
					aSB.Append(' ', aIndent + aIndentInc);
				}
				m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
			}
			if (aMode == JSONTextMode.Indent)
			{
				aSB.AppendLine().Append(' ', aIndent);
			}
			aSB.Append(']');
		}
	}
	public class JSONObject : JSONNode
	{
		private Dictionary<string, JSONNode> m_Dict = new Dictionary<string, JSONNode>();

		private bool inline;

		public override bool Inline
		{
			get
			{
				return inline;
			}
			set
			{
				inline = value;
			}
		}

		public override JSONNodeType Tag => JSONNodeType.Object;

		public override bool IsObject => true;

		public override JSONNode this[string aKey]
		{
			get
			{
				if (m_Dict.ContainsKey(aKey))
				{
					return m_Dict[aKey];
				}
				return new JSONLazyCreator(this, aKey);
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				if (m_Dict.ContainsKey(aKey))
				{
					m_Dict[aKey] = value;
				}
				else
				{
					m_Dict.Add(aKey, value);
				}
			}
		}

		public override JSONNode this[int aIndex]
		{
			get
			{
				if (aIndex < 0 || aIndex >= m_Dict.Count)
				{
					return null;
				}
				return m_Dict.ElementAt(aIndex).Value;
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				if (aIndex >= 0 && aIndex < m_Dict.Count)
				{
					string key = m_Dict.ElementAt(aIndex).Key;
					m_Dict[key] = value;
				}
			}
		}

		public override int Count => m_Dict.Count;

		public override IEnumerable<JSONNode> Children
		{
			get
			{
				foreach (KeyValuePair<string, JSONNode> item in m_Dict)
				{
					yield return item.Value;
				}
			}
		}

		public override Enumerator GetEnumerator()
		{
			return new Enumerator(m_Dict.GetEnumerator());
		}

		public override void Add(string aKey, JSONNode aItem)
		{
			if (aItem == null)
			{
				aItem = JSONNull.CreateOrGet();
			}
			if (!string.IsNullOrEmpty(aKey))
			{
				if (m_Dict.ContainsKey(aKey))
				{
					m_Dict[aKey] = aItem;
				}
				else
				{
					m_Dict.Add(aKey, aItem);
				}
			}
			else
			{
				m_Dict.Add(Guid.NewGuid().ToString(), aItem);
			}
		}

		public override JSONNode Remove(string aKey)
		{
			if (!m_Dict.ContainsKey(aKey))
			{
				return null;
			}
			JSONNode result = m_Dict[aKey];
			m_Dict.Remove(aKey);
			return result;
		}

		public override JSONNode Remove(int aIndex)
		{
			if (aIndex < 0 || aIndex >= m_Dict.Count)
			{
				return null;
			}
			KeyValuePair<string, JSONNode> keyValuePair = m_Dict.ElementAt(aIndex);
			m_Dict.Remove(keyValuePair.Key);
			return keyValuePair.Value;
		}

		public override JSONNode Remove(JSONNode aNode)
		{
			try
			{
				KeyValuePair<string, JSONNode> keyValuePair = m_Dict.Where((KeyValuePair<string, JSONNode> k) => k.Value == aNode).First();
				m_Dict.Remove(keyValuePair.Key);
				return aNode;
			}
			catch
			{
				return null;
			}
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append('{');
			bool flag = true;
			if (inline)
			{
				aMode = JSONTextMode.Compact;
			}
			foreach (KeyValuePair<string, JSONNode> item in m_Dict)
			{
				if (!flag)
				{
					aSB.Append(',');
				}
				flag = false;
				if (aMode == JSONTextMode.Indent)
				{
					aSB.AppendLine();
				}
				if (aMode == JSONTextMode.Indent)
				{
					aSB.Append(' ', aIndent + aIndentInc);
				}
				aSB.Append('"').Append(JSONNode.Escape(item.Key)).Append('"');
				if (aMode == JSONTextMode.Compact)
				{
					aSB.Append(':');
				}
				else
				{
					aSB.Append(" : ");
				}
				item.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
			}
			if (aMode == JSONTextMode.Indent)
			{
				aSB.AppendLine().Append(' ', aIndent);
			}
			aSB.Append('}');
		}
	}
	public class JSONString : JSONNode
	{
		private string m_Data;

		public override JSONNodeType Tag => JSONNodeType.String;

		public override bool IsString => true;

		public override string Value
		{
			get
			{
				return m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONString(string aData)
		{
			m_Data = aData;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append('"').Append(JSONNode.Escape(m_Data)).Append('"');
		}

		public override bool Equals(object obj)
		{
			if (base.Equals(obj))
			{
				return true;
			}
			if (obj is string text)
			{
				return m_Data == text;
			}
			JSONString jSONString = obj as JSONString;
			if (jSONString != null)
			{
				return m_Data == jSONString.m_Data;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return m_Data.GetHashCode();
		}
	}
	public class JSONNumber : JSONNode
	{
		private double m_Data;

		public override JSONNodeType Tag => JSONNodeType.Number;

		public override bool IsNumber => true;

		public override string Value
		{
			get
			{
				return m_Data.ToString();
			}
			set
			{
				if (double.TryParse(value, out var result))
				{
					m_Data = result;
				}
			}
		}

		public override double AsDouble
		{
			get
			{
				return m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONNumber(double aData)
		{
			m_Data = aData;
		}

		public JSONNumber(string aData)
		{
			Value = aData;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append(m_Data);
		}

		private static bool IsNumeric(object value)
		{
			if (!(value is int) && !(value is uint) && !(value is float) && !(value is double) && !(value is decimal) && !(value is long) && !(value is ulong) && !(value is short) && !(value is ushort) && !(value is sbyte))
			{
				return value is byte;
			}
			return true;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (base.Equals(obj))
			{
				return true;
			}
			JSONNumber jSONNumber = obj as JSONNumber;
			if (jSONNumber != null)
			{
				return m_Data == jSONNumber.m_Data;
			}
			if (IsNumeric(obj))
			{
				return Convert.ToDouble(obj) == m_Data;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return m_Data.GetHashCode();
		}
	}
	public class JSONBool : JSONNode
	{
		private bool m_Data;

		public override JSONNodeType Tag => JSONNodeType.Boolean;

		public override bool IsBoolean => true;

		public override string Value
		{
			get
			{
				return m_Data.ToString();
			}
			set
			{
				if (bool.TryParse(value, out var result))
				{
					m_Data = result;
				}
			}
		}

		public override bool AsBool
		{
			get
			{
				return m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONBool(bool aData)
		{
			m_Data = aData;
		}

		public JSONBool(string aData)
		{
			Value = aData;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append(m_Data ? "true" : "false");
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is bool)
			{
				return m_Data == (bool)obj;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return m_Data.GetHashCode();
		}
	}
	public class JSONNull : JSONNode
	{
		private static JSONNull m_StaticInstance = new JSONNull();

		public static bool reuseSameInstance = true;

		public override JSONNodeType Tag => JSONNodeType.NullValue;

		public override bool IsNull => true;

		public override string Value
		{
			get
			{
				return "null";
			}
			set
			{
			}
		}

		public override bool AsBool
		{
			get
			{
				return false;
			}
			set
			{
			}
		}

		public static JSONNull CreateOrGet()
		{
			if (reuseSameInstance)
			{
				return m_StaticInstance;
			}
			return new JSONNull();
		}

		private JSONNull()
		{
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public override bool Equals(object obj)
		{
			if ((object)this == obj)
			{
				return true;
			}
			return obj is JSONNull;
		}

		public override int GetHashCode()
		{
			return 0;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append("null");
		}
	}
	internal class JSONLazyCreator : JSONNode
	{
		private JSONNode m_Node;

		private string m_Key;

		public override JSONNodeType Tag => JSONNodeType.None;

		public override JSONNode this[int aIndex]
		{
			get
			{
				return new JSONLazyCreator(this);
			}
			set
			{
				JSONArray jSONArray = new JSONArray();
				jSONArray.Add(value);
				Set(jSONArray);
			}
		}

		public override JSONNode this[string aKey]
		{
			get
			{
				return new JSONLazyCreator(this, aKey);
			}
			set
			{
				JSONObject jSONObject = new JSONObject();
				jSONObject.Add(aKey, value);
				Set(jSONObject);
			}
		}

		public override int AsInt
		{
			get
			{
				JSONNumber aVal = new JSONNumber(0.0);
				Set(aVal);
				return 0;
			}
			set
			{
				JSONNumber aVal = new JSONNumber(value);
				Set(aVal);
			}
		}

		public override float AsFloat
		{
			get
			{
				JSONNumber aVal = new JSONNumber(0.0);
				Set(aVal);
				return 0f;
			}
			set
			{
				JSONNumber aVal = new JSONNumber(value);
				Set(aVal);
			}
		}

		public override double AsDouble
		{
			get
			{
				JSONNumber aVal = new JSONNumber(0.0);
				Set(aVal);
				return 0.0;
			}
			set
			{
				JSONNumber aVal = new JSONNumber(value);
				Set(aVal);
			}
		}

		public override bool AsBool
		{
			get
			{
				JSONBool aVal = new JSONBool(aData: false);
				Set(aVal);
				return false;
			}
			set
			{
				JSONBool aVal = new JSONBool(value);
				Set(aVal);
			}
		}

		public override JSONArray AsArray
		{
			get
			{
				JSONArray jSONArray = new JSONArray();
				Set(jSONArray);
				return jSONArray;
			}
		}

		public override JSONObject AsObject
		{
			get
			{
				JSONObject jSONObject = new JSONObject();
				Set(jSONObject);
				return jSONObject;
			}
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONLazyCreator(JSONNode aNode)
		{
			m_Node = aNode;
			m_Key = null;
		}

		public JSONLazyCreator(JSONNode aNode, string aKey)
		{
			m_Node = aNode;
			m_Key = aKey;
		}

		private void Set(JSONNode aVal)
		{
			if (m_Key == null)
			{
				m_Node.Add(aVal);
			}
			else
			{
				m_Node.Add(m_Key, aVal);
			}
			m_Node = null;
		}

		public override void Add(JSONNode aItem)
		{
			JSONArray jSONArray = new JSONArray();
			jSONArray.Add(aItem);
			Set(jSONArray);
		}

		public override void Add(string aKey, JSONNode aItem)
		{
			JSONObject jSONObject = new JSONObject();
			jSONObject.Add(aKey, aItem);
			Set(jSONObject);
		}

		public static bool operator ==(JSONLazyCreator a, object b)
		{
			if (b == null)
			{
				return true;
			}
			return (object)a == b;
		}

		public static bool operator !=(JSONLazyCreator a, object b)
		{
			return !(a == b);
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return true;
			}
			return (object)this == obj;
		}

		public override int GetHashCode()
		{
			return 0;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append("null");
		}
	}
	public static class JSON
	{
		public static JSONNode Parse(string aJSON)
		{
			return JSONNode.Parse(aJSON);
		}
	}
}
namespace XUnity.AutoTranslator.Plugin
{
	internal class SceneLoadInformation
	{
		public SceneInformation ActiveScene { get; set; }

		public List<SceneInformation> LoadedScenes { get; set; }

		public SceneLoadInformation()
		{
			LoadedScenes = new List<SceneInformation>();
			if (UnityFeatures.SupportsSceneManager)
			{
				LoadBySceneManager();
			}
			else
			{
				LoadByApplication();
			}
		}

		public void LoadBySceneManager()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			ActiveScene = new SceneInformation(((Scene)(ref activeScene)).buildIndex, ((Scene)(ref activeScene)).name);
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene sceneAt = SceneManager.GetSceneAt(i);
				LoadedScenes.Add(new SceneInformation(((Scene)(ref sceneAt)).buildIndex, ((Scene)(ref sceneAt)).name));
			}
		}

		public void LoadByApplication()
		{
			ActiveScene = new SceneInformation(Application.loadedLevel, Application.loadedLevelName);
			LoadedScenes.Add(new SceneInformation(Application.loadedLevel, Application.loadedLevelName));
		}
	}
	internal class SceneInformation
	{
		public int Id { get; set; }

		public string Name { get; set; }

		public SceneInformation(int id, string name)
		{
			Id = id;
			Name = name;
		}
	}
}
namespace XUnity.AutoTranslator.Plugin.Utilities
{
	internal static class TranslationScopeHelper
	{
		public static int GetScope(object ui)
		{
			if (Settings.EnableTranslationScoping)
			{
				try
				{
					Component val = (Component)((ui is Component) ? ui : null);
					if (val != null && Object.op_Implicit((Object)(object)val))
					{
						return GetScopeFromComponent(val);
					}
					if (ui is GUIContent)
					{
						return -1;
					}
					return GetActiveSceneId();
				}
				catch (MissingMemberException ex)
				{
					XuaLogger.AutoTranslator.Error((Exception)ex, "A 'missing member' error occurred while retriving translation scope. Disabling translation scopes.");
					Settings.EnableTranslationScoping = false;
				}
			}
			return -1;
		}

		private static int GetScopeFromComponent(Component component)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Scene scene = component.gameObject.scene;
			return ((Scene)(ref scene)).buildIndex;
		}

		public static int GetActiveSceneId()
		{
			if (UnityFeatures.SupportsSceneManager)
			{
				return GetActiveSceneIdBySceneManager();
			}
			return GetActiveSceneIdByApplication();
		}

		private static int GetActiveSceneIdBySceneManager()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).buildIndex;
		}

		public static void RegisterSceneLoadCallback(Action<int> sceneLoaded)
		{
			SceneManagerLoader.EnableSceneLoadScanInternal(sceneLoaded);
		}

		private static int GetActiveSceneIdByApplication()
		{
			return Application.loadedLevel;
		}
	}
	internal static class SceneManagerLoader
	{
		public static void EnableSceneLoadScanInternal(Action<int> sceneLoaded)
		{
			SceneManager.sceneLoaded += delegate(Scene arg1, LoadSceneMode arg2)
			{
				sceneLoaded(((Scene)(ref arg1)).buildIndex);
			};
		}
	}
	internal static class TranslationScopes
	{
		public const int None = -1;
	}
}
namespace XUnity.AutoTranslator.Plugin.Core
{
	public class AutoTranslationPlugin : MonoBehaviour, IMonoBehaviour, IMonoBehaviour_Update, IInternalTranslator, ITranslator, ITranslationRegistry
	{
		internal static AutoTranslationPlugin Current;

		private bool _hasResizedCurrentComponentDuringDiscovery;

		internal XuaWindow MainWindow;

		internal TranslationAggregatorWindow TranslationAggregatorWindow;

		internal TranslationAggregatorOptionsWindow TranslationAggregatorOptionsWindow;

		internal TranslationManager TranslationManager;

		internal TextTranslationCache TextCache;

		internal Dictionary<string, TextTranslationCache> PluginTextCaches = new Dictionary<string, TextTranslationCache>(StringComparer.OrdinalIgnoreCase);

		internal TextureTranslationCache TextureCache;

		internal UIResizeCache ResizeCache;

		internal SpamChecker SpamChecker;

		private Dictionary<string, UntranslatedText> CachedKeys = new Dictionary<string, UntranslatedText>(StringComparer.Ordinal);

		private List<Action<ComponentTranslationContext>> _shouldIgnore = new List<Action<ComponentTranslationContext>>();

		private List<string> _textsToCopyToClipboardOrdered = new List<string>();

		private HashSet<string> _textsToCopyToClipboard = new HashSet<string>();

		private float _clipboardUpdated;

		private HashSet<string> _immediatelyTranslating = new HashSet<string>();

		private bool _isInTranslatedMode = true;

		private bool _textHooksEnabled = true;

		private float _batchOperationSecondCounter;

		private bool _hasValidOverrideFont;

		private bool _hasOverridenFont;

		private bool _initialized;

		private bool _started;

		private bool _temporarilyDisabled;

		private string _requireSpriteRendererCheckCausedBy;

		private int _lastSpriteUpdateFrame = -1;

		private bool _isCalledFromSceneManager;

		private bool _translationReloadRequest;

		private bool _hasUiBeenSetup;

		private static bool _inputSupported;

		public void Initialize()
		{
			Current = this;
			Paths.Initialize();
			HarmonyLoader.Load();
			Settings.Configure();
			DebugConsole.Enable();
			InitializeHarmonyDetourBridge();
			InitializeTextTranslationCaches();
			HooksSetup.InstallTextHooks();
			HooksSetup.InstallImageHooks();
			HooksSetup.InstallSpriteRendererHooks();
			HooksSetup.InstallTextGetterCompatHooks();
			HooksSetup.InstallComponentBasedPluginTranslationHooks();
			TextureCache = new TextureTranslationCache();
			TextureCache.TextureTranslationFileChanged += TextureCache_TextureTranslationFileChanged;
			ResizeCache = new UIResizeCache();
			TranslationManager = new TranslationManager();
			TranslationManager.JobCompleted += OnJobCompleted;
			TranslationManager.JobFailed += OnJobFailed;
			TranslationManager.InitializeEndpoints();
			SpamChecker = new SpamChecker(TranslationManager);
			UnityTextParsers.Initialize();
			InitializeResourceRedirector();
			ValidateConfiguration();
			EnableSceneLoadScan();
			LoadFallbackFont();
			LoadTranslations(reload: false);
			XuaLogger.AutoTranslator.Info("Loaded XUnity.AutoTranslator into Unity [" + Application.unityVersion + "] game.");
		}

		private static void LoadFallbackFont()
		{
			try
			{
				if (!string.IsNullOrEmpty(Settings.FallbackFontTextMeshPro))
				{
					Object orCreateFallbackFontTextMeshPro = FontCache.GetOrCreateFallbackFontTextMeshPro();
					if (TMP_Settings_Properties.FallbackFontAssets == null)
					{
						XuaLogger.AutoTranslator.Info("Cannot use fallback font because it is not supported in this version.");
						return;
					}
					if (orCreateFallbackFontTextMeshPro == (Object)null)
					{
						XuaLogger.AutoTranslator.Warn("Could not load fallback font for TextMesh Pro: " + Settings.FallbackFontTextMeshPro);
						return;
					}
					((IList)TMP_Settings_Properties.FallbackFontAssets.Get((object)null)).Add(orCreateFallbackFontTextMeshPro);
					XuaLogger.AutoTranslator.Info("Loaded fallback font for TextMesh Pro: " + Settings.FallbackFontTextMeshPro);
				}
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while trying to load fallback font for TextMesh Pro.");
			}
		}

		private static void InitializeHarmonyDetourBridge()
		{
			try
			{
				if (Settings.InitializeHarmonyDetourBridge)
				{
					InitializeHarmonyDetourBridgeSafe();
				}
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing harmony detour bridge.");
			}
		}

		private static void InitializeHarmonyDetourBridgeSafe()
		{
			HarmonyDetourBridge.Init(true, (Type)0);
		}

		private void InitializeTextTranslationCaches()
		{
			try
			{
				TextCache = new TextTranslationCache();
				TextCache.TextTranslationFileChanged += TextCache_TextTranslationFileChanged;
				DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Settings.TranslationsPath, "plugins"));
				if (directoryInfo.Exists)
				{
					DirectoryInfo[] directories = directoryInfo.GetDirectories();
					foreach (DirectoryInfo directoryInfo2 in directories)
					{
						TextTranslationCache value = new TextTranslationCache(directoryInfo2);
						PluginTextCaches.Add(directoryInfo2.Name, value);
					}
				}
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing text translation caches.");
			}
		}

		private void TextCache_TextTranslationFileChanged()
		{
			_translationReloadRequest = true;
		}

		private void TextureCache_TextureTranslationFileChanged()
		{
			_translationReloadRequest = true;
		}

		private static void EnableLogAllLoadedResources()
		{
			ResourceRedirection.LogAllLoadedResources = true;
		}

		private void EnableTextAssetLoadedHandler()
		{
			new TextAssetLoadedHandler();
		}

		private void InitializeResourceRedirector()
		{
			try
			{
				if (Settings.LogAllLoadedResources)
				{
					EnableLogAllLoadedResources();
				}
				if (Settings.EnableTextAssetRedirector)
				{
					EnableTextAssetLoadedHandler();
				}
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing resource redirectors.");
			}
		}

		private void InitializeGUI()
		{
			Dis