UMM/Core/0Harmony.dll

Decompiled 2 months ago
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.SymbolStore;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Iced.Intel;
using Iced.Intel.BlockEncoderInternal;
using Iced.Intel.DecoderInternal;
using Iced.Intel.EncoderInternal;
using Iced.Intel.Internal;
using Microsoft.Cci;
using Microsoft.Cci.Pdb;
using Microsoft.CodeAnalysis;
using Microsoft.Win32.SafeHandles;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using Mono.Cecil.PE;
using Mono.Collections.Generic;
using Mono.CompilerServices.SymbolWriter;
using Mono.Security.Cryptography;
using MonoMod;
using MonoMod.Backports.ILHelpers;
using MonoMod.Cil;
using MonoMod.Core;
using MonoMod.Core.Interop;
using MonoMod.Core.Interop.Attributes;
using MonoMod.Core.Platforms;
using MonoMod.Core.Platforms.Architectures;
using MonoMod.Core.Platforms.Architectures.AltEntryFactories;
using MonoMod.Core.Platforms.Memory;
using MonoMod.Core.Platforms.Runtimes;
using MonoMod.Core.Platforms.Systems;
using MonoMod.Core.Utils;
using MonoMod.Logs;
using MonoMod.SourceGen.Attributes;
using MonoMod.Utils;
using MonoMod.Utils.Cil;
using MonoMod.Utils.Interop;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: InternalsVisibleTo("HarmonyTests")]
[assembly: InternalsVisibleTo("MonoMod.Utils.Cil.ILGeneratorProxy")]
[assembly: Guid("69aee16a-b6e7-4642-8081-3928b32455df")]
[assembly: AssemblyCompany("Andreas Pardeike")]
[assembly: AssemblyConfiguration("ReleaseFat")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyDescription("A general non-destructive patch library for .NET and Mono modules")]
[assembly: AssemblyFileVersion("2.3.6.0")]
[assembly: AssemblyInformationalVersion("2.3.6.0+f41da7608c5c3e9c7bf16551462b14c0b5392db3")]
[assembly: AssemblyProduct("Harmony")]
[assembly: AssemblyTitle("0Harmony")]
[assembly: SecurityPermission(System.Security.Permissions.SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.3.6.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
internal class <Module>
{
	static <Module>()
	{
		<d93ed7d0-1242-4c9d-a80d-b2e3dba3921c>MMDbgLog.LogVersion();
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 HarmonyLib
{
	public class DelegateTypeFactory
	{
		private readonly ModuleBuilder module;

		private static int counter;

		public DelegateTypeFactory()
		{
			counter++;
			string name = $"HarmonyDTFAssembly{counter}";
			AssemblyBuilder assemblyBuilder = PatchTools.DefineDynamicAssembly(name);
			module = assemblyBuilder.DefineDynamicModule($"HarmonyDTFModule{counter}");
		}

		public Type CreateDelegateType(MethodInfo method)
		{
			System.Reflection.TypeAttributes attr = System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Sealed;
			TypeBuilder typeBuilder = module.DefineType($"HarmonyDTFType{counter}", attr, typeof(MulticastDelegate));
			ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[2]
			{
				typeof(object),
				typeof(IntPtr)
			});
			constructorBuilder.SetImplementationFlags(System.Reflection.MethodImplAttributes.CodeTypeMask);
			ParameterInfo[] parameters = method.GetParameters();
			MethodBuilder methodBuilder = typeBuilder.DefineMethod("Invoke", System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Virtual | System.Reflection.MethodAttributes.HideBySig, method.ReturnType, parameters.Types());
			methodBuilder.SetImplementationFlags(System.Reflection.MethodImplAttributes.CodeTypeMask);
			for (int i = 0; i < parameters.Length; i++)
			{
				methodBuilder.DefineParameter(i + 1, System.Reflection.ParameterAttributes.None, parameters[i].Name);
			}
			return typeBuilder.CreateType();
		}
	}
	[Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Func<T, S>> for property getters")]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public delegate S GetterHandler<in T, out S>(T source);
	[Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Action<T, S>> for property setters")]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public delegate void SetterHandler<in T, in S>(T source, S value);
	public delegate T InstantiationHandler<out T>();
	public static class FastAccess
	{
		public static InstantiationHandler<T> CreateInstantiationHandler<T>()
		{
			ConstructorInfo constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null);
			if ((object)constructor == null)
			{
				throw new ApplicationException($"The type {typeof(T)} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).");
			}
			DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition("InstantiateObject_" + typeof(T).Name, typeof(T), null);
			ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator();
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Newobj, constructor);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
			return Extensions.CreateDelegate<InstantiationHandler<T>>(dynamicMethodDefinition.Generate());
		}

		[Obsolete("Use AccessTools.MethodDelegate<Func<T, S>>(PropertyInfo.GetGetMethod(true))")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public static GetterHandler<T, S> CreateGetterHandler<T, S>(PropertyInfo propertyInfo)
		{
			MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true);
			DynamicMethodDefinition dynamicMethodDefinition = CreateGetDynamicMethod<T, S>(propertyInfo.DeclaringType);
			ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator();
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Call, getMethod);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
			return Extensions.CreateDelegate<GetterHandler<T, S>>(dynamicMethodDefinition.Generate());
		}

		[Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public static GetterHandler<T, S> CreateGetterHandler<T, S>(FieldInfo fieldInfo)
		{
			DynamicMethodDefinition dynamicMethodDefinition = CreateGetDynamicMethod<T, S>(fieldInfo.DeclaringType);
			ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator();
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldfld, fieldInfo);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
			return Extensions.CreateDelegate<GetterHandler<T, S>>(dynamicMethodDefinition.Generate());
		}

		[Obsolete("Use AccessTools.FieldRefAccess<T, S>(name) for fields and AccessTools.MethodDelegate<Func<T, S>>(AccessTools.PropertyGetter(typeof(T), name)) for properties")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public static GetterHandler<T, S> CreateFieldGetter<T, S>(params string[] names)
		{
			foreach (string name in names)
			{
				FieldInfo field = typeof(T).GetField(name, AccessTools.all);
				if ((object)field != null)
				{
					return CreateGetterHandler<T, S>(field);
				}
				PropertyInfo property = typeof(T).GetProperty(name, AccessTools.all);
				if ((object)property != null)
				{
					return CreateGetterHandler<T, S>(property);
				}
			}
			return null;
		}

		[Obsolete("Use AccessTools.MethodDelegate<Action<T, S>>(PropertyInfo.GetSetMethod(true))")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public static SetterHandler<T, S> CreateSetterHandler<T, S>(PropertyInfo propertyInfo)
		{
			MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true);
			DynamicMethodDefinition dynamicMethodDefinition = CreateSetDynamicMethod<T, S>(propertyInfo.DeclaringType);
			ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator();
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_1);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Call, setMethod);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
			return Extensions.CreateDelegate<SetterHandler<T, S>>(dynamicMethodDefinition.Generate());
		}

		[Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public static SetterHandler<T, S> CreateSetterHandler<T, S>(FieldInfo fieldInfo)
		{
			DynamicMethodDefinition dynamicMethodDefinition = CreateSetDynamicMethod<T, S>(fieldInfo.DeclaringType);
			ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator();
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_1);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Stfld, fieldInfo);
			iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
			return Extensions.CreateDelegate<SetterHandler<T, S>>(dynamicMethodDefinition.Generate());
		}

		private static DynamicMethodDefinition CreateGetDynamicMethod<T, S>(Type type)
		{
			return new DynamicMethodDefinition("DynamicGet_" + type.Name, typeof(S), new Type[1] { typeof(T) });
		}

		private static DynamicMethodDefinition CreateSetDynamicMethod<T, S>(Type type)
		{
			return new DynamicMethodDefinition("DynamicSet_" + type.Name, typeof(void), new Type[2]
			{
				typeof(T),
				typeof(S)
			});
		}
	}
	public delegate object FastInvokeHandler(object target, params object[] parameters);
	public static class MethodInvoker
	{
		public static FastInvokeHandler GetHandler(MethodInfo methodInfo, bool directBoxValueAccess = false)
		{
			DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition("FastInvoke_" + methodInfo.Name + "_" + (directBoxValueAccess ? "direct" : "indirect"), typeof(object), new Type[2]
			{
				typeof(object),
				typeof(object[])
			});
			ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator();
			if (!methodInfo.IsStatic)
			{
				Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldarg_0);
				EmitUnboxIfNeeded(iLGenerator, methodInfo.DeclaringType);
			}
			bool flag = true;
			ParameterInfo[] parameters = methodInfo.GetParameters();
			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)
				{
					Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldarg_1);
					EmitFastInt(iLGenerator, i);
				}
				Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldarg_1);
				EmitFastInt(iLGenerator, i);
				if (isByRef && !isValueType)
				{
					Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldelema, typeof(object));
					continue;
				}
				Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldelem_Ref);
				if (!isValueType)
				{
					continue;
				}
				if (!isByRef || !directBoxValueAccess)
				{
					Emit(iLGenerator, System.Reflection.Emit.OpCodes.Unbox_Any, type);
					if (isByRef)
					{
						Emit(iLGenerator, System.Reflection.Emit.OpCodes.Box, type);
						Emit(iLGenerator, System.Reflection.Emit.OpCodes.Dup);
						if (flag)
						{
							flag = false;
							iLGenerator.DeclareLocal(typeof(object), pinned: false);
						}
						Emit(iLGenerator, System.Reflection.Emit.OpCodes.Stloc_0);
						Emit(iLGenerator, System.Reflection.Emit.OpCodes.Stelem_Ref);
						Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldloc_0);
						Emit(iLGenerator, System.Reflection.Emit.OpCodes.Unbox, type);
					}
				}
				else
				{
					Emit(iLGenerator, System.Reflection.Emit.OpCodes.Unbox, type);
				}
			}
			if (methodInfo.IsStatic)
			{
				EmitCall(iLGenerator, System.Reflection.Emit.OpCodes.Call, methodInfo);
			}
			else
			{
				EmitCall(iLGenerator, System.Reflection.Emit.OpCodes.Callvirt, methodInfo);
			}
			if ((object)methodInfo.ReturnType == typeof(void))
			{
				Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldnull);
			}
			else
			{
				EmitBoxIfNeeded(iLGenerator, methodInfo.ReturnType);
			}
			Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ret);
			return Extensions.CreateDelegate<FastInvokeHandler>(dynamicMethodDefinition.Generate());
		}

		internal static void Emit(ILGenerator il, System.Reflection.Emit.OpCode opcode)
		{
			il.Emit(opcode);
		}

		internal static void Emit(ILGenerator il, System.Reflection.Emit.OpCode opcode, Type type)
		{
			il.Emit(opcode, type);
		}

		internal static void EmitCall(ILGenerator il, System.Reflection.Emit.OpCode opcode, MethodInfo methodInfo)
		{
			il.EmitCall(opcode, methodInfo, null);
		}

		private static void EmitUnboxIfNeeded(ILGenerator il, Type type)
		{
			if (type.IsValueType)
			{
				Emit(il, System.Reflection.Emit.OpCodes.Unbox_Any, type);
			}
		}

		private static void EmitBoxIfNeeded(ILGenerator il, Type type)
		{
			if (type.IsValueType)
			{
				Emit(il, System.Reflection.Emit.OpCodes.Box, type);
			}
		}

		internal static void EmitFastInt(ILGenerator il, int value)
		{
			switch (value)
			{
			case -1:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
				return;
			case 0:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
				return;
			case 1:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
				return;
			case 2:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
				return;
			case 3:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_3);
				return;
			case 4:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
				return;
			case 5:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_5);
				return;
			case 6:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_6);
				return;
			case 7:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_7);
				return;
			case 8:
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_8);
				return;
			}
			if (value > -129 && value < 128)
			{
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_S, (sbyte)value);
			}
			else
			{
				il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, value);
			}
		}
	}
	public delegate ref T RefResult<T>();
	internal class AccessCache
	{
		internal enum MemberType
		{
			Any,
			Static,
			Instance
		}

		private const BindingFlags BasicFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;

		private static readonly Dictionary<MemberType, BindingFlags> declaredOnlyBindingFlags = new Dictionary<MemberType, BindingFlags>
		{
			{
				MemberType.Any,
				BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty
			},
			{
				MemberType.Instance,
				BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty
			},
			{
				MemberType.Static,
				BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty
			}
		};

		private readonly Dictionary<Type, Dictionary<string, FieldInfo>> declaredFields = new Dictionary<Type, Dictionary<string, FieldInfo>>();

		private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> declaredProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

		private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> declaredMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>();

		private readonly Dictionary<Type, Dictionary<string, FieldInfo>> inheritedFields = new Dictionary<Type, Dictionary<string, FieldInfo>>();

		private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> inheritedProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

		private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> inheritedMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>();

		private static T Get<T>(Dictionary<Type, Dictionary<string, T>> dict, Type type, string name, Func<T> fetcher)
		{
			lock (dict)
			{
				if (!dict.TryGetValue(type, out var value))
				{
					value = (dict[type] = new Dictionary<string, T>());
				}
				if (!value.TryGetValue(name, out var value2))
				{
					value2 = (value[name] = fetcher());
				}
				return value2;
			}
		}

		private static T Get<T>(Dictionary<Type, Dictionary<string, Dictionary<int, T>>> dict, Type type, string name, Type[] arguments, Func<T> fetcher)
		{
			lock (dict)
			{
				if (!dict.TryGetValue(type, out var value))
				{
					value = (dict[type] = new Dictionary<string, Dictionary<int, T>>());
				}
				if (!value.TryGetValue(name, out var value2))
				{
					value2 = (value[name] = new Dictionary<int, T>());
				}
				int key = AccessTools.CombinedHashCode(arguments);
				if (!value2.TryGetValue(key, out var value3))
				{
					value3 = (value2[key] = fetcher());
				}
				return value3;
			}
		}

		internal FieldInfo GetFieldInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false)
		{
			FieldInfo fieldInfo = Get(declaredFields, type, name, () => type.GetField(name, declaredOnlyBindingFlags[memberType]));
			if ((object)fieldInfo == null && !declaredOnly)
			{
				fieldInfo = Get(inheritedFields, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetField(name, AccessTools.all)));
			}
			return fieldInfo;
		}

		internal PropertyInfo GetPropertyInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false)
		{
			PropertyInfo propertyInfo = Get(declaredProperties, type, name, () => type.GetProperty(name, declaredOnlyBindingFlags[memberType]));
			if ((object)propertyInfo == null && !declaredOnly)
			{
				propertyInfo = Get(inheritedProperties, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetProperty(name, AccessTools.all)));
			}
			return propertyInfo;
		}

		internal MethodBase GetMethodInfo(Type type, string name, Type[] arguments, MemberType memberType = MemberType.Any, bool declaredOnly = false)
		{
			MethodBase methodBase = Get(declaredMethods, type, name, arguments, () => type.GetMethod(name, declaredOnlyBindingFlags[memberType], null, arguments, null));
			if ((object)methodBase == null && !declaredOnly)
			{
				methodBase = Get(inheritedMethods, type, name, arguments, () => AccessTools.Method(type, name, arguments));
			}
			return methodBase;
		}
	}
	internal class ByteBuffer
	{
		internal byte[] buffer;

		internal int position;

		internal ByteBuffer(byte[] buffer)
		{
			this.buffer = buffer;
		}

		internal byte ReadByte()
		{
			CheckCanRead(1);
			return buffer[position++];
		}

		internal byte[] ReadBytes(int length)
		{
			CheckCanRead(length);
			byte[] array = new byte[length];
			Buffer.BlockCopy(buffer, position, array, 0, length);
			position += length;
			return array;
		}

		internal short ReadInt16()
		{
			CheckCanRead(2);
			short result = (short)(buffer[position] | (buffer[position + 1] << 8));
			position += 2;
			return result;
		}

		internal int ReadInt32()
		{
			CheckCanRead(4);
			int result = buffer[position] | (buffer[position + 1] << 8) | (buffer[position + 2] << 16) | (buffer[position + 3] << 24);
			position += 4;
			return result;
		}

		internal long ReadInt64()
		{
			CheckCanRead(8);
			uint num = (uint)(buffer[position] | (buffer[position + 1] << 8) | (buffer[position + 2] << 16) | (buffer[position + 3] << 24));
			uint num2 = (uint)(buffer[position + 4] | (buffer[position + 5] << 8) | (buffer[position + 6] << 16) | (buffer[position + 7] << 24));
			long result = (long)(((ulong)num2 << 32) | num);
			position += 8;
			return result;
		}

		internal float ReadSingle()
		{
			if (!BitConverter.IsLittleEndian)
			{
				byte[] array = ReadBytes(4);
				Array.Reverse((Array)array);
				return BitConverter.ToSingle(array, 0);
			}
			CheckCanRead(4);
			float result = BitConverter.ToSingle(buffer, position);
			position += 4;
			return result;
		}

		internal double ReadDouble()
		{
			if (!BitConverter.IsLittleEndian)
			{
				byte[] array = ReadBytes(8);
				Array.Reverse((Array)array);
				return BitConverter.ToDouble(array, 0);
			}
			CheckCanRead(8);
			double result = BitConverter.ToDouble(buffer, position);
			position += 8;
			return result;
		}

		private void CheckCanRead(int count)
		{
			if (position + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("count", $"position({position}) + count({count}) > buffer.Length({buffer.Length})");
			}
		}
	}
	internal class CodeTranspiler
	{
		[CompilerGenerated]
		private sealed class <ConvertToOurInstructions>d__7 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			private int <>l__initialThreadId;

			private IEnumerable instructions;

			public IEnumerable <>3__instructions;

			private Type codeInstructionType;

			public Type <>3__codeInstructionType;

			private Dictionary<object, Dictionary<string, object>> unassignedValues;

			public Dictionary<object, Dictionary<string, object>> <>3__unassignedValues;

			private List<object> originalInstructions;

			public List<object> <>3__originalInstructions;

			private List<object> <newInstructions>5__2;

			private int <index>5__3;

			private List<object>.Enumerator <>7__wrap3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ConvertToOurInstructions>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<newInstructions>5__2 = null;
				<>7__wrap3 = default(List<object>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<newInstructions>5__2 = instructions.Cast<object>().ToList();
						<index>5__3 = -1;
						<>7__wrap3 = <newInstructions>5__2.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					if (<>7__wrap3.MoveNext())
					{
						object current = <>7__wrap3.Current;
						<index>5__3++;
						object root = AccessTools.MakeDeepCopy(current, codeInstructionType);
						if (unassignedValues.TryGetValue(current, out var value))
						{
							bool flag = ShouldAddExceptionInfo(current, <index>5__3, originalInstructions, <newInstructions>5__2, unassignedValues);
							Traverse traverse = Traverse.Create(root);
							foreach (KeyValuePair<string, object> item in value)
							{
								if (flag || item.Key != "blocks")
								{
									traverse.Field(item.Key).SetValue(item.Value);
								}
							}
						}
						<>2__current = root;
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>7__wrap3 = default(List<object>.Enumerator);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap3).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<object> IEnumerable<object>.GetEnumerator()
			{
				<ConvertToOurInstructions>d__7 <ConvertToOurInstructions>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId)
				{
					<>1__state = 0;
					<ConvertToOurInstructions>d__ = this;
				}
				else
				{
					<ConvertToOurInstructions>d__ = new <ConvertToOurInstructions>d__7(0);
				}
				<ConvertToOurInstructions>d__.instructions = <>3__instructions;
				<ConvertToOurInstructions>d__.codeInstructionType = <>3__codeInstructionType;
				<ConvertToOurInstructions>d__.originalInstructions = <>3__originalInstructions;
				<ConvertToOurInstructions>d__.unassignedValues = <>3__unassignedValues;
				return <ConvertToOurInstructions>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<object>)this).GetEnumerator();
			}
		}

		private readonly IEnumerable<CodeInstruction> codeInstructions;

		private readonly List<MethodInfo> transpilers = new List<MethodInfo>();

		private static readonly Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> allJumpCodes = new Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode>
		{
			{
				System.Reflection.Emit.OpCodes.Beq_S,
				System.Reflection.Emit.OpCodes.Beq
			},
			{
				System.Reflection.Emit.OpCodes.Bge_S,
				System.Reflection.Emit.OpCodes.Bge
			},
			{
				System.Reflection.Emit.OpCodes.Bge_Un_S,
				System.Reflection.Emit.OpCodes.Bge_Un
			},
			{
				System.Reflection.Emit.OpCodes.Bgt_S,
				System.Reflection.Emit.OpCodes.Bgt
			},
			{
				System.Reflection.Emit.OpCodes.Bgt_Un_S,
				System.Reflection.Emit.OpCodes.Bgt_Un
			},
			{
				System.Reflection.Emit.OpCodes.Ble_S,
				System.Reflection.Emit.OpCodes.Ble
			},
			{
				System.Reflection.Emit.OpCodes.Ble_Un_S,
				System.Reflection.Emit.OpCodes.Ble_Un
			},
			{
				System.Reflection.Emit.OpCodes.Blt_S,
				System.Reflection.Emit.OpCodes.Blt
			},
			{
				System.Reflection.Emit.OpCodes.Blt_Un_S,
				System.Reflection.Emit.OpCodes.Blt_Un
			},
			{
				System.Reflection.Emit.OpCodes.Bne_Un_S,
				System.Reflection.Emit.OpCodes.Bne_Un
			},
			{
				System.Reflection.Emit.OpCodes.Brfalse_S,
				System.Reflection.Emit.OpCodes.Brfalse
			},
			{
				System.Reflection.Emit.OpCodes.Brtrue_S,
				System.Reflection.Emit.OpCodes.Brtrue
			},
			{
				System.Reflection.Emit.OpCodes.Br_S,
				System.Reflection.Emit.OpCodes.Br
			},
			{
				System.Reflection.Emit.OpCodes.Leave_S,
				System.Reflection.Emit.OpCodes.Leave
			}
		};

		internal CodeTranspiler(List<ILInstruction> ilInstructions)
		{
			codeInstructions = ilInstructions.Select((ILInstruction ilInstruction) => ilInstruction.GetCodeInstruction()).ToList().AsEnumerable();
		}

		internal void Add(MethodInfo transpiler)
		{
			transpilers.Add(transpiler);
		}

		internal static object ConvertInstruction(Type type, object instruction, out Dictionary<string, object> unassigned)
		{
			Dictionary<string, object> nonExisting = new Dictionary<string, object>();
			object result = AccessTools.MakeDeepCopy(instruction, type, delegate(string namePath, Traverse trvSrc, Traverse trvDest)
			{
				object value = trvSrc.GetValue();
				if (!trvDest.FieldExists())
				{
					nonExisting[namePath] = value;
					return null;
				}
				return (namePath == "opcode") ? ((object)ReplaceShortJumps((System.Reflection.Emit.OpCode)value)) : value;
			});
			unassigned = nonExisting;
			return result;
		}

		internal static bool ShouldAddExceptionInfo(object op, int opIndex, List<object> originalInstructions, List<object> newInstructions, Dictionary<object, Dictionary<string, object>> unassignedValues)
		{
			int num = originalInstructions.IndexOf(op);
			if (num == -1)
			{
				return false;
			}
			if (!unassignedValues.TryGetValue(op, out var unassigned))
			{
				return false;
			}
			if (!unassigned.TryGetValue("blocks", out var blocksObject))
			{
				return false;
			}
			List<ExceptionBlock> blocks = blocksObject as List<ExceptionBlock>;
			int num2 = newInstructions.Count((object instr) => instr == op);
			if (num2 <= 1)
			{
				return true;
			}
			ExceptionBlock exceptionBlock = blocks.FirstOrDefault((ExceptionBlock block) => block.blockType != ExceptionBlockType.EndExceptionBlock);
			ExceptionBlock exceptionBlock2 = blocks.FirstOrDefault((ExceptionBlock block) => block.blockType == ExceptionBlockType.EndExceptionBlock);
			if (exceptionBlock != null && exceptionBlock2 == null)
			{
				object obj = originalInstructions.Skip(num + 1).FirstOrDefault(delegate(object instr)
				{
					if (!unassignedValues.TryGetValue(instr, out unassigned))
					{
						return false;
					}
					if (!unassigned.TryGetValue("blocks", out blocksObject))
					{
						return false;
					}
					blocks = blocksObject as List<ExceptionBlock>;
					return blocks.Count > 0;
				});
				if (obj != null)
				{
					int num3 = num + 1;
					int num4 = num3 + originalInstructions.Skip(num3).ToList().IndexOf(obj) - 1;
					IEnumerable<object> first = originalInstructions.GetRange(num3, num4 - num3).Intersect(newInstructions);
					obj = newInstructions.Skip(opIndex + 1).FirstOrDefault(delegate(object instr)
					{
						if (!unassignedValues.TryGetValue(instr, out unassigned))
						{
							return false;
						}
						if (!unassigned.TryGetValue("blocks", out blocksObject))
						{
							return false;
						}
						blocks = blocksObject as List<ExceptionBlock>;
						return blocks.Count > 0;
					});
					if (obj != null)
					{
						num3 = opIndex + 1;
						num4 = num3 + newInstructions.Skip(opIndex + 1).ToList().IndexOf(obj) - 1;
						List<object> range = newInstructions.GetRange(num3, num4 - num3);
						List<object> list = first.Except(range).ToList();
						return list.Count == 0;
					}
				}
			}
			if (exceptionBlock == null && exceptionBlock2 != null)
			{
				object obj2 = originalInstructions.GetRange(0, num).LastOrDefault(delegate(object instr)
				{
					if (!unassignedValues.TryGetValue(instr, out unassigned))
					{
						return false;
					}
					if (!unassigned.TryGetValue("blocks", out blocksObject))
					{
						return false;
					}
					blocks = blocksObject as List<ExceptionBlock>;
					return blocks.Count > 0;
				});
				if (obj2 != null)
				{
					int num5 = originalInstructions.GetRange(0, num).LastIndexOf(obj2);
					int num6 = num;
					IEnumerable<object> first2 = originalInstructions.GetRange(num5, num6 - num5).Intersect(newInstructions);
					obj2 = newInstructions.GetRange(0, opIndex).LastOrDefault(delegate(object instr)
					{
						if (!unassignedValues.TryGetValue(instr, out unassigned))
						{
							return false;
						}
						if (!unassigned.TryGetValue("blocks", out blocksObject))
						{
							return false;
						}
						blocks = blocksObject as List<ExceptionBlock>;
						return blocks.Count > 0;
					});
					if (obj2 != null)
					{
						num5 = newInstructions.GetRange(0, opIndex).LastIndexOf(obj2);
						num6 = opIndex;
						List<object> range2 = newInstructions.GetRange(num5, num6 - num5);
						IEnumerable<object> source = first2.Except(range2);
						return !source.Any();
					}
				}
			}
			return true;
		}

		internal static IEnumerable ConvertInstructionsAndUnassignedValues(Type type, IEnumerable enumerable, out Dictionary<object, Dictionary<string, object>> unassignedValues)
		{
			Assembly assembly = type.GetGenericTypeDefinition().Assembly;
			Type type2 = assembly.GetType(typeof(List<>).FullName);
			Type type3 = type.GetGenericArguments()[0];
			Type type4 = type2.MakeGenericType(type3);
			Type type5 = assembly.GetType(type4.FullName);
			object obj = Activator.CreateInstance(type5);
			MethodInfo method = obj.GetType().GetMethod("Add");
			unassignedValues = new Dictionary<object, Dictionary<string, object>>();
			foreach (object item in enumerable)
			{
				Dictionary<string, object> unassigned;
				object obj2 = ConvertInstruction(type3, item, out unassigned);
				unassignedValues.Add(obj2, unassigned);
				method.Invoke(obj, new object[1] { obj2 });
			}
			return obj as IEnumerable;
		}

		internal static IEnumerable ConvertToOurInstructions(IEnumerable instructions, Type codeInstructionType, List<object> originalInstructions, Dictionary<object, Dictionary<string, object>> unassignedValues)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ConvertToOurInstructions>d__7(-2)
			{
				<>3__instructions = instructions,
				<>3__codeInstructionType = codeInstructionType,
				<>3__originalInstructions = originalInstructions,
				<>3__unassignedValues = unassignedValues
			};
		}

		private static bool IsCodeInstructionsParameter(Type type)
		{
			if (type.IsGenericType)
			{
				return type.GetGenericTypeDefinition().Name.StartsWith("IEnumerable", StringComparison.Ordinal);
			}
			return false;
		}

		internal static IEnumerable ConvertToGeneralInstructions(MethodInfo transpiler, IEnumerable enumerable, out Dictionary<object, Dictionary<string, object>> unassignedValues)
		{
			Type type = (from p in transpiler.GetParameters()
				select p.ParameterType).FirstOrDefault(IsCodeInstructionsParameter);
			if ((object)type == typeof(IEnumerable<CodeInstruction>))
			{
				unassignedValues = null;
				object obj = enumerable as IList<CodeInstruction>;
				if (obj == null)
				{
					List<CodeInstruction> list = new List<CodeInstruction>();
					list.AddRange((enumerable as IEnumerable<CodeInstruction>) ?? enumerable.Cast<CodeInstruction>());
					obj = list;
				}
				return (IEnumerable)obj;
			}
			return ConvertInstructionsAndUnassignedValues(type, enumerable, out unassignedValues);
		}

		internal static List<object> GetTranspilerCallParameters(ILGenerator generator, MethodInfo transpiler, MethodBase method, IEnumerable instructions)
		{
			List<object> parameter = new List<object>();
			(from param in transpiler.GetParameters()
				select param.ParameterType).Do(delegate(Type type)
			{
				if (type.IsAssignableFrom(typeof(ILGenerator)))
				{
					parameter.Add(generator);
				}
				else if (type.IsAssignableFrom(typeof(MethodBase)))
				{
					parameter.Add(method);
				}
				else if (IsCodeInstructionsParameter(type))
				{
					parameter.Add(instructions);
				}
			});
			return parameter;
		}

		internal List<CodeInstruction> GetResult(ILGenerator generator, MethodBase method)
		{
			IEnumerable instructions = codeInstructions;
			transpilers.ForEach(delegate(MethodInfo transpiler)
			{
				instructions = ConvertToGeneralInstructions(transpiler, instructions, out var unassignedValues);
				List<object> originalInstructions = null;
				if (unassignedValues != null)
				{
					originalInstructions = instructions.Cast<object>().ToList();
				}
				List<object> transpilerCallParameters = GetTranspilerCallParameters(generator, transpiler, method, instructions);
				if (transpiler.Invoke(null, transpilerCallParameters.ToArray()) is IEnumerable enumerable)
				{
					instructions = enumerable;
				}
				if (unassignedValues != null)
				{
					instructions = ConvertToOurInstructions(instructions, typeof(CodeInstruction), originalInstructions, unassignedValues);
				}
			});
			return (instructions as List<CodeInstruction>) ?? instructions.Cast<CodeInstruction>().ToList();
		}

		private static System.Reflection.Emit.OpCode ReplaceShortJumps(System.Reflection.Emit.OpCode opcode)
		{
			foreach (KeyValuePair<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> allJumpCode in allJumpCodes)
			{
				if (opcode == allJumpCode.Key)
				{
					return allJumpCode.Value;
				}
			}
			return opcode;
		}
	}
	internal class LeaveTry
	{
		public override string ToString()
		{
			return "(autogenerated)";
		}
	}
	internal class Emitter
	{
		private readonly CecilILGenerator il;

		private readonly Dictionary<int, CodeInstruction> instructions = new Dictionary<int, CodeInstruction>();

		private readonly bool debug;

		internal Emitter(ILGenerator il, bool debug)
		{
			this.il = il.GetProxiedShim<CecilILGenerator>();
			this.debug = debug;
		}

		internal Dictionary<int, CodeInstruction> GetInstructions()
		{
			return instructions;
		}

		internal void AddInstruction(System.Reflection.Emit.OpCode opcode, object operand)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, operand));
		}

		internal int CurrentPos()
		{
			return il.ILOffset;
		}

		internal static string CodePos(int offset)
		{
			return $"IL_{offset:X4}: ";
		}

		internal string CodePos()
		{
			return CodePos(CurrentPos());
		}

		internal void LogComment(string comment)
		{
			if (debug)
			{
				string str = $"{CodePos()}// {comment}";
				FileLog.LogBuffered(str);
			}
		}

		internal void LogIL(System.Reflection.Emit.OpCode opcode)
		{
			if (debug)
			{
				FileLog.LogBuffered($"{CodePos()}{opcode}");
			}
		}

		internal void LogIL(System.Reflection.Emit.OpCode opcode, object arg, string extra = null)
		{
			if (debug)
			{
				string text = FormatArgument(arg, extra);
				string text2 = ((text.Length > 0) ? " " : "");
				string text3 = opcode.ToString();
				if (opcode.FlowControl == System.Reflection.Emit.FlowControl.Branch || opcode.FlowControl == System.Reflection.Emit.FlowControl.Cond_Branch)
				{
					text3 += " =>";
				}
				text3 = text3.PadRight(10);
				FileLog.LogBuffered($"{CodePos()}{text3}{text2}{text}");
			}
		}

		internal void LogAllLocalVariables()
		{
			if (debug)
			{
				il.IL.Body.Variables.Do(delegate(VariableDefinition v)
				{
					string str = string.Format("{0}Local var {1}: {2}{3}", CodePos(0), v.Index, v.VariableType.FullName, v.IsPinned ? "(pinned)" : "");
					FileLog.LogBuffered(str);
				});
			}
		}

		internal static string FormatArgument(object argument, string extra = null)
		{
			if (argument == null)
			{
				return "NULL";
			}
			Type type = argument.GetType();
			if (argument is MethodBase member)
			{
				return member.FullDescription() + ((extra != null) ? (" " + extra) : "");
			}
			if (argument is FieldInfo fieldInfo)
			{
				return $"{fieldInfo.FieldType.FullDescription()} {fieldInfo.DeclaringType.FullDescription()}::{fieldInfo.Name}";
			}
			if ((object)type == typeof(Label))
			{
				return $"Label{((Label)argument).GetHashCode()}";
			}
			if ((object)type == typeof(Label[]))
			{
				return "Labels" + string.Join(",", ((Label[])argument).Select((Label l) => l.GetHashCode().ToString()).ToArray());
			}
			if ((object)type == typeof(LocalBuilder))
			{
				return $"{((LocalBuilder)argument).LocalIndex} ({((LocalBuilder)argument).LocalType})";
			}
			if ((object)type == typeof(string))
			{
				return argument.ToString().ToLiteral();
			}
			return argument.ToString().Trim();
		}

		internal void MarkLabel(Label label)
		{
			if (debug)
			{
				FileLog.LogBuffered(CodePos() + FormatArgument(label));
			}
			il.MarkLabel(label);
		}

		internal void MarkBlockBefore(ExceptionBlock block, out Label? label)
		{
			label = null;
			switch (block.blockType)
			{
			case ExceptionBlockType.BeginExceptionBlock:
				if (debug)
				{
					FileLog.LogBuffered(".try");
					FileLog.LogBuffered("{");
					FileLog.ChangeIndent(1);
				}
				label = il.BeginExceptionBlock();
				break;
			case ExceptionBlockType.BeginCatchBlock:
				if (debug)
				{
					LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry());
					FileLog.ChangeIndent(-1);
					FileLog.LogBuffered("} // end try");
					FileLog.LogBuffered($".catch {block.catchType}");
					FileLog.LogBuffered("{");
					FileLog.ChangeIndent(1);
				}
				il.BeginCatchBlock(block.catchType);
				break;
			case ExceptionBlockType.BeginExceptFilterBlock:
				if (debug)
				{
					LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry());
					FileLog.ChangeIndent(-1);
					FileLog.LogBuffered("} // end try");
					FileLog.LogBuffered(".filter");
					FileLog.LogBuffered("{");
					FileLog.ChangeIndent(1);
				}
				il.BeginExceptFilterBlock();
				break;
			case ExceptionBlockType.BeginFaultBlock:
				if (debug)
				{
					LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry());
					FileLog.ChangeIndent(-1);
					FileLog.LogBuffered("} // end try");
					FileLog.LogBuffered(".fault");
					FileLog.LogBuffered("{");
					FileLog.ChangeIndent(1);
				}
				il.BeginFaultBlock();
				break;
			case ExceptionBlockType.BeginFinallyBlock:
				if (debug)
				{
					LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry());
					FileLog.ChangeIndent(-1);
					FileLog.LogBuffered("} // end try");
					FileLog.LogBuffered(".finally");
					FileLog.LogBuffered("{");
					FileLog.ChangeIndent(1);
				}
				il.BeginFinallyBlock();
				break;
			}
		}

		internal void MarkBlockAfter(ExceptionBlock block)
		{
			ExceptionBlockType blockType = block.blockType;
			if (blockType == ExceptionBlockType.EndExceptionBlock)
			{
				if (debug)
				{
					LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry());
					FileLog.ChangeIndent(-1);
					FileLog.LogBuffered("} // end handler");
				}
				il.EndExceptionBlock();
			}
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode));
			LogIL(opcode);
			il.Emit(opcode);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, LocalBuilder local)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, local));
			LogIL(opcode, local);
			il.Emit(opcode, local);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, FieldInfo field)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, field));
			LogIL(opcode, field);
			il.Emit(opcode, field);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, Label[] labels)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, labels));
			LogIL(opcode, labels);
			il.Emit(opcode, labels);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, Label label)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, label));
			LogIL(opcode, label);
			il.Emit(opcode, label);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, string str)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, str));
			LogIL(opcode, str);
			il.Emit(opcode, str);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, float arg)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg));
			LogIL(opcode, arg);
			il.Emit(opcode, arg);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, byte arg)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg));
			LogIL(opcode, arg);
			il.Emit(opcode, arg);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, sbyte arg)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg));
			LogIL(opcode, arg);
			il.Emit(opcode, arg);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, double arg)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg));
			LogIL(opcode, arg);
			il.Emit(opcode, arg);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, int arg)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg));
			LogIL(opcode, arg);
			il.Emit(opcode, arg);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, MethodInfo meth)
		{
			if (opcode.Equals(System.Reflection.Emit.OpCodes.Call) || opcode.Equals(System.Reflection.Emit.OpCodes.Callvirt) || opcode.Equals(System.Reflection.Emit.OpCodes.Newobj))
			{
				EmitCall(opcode, meth, null);
				return;
			}
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, meth));
			LogIL(opcode, meth);
			il.Emit(opcode, meth);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, short arg)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg));
			LogIL(opcode, arg);
			il.Emit(opcode, arg);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, SignatureHelper signature)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, signature));
			LogIL(opcode, signature);
			il.Emit(opcode, signature);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, ConstructorInfo con)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, con));
			LogIL(opcode, con);
			il.Emit(opcode, con);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, Type cls)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, cls));
			LogIL(opcode, cls);
			il.Emit(opcode, cls);
		}

		internal void Emit(System.Reflection.Emit.OpCode opcode, long arg)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg));
			LogIL(opcode, arg);
			il.Emit(opcode, arg);
		}

		internal void EmitCall(System.Reflection.Emit.OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, methodInfo));
			string extra = ((optionalParameterTypes != null && optionalParameterTypes.Length != 0) ? optionalParameterTypes.Description() : null);
			LogIL(opcode, methodInfo, extra);
			il.EmitCall(opcode, methodInfo, optionalParameterTypes);
		}

		internal void EmitCalli(System.Reflection.Emit.OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, unmanagedCallConv));
			string extra = returnType.FullName + " " + parameterTypes.Description();
			LogIL(opcode, unmanagedCallConv, extra);
			il.EmitCalli(opcode, unmanagedCallConv, returnType, parameterTypes);
		}

		internal void EmitCalli(System.Reflection.Emit.OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
		{
			instructions.Add(CurrentPos(), new CodeInstruction(opcode, callingConvention));
			string extra = returnType.FullName + " " + parameterTypes.Description() + " " + optionalParameterTypes.Description();
			LogIL(opcode, callingConvention, extra);
			il.EmitCalli(opcode, callingConvention, returnType, parameterTypes, optionalParameterTypes);
		}
	}
	internal static class HarmonySharedState
	{
		private const string name = "HarmonySharedState";

		internal const int internalVersion = 102;

		private static readonly Dictionary<MethodBase, byte[]> state;

		private static readonly Dictionary<MethodInfo, MethodBase> originals;

		private static readonly Dictionary<long, MethodBase[]> originalsMono;

		private static readonly AccessTools.FieldRef<StackFrame, long> methodAddressRef;

		internal static readonly int actualVersion;

		static HarmonySharedState()
		{
			Type orCreateSharedStateType = GetOrCreateSharedStateType();
			if (AccessTools.IsMonoRuntime)
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(StackFrame), "methodAddress");
				if ((object)fieldInfo != null)
				{
					methodAddressRef = AccessTools.FieldRefAccess<StackFrame, long>(fieldInfo);
				}
			}
			FieldInfo field = orCreateSharedStateType.GetField("version");
			if ((int)field.GetValue(null) == 0)
			{
				field.SetValue(null, 102);
			}
			actualVersion = (int)field.GetValue(null);
			FieldInfo field2 = orCreateSharedStateType.GetField("state");
			if (field2.GetValue(null) == null)
			{
				field2.SetValue(null, new Dictionary<MethodBase, byte[]>());
			}
			FieldInfo field3 = orCreateSharedStateType.GetField("originals");
			if ((object)field3 != null && field3.GetValue(null) == null)
			{
				field3.SetValue(null, new Dictionary<MethodInfo, MethodBase>());
			}
			FieldInfo field4 = orCreateSharedStateType.GetField("originalsMono");
			if ((object)field4 != null && field4.GetValue(null) == null)
			{
				field4.SetValue(null, new Dictionary<long, MethodBase[]>());
			}
			state = (Dictionary<MethodBase, byte[]>)field2.GetValue(null);
			originals = new Dictionary<MethodInfo, MethodBase>();
			if ((object)field3 != null)
			{
				originals = (Dictionary<MethodInfo, MethodBase>)field3.GetValue(null);
			}
			originalsMono = new Dictionary<long, MethodBase[]>();
			if ((object)field4 != null)
			{
				originalsMono = (Dictionary<long, MethodBase[]>)field4.GetValue(null);
			}
		}

		private static Type GetOrCreateSharedStateType()
		{
			Type type = Type.GetType("HarmonySharedState", throwOnError: false);
			if ((object)type != null)
			{
				return type;
			}
			using ModuleDefinition moduleDefinition = ModuleDefinition.CreateModule("HarmonySharedState", new ModuleParameters
			{
				Kind = ModuleKind.Dll,
				ReflectionImporterProvider = MMReflectionImporter.Provider
			});
			Mono.Cecil.TypeAttributes attributes = Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.Abstract | Mono.Cecil.TypeAttributes.Sealed;
			TypeDefinition typeDefinition = new TypeDefinition("", "HarmonySharedState", attributes)
			{
				BaseType = moduleDefinition.TypeSystem.Object
			};
			moduleDefinition.Types.Add(typeDefinition);
			typeDefinition.Fields.Add(new FieldDefinition("state", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(Dictionary<MethodBase, byte[]>))));
			typeDefinition.Fields.Add(new FieldDefinition("originals", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(Dictionary<MethodInfo, MethodBase>))));
			typeDefinition.Fields.Add(new FieldDefinition("originalsMono", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(Dictionary<long, MethodBase[]>))));
			typeDefinition.Fields.Add(new FieldDefinition("version", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(int))));
			return ReflectionHelper.Load(moduleDefinition).GetType("HarmonySharedState");
		}

		internal static PatchInfo GetPatchInfo(MethodBase method)
		{
			byte[] valueSafe;
			lock (state)
			{
				valueSafe = state.GetValueSafe(method);
			}
			if (valueSafe == null)
			{
				return null;
			}
			return PatchInfoSerialization.Deserialize(valueSafe);
		}

		internal static IEnumerable<MethodBase> GetPatchedMethods()
		{
			lock (state)
			{
				return state.Keys.ToArray();
			}
		}

		internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement, PatchInfo patchInfo)
		{
			byte[] value = patchInfo.Serialize();
			lock (state)
			{
				state[original] = value;
			}
			lock (originals)
			{
				originals[replacement.Identifiable()] = original;
			}
			if (AccessTools.IsMonoRuntime)
			{
				long key = (long)replacement.MethodHandle.GetFunctionPointer();
				lock (originalsMono)
				{
					originalsMono[key] = new MethodBase[2] { original, replacement };
				}
			}
		}

		internal static MethodBase GetRealMethod(MethodInfo method, bool useReplacement)
		{
			MethodInfo key = method.Identifiable();
			lock (originals)
			{
				if (originals.TryGetValue(key, out var value))
				{
					return value;
				}
			}
			if (AccessTools.IsMonoRuntime)
			{
				long key2 = (long)method.MethodHandle.GetFunctionPointer();
				lock (originalsMono)
				{
					if (originalsMono.TryGetValue(key2, out var value2))
					{
						return useReplacement ? value2[1] : value2[0];
					}
				}
			}
			return method;
		}

		internal static MethodBase GetStackFrameMethod(StackFrame frame, bool useReplacement)
		{
			if (frame.GetMethod() is MethodInfo method)
			{
				return GetRealMethod(method, useReplacement);
			}
			if (methodAddressRef != null)
			{
				long key = methodAddressRef(frame);
				lock (originalsMono)
				{
					if (originalsMono.TryGetValue(key, out var value))
					{
						return useReplacement ? value[1] : value[0];
					}
				}
			}
			return null;
		}
	}
	internal class ILInstruction
	{
		internal int offset;

		internal System.Reflection.Emit.OpCode opcode;

		internal object operand;

		internal object argument;

		internal List<Label> labels = new List<Label>();

		internal List<ExceptionBlock> blocks = new List<ExceptionBlock>();

		internal ILInstruction(System.Reflection.Emit.OpCode opcode, object operand = null)
		{
			this.opcode = opcode;
			this.operand = operand;
			argument = operand;
		}

		internal CodeInstruction GetCodeInstruction()
		{
			CodeInstruction codeInstruction = new CodeInstruction(opcode, argument);
			if (opcode.OperandType == System.Reflection.Emit.OperandType.InlineNone)
			{
				codeInstruction.operand = null;
			}
			codeInstruction.labels = labels;
			codeInstruction.blocks = blocks;
			return codeInstruction;
		}

		internal int GetSize()
		{
			int num = opcode.Size;
			switch (opcode.OperandType)
			{
			case System.Reflection.Emit.OperandType.InlineSwitch:
				num += (1 + ((Array)operand).Length) * 4;
				break;
			case System.Reflection.Emit.OperandType.InlineI8:
			case System.Reflection.Emit.OperandType.InlineR:
				num += 8;
				break;
			case System.Reflection.Emit.OperandType.InlineBrTarget:
			case System.Reflection.Emit.OperandType.InlineField:
			case System.Reflection.Emit.OperandType.InlineI:
			case System.Reflection.Emit.OperandType.InlineMethod:
			case System.Reflection.Emit.OperandType.InlineSig:
			case System.Reflection.Emit.OperandType.InlineString:
			case System.Reflection.Emit.OperandType.InlineTok:
			case System.Reflection.Emit.OperandType.InlineType:
			case System.Reflection.Emit.OperandType.ShortInlineR:
				num += 4;
				break;
			case System.Reflection.Emit.OperandType.InlineVar:
				num += 2;
				break;
			case System.Reflection.Emit.OperandType.ShortInlineBrTarget:
			case System.Reflection.Emit.OperandType.ShortInlineI:
			case System.Reflection.Emit.OperandType.ShortInlineVar:
				num++;
				break;
			}
			return num;
		}

		public override string ToString()
		{
			string str = "";
			AppendLabel(ref str, this);
			str = str + ": " + opcode.Name;
			if (operand == null)
			{
				return str;
			}
			str += " ";
			switch (opcode.OperandType)
			{
			case System.Reflection.Emit.OperandType.InlineBrTarget:
			case System.Reflection.Emit.OperandType.ShortInlineBrTarget:
				AppendLabel(ref str, operand);
				break;
			case System.Reflection.Emit.OperandType.InlineSwitch:
			{
				ILInstruction[] array = (ILInstruction[])operand;
				for (int i = 0; i < array.Length; i++)
				{
					if (i > 0)
					{
						str += ",";
					}
					AppendLabel(ref str, array[i]);
				}
				break;
			}
			case System.Reflection.Emit.OperandType.InlineString:
				str += $"\"{operand}\"";
				break;
			default:
				str += operand;
				break;
			}
			return str;
		}

		private static void AppendLabel(ref string str, object argument)
		{
			ILInstruction iLInstruction = argument as ILInstruction;
			str += $"IL_{iLInstruction?.offset.ToString("X4") ?? argument}";
		}
	}
	internal static class InlineSignatureParser
	{
		internal static InlineSignature ImportCallSite(Module moduleFrom, byte[] data)
		{
			InlineSignature inlineSignature = new InlineSignature();
			BinaryReader reader;
			using (MemoryStream input = new MemoryStream(data, writable: false))
			{
				reader = new BinaryReader(input);
				try
				{
					ReadMethodSignature(inlineSignature);
					return inlineSignature;
				}
				finally
				{
					if (reader != null)
					{
						((IDisposable)reader).Dispose();
					}
				}
			}
			Type GetTypeDefOrRef()
			{
				uint num3 = ReadCompressedUInt32();
				uint num4 = num3 >> 2;
				return moduleFrom.ResolveType((num3 & 3) switch
				{
					0u => (int)(0x2000000 | num4), 
					1u => (int)(0x1000000 | num4), 
					2u => (int)(0x1B000000 | num4), 
					_ => 0, 
				});
			}
			int ReadCompressedInt32()
			{
				byte b = reader.ReadByte();
				reader.BaseStream.Seek(-1L, SeekOrigin.Current);
				int num = (int)ReadCompressedUInt32();
				int num2 = num >> 1;
				if ((num & 1) == 0)
				{
					return num2;
				}
				switch (b & 0xC0)
				{
				case 0:
				case 64:
					return num2 - 64;
				case 128:
					return num2 - 8192;
				default:
					return num2 - 268435456;
				}
			}
			uint ReadCompressedUInt32()
			{
				byte b2 = reader.ReadByte();
				if ((b2 & 0x80) == 0)
				{
					return b2;
				}
				if ((b2 & 0x40) == 0)
				{
					return (uint)(((b2 & -129) << 8) | reader.ReadByte());
				}
				return (uint)(((b2 & -193) << 24) | (reader.ReadByte() << 16) | (reader.ReadByte() << 8) | reader.ReadByte());
			}
			void ReadMethodSignature(InlineSignature method)
			{
				byte b3 = reader.ReadByte();
				if ((b3 & 0x20u) != 0)
				{
					method.HasThis = true;
					b3 = (byte)(b3 & 0xFFFFFFDFu);
				}
				if ((b3 & 0x40u) != 0)
				{
					method.ExplicitThis = true;
					b3 = (byte)(b3 & 0xFFFFFFBFu);
				}
				method.CallingConvention = (CallingConvention)(b3 + 1);
				if ((b3 & 0x10u) != 0)
				{
					ReadCompressedUInt32();
				}
				uint num7 = ReadCompressedUInt32();
				method.ReturnType = ReadTypeSignature();
				for (int k = 0; k < num7; k++)
				{
					method.Parameters.Add(ReadTypeSignature());
				}
			}
			object ReadTypeSignature()
			{
				MetadataType metadataType = (MetadataType)reader.ReadByte();
				switch (metadataType)
				{
				case MetadataType.ValueType:
				case MetadataType.Class:
					return GetTypeDefOrRef();
				case MetadataType.Pointer:
					return ((Type)ReadTypeSignature()).MakePointerType();
				case MetadataType.FunctionPointer:
				{
					InlineSignature inlineSignature2 = new InlineSignature();
					ReadMethodSignature(inlineSignature2);
					return inlineSignature2;
				}
				case MetadataType.ByReference:
					return ((Type)ReadTypeSignature()).MakePointerType();
				case (MetadataType)29:
					return ((Type)ReadTypeSignature()).MakeArrayType();
				case MetadataType.Array:
				{
					Type type = (Type)ReadTypeSignature();
					uint rank = ReadCompressedUInt32();
					uint num5 = ReadCompressedUInt32();
					for (int i = 0; i < num5; i++)
					{
						ReadCompressedUInt32();
					}
					uint num6 = ReadCompressedUInt32();
					for (int j = 0; j < num6; j++)
					{
						ReadCompressedInt32();
					}
					return type.MakeArrayType((int)rank);
				}
				case MetadataType.OptionalModifier:
					return new InlineSignature.ModifierType
					{
						IsOptional = true,
						Modifier = GetTypeDefOrRef(),
						Type = ReadTypeSignature()
					};
				case MetadataType.RequiredModifier:
					return new InlineSignature.ModifierType
					{
						IsOptional = false,
						Modifier = GetTypeDefOrRef(),
						Type = ReadTypeSignature()
					};
				case MetadataType.Var:
				case MetadataType.MVar:
					throw new NotSupportedException($"Unsupported generic callsite element: {metadataType}");
				case MetadataType.GenericInstance:
				{
					reader.ReadByte();
					Type typeDefOrRef = GetTypeDefOrRef();
					int count = (int)ReadCompressedUInt32();
					return typeDefOrRef.MakeGenericType((from _ in Enumerable.Range(0, count)
						select (Type)ReadTypeSignature()).ToArray());
				}
				case MetadataType.Object:
					return typeof(object);
				case MetadataType.Void:
					return typeof(void);
				case MetadataType.TypedByReference:
					return typeof(TypedReference);
				case MetadataType.IntPtr:
					return typeof(IntPtr);
				case MetadataType.UIntPtr:
					return typeof(UIntPtr);
				case MetadataType.Boolean:
					return typeof(bool);
				case MetadataType.Char:
					return typeof(char);
				case MetadataType.SByte:
					return typeof(sbyte);
				case MetadataType.Byte:
					return typeof(byte);
				case MetadataType.Int16:
					return typeof(short);
				case MetadataType.UInt16:
					return typeof(ushort);
				case MetadataType.Int32:
					return typeof(int);
				case MetadataType.UInt32:
					return typeof(uint);
				case MetadataType.Int64:
					return typeof(long);
				case MetadataType.UInt64:
					return typeof(ulong);
				case MetadataType.Single:
					return typeof(float);
				case MetadataType.Double:
					return typeof(double);
				case MetadataType.String:
					return typeof(string);
				default:
					throw new NotSupportedException($"Unsupported callsite element: {metadataType}");
				}
			}
		}
	}
	internal class MethodCopier
	{
		private readonly MethodBodyReader reader;

		private readonly List<MethodInfo> transpilers = new List<MethodInfo>();

		internal MethodCopier(MethodBase fromMethod, ILGenerator toILGenerator, LocalBuilder[] existingVariables = null)
		{
			if ((object)fromMethod == null)
			{
				throw new ArgumentNullException("fromMethod");
			}
			reader = new MethodBodyReader(fromMethod, toILGenerator);
			reader.DeclareVariables(existingVariables);
			reader.GenerateInstructions();
		}

		internal void SetDebugging(bool debug)
		{
			reader.SetDebugging(debug);
		}

		internal void AddTranspiler(MethodInfo transpiler)
		{
			transpilers.Add(transpiler);
		}

		internal List<CodeInstruction> Finalize(Emitter emitter, List<Label> endLabels, out bool hasReturnCode, out bool methodEndsInDeadCode)
		{
			return reader.FinalizeILCodes(emitter, transpilers, endLabels, out hasReturnCode, out methodEndsInDeadCode);
		}

		internal static List<CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers)
		{
			if (generator == null)
			{
				throw new ArgumentNullException("generator");
			}
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			LocalBuilder[] existingVariables = MethodPatcher.DeclareOriginalLocalVariables(generator, method);
			MethodCopier methodCopier = new MethodCopier(method, generator, existingVariables);
			Patches patchInfo = Harmony.GetPatchInfo(method);
			if (patchInfo != null)
			{
				List<MethodInfo> sortedPatchMethods = PatchFunctions.GetSortedPatchMethods(method, patchInfo.Transpilers.ToArray(), debug: false);
				for (int i = 0; i < maxTranspilers && i < sortedPatchMethods.Count; i++)
				{
					methodCopier.AddTranspiler(sortedPatchMethods[i]);
				}
			}
			bool hasReturnCode;
			bool methodEndsInDeadCode;
			return methodCopier.Finalize(null, null, out hasReturnCode, out methodEndsInDeadCode);
		}
	}
	internal class MethodBodyReader
	{
		private class ThisParameter : ParameterInfo
		{
			internal ThisParameter(MethodBase method)
			{
				MemberImpl = method;
				ClassImpl = method.DeclaringType;
				NameImpl = "this";
				PositionImpl = -1;
			}
		}

		private readonly ILGenerator generator;

		private readonly MethodBase method;

		private bool debug;

		private readonly Module module;

		private readonly Type[] typeArguments;

		private readonly Type[] methodArguments;

		private readonly ByteBuffer ilBytes;

		private readonly ParameterInfo this_parameter;

		private readonly ParameterInfo[] parameters;

		private readonly IList<ExceptionHandlingClause> exceptions;

		private readonly List<ILInstruction> ilInstructions;

		private readonly List<LocalVariableInfo> localVariables;

		private LocalBuilder[] variables;

		private static readonly Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> shortJumps;

		private static readonly System.Reflection.Emit.OpCode[] one_byte_opcodes;

		private static readonly System.Reflection.Emit.OpCode[] two_bytes_opcodes;

		internal static List<ILInstruction> GetInstructions(ILGenerator generator, MethodBase method)
		{
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			MethodBodyReader methodBodyReader = new MethodBodyReader(method, generator);
			methodBodyReader.DeclareVariables(null);
			methodBodyReader.GenerateInstructions();
			return methodBodyReader.ilInstructions;
		}

		internal MethodBodyReader(MethodBase method, ILGenerator generator)
		{
			this.generator = generator;
			this.method = method;
			module = method.Module;
			System.Reflection.MethodBody methodBody = method.GetMethodBody();
			if ((methodBody?.GetILAsByteArray()?.Length).GetValueOrDefault() == 0)
			{
				ilBytes = new ByteBuffer(new byte[0]);
				ilInstructions = new List<ILInstruction>();
			}
			else
			{
				byte[] iLAsByteArray = methodBody.GetILAsByteArray();
				if (iLAsByteArray == null)
				{
					throw new ArgumentException("Can not get IL bytes of method " + method.FullDescription());
				}
				ilBytes = new ByteBuffer(iLAsByteArray);
				ilInstructions = new List<ILInstruction>((iLAsByteArray.Length + 1) / 2);
			}
			Type declaringType = method.DeclaringType;
			if ((object)declaringType != null && declaringType.IsGenericType)
			{
				try
				{
					typeArguments = declaringType.GetGenericArguments();
				}
				catch
				{
					typeArguments = null;
				}
			}
			if (method.IsGenericMethod)
			{
				try
				{
					methodArguments = method.GetGenericArguments();
				}
				catch
				{
					methodArguments = null;
				}
			}
			if (!method.IsStatic)
			{
				this_parameter = new ThisParameter(method);
			}
			parameters = method.GetParameters();
			localVariables = methodBody?.LocalVariables?.ToList() ?? new List<LocalVariableInfo>();
			exceptions = methodBody?.ExceptionHandlingClauses ?? new List<ExceptionHandlingClause>();
		}

		internal void SetDebugging(bool debug)
		{
			this.debug = debug;
		}

		internal void GenerateInstructions()
		{
			while (ilBytes.position < ilBytes.buffer.Length)
			{
				int position = ilBytes.position;
				ILInstruction iLInstruction = new ILInstruction(ReadOpCode())
				{
					offset = position
				};
				ReadOperand(iLInstruction);
				ilInstructions.Add(iLInstruction);
			}
			HandleNativeMethod();
			ResolveBranches();
			ParseExceptions();
		}

		internal void HandleNativeMethod()
		{
			if (!(method is MethodInfo methodInfo))
			{
				return;
			}
			DllImportAttribute dllImportAttribute = methodInfo.GetCustomAttributes(inherit: false).OfType<DllImportAttribute>().FirstOrDefault();
			if (dllImportAttribute != null)
			{
				string assemblyName = (methodInfo.DeclaringType?.FullName ?? "").Replace(".", "_") + "_" + methodInfo.Name;
				AssemblyName assemblyName2 = new AssemblyName(assemblyName);
				AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName2, AssemblyBuilderAccess.Run);
				ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName2.Name);
				TypeBuilder typeBuilder = moduleBuilder.DefineType("NativeMethodHolder", System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.UnicodeClass);
				MethodBuilder methodBuilder = typeBuilder.DefinePInvokeMethod(methodInfo.Name, dllImportAttribute.Value, System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Static | System.Reflection.MethodAttributes.PinvokeImpl, CallingConventions.Standard, methodInfo.ReturnType, (from x in methodInfo.GetParameters()
					select x.ParameterType).ToArray(), dllImportAttribute.CallingConvention, dllImportAttribute.CharSet);
				methodBuilder.SetImplementationFlags(methodBuilder.GetMethodImplementationFlags() | System.Reflection.MethodImplAttributes.PreserveSig);
				Type type = typeBuilder.CreateType();
				MethodInfo operand = type.GetMethod(methodInfo.Name);
				int num = method.GetParameters().Length;
				for (int i = 0; i < num; i++)
				{
					ilInstructions.Add(new ILInstruction(System.Reflection.Emit.OpCodes.Ldarg, i)
					{
						offset = 0
					});
				}
				ilInstructions.Add(new ILInstruction(System.Reflection.Emit.OpCodes.Call, operand)
				{
					offset = num
				});
				ilInstructions.Add(new ILInstruction(System.Reflection.Emit.OpCodes.Ret)
				{
					offset = num + 5
				});
			}
		}

		internal void DeclareVariables(LocalBuilder[] existingVariables)
		{
			if (generator == null)
			{
				return;
			}
			if (existingVariables != null)
			{
				variables = existingVariables;
				return;
			}
			variables = localVariables.Select((LocalVariableInfo lvi) => generator.DeclareLocal(lvi.LocalType, lvi.IsPinned)).ToArray();
		}

		private void ResolveBranches()
		{
			foreach (ILInstruction ilInstruction in ilInstructions)
			{
				switch (ilInstruction.opcode.OperandType)
				{
				case System.Reflection.Emit.OperandType.InlineBrTarget:
				case System.Reflection.Emit.OperandType.ShortInlineBrTarget:
					ilInstruction.operand = GetInstruction((int)ilInstruction.operand, isEndOfInstruction: false);
					break;
				case System.Reflection.Emit.OperandType.InlineSwitch:
				{
					int[] array = (int[])ilInstruction.operand;
					ILInstruction[] array2 = new ILInstruction[array.Length];
					for (int i = 0; i < array.Length; i++)
					{
						array2[i] = GetInstruction(array[i], isEndOfInstruction: false);
					}
					ilInstruction.operand = array2;
					break;
				}
				}
			}
		}

		private void ParseExceptions()
		{
			foreach (ExceptionHandlingClause exception in exceptions)
			{
				int tryOffset = exception.TryOffset;
				int handlerOffset = exception.HandlerOffset;
				int offset = exception.HandlerOffset + exception.HandlerLength - 1;
				ILInstruction instruction = GetInstruction(tryOffset, isEndOfInstruction: false);
				instruction.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginExceptionBlock));
				ILInstruction instruction2 = GetInstruction(offset, isEndOfInstruction: true);
				instruction2.blocks.Add(new ExceptionBlock(ExceptionBlockType.EndExceptionBlock));
				switch (exception.Flags)
				{
				case ExceptionHandlingClauseOptions.Filter:
				{
					ILInstruction instruction6 = GetInstruction(exception.FilterOffset, isEndOfInstruction: false);
					instruction6.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginExceptFilterBlock));
					break;
				}
				case ExceptionHandlingClauseOptions.Finally:
				{
					ILInstruction instruction5 = GetInstruction(handlerOffset, isEndOfInstruction: false);
					instruction5.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginFinallyBlock));
					break;
				}
				case ExceptionHandlingClauseOptions.Clause:
				{
					ILInstruction instruction4 = GetInstruction(handlerOffset, isEndOfInstruction: false);
					instruction4.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginCatchBlock, exception.CatchType));
					break;
				}
				case ExceptionHandlingClauseOptions.Fault:
				{
					ILInstruction instruction3 = GetInstruction(handlerOffset, isEndOfInstruction: false);
					instruction3.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginFaultBlock));
					break;
				}
				}
			}
		}

		private bool EndsInDeadCode(List<CodeInstruction> list)
		{
			int count = list.Count;
			if (count < 2 || list.Last().opcode != System.Reflection.Emit.OpCodes.Throw)
			{
				return false;
			}
			return list.GetRange(0, count - 1).All((CodeInstruction code) => code.opcode != System.Reflection.Emit.OpCodes.Ret);
		}

		internal List<CodeInstruction> FinalizeILCodes(Emitter emitter, List<MethodInfo> transpilers, List<Label> endLabels, out bool hasReturnCode, out bool methodEndsInDeadCode)
		{
			hasReturnCode = false;
			methodEndsInDeadCode = false;
			if (generator == null)
			{
				return null;
			}
			foreach (ILInstruction ilInstruction in ilInstructions)
			{
				switch (ilInstruction.opcode.OperandType)
				{
				case System.Reflection.Emit.OperandType.InlineSwitch:
					if (ilInstruction.operand is ILInstruction[] array)
					{
						List<Label> list = new List<Label>();
						ILInstruction[] array2 = array;
						foreach (ILInstruction iLInstruction2 in array2)
						{
							Label item = generator.DefineLabel();
							iLInstruction2.labels.Add(item);
							list.Add(item);
						}
						ilInstruction.argument = list.ToArray();
					}
					break;
				case System.Reflection.Emit.OperandType.InlineBrTarget:
				case System.Reflection.Emit.OperandType.ShortInlineBrTarget:
					if (ilInstruction.operand is ILInstruction iLInstruction)
					{
						Label label2 = generator.DefineLabel();
						iLInstruction.labels.Add(label2);
						ilInstruction.argument = label2;
					}
					break;
				}
			}
			CodeTranspiler codeTranspiler = new CodeTranspiler(ilInstructions);
			transpilers.Do(codeTranspiler.Add);
			List<CodeInstruction> result = codeTranspiler.GetResult(generator, method);
			if (emitter == null)
			{
				return result;
			}
			emitter.LogComment("start original");
			if (debug)
			{
				List<string> buffer = FileLog.GetBuffer(clear: true);
				emitter.LogAllLocalVariables();
				FileLog.LogBuffered(buffer);
			}
			hasReturnCode = result.Any((CodeInstruction code) => code.opcode == System.Reflection.Emit.OpCodes.Ret);
			methodEndsInDeadCode = EndsInDeadCode(result);
			while (true)
			{
				CodeInstruction codeInstruction2 = result.LastOrDefault();
				if (codeInstruction2 == null || codeInstruction2.opcode != System.Reflection.Emit.OpCodes.Ret)
				{
					break;
				}
				endLabels.AddRange(codeInstruction2.labels);
				result.RemoveAt(result.Count - 1);
			}
			result.Do(delegate(CodeInstruction codeInstruction)
			{
				codeInstruction.labels.Do(delegate(Label label)
				{
					emitter.MarkLabel(label);
				});
				codeInstruction.blocks.Do(delegate(ExceptionBlock block)
				{
					emitter.MarkBlockBefore(block, out var _);
				});
				System.Reflection.Emit.OpCode opCode = codeInstruction.opcode;
				object obj = codeInstruction.operand;
				if (opCode == System.Reflection.Emit.OpCodes.Ret)
				{
					Label label3 = generator.DefineLabel();
					opCode = System.Reflection.Emit.OpCodes.Br;
					obj = label3;
					endLabels.Add(label3);
				}
				if (shortJumps.TryGetValue(opCode, out var value))
				{
					opCode = value;
				}
				switch (opCode.OperandType)
				{
				case System.Reflection.Emit.OperandType.InlineNone:
					emitter.Emit(opCode);
					break;
				case System.Reflection.Emit.OperandType.InlineSig:
				{
					CecilILGenerator proxiedShim = generator.GetProxiedShim<CecilILGenerator>();
					if (proxiedShim == null)
					{
						throw new NotSupportedException();
					}
					if (obj == null)
					{
						throw new Exception($"Wrong null argument: {codeInstruction}");
					}
					if (!(obj is ICallSiteGenerator))
					{
						throw new Exception($"Wrong Emit argument type {obj.GetType()} in {codeInstruction}");
					}
					emitter.AddInstruction(opCode, obj);
					emitter.LogIL(opCode, obj);
					proxiedShim.Emit(opCode, (ICallSiteGenerator)obj);
					break;
				}
				default:
					if (obj == null)
					{
						throw new Exception($"Wrong null argument: {codeInstruction}");
					}
					emitter.AddInstruction(opCode, obj);
					emitter.LogIL(opCode, obj);
					generator.DynEmit(opCode, obj);
					break;
				}
				codeInstruction.blocks.Do(delegate(ExceptionBlock block)
				{
					emitter.MarkBlockAfter(block);
				});
			});
			emitter.LogComment("end original" + (methodEndsInDeadCode ? " (has dead code end)" : ""));
			return result;
		}

		private static void GetMemberInfoValue(MemberInfo info, out object result)
		{
			result = null;
			switch (info.MemberType)
			{
			case MemberTypes.Constructor:
				result = (ConstructorInfo)info;
				break;
			case MemberTypes.Event:
				result = (EventInfo)info;
				break;
			case MemberTypes.Field:
				result = (FieldInfo)info;
				break;
			case MemberTypes.Method:
				result = (MethodInfo)info;
				break;
			case MemberTypes.TypeInfo:
			case MemberTypes.NestedType:
				result = (Type)info;
				break;
			case MemberTypes.Property:
				result = (PropertyInfo)info;
				break;
			}
		}

		private void ReadOperand(ILInstruction instruction)
		{
			switch (instruction.opcode.OperandType)
			{
			case System.Reflection.Emit.OperandType.InlineNone:
				instruction.argument = null;
				break;
			case System.Reflection.Emit.OperandType.InlineSwitch:
			{
				int num6 = ilBytes.ReadInt32();
				int num7 = ilBytes.position + 4 * num6;
				int[] array3 = new int[num6];
				for (int i = 0; i < num6; i++)
				{
					array3[i] = ilBytes.ReadInt32() + num7;
				}
				instruction.operand = array3;
				break;
			}
			case System.Reflection.Emit.OperandType.ShortInlineBrTarget:
			{
				sbyte b4 = (sbyte)ilBytes.ReadByte();
				instruction.operand = b4 + ilBytes.position;
				break;
			}
			case System.Reflection.Emit.OperandType.InlineBrTarget:
			{
				int num8 = ilBytes.ReadInt32();
				instruction.operand = num8 + ilBytes.position;
				break;
			}
			case System.Reflection.Emit.OperandType.ShortInlineI:
				if (instruction.opcode == System.Reflection.Emit.OpCodes.Ldc_I4_S)
				{
					sbyte b = (sbyte)ilBytes.ReadByte();
					instruction.operand = b;
					instruction.argument = (sbyte)instruction.operand;
				}
				else
				{
					byte b2 = ilBytes.ReadByte();
					instruction.operand = b2;
					instruction.argument = (byte)instruction.operand;
				}
				break;
			case System.Reflection.Emit.OperandType.InlineI:
			{
				int num5 = ilBytes.ReadInt32();
				instruction.operand = num5;
				instruction.argument = (int)instruction.operand;
				break;
			}
			case System.Reflection.Emit.OperandType.ShortInlineR:
			{
				float num4 = ilBytes.ReadSingle();
				instruction.operand = num4;
				instruction.argument = (float)instruction.operand;
				break;
			}
			case System.Reflection.Emit.OperandType.InlineR:
			{
				double num3 = ilBytes.ReadDouble();
				instruction.operand = num3;
				instruction.argument = (double)instruction.operand;
				break;
			}
			case System.Reflection.Emit.OperandType.InlineI8:
			{
				long num2 = ilBytes.ReadInt64();
				instruction.operand = num2;
				instruction.argument = (long)instruction.operand;
				break;
			}
			case System.Reflection.Emit.OperandType.InlineSig:
			{
				int metadataToken3 = ilBytes.ReadInt32();
				byte[] data = module.ResolveSignature(metadataToken3);
				instruction.argument = (instruction.operand = InlineSignatureParser.ImportCallSite(module, data));
				break;
			}
			case System.Reflection.Emit.OperandType.InlineString:
			{
				int metadataToken6 = ilBytes.ReadInt32();
				instruction.operand = module.ResolveString(metadataToken6);
				instruction.argument = (string)instruction.operand;
				break;
			}
			case System.Reflection.Emit.OperandType.InlineTok:
			{
				int metadataToken5 = ilBytes.ReadInt32();
				instruction.operand = module.ResolveMember(metadataToken5, typeArguments, methodArguments);
				((MemberInfo)instruction.operand).DeclaringType?.FixReflectionCacheAuto();
				GetMemberInfoValue((MemberInfo)instruction.operand, out instruction.argument);
				break;
			}
			case System.Reflection.Emit.OperandType.InlineType:
			{
				int metadataToken4 = ilBytes.ReadInt32();
				instruction.operand = module.ResolveType(metadataToken4, typeArguments, methodArguments);
				((Type)instruction.operand).FixReflectionCacheAuto();
				instruction.argument = (Type)instruction.operand;
				break;
			}
			case System.Reflection.Emit.OperandType.InlineMethod:
			{
				int metadataToken2 = ilBytes.ReadInt32();
				instruction.operand = module.ResolveMethod(metadataToken2, typeArguments, methodArguments);
				((MemberInfo)instruction.operand).DeclaringType?.FixReflectionCacheAuto();
				if (instruction.operand is ConstructorInfo)
				{
					instruction.argument = (ConstructorInfo)instruction.operand;
				}
				else
				{
					instruction.argument = (MethodInfo)instruction.operand;
				}
				break;
			}
			case System.Reflection.Emit.OperandType.InlineField:
			{
				int metadataToken = ilBytes.ReadInt32();
				instruction.operand = module.ResolveField(metadataToken, typeArguments, methodArguments);
				((MemberInfo)instruction.operand).DeclaringType?.FixReflectionCacheAuto();
				instruction.argument = (FieldInfo)instruction.operand;
				break;
			}
			case System.Reflection.Emit.OperandType.ShortInlineVar:
			{
				byte b3 = ilBytes.ReadByte();
				if (TargetsLocalVariable(instruction.opcode))
				{
					LocalVariableInfo localVariable2 = GetLocalVariable(b3);
					if (localVariable2 == null)
					{
						instruction.argument = b3;
						break;
					}
					instruction.operand = localVariable2;
					LocalBuilder[] array2 = variables;
					instruction.argument = ((array2 != null) ? array2[localVariable2.LocalIndex] : null) ?? localVariable2;
				}
				else
				{
					instruction.operand = GetParameter(b3);
					instruction.argument = b3;
				}
				break;
			}
			case System.Reflection.Emit.OperandType.InlineVar:
			{
				short num = ilBytes.ReadInt16();
				if (TargetsLocalVariable(instruction.opcode))
				{
					LocalVariableInfo localVariable = GetLocalVariable(num);
					if (localVariable == null)
					{
						instruction.argument = num;
						break;
					}
					instruction.operand = localVariable;
					LocalBuilder[] array = variables;
					instruction.argument = ((array != null) ? array[localVariable.LocalIndex] : null) ?? localVariable;
				}
				else
				{
					instruction.operand = GetParameter(num);
					instruction.argument = num;
				}
				break;
			}
			default:
				throw new NotSupportedException();
			}
		}

		private ILInstruction GetInstruction(int offset, bool isEndOfInstruction)
		{
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset", offset, $"Instruction offset {offset} is less than 0");
			}
			int num = ilInstructions.Count - 1;
			ILInstruction iLInstruction = ilInstructions[num];
			if (offset > iLInstruction.offset + iLInstruction.GetSize() - 1)
			{
				throw new ArgumentOutOfRangeException("offset", offset, $"Instruction offset {offset} is outside valid range 0 - {iLInstruction.offset + iLInstruction.GetSize() - 1}");
			}
			int num2 = 0;
			int num3 = num;
			while (num2 <= num3)
			{
				int num4 = num2 + (num3 - num2) / 2;
				iLInstruction = ilInstructions[num4];
				if (isEndOfInstruction)
				{
					if (offset == iLInstruction.offset + iLInstruction.GetSize() - 1)
					{
						return iLInstruction;
					}
				}
				else if (offset == iLInstruction.offset)
				{
					return iLInstruction;
				}
				if (offset < iLInstruction.offset)
				{
					num3 = num4 - 1;
				}
				else
				{
					num2 = num4 + 1;
				}
			}
			throw new Exception($"Cannot find instruction for {offset:X4}");
		}

		private static bool TargetsLocalVariable(System.Reflection.Emit.OpCode opcode)
		{
			return opcode.Name.Contains("loc");
		}

		private LocalVariableInfo GetLocalVariable(int index)
		{
			return localVariables?[index];
		}

		private ParameterInfo GetParameter(int index)
		{
			if (index == 0)
			{
				return this_parameter;
			}
			return parameters[index - 1];
		}

		private System.Reflection.Emit.OpCode ReadOpCode()
		{
			byte b = ilBytes.ReadByte();
			if (b == 254)
			{
				return two_bytes_opcodes[ilBytes.ReadByte()];
			}
			return one_byte_opcodes[b];
		}

		[MethodImpl(MethodImplOptions.Synchronized)]
		static MethodBodyReader()
		{
			shortJumps = new Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode>
			{
				{
					System.Reflection.Emit.OpCodes.Leave_S,
					System.Reflection.Emit.OpCodes.Leave
				},
				{
					System.Reflection.Emit.OpCodes.Brfalse_S,
					System.Reflection.Emit.OpCodes.Brfalse
				},
				{
					System.Reflection.Emit.OpCodes.Brtrue_S,
					System.Reflection.Emit.OpCodes.Brtrue
				},
				{
					System.Reflection.Emit.OpCodes.Beq_S,
					System.Reflection.Emit.OpCodes.Beq
				},
				{
					System.Reflection.Emit.OpCodes.Bge_S,
					System.Reflection.Emit.OpCodes.Bge
				},
				{
					System.Reflection.Emit.OpCodes.Bgt_S,
					System.Reflection.Emit.OpCodes.Bgt
				},
				{
					System.Reflection.Emit.OpCodes.Ble_S,
					System.Reflection.Emit.OpCodes.Ble
				},
				{
					System.Reflection.Emit.OpCodes.Blt_S,
					System.Reflection.Emit.OpCodes.Blt
				},
				{
					System.Reflection.Emit.OpCodes.Bne_Un_S,
					System.Reflection.Emit.OpCodes.Bne_Un
				},
				{
					System.Reflection.Emit.OpCodes.Bge_Un_S,
					System.Reflection.Emit.OpCodes.Bge_Un
				},
				{
					System.Reflection.Emit.OpCodes.Bgt_Un_S,
					System.Reflection.Emit.OpCodes.Bgt_Un
				},
				{
					System.Reflection.Emit.OpCodes.Ble_Un_S,
					System.Reflection.Emit.OpCodes.Ble_Un
				},
				{
					System.Reflection.Emit.OpCodes.Br_S,
					System.Reflection.Emit.OpCodes.Br
				},
				{
					System.Reflection.Emit.OpCodes.Blt_Un_S,
					System.Reflection.Emit.OpCodes.Blt_Un
				}
			};
			one_byte_opcodes = new System.Reflection.Emit.OpCode[225];
			two_bytes_opcodes = new System.Reflection.Emit.OpCode[31];
			FieldInfo[] fields = typeof(System.Reflection.Emit.OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				System.Reflection.Emit.OpCode opCode = (System.Reflection.Emit.OpCode)fieldInfo.GetValue(null);
				if (opCode.OpCodeType != System.Reflection.Emit.OpCodeType.Nternal)
				{
					if (opCode.Size == 1)
					{
						one_byte_opcodes[opCode.Value] = opCode;
					}
					else
					{
						two_bytes_opcodes[opCode.Value & 0xFF] = opCode;
					}
				}
			}
		}
	}
	internal class MethodPatcher
	{
		private const string INSTANCE_PARAM = "__instance";

		private const string ORIGINAL_METHOD_PARAM = "__originalMethod";

		private const string ARGS_ARRAY_VAR = "__args";

		private const string RESULT_VAR = "__result";

		private const string RESULT_REF_VAR = "__resultRef";

		private const string STATE_VAR = "__state";

		private const string EXCEPTION_VAR = "__exception";

		private const string RUN_ORIGINAL_VAR = "__runOriginal";

		private const string PARAM_INDEX_PREFIX = "__";

		private const string INSTANCE_FIELD_PREFIX = "___";

		private readonly bool debug;

		private readonly MethodBase original;

		private readonly MethodBase source;

		private readonly List<MethodInfo> prefixes;

		private readonly List<MethodInfo> postfixes;

		private readonly List<MethodInfo> transpilers;

		private readonly List<MethodInfo> finalizers;

		private readonly int idx;

		private readonly Type returnType;

		private readonly DynamicMethodDefinition patch;

		private readonly ILGenerator il;

		private readonly Emitter emitter;

		private static readonly HashSet<Type> PrimitivesWithObjectTypeCode = new HashSet<Type>
		{
			typeof(IntPtr),
			typeof(UIntPtr),
			typeof(IntPtr),
			typeof(UIntPtr)
		};

		private static readonly MethodInfo m_GetMethodFromHandle1 = typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[1] { typeof(RuntimeMethodHandle) });

		private static readonly MethodInfo m_GetMethodFromHandle2 = typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[2]
		{
			typeof(RuntimeMethodHandle),
			typeof(RuntimeTypeHandle)
		});

		internal MethodPatcher(MethodBase original, MethodBase source, List<MethodInfo> prefixes, List<MethodInfo> postfixes, List<MethodInfo> transpilers, List<MethodInfo> finalizers, bool debug)
		{
			if ((object)original == null)
			{
				throw new ArgumentNullException("original");
			}
			this.debug = debug;
			this.original = original;
			this.source = source;
			this.prefixes = prefixes;
			this.postfixes = postfixes;
			this.transpilers = transpilers;
			this.finalizers = finalizers;
			if (debug)
			{
				FileLog.LogBuffered("### Patch: " + original.FullDescription());
				FileLog.FlushBuffer();
			}
			idx = prefixes.Count + postfixes.Count + finalizers.Count;
			returnType = AccessTools.GetReturnedType(original);
			patch = CreateDynamicMethod(original, $"_Patch{idx}", debug);
			if (patch == null)
			{
				throw new Exception("Could not create replacement method");
			}
			il = patch.GetILGenerator();
			emitter = new Emitter(il, debug);
		}

		internal static IEnumerable<(ParameterInfo info, string realName)> OriginalParameters(MethodInfo method)
		{
			IEnumerable<HarmonyArgument> baseArgs = method.GetArgumentAttributes();
			if ((object)method.DeclaringType != null)
			{
				baseArgs = baseArgs.Union(method.DeclaringType.GetArgumentAttributes());
			}
			return method.GetParameters().Select(delegate(ParameterInfo p)
			{
				HarmonyArgument argumentAttribute = p.GetArgumentAttribute();
				return (argumentAttribute != null) ? (p, argumentAttribute.OriginalName ?? p.Name) : (p, baseArgs.GetRealName(p.Name, null) ?? p.Name);
			});
		}

		internal static Dictionary<string, string> RealNames(MethodInfo method)
		{
			return OriginalParameters(method).ToDictionary(((ParameterInfo info, string realName) pair) => pair.info.Name, ((ParameterInfo info, string realName) pair) => pair.realName);
		}

		internal MethodInfo CreateReplacement(out Dictionary<int, CodeInstruction> finalInstructions)
		{
			LocalBuilder[] existingVariables = DeclareOriginalLocalVariables(il, source ?? original);
			Dictionary<string, LocalBuilder> privateVars = new Dictionary<string, LocalBuilder>();
			List<MethodInfo> list = prefixes.Union(postfixes).Union(finalizers).ToList();
			Dictionary<MethodInfo, HashSet<(ParameterInfo info, string realName)>> parameterNames = list.ToDictionary((MethodInfo fix) => fix, (MethodInfo fix) => new HashSet<(ParameterInfo, string)>(OriginalParameters(fix)));
			LocalBuilder localBuilder = null;
			if (idx > 0)
			{
				localBuilder = DeclareLocalVariable(returnType, isReturnValue: true);
				privateVars["__result"] = localBuilder;
			}
			if (list.Any((MethodInfo fix) => parameterNames[fix].Any(((ParameterInfo info, string realName) pair) => pair.realName == "__resultRef")) && returnType.IsByRef)
			{
				LocalBuilder localBuilder2 = il.DeclareLocal(typeof(RefResult<>).MakeGenericType(returnType.GetElementType()));
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldnull);
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder2);
				privateVars["__resultRef"] = localBuilder2;
			}
			LocalBuilder localBuilder3 = null;
			if (list.Any((MethodInfo fix) => parameterNames[fix].Any(((ParameterInfo info, string realName) pair) => pair.realName == "__args")))
			{
				PrepareArgumentArray();
				localBuilder3 = il.DeclareLocal(typeof(object[]));
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder3);
				privateVars["__args"] = localBuilder3;
			}
			Label? label = null;
			LocalBuilder localBuilder4 = null;
			bool flag = prefixes.Any(PrefixAffectsOriginal);
			bool flag2 = list.Any((MethodInfo fix) => parameterNames[fix].Any(((ParameterInfo info, string realName) pair) => pair.realName == "__runOriginal"));
			if (flag || flag2)
			{
				localBuilder4 = DeclareLocalVariable(typeof(bool));
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder4);
				if (flag)
				{
					label = il.DefineLabel();
				}
			}
			list.ForEach(delegate(MethodInfo fix)
			{
				if ((object)fix.DeclaringType != null && !privateVars.ContainsKey(fix.DeclaringType.AssemblyQualifiedName))
				{
					(from pair in parameterNames[fix]
						where pair.realName == "__state"
						select pair.info).Do(delegate(ParameterInfo patchParam)
					{
						LocalBuilder value = DeclareLocalVariable(patchParam.ParameterType);
						privateVars[fix.DeclaringType.AssemblyQualifiedName] = value;
					});
				}
			});
			LocalBuilder local = null;
			if (finalizers.Count > 0)
			{
				local = DeclareLocalVariable(typeof(bool));
				privateVars["__exception"] = DeclareLocalVariable(typeof(Exception));
				emitter.MarkBlockBefore(new ExceptionBlock(ExceptionBlockType.BeginExceptionBlock), out var _);
			}
			AddPrefixes(privateVars, localBuilder4);
			if (label.HasValue)
			{
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder4);
				emitter.Emit(System.Reflection.Emit.OpCodes.Brfalse, label.Value);
			}
			MethodCopier methodCopier = new MethodCopier(source ?? original, il, existingVariables);
			methodCopier.SetDebugging(debug);
			foreach (MethodInfo transpiler in transpilers)
			{
				methodCopier.AddTranspiler(transpiler);
			}
			methodCopier.AddTranspiler(PatchTools.m_GetExecutingAssemblyReplacementTranspiler);
			List<Label> list2 = new List<Label>();
			methodCopier.Finalize(emitter, list2, out var hasReturnCode, out var methodEndsInDeadCode);
			foreach (Label item in list2)
			{
				emitter.MarkLabel(item);
			}
			if (localBuilder != null && hasReturnCode)
			{
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder);
			}
			if (label.HasValue)
			{
				emitter.MarkLabel(label.Value);
			}
			AddPostfixes(privateVars, localBuilder4, passthroughPatches: false);
			if (localBuilder != null && (hasReturnCode || (methodEndsInDeadCode && label.HasValue)))
			{
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder);
			}
			bool flag3 = AddPostfixes(privateVars, localBuilder4, passthroughPatches: true);
			bool flag4 = finalizers.Count > 0;
			if (flag4)
			{
				if (flag3)
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder);
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder);
				}
				AddFinalizers(privateVars, localBuilder4, catchExceptions: false);
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, local);
				Label label3 = il.DefineLabel();
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]);
				emitter.Emit(System.Reflection.Emit.OpCodes.Brfalse, label3);
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]);
				emitter.Emit(System.Reflection.Emit.OpCodes.Throw);
				emitter.MarkLabel(label3);
				emitter.MarkBlockBefore(new ExceptionBlock(ExceptionBlockType.BeginCatchBlock), out var _);
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, privateVars["__exception"]);
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, local);
				Label label5 = il.DefineLabel();
				emitter.Emit(System.Reflection.Emit.OpCodes.Brtrue, label5);
				bool flag5 = AddFinalizers(privateVars, localBuilder4, catchExceptions: true);
				emitter.MarkLabel(label5);
				Label label6 = il.DefineLabel();
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]);
				emitter.Emit(System.Reflection.Emit.OpCodes.Brfalse, label6);
				if (flag5)
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Rethrow);
				}
				else
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]);
					emitter.Emit(System.Reflection.Emit.OpCodes.Throw);
				}
				emitter.MarkLabel(label6);
				emitter.MarkBlockAfter(new ExceptionBlock(ExceptionBlockType.EndExceptionBlock));
				if (localBuilder != null)
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder);
				}
			}
			if (!methodEndsInDeadCode || label.HasValue || flag4 || postfixes.Count > 0)
			{
				emitter.Emit(System.Reflection.Emit.OpCodes.Ret);
			}
			finalInstructions = emitter.GetInstructions();
			if (debug)
			{
				FileLog.LogBuffered("DONE");
				FileLog.LogBuffered("");
				FileLog.FlushBuffer();
			}
			return patch.Generate();
		}

		internal static DynamicMethodDefinition CreateDynamicMethod(MethodBase original, string suffix, bool debug)
		{
			if ((object)original == null)
			{
				throw new ArgumentNullException("original");
			}
			string text = (original.DeclaringType?.FullName ?? "GLOBALTYPE") + "." + original.Name + suffix;
			text = text.Replace("<>", "");
			ParameterInfo[] parameters = original.GetParameters();
			List<Type> list = new List<Type>();
			list.AddRange(parameters.Types());
			if (!original.IsStatic)
			{
				if (AccessTools.IsStruct(original.DeclaringType))
				{
					list.Insert(0, original.DeclaringType.MakeByRefType());
				}
				else
				{
					list.Insert(0, original.DeclaringType);
				}
			}
			Type returnedType = AccessTools.GetReturnedType(original);
			DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition(text, returnedType, list.ToArray());
			int num = ((!original.IsStatic) ? 1 : 0);
			if (!original.IsStatic)
			{
				dynamicMethodDefinition.Definition.Parameters[0].Name = "this";
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				ParameterDefinition parameterDefinition = dynamicMethodDefinition.Definition.Parameters[i + num];
				parameterDefinition.Attributes = (Mono.Cecil.ParameterAttributes)parameters[i].Attributes;
				parameterDefinition.Name = parameters[i].Name;
			}
			if (debug)
			{
				List<string> list2 = list.Select((Type p) => p.FullDescription()).ToList();
				if (list.Count == dynamicMethodDefinition.Definition.Parameters.Count)
				{
					for (int j = 0; j < list.Count; j++)
					{
						List<string> list3 = list2;
						int index = j;
						list3[index] = list3[index] + " " + dynamicMethodDefinition.Definition.Parameters[j].Name;
					}
				}
				FileLog.Log($"### Replacement: static {returnedType.FullDescription()} {original.DeclaringType?.FullName ?? "GLOBALTYPE"}::{text}({list2.Join()})");
			}
			return dynamicMethodDefinition;
		}

		internal static LocalBuilder[] DeclareOriginalLocalVariables(ILGenerator il, MethodBase member)
		{
			IList<LocalVariableInfo> list = member.GetMethodBody()?.LocalVariables;
			if (list == null)
			{
				return new LocalBuilder[0];
			}
			return list.Select((LocalVariableInfo lvi) => il.DeclareLocal(lvi.LocalType, lvi.IsPinned)).ToArray();
		}

		private LocalBuilder DeclareLocalVariable(Type type, bool isReturnValue = false)
		{
			if (type.IsByRef)
			{
				if (isReturnValue)
				{
					LocalBuilder localBuilder = il.DeclareLocal(type);
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
					emitter.Emit(System.Reflection.Emit.OpCodes.Newarr, type.GetElementType());
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldelema, type.GetElementType());
					emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder);
					return localBuilder;
				}
				type = type.GetElementType();
			}
			if (type.IsEnum)
			{
				type = Enum.GetUnderlyingType(type);
			}
			if (AccessTools.IsClass(type))
			{
				LocalBuilder localBuilder2 = il.DeclareLocal(type);
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldnull);
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder2);
				return localBuilder2;
			}
			if (AccessTools.IsStruct(type))
			{
				LocalBuilder localBuilder3 = il.DeclareLocal(type);
				emitter.Emit(System.Reflection.Emit.OpCodes.Ldloca, localBuilder3);
				emitter.Emit(System.Reflection.Emit.OpCodes.Initobj, type);
				return localBuilder3;
			}
			if (AccessTools.IsValue(type))
			{
				LocalBuilder localBuilder4 = il.DeclareLocal(type);
				if ((object)type == typeof(float))
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_R4, 0f);
				}
				else if ((object)type == typeof(double))
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 0.0);
				}
				else if ((object)type == typeof(long) || (object)type == typeof(ulong))
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I8, 0L);
				}
				else
				{
					emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, 0);
				}
				emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder4);
				return localBuilder4;
			}
			return null;
		}

		private static System.Reflection.Emit.OpCode LoadIndOpCodeFor(Type type)
		{
			if (PrimitivesWithObjectTypeCode.Contains(type))
			{
				return System.Reflection.Emit.OpCodes.Ldind_I;
			}
			switch (Type.GetTypeCode(type))
			{
			case TypeCode.Boolean:
			case TypeCode.SByte:
			case TypeCode.Byte:
				return System.Reflection.Emit.OpCodes.Ldind_I1;
			case TypeCode.Char:
			case TypeCode.Int16:
			case TypeCode.UInt16:
				return System.Reflection.Emit.OpCodes.Ldind_I2;
			case TypeCode.Int32:
			case TypeCode.UInt32:
				return System.Reflection.Emit.OpCodes.Ldind_I4;
			case TypeCode.Int64:
			case TypeCode.UInt64:
				return System.Reflection.Emit.OpCodes.Ldind_I8;
			case TypeCode.Single:
				return System.Reflection.Emit.OpCodes.Ldind_R4;
			case TypeCode.Double:
				return System.Reflection.Emit.OpCodes.Ldind_R8;
			case TypeCode.Decimal:
			case TypeCode.DateTime:
				throw new NotSupportedException();
			case TypeCode.Empty:
			case TypeCode.Object:
			case TypeCode.DBNull:
			case TypeCode.String:
				return System.Reflection.Emit.OpCodes.Ldind_Ref;
			default:
				return System.Reflection.Emit.OpCodes.Ldind_Ref;
			}
		}

		private static System.Reflection.Emit.OpCode StoreIndOpCodeFor(Type type)
		{
			if (PrimitivesWithObjectTypeCode.Contains(type))
			{
				return System.Reflection.Emit.OpCodes.Stind_I;
			}
			switch (Type.GetTypeCode(type))
			{
			case TypeCode.Boolean:
			case TypeCode.SByte:
			case TypeCode.Byte:
				return System.Reflection.Emit.OpCodes.Stind_I1;
			case TypeCode.Char:
			case TypeCode.Int16:
			case TypeCode.UInt16:
				return System.Reflection.Emit.OpCodes.Stind_I2;
			case TypeCode.Int32:
			case TypeCode.UInt32:
				return System.Reflection.Emit.OpCodes.Stind_I4;
			case TypeCode.Int64:
			case TypeCode.UInt64:
				return System.Reflection.Emit.OpCodes.Stind_I8;
			case TypeCode.Single:
				return System.Reflection.Emit.OpCodes.Stind_R4;
			case TypeCode.Double:
				return System.Reflection.Emit.OpCodes.Stind_R8;
			case TypeCode.Decimal:
			case TypeCode.DateTime:
				throw new NotSupportedException();
			case TypeCode.Empty:
			case TypeCode.Object:
			case TypeCode.DBNull:
			case

UMM/Core/dnlib.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
using Microsoft.CodeAnalysis;
using Microsoft.Win32.SafeHandles;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
using dnlib.DotNet.Pdb.Dss;
using dnlib.DotNet.Pdb.Managed;
using dnlib.DotNet.Pdb.Portable;
using dnlib.DotNet.Pdb.Symbols;
using dnlib.DotNet.Pdb.WindowsPdb;
using dnlib.DotNet.Writer;
using dnlib.IO;
using dnlib.PE;
using dnlib.Threading;
using dnlib.Utils;
using dnlib.W32Resources;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("0xd4d")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2012-2018 [email protected]")]
[assembly: AssemblyDescription("Reads and writes .NET assemblies and modules")]
[assembly: AssemblyFileVersion("3.1.0.0")]
[assembly: AssemblyInformationalVersion("3.1.0+83b4eaa999fab374f28697c8900d51a60a366658")]
[assembly: AssemblyProduct("dnlib")]
[assembly: AssemblyTitle("dnlib (thread safe)")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(System.Security.Permissions.SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.1.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace dnlib
{
	public static class Settings
	{
		public static bool IsThreadSafe => true;
	}
}
namespace dnlib.W32Resources
{
	public sealed class ResourceData : ResourceDirectoryEntry
	{
		private readonly DataReaderFactory dataReaderFactory;

		private readonly uint resourceStartOffset;

		private readonly uint resourceLength;

		private uint codePage;

		private uint reserved;

		public uint CodePage
		{
			get
			{
				return codePage;
			}
			set
			{
				codePage = value;
			}
		}

		public uint Reserved
		{
			get
			{
				return reserved;
			}
			set
			{
				reserved = value;
			}
		}

		public DataReader CreateReader()
		{
			return dataReaderFactory.CreateReader(resourceStartOffset, resourceLength);
		}

		public ResourceData(ResourceName name)
			: this(name, ByteArrayDataReaderFactory.Create(Array2.Empty<byte>(), null), 0u, 0u)
		{
		}

		public ResourceData(ResourceName name, DataReaderFactory dataReaderFactory, uint offset, uint length)
			: this(name, dataReaderFactory, offset, length, 0u, 0u)
		{
		}

		public ResourceData(ResourceName name, DataReaderFactory dataReaderFactory, uint offset, uint length, uint codePage, uint reserved)
			: base(name)
		{
			this.dataReaderFactory = dataReaderFactory ?? throw new ArgumentNullException("dataReaderFactory");
			resourceStartOffset = offset;
			resourceLength = length;
			this.codePage = codePage;
			this.reserved = reserved;
		}
	}
	public abstract class ResourceDirectory : ResourceDirectoryEntry
	{
		protected uint characteristics;

		protected uint timeDateStamp;

		protected ushort majorVersion;

		protected ushort minorVersion;

		private protected LazyList<ResourceDirectory> directories;

		private protected LazyList<ResourceData> data;

		public uint Characteristics
		{
			get
			{
				return characteristics;
			}
			set
			{
				characteristics = value;
			}
		}

		public uint TimeDateStamp
		{
			get
			{
				return timeDateStamp;
			}
			set
			{
				timeDateStamp = value;
			}
		}

		public ushort MajorVersion
		{
			get
			{
				return majorVersion;
			}
			set
			{
				majorVersion = value;
			}
		}

		public ushort MinorVersion
		{
			get
			{
				return minorVersion;
			}
			set
			{
				minorVersion = value;
			}
		}

		public IList<ResourceDirectory> Directories => directories;

		public IList<ResourceData> Data => data;

		protected ResourceDirectory(ResourceName name)
			: base(name)
		{
		}

		public ResourceDirectory FindDirectory(ResourceName name)
		{
			foreach (ResourceDirectory directory in directories)
			{
				if (directory.Name == name)
				{
					return directory;
				}
			}
			return null;
		}

		public ResourceData FindData(ResourceName name)
		{
			foreach (ResourceData datum in data)
			{
				if (datum.Name == name)
				{
					return datum;
				}
			}
			return null;
		}
	}
	public class ResourceDirectoryUser : ResourceDirectory
	{
		public ResourceDirectoryUser(ResourceName name)
			: base(name)
		{
			directories = new LazyList<ResourceDirectory>();
			data = new LazyList<ResourceData>();
		}
	}
	public sealed class ResourceDirectoryPE : ResourceDirectory
	{
		private readonly struct EntryInfo
		{
			public readonly ResourceName name;

			public readonly uint offset;

			public EntryInfo(ResourceName name, uint offset)
			{
				this.name = name;
				this.offset = offset;
			}

			public override string ToString()
			{
				return $"{offset:X8} {name}";
			}
		}

		private const uint MAX_DIR_DEPTH = 10u;

		private readonly Win32ResourcesPE resources;

		private uint depth;

		private List<EntryInfo> dataInfos;

		private List<EntryInfo> dirInfos;

		public ResourceDirectoryPE(uint depth, ResourceName name, Win32ResourcesPE resources, ref DataReader reader)
			: base(name)
		{
			this.resources = resources;
			this.depth = depth;
			Initialize(ref reader);
		}

		private void Initialize(ref DataReader reader)
		{
			if (depth > 10 || !reader.CanRead(16u))
			{
				InitializeDefault();
				return;
			}
			characteristics = reader.ReadUInt32();
			timeDateStamp = reader.ReadUInt32();
			majorVersion = reader.ReadUInt16();
			minorVersion = reader.ReadUInt16();
			ushort num = reader.ReadUInt16();
			ushort num2 = reader.ReadUInt16();
			int num3 = num + num2;
			if (!reader.CanRead((uint)(num3 * 8)))
			{
				InitializeDefault();
				return;
			}
			dataInfos = new List<EntryInfo>();
			dirInfos = new List<EntryInfo>();
			uint num4 = reader.Position;
			int num5 = 0;
			while (num5 < num3)
			{
				reader.Position = num4;
				uint num6 = reader.ReadUInt32();
				uint num7 = reader.ReadUInt32();
				ResourceName resourceName = (((num6 & 0x80000000u) == 0) ? new ResourceName((int)num6) : new ResourceName(ReadString(ref reader, num6 & 0x7FFFFFFFu) ?? string.Empty));
				if ((num7 & 0x80000000u) == 0)
				{
					dataInfos.Add(new EntryInfo(resourceName, num7));
				}
				else
				{
					dirInfos.Add(new EntryInfo(resourceName, num7 & 0x7FFFFFFFu));
				}
				num5++;
				num4 += 8;
			}
			directories = new LazyList<ResourceDirectory, object>(dirInfos.Count, null, (object ctx, int i) => ReadResourceDirectory(i));
			data = new LazyList<ResourceData, object>(dataInfos.Count, null, (object ctx, int i) => ReadResourceData(i));
		}

		private static string ReadString(ref DataReader reader, uint offset)
		{
			reader.Position = offset;
			if (!reader.CanRead(2u))
			{
				return null;
			}
			int num = reader.ReadUInt16() * 2;
			if (!reader.CanRead((uint)num))
			{
				return null;
			}
			try
			{
				return reader.ReadUtf16String(num / 2);
			}
			catch
			{
				return null;
			}
		}

		private ResourceDirectory ReadResourceDirectory(int i)
		{
			EntryInfo entryInfo = dirInfos[i];
			DataReader reader = resources.GetResourceReader();
			reader.Position = Math.Min(reader.Length, entryInfo.offset);
			return new ResourceDirectoryPE(depth + 1, entryInfo.name, resources, ref reader);
		}

		private ResourceData ReadResourceData(int i)
		{
			EntryInfo entryInfo = dataInfos[i];
			DataReader resourceReader = resources.GetResourceReader();
			resourceReader.Position = Math.Min(resourceReader.Length, entryInfo.offset);
			if (resourceReader.CanRead(16u))
			{
				RVA rva = (RVA)resourceReader.ReadUInt32();
				uint size = resourceReader.ReadUInt32();
				uint codePage = resourceReader.ReadUInt32();
				uint reserved = resourceReader.ReadUInt32();
				resources.GetDataReaderInfo(rva, size, out var dataReaderFactory, out var dataOffset, out var dataLength);
				return new ResourceData(entryInfo.name, dataReaderFactory, dataOffset, dataLength, codePage, reserved);
			}
			return new ResourceData(entryInfo.name);
		}

		private void InitializeDefault()
		{
			directories = new LazyList<ResourceDirectory>();
			data = new LazyList<ResourceData>();
		}
	}
	public abstract class ResourceDirectoryEntry
	{
		private ResourceName name;

		public ResourceName Name
		{
			get
			{
				return name;
			}
			set
			{
				name = value;
			}
		}

		protected ResourceDirectoryEntry(ResourceName name)
		{
			this.name = name;
		}

		public override string ToString()
		{
			return name.ToString();
		}
	}
	public readonly struct ResourceName : IComparable<ResourceName>, IEquatable<ResourceName>
	{
		private readonly int id;

		private readonly string name;

		public bool HasId => name == null;

		public bool HasName => name != null;

		public int Id => id;

		public string Name => name;

		public ResourceName(int id)
		{
			this.id = id;
			name = null;
		}

		public ResourceName(string name)
		{
			id = 0;
			this.name = name;
		}

		public static implicit operator ResourceName(int id)
		{
			return new ResourceName(id);
		}

		public static implicit operator ResourceName(string name)
		{
			return new ResourceName(name);
		}

		public static bool operator <(ResourceName left, ResourceName right)
		{
			return left.CompareTo(right) < 0;
		}

		public static bool operator <=(ResourceName left, ResourceName right)
		{
			return left.CompareTo(right) <= 0;
		}

		public static bool operator >(ResourceName left, ResourceName right)
		{
			return left.CompareTo(right) > 0;
		}

		public static bool operator >=(ResourceName left, ResourceName right)
		{
			return left.CompareTo(right) >= 0;
		}

		public static bool operator ==(ResourceName left, ResourceName right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(ResourceName left, ResourceName right)
		{
			return !left.Equals(right);
		}

		public int CompareTo(ResourceName other)
		{
			if (HasId != other.HasId)
			{
				if (!HasName)
				{
					return 1;
				}
				return -1;
			}
			if (HasId)
			{
				int num = id;
				return num.CompareTo(other.id);
			}
			return name.ToUpperInvariant().CompareTo(other.name.ToUpperInvariant());
		}

		public bool Equals(ResourceName other)
		{
			return CompareTo(other) == 0;
		}

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

		public override int GetHashCode()
		{
			if (HasId)
			{
				return id;
			}
			return name.GetHashCode();
		}

		public override string ToString()
		{
			if (!HasId)
			{
				return name;
			}
			int num = id;
			return num.ToString();
		}
	}
	public abstract class Win32Resources : IDisposable
	{
		public abstract ResourceDirectory Root { get; set; }

		public ResourceDirectory Find(ResourceName type)
		{
			return Root?.FindDirectory(type);
		}

		public ResourceDirectory Find(ResourceName type, ResourceName name)
		{
			return Find(type)?.FindDirectory(name);
		}

		public ResourceData Find(ResourceName type, ResourceName name, ResourceName langId)
		{
			return Find(type, name)?.FindData(langId);
		}

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

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				Root = null;
			}
		}
	}
	public class Win32ResourcesUser : Win32Resources
	{
		private ResourceDirectory root = new ResourceDirectoryUser(new ResourceName("root"));

		public override ResourceDirectory Root
		{
			get
			{
				return root;
			}
			set
			{
				Interlocked.Exchange(ref root, value);
			}
		}
	}
	public sealed class Win32ResourcesPE : Win32Resources
	{
		private readonly IRvaFileOffsetConverter rvaConverter;

		private DataReaderFactory dataReader_factory;

		private uint dataReader_offset;

		private uint dataReader_length;

		private bool owns_dataReader_factory;

		private DataReaderFactory rsrcReader_factory;

		private uint rsrcReader_offset;

		private uint rsrcReader_length;

		private bool owns_rsrcReader_factory;

		private UserValue<ResourceDirectory> root;

		private readonly Lock theLock = Lock.Create();

		public override ResourceDirectory Root
		{
			get
			{
				return root.Value;
			}
			set
			{
				if (!root.IsValueInitialized || root.Value != value)
				{
					root.Value = value;
				}
			}
		}

		internal DataReader GetResourceReader()
		{
			return rsrcReader_factory.CreateReader(rsrcReader_offset, rsrcReader_length);
		}

		public Win32ResourcesPE(IRvaFileOffsetConverter rvaConverter, DataReaderFactory rsrcReader_factory, uint rsrcReader_offset, uint rsrcReader_length, bool owns_rsrcReader_factory, DataReaderFactory dataReader_factory, uint dataReader_offset, uint dataReader_length, bool owns_dataReader_factory)
		{
			this.rvaConverter = rvaConverter ?? throw new ArgumentNullException("rvaConverter");
			this.rsrcReader_factory = rsrcReader_factory ?? throw new ArgumentNullException("rsrcReader_factory");
			this.rsrcReader_offset = rsrcReader_offset;
			this.rsrcReader_length = rsrcReader_length;
			this.owns_rsrcReader_factory = owns_rsrcReader_factory;
			this.dataReader_factory = dataReader_factory ?? throw new ArgumentNullException("dataReader_factory");
			this.dataReader_offset = dataReader_offset;
			this.dataReader_length = dataReader_length;
			this.owns_dataReader_factory = owns_dataReader_factory;
			Initialize();
		}

		public Win32ResourcesPE(IPEImage peImage)
			: this(peImage, null, 0u, 0u, owns_rsrcReader_factory: false)
		{
		}

		public Win32ResourcesPE(IPEImage peImage, DataReaderFactory rsrcReader_factory, uint rsrcReader_offset, uint rsrcReader_length, bool owns_rsrcReader_factory)
		{
			rvaConverter = peImage ?? throw new ArgumentNullException("peImage");
			dataReader_factory = peImage.DataReaderFactory;
			dataReader_offset = 0u;
			dataReader_length = dataReader_factory.Length;
			if (rsrcReader_factory != null)
			{
				this.rsrcReader_factory = rsrcReader_factory;
				this.rsrcReader_offset = rsrcReader_offset;
				this.rsrcReader_length = rsrcReader_length;
				this.owns_rsrcReader_factory = owns_rsrcReader_factory;
			}
			else
			{
				ImageDataDirectory imageDataDirectory = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[2];
				if (imageDataDirectory.VirtualAddress != 0 && imageDataDirectory.Size != 0)
				{
					DataReader dataReader = peImage.CreateReader(imageDataDirectory.VirtualAddress, imageDataDirectory.Size);
					this.rsrcReader_factory = peImage.DataReaderFactory;
					this.rsrcReader_offset = dataReader.StartOffset;
					this.rsrcReader_length = dataReader.Length;
				}
				else
				{
					this.rsrcReader_factory = ByteArrayDataReaderFactory.Create(Array2.Empty<byte>(), null);
					this.rsrcReader_offset = 0u;
					this.rsrcReader_length = 0u;
				}
			}
			Initialize();
		}

		private void Initialize()
		{
			root.ReadOriginalValue = delegate
			{
				DataReaderFactory dataReaderFactory = rsrcReader_factory;
				if (dataReaderFactory == null)
				{
					return null;
				}
				DataReader reader = dataReaderFactory.CreateReader(rsrcReader_offset, rsrcReader_length);
				return new ResourceDirectoryPE(0u, new ResourceName("root"), this, ref reader);
			};
			root.Lock = theLock;
		}

		public DataReader CreateReader(RVA rva, uint size)
		{
			GetDataReaderInfo(rva, size, out var dataReaderFactory, out var dataOffset, out var dataLength);
			return dataReaderFactory.CreateReader(dataOffset, dataLength);
		}

		internal void GetDataReaderInfo(RVA rva, uint size, out DataReaderFactory dataReaderFactory, out uint dataOffset, out uint dataLength)
		{
			dataOffset = (uint)rvaConverter.ToFileOffset(rva);
			if ((ulong)((long)dataOffset + (long)size) <= (ulong)dataReader_factory.Length)
			{
				dataReaderFactory = dataReader_factory;
				dataLength = size;
			}
			else
			{
				dataReaderFactory = ByteArrayDataReaderFactory.Create(Array2.Empty<byte>(), null);
				dataOffset = 0u;
				dataLength = 0u;
			}
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (owns_dataReader_factory)
				{
					dataReader_factory?.Dispose();
				}
				if (owns_rsrcReader_factory)
				{
					rsrcReader_factory?.Dispose();
				}
				dataReader_factory = null;
				rsrcReader_factory = null;
				base.Dispose(disposing);
			}
		}
	}
}
namespace dnlib.Utils
{
	internal class CollectionDebugView<TValue>
	{
		private readonly ICollection<TValue> list;

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public TValue[] Items
		{
			get
			{
				TValue[] array = new TValue[list.Count];
				list.CopyTo(array, 0);
				return array;
			}
		}

		public CollectionDebugView(ICollection<TValue> list)
		{
			this.list = list ?? throw new ArgumentNullException("list");
		}
	}
	internal class CollectionDebugView<TValue, TOther> : CollectionDebugView<TValue>
	{
		public CollectionDebugView(ICollection<TValue> list)
			: base(list)
		{
		}
	}
	internal sealed class LocalList_CollectionDebugView : CollectionDebugView<Local>
	{
		public LocalList_CollectionDebugView(LocalList list)
			: base((ICollection<Local>)list)
		{
		}
	}
	internal sealed class ParameterList_CollectionDebugView : CollectionDebugView<Parameter>
	{
		public ParameterList_CollectionDebugView(ParameterList list)
			: base((ICollection<Parameter>)list)
		{
		}
	}
	internal interface ILazyList<TValue> : IList<TValue>, ICollection<TValue>, IEnumerable<TValue>, IEnumerable
	{
	}
	public interface IListListener<TListValue>
	{
		void OnLazyAdd(int index, ref TListValue value);

		void OnAdd(int index, TListValue value);

		void OnRemove(int index, TListValue value);

		void OnResize(int index);

		void OnClear();
	}
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy(typeof(CollectionDebugView<>))]
	public class LazyList<TValue> : ILazyList<TValue>, IList<TValue>, ICollection<TValue>, IEnumerable<TValue>, IEnumerable where TValue : class
	{
		private protected class Element
		{
			protected TValue value;

			public virtual bool IsInitialized_NoLock => true;

			protected Element()
			{
			}

			public Element(TValue data)
			{
				value = data;
			}

			public virtual TValue GetValue_NoLock(int index)
			{
				return value;
			}

			public virtual void SetValue_NoLock(int index, TValue value)
			{
				this.value = value;
			}

			public override string ToString()
			{
				return value?.ToString() ?? string.Empty;
			}
		}

		public struct Enumerator : IEnumerator<TValue>, IDisposable, IEnumerator
		{
			private readonly LazyList<TValue> list;

			private readonly int id;

			private int index;

			private TValue current;

			public TValue Current => current;

			object IEnumerator.Current => current;

			internal Enumerator(LazyList<TValue> list)
			{
				this.list = list;
				index = 0;
				current = null;
				list.theLock.EnterReadLock();
				try
				{
					id = list.id;
				}
				finally
				{
					list.theLock.ExitReadLock();
				}
			}

			public bool MoveNext()
			{
				list.theLock.EnterWriteLock();
				try
				{
					if (list.id == id && index < list.Count_NoLock)
					{
						current = list.list[index].GetValue_NoLock(index);
						index++;
						return true;
					}
					return MoveNextDoneOrThrow_NoLock();
				}
				finally
				{
					list.theLock.ExitWriteLock();
				}
			}

			private bool MoveNextDoneOrThrow_NoLock()
			{
				if (list.id != id)
				{
					throw new InvalidOperationException("List was modified");
				}
				current = null;
				return false;
			}

			public void Dispose()
			{
			}

			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private protected readonly List<Element> list;

		private int id;

		private protected readonly IListListener<TValue> listener;

		private readonly Lock theLock = Lock.Create();

		public int Count
		{
			get
			{
				theLock.EnterReadLock();
				try
				{
					return Count_NoLock;
				}
				finally
				{
					theLock.ExitReadLock();
				}
			}
		}

		internal int Count_NoLock => list.Count;

		public bool IsReadOnly => false;

		public TValue this[int index]
		{
			get
			{
				theLock.EnterWriteLock();
				try
				{
					return Get_NoLock(index);
				}
				finally
				{
					theLock.ExitWriteLock();
				}
			}
			set
			{
				theLock.EnterWriteLock();
				try
				{
					Set_NoLock(index, value);
				}
				finally
				{
					theLock.ExitWriteLock();
				}
			}
		}

		internal TValue Get_NoLock(int index)
		{
			return list[index].GetValue_NoLock(index);
		}

		private void Set_NoLock(int index, TValue value)
		{
			if (listener != null)
			{
				listener.OnRemove(index, list[index].GetValue_NoLock(index));
				listener.OnAdd(index, value);
			}
			list[index].SetValue_NoLock(index, value);
			id++;
		}

		public LazyList()
			: this((IListListener<TValue>)null)
		{
		}

		public LazyList(IListListener<TValue> listener)
		{
			this.listener = listener;
			list = new List<Element>();
		}

		private protected LazyList(int length, IListListener<TValue> listener)
		{
			this.listener = listener;
			list = new List<Element>(length);
		}

		public int IndexOf(TValue item)
		{
			theLock.EnterWriteLock();
			try
			{
				return IndexOf_NoLock(item);
			}
			finally
			{
				theLock.ExitWriteLock();
			}
		}

		private int IndexOf_NoLock(TValue item)
		{
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].GetValue_NoLock(i) == item)
				{
					return i;
				}
			}
			return -1;
		}

		public void Insert(int index, TValue item)
		{
			theLock.EnterWriteLock();
			try
			{
				Insert_NoLock(index, item);
			}
			finally
			{
				theLock.ExitWriteLock();
			}
		}

		private void Insert_NoLock(int index, TValue item)
		{
			if (listener != null)
			{
				listener.OnAdd(index, item);
			}
			list.Insert(index, new Element(item));
			if (listener != null)
			{
				listener.OnResize(index);
			}
			id++;
		}

		public void RemoveAt(int index)
		{
			theLock.EnterWriteLock();
			try
			{
				RemoveAt_NoLock(index);
			}
			finally
			{
				theLock.ExitWriteLock();
			}
		}

		private void RemoveAt_NoLock(int index)
		{
			if (listener != null)
			{
				listener.OnRemove(index, list[index].GetValue_NoLock(index));
			}
			list.RemoveAt(index);
			if (listener != null)
			{
				listener.OnResize(index);
			}
			id++;
		}

		public void Add(TValue item)
		{
			theLock.EnterWriteLock();
			try
			{
				Add_NoLock(item);
			}
			finally
			{
				theLock.ExitWriteLock();
			}
		}

		private void Add_NoLock(TValue item)
		{
			int count = list.Count;
			if (listener != null)
			{
				listener.OnAdd(count, item);
			}
			list.Add(new Element(item));
			if (listener != null)
			{
				listener.OnResize(count);
			}
			id++;
		}

		public void Clear()
		{
			theLock.EnterWriteLock();
			try
			{
				Clear_NoLock();
			}
			finally
			{
				theLock.ExitWriteLock();
			}
		}

		private void Clear_NoLock()
		{
			if (listener != null)
			{
				listener.OnClear();
			}
			list.Clear();
			if (listener != null)
			{
				listener.OnResize(0);
			}
			id++;
		}

		public bool Contains(TValue item)
		{
			return IndexOf(item) >= 0;
		}

		public void CopyTo(TValue[] array, int arrayIndex)
		{
			theLock.EnterWriteLock();
			try
			{
				CopyTo_NoLock(array, arrayIndex);
			}
			finally
			{
				theLock.ExitWriteLock();
			}
		}

		private void CopyTo_NoLock(TValue[] array, int arrayIndex)
		{
			for (int i = 0; i < list.Count; i++)
			{
				array[arrayIndex + i] = list[i].GetValue_NoLock(i);
			}
		}

		public bool Remove(TValue item)
		{
			theLock.EnterWriteLock();
			try
			{
				return Remove_NoLock(item);
			}
			finally
			{
				theLock.ExitWriteLock();
			}
		}

		private bool Remove_NoLock(TValue item)
		{
			int num = IndexOf_NoLock(item);
			if (num < 0)
			{
				return false;
			}
			RemoveAt_NoLock(num);
			return true;
		}

		internal bool IsInitialized(int index)
		{
			theLock.EnterReadLock();
			try
			{
				return IsInitialized_NoLock(index);
			}
			finally
			{
				theLock.ExitReadLock();
			}
		}

		private bool IsInitialized_NoLock(int index)
		{
			if ((uint)index >= (uint)list.Count)
			{
				return false;
			}
			return list[index].IsInitialized_NoLock;
		}

		public Enumerator GetEnumerator()
		{
			return new Enumerator(this);
		}

		IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
		{
			return GetEnumerator();
		}

		internal IEnumerable<TValue> GetEnumerable_NoLock()
		{
			int id2 = id;
			for (int i = 0; i < list.Count; i++)
			{
				if (id != id2)
				{
					throw new InvalidOperationException("List was modified");
				}
				yield return list[i].GetValue_NoLock(i);
			}
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy(typeof(CollectionDebugView<, >))]
	public class LazyList<TValue, TContext> : LazyList<TValue>, ILazyList<TValue>, IList<TValue>, ICollection<TValue>, IEnumerable<TValue>, IEnumerable where TValue : class
	{
		private sealed class LazyElement : Element
		{
			internal readonly int origIndex;

			private LazyList<TValue, TContext> lazyList;

			public override bool IsInitialized_NoLock => lazyList == null;

			public override TValue GetValue_NoLock(int index)
			{
				if (lazyList != null)
				{
					value = lazyList.ReadOriginalValue_NoLock(index, origIndex);
					lazyList = null;
				}
				return value;
			}

			public override void SetValue_NoLock(int index, TValue value)
			{
				base.value = value;
				lazyList = null;
			}

			public LazyElement(int origIndex, LazyList<TValue, TContext> lazyList)
			{
				this.origIndex = origIndex;
				this.lazyList = lazyList;
			}

			public override string ToString()
			{
				if (lazyList != null)
				{
					value = lazyList.ReadOriginalValue_NoLock(this);
					lazyList = null;
				}
				if (value != null)
				{
					return value.ToString();
				}
				return string.Empty;
			}
		}

		private TContext context;

		private readonly Func<TContext, int, TValue> readOriginalValue;

		public LazyList()
			: this((IListListener<TValue>)null)
		{
		}

		public LazyList(IListListener<TValue> listener)
			: base(listener)
		{
		}

		public LazyList(int length, TContext context, Func<TContext, int, TValue> readOriginalValue)
			: this(length, (IListListener<TValue>)null, context, readOriginalValue)
		{
		}

		public LazyList(int length, IListListener<TValue> listener, TContext context, Func<TContext, int, TValue> readOriginalValue)
			: base(length, listener)
		{
			this.context = context;
			this.readOriginalValue = readOriginalValue;
			for (int i = 0; i < length; i++)
			{
				list.Add(new LazyElement(i, this));
			}
		}

		private TValue ReadOriginalValue_NoLock(LazyElement elem)
		{
			return ReadOriginalValue_NoLock(list.IndexOf(elem), elem.origIndex);
		}

		private TValue ReadOriginalValue_NoLock(int index, int origIndex)
		{
			TValue value = readOriginalValue(context, origIndex);
			listener?.OnLazyAdd(index, ref value);
			return value;
		}
	}
	[DebuggerDisplay("Count = {Length}")]
	internal sealed class SimpleLazyList<T> where T : class
	{
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		private readonly T[] elements;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private readonly Func<uint, T> readElementByRID;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private readonly uint length;

		public uint Length => length;

		public T this[uint index]
		{
			get
			{
				if (index >= length)
				{
					return null;
				}
				if (elements[index] == null)
				{
					Interlocked.CompareExchange(ref elements[index], readElementByRID(index + 1), null);
				}
				return elements[index];
			}
		}

		public SimpleLazyList(uint length, Func<uint, T> readElementByRID)
		{
			this.length = length;
			this.readElementByRID = readElementByRID;
			elements = new T[length];
		}
	}
	[DebuggerDisplay("Count = {Length}")]
	internal sealed class SimpleLazyList2<T> where T : class, IContainsGenericParameter
	{
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		private readonly T[] elements;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private readonly Func<uint, GenericParamContext, T> readElementByRID;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private readonly uint length;

		public uint Length => length;

		public T this[uint index, GenericParamContext gpContext]
		{
			get
			{
				if (index >= length)
				{
					return null;
				}
				if (elements[index] == null)
				{
					T val = readElementByRID(index + 1, gpContext);
					if (val.ContainsGenericParameter)
					{
						return val;
					}
					Interlocked.CompareExchange(ref elements[index], val, null);
				}
				return elements[index];
			}
		}

		public SimpleLazyList2(uint length, Func<uint, GenericParamContext, T> readElementByRID)
		{
			this.length = length;
			this.readElementByRID = readElementByRID;
			elements = new T[length];
		}
	}
	[DebuggerDisplay("{value}")]
	internal struct UserValue<TValue>
	{
		private Lock theLock;

		private Func<TValue> readOriginalValue;

		private TValue value;

		private bool isUserValue;

		private bool isValueInitialized;

		public Lock Lock
		{
			set
			{
				theLock = value;
			}
		}

		public Func<TValue> ReadOriginalValue
		{
			set
			{
				readOriginalValue = value;
			}
		}

		public TValue Value
		{
			get
			{
				theLock?.EnterWriteLock();
				try
				{
					if (!isValueInitialized)
					{
						value = readOriginalValue();
						readOriginalValue = null;
						isValueInitialized = true;
					}
					return value;
				}
				finally
				{
					theLock?.ExitWriteLock();
				}
			}
			set
			{
				theLock?.EnterWriteLock();
				try
				{
					this.value = value;
					readOriginalValue = null;
					isUserValue = true;
					isValueInitialized = true;
				}
				finally
				{
					theLock?.ExitWriteLock();
				}
			}
		}

		public bool IsValueInitialized
		{
			get
			{
				theLock?.EnterReadLock();
				try
				{
					return isValueInitialized;
				}
				finally
				{
					theLock?.ExitReadLock();
				}
			}
		}

		public bool IsUserValue
		{
			get
			{
				theLock?.EnterReadLock();
				try
				{
					return isUserValue;
				}
				finally
				{
					theLock?.ExitReadLock();
				}
			}
		}
	}
}
namespace dnlib.Threading
{
	public interface ICancellationToken
	{
		void ThrowIfCancellationRequested();
	}
	[Serializable]
	internal class LockException : Exception
	{
		public LockException()
		{
		}

		public LockException(string msg)
			: base(msg)
		{
		}

		protected LockException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	internal class Lock
	{
		private readonly object lockObj;

		private int recurseCount;

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

		private Lock()
		{
			lockObj = new object();
			recurseCount = 0;
		}

		public void EnterReadLock()
		{
			Monitor.Enter(lockObj);
			if (recurseCount != 0)
			{
				Monitor.Exit(lockObj);
				throw new LockException("Recursive locks aren't supported");
			}
			recurseCount++;
		}

		public void ExitReadLock()
		{
			if (recurseCount <= 0)
			{
				throw new LockException("Too many exit lock method calls");
			}
			recurseCount--;
			Monitor.Exit(lockObj);
		}

		public void EnterWriteLock()
		{
			Monitor.Enter(lockObj);
			if (recurseCount != 0)
			{
				Monitor.Exit(lockObj);
				throw new LockException("Recursive locks aren't supported");
			}
			recurseCount--;
		}

		public void ExitWriteLock()
		{
			if (recurseCount >= 0)
			{
				throw new LockException("Too many exit lock method calls");
			}
			recurseCount++;
			Monitor.Exit(lockObj);
		}
	}
}
namespace dnlib.PE
{
	[Flags]
	public enum Characteristics : ushort
	{
		RelocsStripped = 1,
		ExecutableImage = 2,
		LineNumsStripped = 4,
		LocalSymsStripped = 8,
		AggressiveWsTrim = 0x10,
		LargeAddressAware = 0x20,
		Reserved1 = 0x40,
		BytesReversedLo = 0x80,
		[Obsolete("Use Bit32Machine", false)]
		_32BitMachine = 0x100,
		Bit32Machine = 0x100,
		DebugStripped = 0x200,
		RemovableRunFromSwap = 0x400,
		NetRunFromSwap = 0x800,
		System = 0x1000,
		Dll = 0x2000,
		UpSystemOnly = 0x4000,
		BytesReversedHi = 0x8000
	}
	[Flags]
	public enum DllCharacteristics : ushort
	{
		Reserved1 = 1,
		Reserved2 = 2,
		Reserved3 = 4,
		Reserved4 = 8,
		Reserved5 = 0x10,
		HighEntropyVA = 0x20,
		DynamicBase = 0x40,
		ForceIntegrity = 0x80,
		NxCompat = 0x100,
		NoIsolation = 0x200,
		NoSeh = 0x400,
		NoBind = 0x800,
		AppContainer = 0x1000,
		WdmDriver = 0x2000,
		GuardCf = 0x4000,
		TerminalServerAware = 0x8000
	}
	public interface IImageOptionalHeader : IFileSection
	{
		ushort Magic { get; }

		byte MajorLinkerVersion { get; }

		byte MinorLinkerVersion { get; }

		uint SizeOfCode { get; }

		uint SizeOfInitializedData { get; }

		uint SizeOfUninitializedData { get; }

		RVA AddressOfEntryPoint { get; }

		RVA BaseOfCode { get; }

		RVA BaseOfData { get; }

		ulong ImageBase { get; }

		uint SectionAlignment { get; }

		uint FileAlignment { get; }

		ushort MajorOperatingSystemVersion { get; }

		ushort MinorOperatingSystemVersion { get; }

		ushort MajorImageVersion { get; }

		ushort MinorImageVersion { get; }

		ushort MajorSubsystemVersion { get; }

		ushort MinorSubsystemVersion { get; }

		uint Win32VersionValue { get; }

		uint SizeOfImage { get; }

		uint SizeOfHeaders { get; }

		uint CheckSum { get; }

		Subsystem Subsystem { get; }

		DllCharacteristics DllCharacteristics { get; }

		ulong SizeOfStackReserve { get; }

		ulong SizeOfStackCommit { get; }

		ulong SizeOfHeapReserve { get; }

		ulong SizeOfHeapCommit { get; }

		uint LoaderFlags { get; }

		uint NumberOfRvaAndSizes { get; }

		ImageDataDirectory[] DataDirectories { get; }
	}
	[DebuggerDisplay("{virtualAddress} {dataSize}")]
	public sealed class ImageDataDirectory : FileSection
	{
		private readonly RVA virtualAddress;

		private readonly uint dataSize;

		public RVA VirtualAddress => virtualAddress;

		public uint Size => dataSize;

		public ImageDataDirectory()
		{
		}

		public ImageDataDirectory(ref DataReader reader, bool verify)
		{
			SetStartOffset(ref reader);
			virtualAddress = (RVA)reader.ReadUInt32();
			dataSize = reader.ReadUInt32();
			SetEndoffset(ref reader);
		}
	}
	[DebuggerDisplay("{type}: TS:{timeDateStamp,h} V:{majorVersion,d}.{minorVersion,d} SZ:{sizeOfData} RVA:{addressOfRawData,h} FO:{pointerToRawData,h}")]
	public sealed class ImageDebugDirectory : FileSection
	{
		private readonly uint characteristics;

		private readonly uint timeDateStamp;

		private readonly ushort majorVersion;

		private readonly ushort minorVersion;

		private readonly ImageDebugType type;

		private readonly uint sizeOfData;

		private readonly uint addressOfRawData;

		private readonly uint pointerToRawData;

		public uint Characteristics => characteristics;

		public uint TimeDateStamp => timeDateStamp;

		public ushort MajorVersion => majorVersion;

		public ushort MinorVersion => minorVersion;

		public ImageDebugType Type => type;

		public uint SizeOfData => sizeOfData;

		public RVA AddressOfRawData => (RVA)addressOfRawData;

		public FileOffset PointerToRawData => (FileOffset)pointerToRawData;

		public ImageDebugDirectory(ref DataReader reader, bool verify)
		{
			SetStartOffset(ref reader);
			characteristics = reader.ReadUInt32();
			timeDateStamp = reader.ReadUInt32();
			majorVersion = reader.ReadUInt16();
			minorVersion = reader.ReadUInt16();
			type = (ImageDebugType)reader.ReadUInt32();
			sizeOfData = reader.ReadUInt32();
			addressOfRawData = reader.ReadUInt32();
			pointerToRawData = reader.ReadUInt32();
			SetEndoffset(ref reader);
		}
	}
	public enum ImageDebugType : uint
	{
		Unknown = 0u,
		Coff = 1u,
		CodeView = 2u,
		FPO = 3u,
		Misc = 4u,
		Exception = 5u,
		Fixup = 6u,
		OmapToSrc = 7u,
		OmapFromSrc = 8u,
		Borland = 9u,
		Reserved10 = 10u,
		CLSID = 11u,
		VcFeature = 12u,
		POGO = 13u,
		ILTCG = 14u,
		MPX = 15u,
		Reproducible = 16u,
		EmbeddedPortablePdb = 17u,
		PdbChecksum = 19u
	}
	public sealed class ImageDosHeader : FileSection
	{
		private readonly uint ntHeadersOffset;

		public uint NTHeadersOffset => ntHeadersOffset;

		public ImageDosHeader(ref DataReader reader, bool verify)
		{
			SetStartOffset(ref reader);
			ushort num = reader.ReadUInt16();
			if (verify && num != 23117)
			{
				throw new BadImageFormatException("Invalid DOS signature");
			}
			reader.Position = (uint)(startOffset + 60);
			ntHeadersOffset = reader.ReadUInt32();
			SetEndoffset(ref reader);
		}
	}
	public sealed class ImageFileHeader : FileSection
	{
		private readonly Machine machine;

		private readonly ushort numberOfSections;

		private readonly uint timeDateStamp;

		private readonly uint pointerToSymbolTable;

		private readonly uint numberOfSymbols;

		private readonly ushort sizeOfOptionalHeader;

		private readonly Characteristics characteristics;

		public Machine Machine => machine;

		public int NumberOfSections => numberOfSections;

		public uint TimeDateStamp => timeDateStamp;

		public uint PointerToSymbolTable => pointerToSymbolTable;

		public uint NumberOfSymbols => numberOfSymbols;

		public uint SizeOfOptionalHeader => sizeOfOptionalHeader;

		public Characteristics Characteristics => characteristics;

		public ImageFileHeader(ref DataReader reader, bool verify)
		{
			SetStartOffset(ref reader);
			machine = (Machine)reader.ReadUInt16();
			numberOfSections = reader.ReadUInt16();
			timeDateStamp = reader.ReadUInt32();
			pointerToSymbolTable = reader.ReadUInt32();
			numberOfSymbols = reader.ReadUInt32();
			sizeOfOptionalHeader = reader.ReadUInt16();
			characteristics = (Characteristics)reader.ReadUInt16();
			SetEndoffset(ref reader);
			if (verify && sizeOfOptionalHeader == 0)
			{
				throw new BadImageFormatException("Invalid SizeOfOptionalHeader");
			}
		}
	}
	public sealed class ImageNTHeaders : FileSection
	{
		private readonly uint signature;

		private readonly ImageFileHeader imageFileHeader;

		private readonly IImageOptionalHeader imageOptionalHeader;

		public uint Signature => signature;

		public ImageFileHeader FileHeader => imageFileHeader;

		public IImageOptionalHeader OptionalHeader => imageOptionalHeader;

		public ImageNTHeaders(ref DataReader reader, bool verify)
		{
			SetStartOffset(ref reader);
			signature = reader.ReadUInt32();
			if (verify && (ushort)signature != 17744)
			{
				throw new BadImageFormatException("Invalid NT headers signature");
			}
			imageFileHeader = new ImageFileHeader(ref reader, verify);
			imageOptionalHeader = CreateImageOptionalHeader(ref reader, verify);
			SetEndoffset(ref reader);
		}

		private IImageOptionalHeader CreateImageOptionalHeader(ref DataReader reader, bool verify)
		{
			ushort num = reader.ReadUInt16();
			reader.Position -= 2u;
			return num switch
			{
				267 => new ImageOptionalHeader32(ref reader, imageFileHeader.SizeOfOptionalHeader, verify), 
				523 => new ImageOptionalHeader64(ref reader, imageFileHeader.SizeOfOptionalHeader, verify), 
				_ => throw new BadImageFormatException("Invalid optional header magic"), 
			};
		}
	}
	public sealed class ImageOptionalHeader32 : FileSection, IImageOptionalHeader, IFileSection
	{
		private readonly ushort magic;

		private readonly byte majorLinkerVersion;

		private readonly byte minorLinkerVersion;

		private readonly uint sizeOfCode;

		private readonly uint sizeOfInitializedData;

		private readonly uint sizeOfUninitializedData;

		private readonly RVA addressOfEntryPoint;

		private readonly RVA baseOfCode;

		private readonly RVA baseOfData;

		private readonly uint imageBase;

		private readonly uint sectionAlignment;

		private readonly uint fileAlignment;

		private readonly ushort majorOperatingSystemVersion;

		private readonly ushort minorOperatingSystemVersion;

		private readonly ushort majorImageVersion;

		private readonly ushort minorImageVersion;

		private readonly ushort majorSubsystemVersion;

		private readonly ushort minorSubsystemVersion;

		private readonly uint win32VersionValue;

		private readonly uint sizeOfImage;

		private readonly uint sizeOfHeaders;

		private readonly uint checkSum;

		private readonly Subsystem subsystem;

		private readonly DllCharacteristics dllCharacteristics;

		private readonly uint sizeOfStackReserve;

		private readonly uint sizeOfStackCommit;

		private readonly uint sizeOfHeapReserve;

		private readonly uint sizeOfHeapCommit;

		private readonly uint loaderFlags;

		private readonly uint numberOfRvaAndSizes;

		private readonly ImageDataDirectory[] dataDirectories = new ImageDataDirectory[16];

		public ushort Magic => magic;

		public byte MajorLinkerVersion => majorLinkerVersion;

		public byte MinorLinkerVersion => minorLinkerVersion;

		public uint SizeOfCode => sizeOfCode;

		public uint SizeOfInitializedData => sizeOfInitializedData;

		public uint SizeOfUninitializedData => sizeOfUninitializedData;

		public RVA AddressOfEntryPoint => addressOfEntryPoint;

		public RVA BaseOfCode => baseOfCode;

		public RVA BaseOfData => baseOfData;

		public ulong ImageBase => imageBase;

		public uint SectionAlignment => sectionAlignment;

		public uint FileAlignment => fileAlignment;

		public ushort MajorOperatingSystemVersion => majorOperatingSystemVersion;

		public ushort MinorOperatingSystemVersion => minorOperatingSystemVersion;

		public ushort MajorImageVersion => majorImageVersion;

		public ushort MinorImageVersion => minorImageVersion;

		public ushort MajorSubsystemVersion => majorSubsystemVersion;

		public ushort MinorSubsystemVersion => minorSubsystemVersion;

		public uint Win32VersionValue => win32VersionValue;

		public uint SizeOfImage => sizeOfImage;

		public uint SizeOfHeaders => sizeOfHeaders;

		public uint CheckSum => checkSum;

		public Subsystem Subsystem => subsystem;

		public DllCharacteristics DllCharacteristics => dllCharacteristics;

		public ulong SizeOfStackReserve => sizeOfStackReserve;

		public ulong SizeOfStackCommit => sizeOfStackCommit;

		public ulong SizeOfHeapReserve => sizeOfHeapReserve;

		public ulong SizeOfHeapCommit => sizeOfHeapCommit;

		public uint LoaderFlags => loaderFlags;

		public uint NumberOfRvaAndSizes => numberOfRvaAndSizes;

		public ImageDataDirectory[] DataDirectories => dataDirectories;

		public ImageOptionalHeader32(ref DataReader reader, uint totalSize, bool verify)
		{
			if (totalSize < 96)
			{
				throw new BadImageFormatException("Invalid optional header size");
			}
			if (verify && (ulong)((long)reader.Position + (long)totalSize) > (ulong)reader.Length)
			{
				throw new BadImageFormatException("Invalid optional header size");
			}
			SetStartOffset(ref reader);
			magic = reader.ReadUInt16();
			majorLinkerVersion = reader.ReadByte();
			minorLinkerVersion = reader.ReadByte();
			sizeOfCode = reader.ReadUInt32();
			sizeOfInitializedData = reader.ReadUInt32();
			sizeOfUninitializedData = reader.ReadUInt32();
			addressOfEntryPoint = (RVA)reader.ReadUInt32();
			baseOfCode = (RVA)reader.ReadUInt32();
			baseOfData = (RVA)reader.ReadUInt32();
			imageBase = reader.ReadUInt32();
			sectionAlignment = reader.ReadUInt32();
			fileAlignment = reader.ReadUInt32();
			majorOperatingSystemVersion = reader.ReadUInt16();
			minorOperatingSystemVersion = reader.ReadUInt16();
			majorImageVersion = reader.ReadUInt16();
			minorImageVersion = reader.ReadUInt16();
			majorSubsystemVersion = reader.ReadUInt16();
			minorSubsystemVersion = reader.ReadUInt16();
			win32VersionValue = reader.ReadUInt32();
			sizeOfImage = reader.ReadUInt32();
			sizeOfHeaders = reader.ReadUInt32();
			checkSum = reader.ReadUInt32();
			subsystem = (Subsystem)reader.ReadUInt16();
			dllCharacteristics = (DllCharacteristics)reader.ReadUInt16();
			sizeOfStackReserve = reader.ReadUInt32();
			sizeOfStackCommit = reader.ReadUInt32();
			sizeOfHeapReserve = reader.ReadUInt32();
			sizeOfHeapCommit = reader.ReadUInt32();
			loaderFlags = reader.ReadUInt32();
			numberOfRvaAndSizes = reader.ReadUInt32();
			for (int i = 0; i < dataDirectories.Length; i++)
			{
				if ((uint)(reader.Position - startOffset + 8) <= totalSize)
				{
					dataDirectories[i] = new ImageDataDirectory(ref reader, verify);
				}
				else
				{
					dataDirectories[i] = new ImageDataDirectory();
				}
			}
			reader.Position = (uint)(startOffset + totalSize);
			SetEndoffset(ref reader);
		}
	}
	public sealed class ImageOptionalHeader64 : FileSection, IImageOptionalHeader, IFileSection
	{
		private readonly ushort magic;

		private readonly byte majorLinkerVersion;

		private readonly byte minorLinkerVersion;

		private readonly uint sizeOfCode;

		private readonly uint sizeOfInitializedData;

		private readonly uint sizeOfUninitializedData;

		private readonly RVA addressOfEntryPoint;

		private readonly RVA baseOfCode;

		private readonly ulong imageBase;

		private readonly uint sectionAlignment;

		private readonly uint fileAlignment;

		private readonly ushort majorOperatingSystemVersion;

		private readonly ushort minorOperatingSystemVersion;

		private readonly ushort majorImageVersion;

		private readonly ushort minorImageVersion;

		private readonly ushort majorSubsystemVersion;

		private readonly ushort minorSubsystemVersion;

		private readonly uint win32VersionValue;

		private readonly uint sizeOfImage;

		private readonly uint sizeOfHeaders;

		private readonly uint checkSum;

		private readonly Subsystem subsystem;

		private readonly DllCharacteristics dllCharacteristics;

		private readonly ulong sizeOfStackReserve;

		private readonly ulong sizeOfStackCommit;

		private readonly ulong sizeOfHeapReserve;

		private readonly ulong sizeOfHeapCommit;

		private readonly uint loaderFlags;

		private readonly uint numberOfRvaAndSizes;

		private readonly ImageDataDirectory[] dataDirectories = new ImageDataDirectory[16];

		public ushort Magic => magic;

		public byte MajorLinkerVersion => majorLinkerVersion;

		public byte MinorLinkerVersion => minorLinkerVersion;

		public uint SizeOfCode => sizeOfCode;

		public uint SizeOfInitializedData => sizeOfInitializedData;

		public uint SizeOfUninitializedData => sizeOfUninitializedData;

		public RVA AddressOfEntryPoint => addressOfEntryPoint;

		public RVA BaseOfCode => baseOfCode;

		public RVA BaseOfData => (RVA)0u;

		public ulong ImageBase => imageBase;

		public uint SectionAlignment => sectionAlignment;

		public uint FileAlignment => fileAlignment;

		public ushort MajorOperatingSystemVersion => majorOperatingSystemVersion;

		public ushort MinorOperatingSystemVersion => minorOperatingSystemVersion;

		public ushort MajorImageVersion => majorImageVersion;

		public ushort MinorImageVersion => minorImageVersion;

		public ushort MajorSubsystemVersion => majorSubsystemVersion;

		public ushort MinorSubsystemVersion => minorSubsystemVersion;

		public uint Win32VersionValue => win32VersionValue;

		public uint SizeOfImage => sizeOfImage;

		public uint SizeOfHeaders => sizeOfHeaders;

		public uint CheckSum => checkSum;

		public Subsystem Subsystem => subsystem;

		public DllCharacteristics DllCharacteristics => dllCharacteristics;

		public ulong SizeOfStackReserve => sizeOfStackReserve;

		public ulong SizeOfStackCommit => sizeOfStackCommit;

		public ulong SizeOfHeapReserve => sizeOfHeapReserve;

		public ulong SizeOfHeapCommit => sizeOfHeapCommit;

		public uint LoaderFlags => loaderFlags;

		public uint NumberOfRvaAndSizes => numberOfRvaAndSizes;

		public ImageDataDirectory[] DataDirectories => dataDirectories;

		public ImageOptionalHeader64(ref DataReader reader, uint totalSize, bool verify)
		{
			if (totalSize < 112)
			{
				throw new BadImageFormatException("Invalid optional header size");
			}
			if (verify && (ulong)((long)reader.Position + (long)totalSize) > (ulong)reader.Length)
			{
				throw new BadImageFormatException("Invalid optional header size");
			}
			SetStartOffset(ref reader);
			magic = reader.ReadUInt16();
			majorLinkerVersion = reader.ReadByte();
			minorLinkerVersion = reader.ReadByte();
			sizeOfCode = reader.ReadUInt32();
			sizeOfInitializedData = reader.ReadUInt32();
			sizeOfUninitializedData = reader.ReadUInt32();
			addressOfEntryPoint = (RVA)reader.ReadUInt32();
			baseOfCode = (RVA)reader.ReadUInt32();
			imageBase = reader.ReadUInt64();
			sectionAlignment = reader.ReadUInt32();
			fileAlignment = reader.ReadUInt32();
			majorOperatingSystemVersion = reader.ReadUInt16();
			minorOperatingSystemVersion = reader.ReadUInt16();
			majorImageVersion = reader.ReadUInt16();
			minorImageVersion = reader.ReadUInt16();
			majorSubsystemVersion = reader.ReadUInt16();
			minorSubsystemVersion = reader.ReadUInt16();
			win32VersionValue = reader.ReadUInt32();
			sizeOfImage = reader.ReadUInt32();
			sizeOfHeaders = reader.ReadUInt32();
			checkSum = reader.ReadUInt32();
			subsystem = (Subsystem)reader.ReadUInt16();
			dllCharacteristics = (DllCharacteristics)reader.ReadUInt16();
			sizeOfStackReserve = reader.ReadUInt64();
			sizeOfStackCommit = reader.ReadUInt64();
			sizeOfHeapReserve = reader.ReadUInt64();
			sizeOfHeapCommit = reader.ReadUInt64();
			loaderFlags = reader.ReadUInt32();
			numberOfRvaAndSizes = reader.ReadUInt32();
			for (int i = 0; i < dataDirectories.Length; i++)
			{
				if ((uint)(reader.Position - startOffset + 8) <= totalSize)
				{
					dataDirectories[i] = new ImageDataDirectory(ref reader, verify);
				}
				else
				{
					dataDirectories[i] = new ImageDataDirectory();
				}
			}
			reader.Position = (uint)(startOffset + totalSize);
			SetEndoffset(ref reader);
		}
	}
	[DebuggerDisplay("RVA:{virtualAddress} VS:{virtualSize} FO:{pointerToRawData} FS:{sizeOfRawData} {displayName}")]
	public sealed class ImageSectionHeader : FileSection
	{
		private readonly string displayName;

		private readonly byte[] name;

		private readonly uint virtualSize;

		private readonly RVA virtualAddress;

		private readonly uint sizeOfRawData;

		private readonly uint pointerToRawData;

		private readonly uint pointerToRelocations;

		private readonly uint pointerToLinenumbers;

		private readonly ushort numberOfRelocations;

		private readonly ushort numberOfLinenumbers;

		private readonly uint characteristics;

		public string DisplayName => displayName;

		public byte[] Name => name;

		public uint VirtualSize => virtualSize;

		public RVA VirtualAddress => virtualAddress;

		public uint SizeOfRawData => sizeOfRawData;

		public uint PointerToRawData => pointerToRawData;

		public uint PointerToRelocations => pointerToRelocations;

		public uint PointerToLinenumbers => pointerToLinenumbers;

		public ushort NumberOfRelocations => numberOfRelocations;

		public ushort NumberOfLinenumbers => numberOfLinenumbers;

		public uint Characteristics => characteristics;

		public ImageSectionHeader(ref DataReader reader, bool verify)
		{
			SetStartOffset(ref reader);
			name = reader.ReadBytes(8);
			virtualSize = reader.ReadUInt32();
			virtualAddress = (RVA)reader.ReadUInt32();
			sizeOfRawData = reader.ReadUInt32();
			pointerToRawData = reader.ReadUInt32();
			pointerToRelocations = reader.ReadUInt32();
			pointerToLinenumbers = reader.ReadUInt32();
			numberOfRelocations = reader.ReadUInt16();
			numberOfLinenumbers = reader.ReadUInt16();
			characteristics = reader.ReadUInt32();
			SetEndoffset(ref reader);
			displayName = ToString(name);
		}

		private static string ToString(byte[] name)
		{
			StringBuilder stringBuilder = new StringBuilder(name.Length);
			foreach (byte b in name)
			{
				if (b == 0)
				{
					break;
				}
				stringBuilder.Append((char)b);
			}
			return stringBuilder.ToString();
		}
	}
	public interface IRvaFileOffsetConverter
	{
		RVA ToRVA(FileOffset offset);

		FileOffset ToFileOffset(RVA rva);
	}
	public interface IPEImage : IRvaFileOffsetConverter, IDisposable
	{
		bool IsFileImageLayout { get; }

		bool MayHaveInvalidAddresses { get; }

		string Filename { get; }

		ImageDosHeader ImageDosHeader { get; }

		ImageNTHeaders ImageNTHeaders { get; }

		IList<ImageSectionHeader> ImageSectionHeaders { get; }

		IList<ImageDebugDirectory> ImageDebugDirectories { get; }

		Win32Resources Win32Resources { get; set; }

		DataReaderFactory DataReaderFactory { get; }

		DataReader CreateReader(FileOffset offset);

		DataReader CreateReader(FileOffset offset, uint length);

		DataReader CreateReader(RVA rva);

		DataReader CreateReader(RVA rva, uint length);

		DataReader CreateReader();
	}
	public interface IInternalPEImage : IPEImage, IRvaFileOffsetConverter, IDisposable
	{
		bool IsMemoryMappedIO { get; }

		void UnsafeDisableMemoryMappedIO();
	}
	public static class PEExtensions
	{
		public static ResourceData FindWin32ResourceData(this IPEImage self, ResourceName type, ResourceName name, ResourceName langId)
		{
			return self.Win32Resources?.Find(type, name, langId);
		}

		internal static uint CalculatePECheckSum(this Stream stream, long length, long checkSumOffset)
		{
			if ((length & 1) != 0L)
			{
				ThrowInvalidOperationException("Invalid PE length");
			}
			byte[] buffer = new byte[(int)Math.Min(length, 8192L)];
			uint checkSum = 0u;
			checkSum = CalculatePECheckSum(stream, checkSumOffset, checkSum, buffer);
			stream.Position += 4L;
			checkSum = CalculatePECheckSum(stream, length - checkSumOffset - 4, checkSum, buffer);
			ulong num = (ulong)(checkSum + length);
			return (uint)((int)num + (int)(num >> 32));
		}

		private static uint CalculatePECheckSum(Stream stream, long length, uint checkSum, byte[] buffer)
		{
			int num3;
			for (long num = 0L; num < length; num += num3)
			{
				int num2 = (int)Math.Min(length - num, buffer.Length);
				num3 = stream.Read(buffer, 0, num2);
				if (num3 != num2)
				{
					ThrowInvalidOperationException("Couldn't read all bytes");
				}
				int num4 = 0;
				while (num4 < num3)
				{
					checkSum += (uint)(buffer[num4++] | (buffer[num4++] << 8));
					checkSum = (ushort)(checkSum + (checkSum >> 16));
				}
			}
			return checkSum;
		}

		private static void ThrowInvalidOperationException(string message)
		{
			throw new InvalidOperationException(message);
		}

		public static RVA AlignUp(this RVA rva, uint alignment)
		{
			return (RVA)((uint)(rva + alignment - 1) & ~(alignment - 1));
		}

		public static RVA AlignUp(this RVA rva, int alignment)
		{
			return (RVA)(((long)rva + (long)alignment - 1) & ~(alignment - 1));
		}
	}
	internal interface IPEType
	{
		RVA ToRVA(PEInfo peInfo, FileOffset offset);

		FileOffset ToFileOffset(PEInfo peInfo, RVA rva);
	}
	public enum Machine : ushort
	{
		Unknown = 0,
		I386 = 332,
		R3000 = 354,
		R4000 = 358,
		R10000 = 360,
		WCEMIPSV2 = 361,
		ALPHA = 388,
		SH3 = 418,
		SH3DSP = 419,
		SH3E = 420,
		SH4 = 422,
		SH5 = 424,
		ARM = 448,
		THUMB = 450,
		ARMNT = 452,
		AM33 = 467,
		POWERPC = 496,
		POWERPCFP = 497,
		IA64 = 512,
		MIPS16 = 614,
		ALPHA64 = 644,
		MIPSFPU = 870,
		MIPSFPU16 = 1126,
		TRICORE = 1312,
		CEF = 3311,
		EBC = 3772,
		AMD64 = 34404,
		M32R = 36929,
		ARM64 = 43620,
		CEE = 49390,
		I386_Native_Apple = 18184,
		AMD64_Native_Apple = 49184,
		ARMNT_Native_Apple = 18304,
		ARM64_Native_Apple = 60448,
		I386_Native_FreeBSD = 44168,
		AMD64_Native_FreeBSD = 11168,
		ARMNT_Native_FreeBSD = 44032,
		ARM64_Native_FreeBSD = 1952,
		I386_Native_Linux = 31285,
		AMD64_Native_Linux = 64797,
		ARMNT_Native_Linux = 31421,
		ARM64_Native_Linux = 53533,
		I386_Native_NetBSD = 6367,
		AMD64_Native_NetBSD = 40951,
		ARMNT_Native_NetBSD = 6231,
		ARM64_Native_NetBSD = 46071
	}
	public static class MachineExtensions
	{
		public static bool Is64Bit(this Machine machine)
		{
			switch (machine)
			{
			case Machine.IA64:
			case Machine.ARM64_Native_FreeBSD:
			case Machine.AMD64_Native_FreeBSD:
			case Machine.AMD64:
			case Machine.AMD64_Native_NetBSD:
			case Machine.ARM64:
			case Machine.ARM64_Native_NetBSD:
			case Machine.AMD64_Native_Apple:
			case Machine.ARM64_Native_Linux:
			case Machine.ARM64_Native_Apple:
			case Machine.AMD64_Native_Linux:
				return true;
			default:
				return false;
			}
		}

		public static bool IsI386(this Machine machine)
		{
			switch (machine)
			{
			case Machine.I386:
			case Machine.I386_Native_NetBSD:
			case Machine.I386_Native_Apple:
			case Machine.I386_Native_Linux:
			case Machine.I386_Native_FreeBSD:
				return true;
			default:
				return false;
			}
		}

		public static bool IsAMD64(this Machine machine)
		{
			switch (machine)
			{
			case Machine.AMD64_Native_FreeBSD:
			case Machine.AMD64:
			case Machine.AMD64_Native_NetBSD:
			case Machine.AMD64_Native_Apple:
			case Machine.AMD64_Native_Linux:
				return true;
			default:
				return false;
			}
		}

		public static bool IsARMNT(this Machine machine)
		{
			switch (machine)
			{
			case Machine.ARMNT:
			case Machine.ARMNT_Native_NetBSD:
			case Machine.ARMNT_Native_Apple:
			case Machine.ARMNT_Native_Linux:
			case Machine.ARMNT_Native_FreeBSD:
				return true;
			default:
				return false;
			}
		}

		public static bool IsARM64(this Machine machine)
		{
			switch (machine)
			{
			case Machine.ARM64_Native_FreeBSD:
			case Machine.ARM64:
			case Machine.ARM64_Native_NetBSD:
			case Machine.ARM64_Native_Linux:
			case Machine.ARM64_Native_Apple:
				return true;
			default:
				return false;
			}
		}
	}
	public enum ImageLayout
	{
		File,
		Memory
	}
	public sealed class PEImage : IInternalPEImage, IPEImage, IRvaFileOffsetConverter, IDisposable
	{
		private sealed class FilePEType : IPEType
		{
			public RVA ToRVA(PEInfo peInfo, FileOffset offset)
			{
				return peInfo.ToRVA(offset);
			}

			public FileOffset ToFileOffset(PEInfo peInfo, RVA rva)
			{
				return peInfo.ToFileOffset(rva);
			}
		}

		private sealed class MemoryPEType : IPEType
		{
			public RVA ToRVA(PEInfo peInfo, FileOffset offset)
			{
				return (RVA)offset;
			}

			public FileOffset ToFileOffset(PEInfo peInfo, RVA rva)
			{
				return (FileOffset)rva;
			}
		}

		private const bool USE_MEMORY_LAYOUT_WITH_MAPPED_FILES = false;

		private static readonly IPEType MemoryLayout = new MemoryPEType();

		private static readonly IPEType FileLayout = new FilePEType();

		private DataReaderFactory dataReaderFactory;

		private IPEType peType;

		private PEInfo peInfo;

		private UserValue<Win32Resources> win32Resources;

		private readonly Lock theLock = Lock.Create();

		private ImageDebugDirectory[] imageDebugDirectories;

		public bool IsFileImageLayout => peType is FilePEType;

		public bool MayHaveInvalidAddresses => !IsFileImageLayout;

		public string Filename => dataReaderFactory.Filename;

		public ImageDosHeader ImageDosHeader => peInfo.ImageDosHeader;

		public ImageNTHeaders ImageNTHeaders => peInfo.ImageNTHeaders;

		public IList<ImageSectionHeader> ImageSectionHeaders => peInfo.ImageSectionHeaders;

		public IList<ImageDebugDirectory> ImageDebugDirectories
		{
			get
			{
				if (imageDebugDirectories == null)
				{
					imageDebugDirectories = ReadImageDebugDirectories();
				}
				return imageDebugDirectories;
			}
		}

		public DataReaderFactory DataReaderFactory => dataReaderFactory;

		public Win32Resources Win32Resources
		{
			get
			{
				return win32Resources.Value;
			}
			set
			{
				IDisposable disposable = null;
				if (win32Resources.IsValueInitialized)
				{
					disposable = win32Resources.Value;
					if (disposable == value)
					{
						return;
					}
				}
				win32Resources.Value = value;
				disposable?.Dispose();
			}
		}

		bool IInternalPEImage.IsMemoryMappedIO
		{
			get
			{
				if (dataReaderFactory is MemoryMappedDataReaderFactory memoryMappedDataReaderFactory)
				{
					return memoryMappedDataReaderFactory.IsMemoryMappedIO;
				}
				return false;
			}
		}

		public PEImage(DataReaderFactory dataReaderFactory, ImageLayout imageLayout, bool verify)
		{
			try
			{
				this.dataReaderFactory = dataReaderFactory;
				peType = ConvertImageLayout(imageLayout);
				DataReader reader = dataReaderFactory.CreateReader();
				peInfo = new PEInfo(ref reader, verify);
				Initialize();
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		private void Initialize()
		{
			win32Resources.ReadOriginalValue = delegate
			{
				ImageDataDirectory imageDataDirectory = peInfo.ImageNTHeaders.OptionalHeader.DataDirectories[2];
				return (imageDataDirectory.VirtualAddress == (RVA)0u || imageDataDirectory.Size == 0) ? null : new Win32ResourcesPE(this);
			};
			win32Resources.Lock = theLock;
		}

		private static IPEType ConvertImageLayout(ImageLayout imageLayout)
		{
			return imageLayout switch
			{
				ImageLayout.File => FileLayout, 
				ImageLayout.Memory => MemoryLayout, 
				_ => throw new ArgumentException("imageLayout"), 
			};
		}

		internal PEImage(string filename, bool mapAsImage, bool verify)
			: this(DataReaderFactoryFactory.Create(filename, mapAsImage), mapAsImage ? ImageLayout.Memory : ImageLayout.File, verify)
		{
			try
			{
				if (mapAsImage && dataReaderFactory is MemoryMappedDataReaderFactory)
				{
					((MemoryMappedDataReaderFactory)dataReaderFactory).SetLength(peInfo.GetImageSize());
				}
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		public PEImage(string filename, bool verify)
			: this(filename, mapAsImage: false, verify)
		{
		}

		public PEImage(string filename)
			: this(filename, verify: true)
		{
		}

		public PEImage(byte[] data, string filename, ImageLayout imageLayout, bool verify)
			: this(ByteArrayDataReaderFactory.Create(data, filename), imageLayout, verify)
		{
		}

		public PEImage(byte[] data, ImageLayout imageLayout, bool verify)
			: this(data, null, imageLayout, verify)
		{
		}

		public PEImage(byte[] data, bool verify)
			: this(data, null, ImageLayout.File, verify)
		{
		}

		public PEImage(byte[] data, string filename, bool verify)
			: this(data, filename, ImageLayout.File, verify)
		{
		}

		public PEImage(byte[] data)
			: this(data, null, verify: true)
		{
		}

		public PEImage(byte[] data, string filename)
			: this(data, filename, verify: true)
		{
		}

		public unsafe PEImage(IntPtr baseAddr, uint length, ImageLayout imageLayout, bool verify)
			: this(NativeMemoryDataReaderFactory.Create((byte*)(void*)baseAddr, length, null), imageLayout, verify)
		{
		}

		public PEImage(IntPtr baseAddr, uint length, bool verify)
			: this(baseAddr, length, ImageLayout.Memory, verify)
		{
		}

		public PEImage(IntPtr baseAddr, uint length)
			: this(baseAddr, length, verify: true)
		{
		}

		public unsafe PEImage(IntPtr baseAddr, ImageLayout imageLayout, bool verify)
			: this(NativeMemoryDataReaderFactory.Create((byte*)(void*)baseAddr, 65536u, null), imageLayout, verify)
		{
			try
			{
				((NativeMemoryDataReaderFactory)dataReaderFactory).SetLength(peInfo.GetImageSize());
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		public PEImage(IntPtr baseAddr, bool verify)
			: this(baseAddr, ImageLayout.Memory, verify)
		{
		}

		public PEImage(IntPtr baseAddr)
			: this(baseAddr, verify: true)
		{
		}

		public RVA ToRVA(FileOffset offset)
		{
			return peType.ToRVA(peInfo, offset);
		}

		public FileOffset ToFileOffset(RVA rva)
		{
			return peType.ToFileOffset(peInfo, rva);
		}

		public void Dispose()
		{
			IDisposable value;
			if (win32Resources.IsValueInitialized && (value = win32Resources.Value) != null)
			{
				value.Dispose();
			}
			dataReaderFactory?.Dispose();
			win32Resources.Value = null;
			dataReaderFactory = null;
			peType = null;
			peInfo = null;
		}

		public DataReader CreateReader(FileOffset offset)
		{
			return DataReaderFactory.CreateReader((uint)offset, (uint)(DataReaderFactory.Length - offset));
		}

		public DataReader CreateReader(FileOffset offset, uint length)
		{
			return DataReaderFactory.CreateReader((uint)offset, length);
		}

		public DataReader CreateReader(RVA rva)
		{
			return CreateReader(ToFileOffset(rva));
		}

		public DataReader CreateReader(RVA rva, uint length)
		{
			return CreateReader(ToFileOffset(rva), length);
		}

		public DataReader CreateReader()
		{
			return DataReaderFactory.CreateReader();
		}

		void IInternalPEImage.UnsafeDisableMemoryMappedIO()
		{
			if (dataReaderFactory is MemoryMappedDataReaderFactory memoryMappedDataReaderFactory)
			{
				memoryMappedDataReaderFactory.UnsafeDisableMemoryMappedIO();
			}
		}

		private ImageDebugDirectory[] ReadImageDebugDirectories()
		{
			try
			{
				ImageDataDirectory imageDataDirectory = ImageNTHeaders.OptionalHeader.DataDirectories[6];
				if (imageDataDirectory.VirtualAddress == (RVA)0u)
				{
					return Array2.Empty<ImageDebugDirectory>();
				}
				DataReader reader = DataReaderFactory.CreateReader();
				if (imageDataDirectory.Size > reader.Length)
				{
					return Array2.Empty<ImageDebugDirectory>();
				}
				int num = (int)(imageDataDirectory.Size / 28);
				if (num == 0)
				{
					return Array2.Empty<ImageDebugDirectory>();
				}
				reader.CurrentOffset = (uint)ToFileOffset(imageDataDirectory.VirtualAddress);
				if ((ulong)((long)reader.CurrentOffset + (long)imageDataDirectory.Size) > (ulong)reader.Length)
				{
					return Array2.Empty<ImageDebugDirectory>();
				}
				ImageDebugDirectory[] array = new ImageDebugDirectory[num];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = new ImageDebugDirectory(ref reader, verify: true);
				}
				return array;
			}
			catch (IOException)
			{
			}
			return Array2.Empty<ImageDebugDirectory>();
		}
	}
	internal sealed class PEInfo
	{
		private readonly ImageDosHeader imageDosHeader;

		private readonly ImageNTHeaders imageNTHeaders;

		private readonly ImageSectionHeader[] imageSectionHeaders;

		public ImageDosHeader ImageDosHeader => imageDosHeader;

		public ImageNTHeaders ImageNTHeaders => imageNTHeaders;

		public ImageSectionHeader[] ImageSectionHeaders => imageSectionHeaders;

		public PEInfo(ref DataReader reader, bool verify)
		{
			reader.Position = 0u;
			imageDosHeader = new ImageDosHeader(ref reader, verify);
			if (verify && imageDosHeader.NTHeadersOffset == 0)
			{
				throw new BadImageFormatException("Invalid NT headers offset");
			}
			reader.Position = imageDosHeader.NTHeadersOffset;
			imageNTHeaders = new ImageNTHeaders(ref reader, verify);
			reader.Position = (uint)(imageNTHeaders.OptionalHeader.StartOffset + imageNTHeaders.FileHeader.SizeOfOptionalHeader);
			int num = imageNTHeaders.FileHeader.NumberOfSections;
			if (num > 0)
			{
				DataReader dataReader = reader;
				dataReader.Position += 20u;
				uint num2 = dataReader.ReadUInt32();
				num = Math.Min(num, (int)((num2 - reader.Position) / 40));
			}
			imageSectionHeaders = new ImageSectionHeader[num];
			for (int i = 0; i < imageSectionHeaders.Length; i++)
			{
				imageSectionHeaders[i] = new ImageSectionHeader(ref reader, verify);
			}
		}

		public ImageSectionHeader ToImageSectionHeader(FileOffset offset)
		{
			ImageSectionHeader[] array = imageSectionHeaders;
			foreach (ImageSectionHeader imageSectionHeader in array)
			{
				if ((long)offset >= (long)imageSectionHeader.PointerToRawData && (long)offset < (long)(imageSectionHeader.PointerToRawData + imageSectionHeader.SizeOfRawData))
				{
					return imageSectionHeader;
				}
			}
			return null;
		}

		public ImageSectionHeader ToImageSectionHeader(RVA rva)
		{
			ImageSectionHeader[] array = imageSectionHeaders;
			foreach (ImageSectionHeader imageSectionHeader in array)
			{
				if (rva >= imageSectionHeader.VirtualAddress && rva < imageSectionHeader.VirtualAddress + Math.Max(imageSectionHeader.VirtualSize, imageSectionHeader.SizeOfRawData))
				{
					return imageSectionHeader;
				}
			}
			return null;
		}

		public RVA ToRVA(FileOffset offset)
		{
			ImageSectionHeader imageSectionHeader = ToImageSectionHeader(offset);
			if (imageSectionHeader != null)
			{
				return (RVA)((uint)(offset - imageSectionHeader.PointerToRawData) + (uint)imageSectionHeader.VirtualAddress);
			}
			return (RVA)offset;
		}

		public FileOffset ToFileOffset(RVA rva)
		{
			ImageSectionHeader imageSectionHeader = ToImageSectionHeader(rva);
			if (imageSectionHeader != null)
			{
				return (FileOffset)(rva - imageSectionHeader.VirtualAddress + imageSectionHeader.PointerToRawData);
			}
			return (FileOffset)rva;
		}

		private static ulong AlignUp(ulong val, uint alignment)
		{
			return (val + alignment - 1) & ~(ulong)(alignment - 1);
		}

		public uint GetImageSize()
		{
			IImageOptionalHeader optionalHeader = ImageNTHeaders.OptionalHeader;
			uint sectionAlignment = optionalHeader.SectionAlignment;
			ulong num = AlignUp(optionalHeader.SizeOfHeaders, sectionAlignment);
			ImageSectionHeader[] array = imageSectionHeaders;
			foreach (ImageSectionHeader imageSectionHeader in array)
			{
				ulong num2 = AlignUp((ulong)imageSectionHeader.VirtualAddress + (ulong)Math.Max(imageSectionHeader.VirtualSize, imageSectionHeader.SizeOfRawData), sectionAlignment);
				if (num2 > num)
				{
					num = num2;
				}
			}
			return (uint)Math.Min(num, 4294967295uL);
		}
	}
	internal static class ProcessorArchUtils
	{
		private static class RuntimeInformationUtils
		{
			private static Assembly RuntimeInformationAssembly => typeof(object).Assembly;

			private static Type System_Runtime_InteropServices_RuntimeInformation => RuntimeInformationAssembly.GetType("System.Runtime.InteropServices.RuntimeInformation", throwOnError: false);

			public static bool TryGet_RuntimeInformation_Architecture(out Machine machine)
			{
				machine = Machine.Unknown;
				MethodInfo methodInfo = System_Runtime_InteropServices_RuntimeInformation?.GetMethod("get_ProcessArchitecture", Array2.Empty<Type>());
				if ((object)methodInfo == null)
				{
					return false;
				}
				return TryGetArchitecture((int)methodInfo.Invoke(null, Array2.Empty<object>()), out machine);
			}

			private static bool TryGetArchitecture(int architecture, out Machine machine)
			{
				switch (architecture)
				{
				case 0:
					machine = Machine.I386;
					return true;
				case 1:
					machine = Machine.AMD64;
					return true;
				case 2:
					machine = Machine.ARMNT;
					return true;
				case 3:
					machine = Machine.ARM64;
					return true;
				default:
					machine = Machine.Unknown;
					return false;
				}
			}
		}

		private static class WindowsUtils
		{
			private struct SYSTEM_INFO
			{
				public ushort wProcessorArchitecture;

				public ushort wReserved;

				public uint dwPageSize;

				public IntPtr lpMinimumApplicationAddress;

				public IntPtr lpMaximumApplicationAddress;

				public IntPtr dwActiveProcessorMask;

				public uint dwNumberOfProcessors;

				public uint dwProcessorType;

				public uint dwAllocationGranularity;

				public ushort wProcessorLevel;

				public ushort wProcessorRevision;
			}

			private enum ProcessorArchitecture : ushort
			{
				INTEL = 0,
				ARM = 5,
				IA64 = 6,
				AMD64 = 9,
				ARM64 = 12,
				UNKNOWN = ushort.MaxValue
			}

			private static bool canTryGetSystemInfo = true;

			[DllImport("kernel32")]
			private static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);

			public static bool TryGetProcessCpuArchitecture(out Machine machine)
			{
				if (canTryGetSystemInfo)
				{
					try
					{
						GetSystemInfo(out var lpSystemInfo);
						switch ((ProcessorArchitecture)lpSystemInfo.wProcessorArchitecture)
						{
						case ProcessorArchitecture.INTEL:
							machine = Machine.I386;
							return true;
						case ProcessorArchitecture.ARM:
							machine = Machine.ARMNT;
							return true;
						case ProcessorArchitecture.IA64:
							machine = Machine.IA64;
							return true;
						case ProcessorArchitecture.AMD64:
							machine = Machine.AMD64;
							return true;
						case ProcessorArchitecture.ARM64:
							machine = Machine.ARM64;
							return true;
						}
					}
					catch (EntryPointNotFoundException)
					{
						canTryGetSystemInfo = false;
					}
					catch (DllNotFoundException)
					{
						canTryGetSystemInfo = false;
					}
				}
				machine = Machine.Unknown;
				return false;
			}
		}

		private static Machine cachedMachine;

		public static Machine GetProcessCpuArchitecture()
		{
			if (cachedMachine == Machine.Unknown)
			{
				cachedMachine = GetProcessCpuArchitectureCore();
			}
			return cachedMachine;
		}

		private static Machine GetProcessCpuArchitectureCore()
		{
			if (WindowsUtils.TryGetProcessCpuArchitecture(out var machine))
			{
				return machine;
			}
			try
			{
				if (RuntimeInformationUtils.TryGet_RuntimeInformation_Architecture(out machine))
				{
					return machine;
				}
			}
			catch (PlatformNotSupportedException)
			{
			}
			if (IntPtr.Size != 4)
			{
				return Machine.AMD64;
			}
			return Machine.I386;
		}
	}
	public enum RVA : uint
	{

	}
	public enum Subsystem : ushort
	{
		Unknown = 0,
		Native = 1,
		WindowsGui = 2,
		WindowsCui = 3,
		Os2Cui = 5,
		PosixCui = 7,
		NativeWindows = 8,
		WindowsCeGui = 9,
		EfiApplication = 10,
		EfiBootServiceDriver = 11,
		EfiRuntimeDriver = 12,
		EfiRom = 13,
		Xbox = 14,
		WindowsBootApplication = 16
	}
}
namespace dnlib.IO
{
	internal sealed class AlignedByteArrayDataStream : DataStream
	{
		private readonly byte[] data;

		public AlignedByteArrayDataStream(byte[] data)
		{
			this.data = data;
		}

		public unsafe override void ReadBytes(uint offset, void* destination, int length)
		{
			Marshal.Copy(data, (int)offset, (IntPtr)destination, length);
		}

		public override void ReadBytes(uint offset, byte[] destination, int destinationIndex, int length)
		{
			Array.Copy(data, (int)offset, destination, destinationIndex, length);
		}

		public override byte ReadByte(uint offset)
		{
			return data[offset];
		}

		public override ushort ReadUInt16(uint offset)
		{
			int num = (int)offset;
			byte[] array = data;
			return (ushort)(array[num++] | (array[num] << 8));
		}

		public override uint ReadUInt32(uint offset)
		{
			int num = (int)offset;
			byte[] array = data;
			return (uint)(array[num++] | (array[num++] << 8) | (array[num++] << 16) | (array[num] << 24));
		}

		public override ulong ReadUInt64(uint offset)
		{
			int num = (int)offset;
			byte[] array = data;
			return array[num++] | ((ulong)array[num++] << 8) | ((ulong)array[num++] << 16) | ((ulong)array[num++] << 24) | ((ulong)array[num++] << 32) | ((ulong)array[num++] << 40) | ((ulong)array[num++] << 48) | ((ulong)array[num] << 56);
		}

		public unsafe override float ReadSingle(uint offset)
		{
			int num = (int)offset;
			byte[] array = data;
			uint num2 = (uint)(array[num++] | (array[num++] << 8) | (array[num++] << 16) | (array[num] << 24));
			return *(float*)(&num2);
		}

		public unsafe override double ReadDouble(uint offset)
		{
			int num = (int)offset;
			byte[] array = data;
			ulong num2 = array[num++] | ((ulong)array[num++] << 8) | ((ulong)array[num++] << 16) | ((ulong)array[num++] << 24) | ((ulong)array[num++] << 32) | ((ulong)array[num++] << 40) | ((ulong)array[num++] << 48) | ((ulong)array[num] << 56);
			return *(double*)(&num2);
		}

		public unsafe override string ReadUtf16String(uint offset, int chars)
		{
			fixed (byte* ptr = data)
			{
				return new string((char*)(ptr + offset), 0, chars);
			}
		}

		public unsafe override string ReadString(uint offset, int length, Encoding encoding)
		{
			fixed (byte* ptr = data)
			{
				return new string((sbyte*)(ptr + offset), 0, length, encoding);
			}
		}

		public unsafe override bool TryGetOffsetOf(uint offset, uint endOffset, byte value, out uint valueOffset)
		{
			fixed (byte* ptr = data)
			{
				byte* ptr2 = ptr + offset;
				uint num = (endOffset - offset) / 4;
				for (uint num2 = 0u; num2 < num; num2++)
				{
					if (*ptr2 == value)
					{
						valueOffset = (uint)(ptr2 - ptr);
						return true;
					}
					ptr2++;
					if (*ptr2 == value)
					{
						valueOffset = (uint)(ptr2 - ptr);
						return true;
					}
					ptr2++;
					if (*ptr2 == value)
					{
						valueOffset = (uint)(ptr2 - ptr);
						return true;
					}
					ptr2++;
					if (*ptr2 == value)
					{
						valueOffset = (uint)(ptr2 - ptr);
						return true;
					}
					ptr2++;
				}
				for (byte* ptr3 = ptr + endOffset; ptr2 != ptr3; ptr2++)
				{
					if (*ptr2 == value)
					{
						valueOffset = (uint)(ptr2 - ptr);
						return true;
					}
				}
				valueOffset = 0u;
				return false;
			}
		}
	}
	internal sealed class AlignedNativeMemoryDataStream : DataStream
	{
		private unsafe readonly byte* data;

		public unsafe AlignedNativeMemoryDataStream(byte* data)
		{
			this.data = data;
		}

		public unsafe override void ReadBytes(uint offset, void* destination, int length)
		{
			byte* ptr = data + offset;
			byte* ptr2 = (byte*)destination;
			int num = length / 4;
			length %= 4;
			for (int i = 0; i < num; i++)
			{
				*ptr2 = *ptr;
				ptr2++;
				ptr++;
				*ptr2 = *ptr;
				ptr2++;
				ptr++;
				*ptr2 = *ptr;
				ptr2++;
				ptr++;
				*ptr2 = *ptr;
				ptr2++;
				ptr++;
			}
			int num2 = 0;
			while (num2 < length)
			{
				*ptr2 = *ptr;
				num2++;
				ptr++;
				ptr2++;
			}
		}

		public unsafe override void ReadBytes(uint offset, byte[] destination, int destinationIndex, int length)
		{
			Marshal.Copy((IntPtr)(data + offset), destination, destinationIndex, length);
		}

		public unsafe override byte ReadByte(uint offset)
		{
			return data[offset];
		}

		public unsafe override ushort ReadUInt16(uint offset)
		{
			byte* ptr = data + offset;
			return (ushort)(*(ptr++) | (*ptr << 8));
		}

		public unsafe override uint ReadUInt32(uint offset)
		{
			byte* ptr = data + offset;
			return (uint)(*(ptr++) | (*(ptr++) << 8) | (*(ptr++) << 16) | (*ptr << 24));
		}

		public unsafe override ulong ReadUInt64(uint offset)
		{
			byte* ptr = data + offset;
			return *(ptr++) | ((ulong)(*(ptr++)) << 8) | ((ulong)(*(ptr++)) << 16) | ((ulong)(*(ptr++)) << 24) | ((ulong)(*(ptr++)) << 32) | ((ulong)(*(ptr++)) << 40) | ((ulong)(*(ptr++)) << 48) | ((ulong)(*ptr) << 56);
		}

		public unsafe override float ReadSingle(uint offset)
		{
			byte* ptr = data + offset;
			uint num = (uint)(*(ptr++) | (*(ptr++) << 8) | (*(ptr++) << 16) | (*ptr << 24));
			return *(float*)(&num);
		}

		public unsafe override double ReadDouble(uint offset)
		{
			byte* ptr = data + offset;
			ulong num = *(ptr++) | ((ulong)(*(ptr++)) << 8) | ((ulong)(*(ptr++)) << 16) | ((ulong)(*(ptr++)) << 24) | ((ulong)(*(ptr++)) << 32) | ((ulong)(*(ptr++)) << 40) | ((ulong)(*(ptr++)) << 48) | ((ulong)(*ptr) << 56);
			return *(double*)(&num);
		}

		public unsafe override string ReadUtf16String(uint offset, int chars)
		{
			return new string((char*)(data + offset), 0, chars);
		}

		public unsafe override string ReadString(uint offset, int length, Encoding encoding)
		{
			return new string((sbyte*)(data + offset), 0, length, encoding);
		}

		public unsafe override bool TryGetOffsetOf(uint offset, uint endOffset, byte value, out uint valueOffset)
		{
			byte* ptr = data;
			byte* ptr2 = ptr + offset;
			uint num = (endOffset - offset) / 4;
			for (uint num2 = 0u; num2 < num; num2++)
			{
				if (*ptr2 == value)
				{
					valueOffset = (uint)(ptr2 - ptr);
					return true;
				}
				ptr2++;
				if (*ptr2 == value)
				{
					valueOffset = (uint)(ptr2 - ptr);
					return true;
				}
				ptr2++;
				if (*ptr2 == value)
				{
					valueOffset = (uint)(ptr2 - ptr);
					return true;
				}
				ptr2++;
				if (*ptr2 == value)
				{
					valueOffset = (uint)(ptr2 - ptr);
					return true;
				}
				ptr2++;
			}
			for (byte* ptr3 = ptr + endOffset; ptr2 != ptr3; ptr2++)
			{
				if (*ptr2 == value)
				{
					valueOffset = (uint)(ptr2 - ptr);
					return true;
				}
			}
			valueOffset = 0u;
			return false;
		}
	}
	public sealed class ByteArrayDataReaderFactory : DataReaderFactory
	{
		private DataStream stream;

		private string filename;

		private uint length;

		private byte[] data;

		public override string Filename => filename;

		public override uint Length => length;

		internal byte[] DataArray => data;

		internal uint DataOffset => 0u;

		private ByteArrayDataReaderFactory(byte[] data, string filename)
		{
			this.filename = filename;
			length = (uint)data.Length;
			stream = DataStreamFactory.Create(data);
			this.data = data;
		}

		public static ByteArrayDataReaderFactory Create(byte[] data, string filename)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			return new ByteArrayDataReaderFactory(data, filename);
		}

		public static DataReader CreateReader(byte[] data)
		{
			return Create(data, null).CreateReader();
		}

		public override DataReader CreateReader(uint offset, uint length)
		{
			return CreateReader(stream, offset, length);
		}

		public override void Dispose()
		{
			stream = EmptyDataStream.Instance;
			length = 0u;
			filename = null;
			data = null;
		}
	}
	[Serializable]
	public sealed class DataReaderException : IOException
	{
		internal DataReaderException(string message)
			: base(message)
		{
		}

		internal DataReaderException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	[DebuggerDisplay("{StartOffset,h}-{EndOffset,h} Length={Length} BytesLeft={BytesLeft}")]
	public struct DataReader
	{
		private readonly DataStream stream;

		private readonly uint startOffset;

		private readonly uint endOffset;

		private uint currentOffset;

		public uint StartOffset => startOffset;

		public uint EndOffset => endOffset;

		public uint Length => endOffset - startOffset;

		public uint CurrentOffset
		{
			get
			{
				return currentOffset;
			}
			set
			{
				if (value < startOffset || value > endOffset)
				{
					ThrowDataReaderException("Invalid new CurrentOffset");
				}
				currentOffset = value;
			}
		}

		public uint Position
		{
			get
			{
				return currentOffset - startOffset;
			}
			set
			{
				if (value > Length)
				{
					ThrowDataReaderException("Invalid new Position");
				}
				currentOffset = startOffset + value;
			}
		}

		public uint BytesLeft => endOffset - currentOffset;

		public DataReader(DataStream stream, uint offset, uint length)
		{
			this.stream = stream;
			startOffset = offset;
			endOffset = offset + length;
			currentOffset = offset;
		}

		[Conditional("DEBUG")]
		private void VerifyState()
		{
		}

		private static void ThrowNoMoreBytesLeft()
		{
			throw new DataReaderException("There's not enough bytes left to read");
		}

		private static void ThrowDataReaderException(string message)
		{
			throw new DataReaderException(message);
		}

		private static void ThrowInvalidOperationException()
		{
			throw new InvalidOperationException();
		}

		private static void ThrowArgumentNullException(string paramName)
		{
			throw new ArgumentNullException(paramName);
		}

		private static void ThrowInvalidArgument(string paramName)
		{
			throw new DataReaderException("Invalid argument value");
		}

		public void Reset()
		{
			currentOffset = startOffset;
		}

		public DataReader Slice(uint start, uint length)
		{
			if ((ulong)((long)start + (long)length) > (ulong)Length)
			{
				ThrowInvalidArgument("length");
			}
			return new DataReader(stream, startOffset + start, length);
		}

		public DataReader Slice(uint start)
		{
			if (start > Length)
			{
				ThrowInvalidArgument("start");
			}
			return Slice(start, Length - start);
		}

		public DataReader Slice(int start, int length)
		{
			if (start < 0)
			{
				ThrowInvalidArgument("start");
			}
			if (length < 0)
			{
				ThrowInvalidArgument("length");
			}
			return Slice((uint)start, (uint)length);
		}

		public DataReader Slice(int start)
		{
			if (start < 0)
			{
				ThrowInvalidArgument("start");
			}
			if ((uint)start > Length)
			{
				ThrowInvalidArgument("start");
			}
			return Slice((uint)start, Length - (uint)start);
		}

		public bool CanRead(int length)
		{
			if (length >= 0)
			{
				return (uint)length <= BytesLeft;
			}
			return false;
		}

		public bool CanRead(uint length)
		{
			return length <= BytesLeft;
		}

		public bool ReadBoolean()
		{
			return ReadByte() != 0;
		}

		public char ReadChar()
		{
			return (char)ReadUInt16();
		}

		public sbyte ReadSByte()
		{
			return (sbyte)ReadByte();
		}

		public byte ReadByte()
		{
			uint num = currentOffset;
			if (num == endOffset)
			{
				ThrowNoMoreBytesLeft();
			}
			byte result = stream.ReadByte(num);
			currentOffset = num + 1;
			return result;
		}

		public short ReadInt16()
		{
			return (short)ReadUInt16();
		}

		public ushort ReadUInt16()
		{
			uint num = currentOffset;
			if (endOffset - num < 2)
			{
				ThrowNoMoreBytesLeft();
			}
			ushort result = stream.ReadUInt16(num);
			currentOffset = num + 2;
			return result;
		}

		public int ReadInt32()
		{
			return (int)ReadUInt32();
		}

		public uint ReadUInt32()
		{
			uint num = currentOffset;
			if (endOffset - num < 4)
			{
				ThrowNoMoreBytesLeft();
			}
			uint result = stream.ReadUInt32(num);
			currentOffset = num + 4;
			return result;
		}

		internal byte Unsafe_ReadByte()
		{
			uint num = currentOffset;
			byte result = stream.ReadByte(num);
			currentOffset = num + 1;
			return result;
		}

		internal ushort Unsafe_ReadUInt16()
		{
			uint num = currentOffset;
			ushort result = stream.ReadUInt16(num);
			currentOffset = num + 2;
			return result;
		}

		internal uint Unsafe_ReadUInt32()
		{
			uint num = currentOffset;
			uint result = stream.ReadUInt32(num);
			currentOffset = num + 4;
			return result;
		}

		public long ReadInt64()
		{
			return (long)ReadUInt64();
		}

		public ulong ReadUInt64()
		{
			uint num = currentOffset;
			if (endOffset - num < 8)
			{
				ThrowNoMoreBytesLeft();
			}
			ulong result = stream.ReadUInt64(num);
			currentOffset = num + 8;
			return result;
		}

		public float ReadSingle()
		{
			uint num = currentOffset;
			if (endOffset - num < 4)
			{
				ThrowNoMoreBytesLeft();
			}
			float result = stream.ReadSingle(num);
			currentOffset = num + 4;
			return result;
		}

		public double ReadDouble()
		{
			uint num = currentOffset;
			if (endOffset - num < 8)
			{
				ThrowNoMoreBytesLeft();
			}
			double result = stream.ReadDouble(num);
			currentOffset = num + 8;
			return result;
		}

		public Guid ReadGuid()
		{
			uint num = currentOffset;
			if (endOffset - num < 16)
			{
				ThrowNoMoreBytesLeft();
			}
			Guid result = stream.ReadGuid(num);
			currentOffset = num + 16;
			return result;
		}

		public decimal ReadDecimal()
		{
			return new decimal(new int[4]
			{
				ReadInt32(),
				ReadInt32(),
				ReadInt32(),
				ReadInt32()
			});
		}

		public string ReadUtf16String(int chars)
		{
			if (chars < 0)
			{
				ThrowInvalidArgument("chars");
			}
			if (chars == 0)
			{
				return string.Empty;
			}
			uint num = (uint)(chars * 2);
			uint num2 = currentOffset;
			if (endOffset - num2 < num)
			{
				ThrowNoMoreBytesLeft();
			}
			string result = ((num == 0) ? string.Empty : stream.ReadUtf16String(num2, chars));
			currentOffset = num2 + num;
			return result;
		}

		public unsafe void ReadBytes(void* destination, int length)
		{
			if (destination == null && length != 0)
			{
				ThrowArgumentNullException("destination");
			}
			if (length < 0)
			{
				ThrowInvalidArgument("length");
			}
			if (length != 0)
			{
				uint num = currentOffset;
				if (endOffset - num < (uint)length)
				{
					ThrowNoMoreBytesLeft();
				}
				stream.ReadBytes(num, destination, length);
				currentOffset = num + (uint)length;
			}
		}

		public void ReadBytes(byte[] destination, int destinationIndex, int length)
		{
			if (destination == null)
			{
				ThrowArgumentNullException("destination");
			}
			if (destinationIndex < 0)
			{
				ThrowInvalidArgument("destinationIndex");
			}
			if (length < 0)
			{
				ThrowInvalidArgument("length");
			}
			if (length != 0)
			{
				uint num = currentOffset;
				if (endOffset - num < (uint)length)
				{
					ThrowNoMoreBytesLeft();
				}
				stream.ReadBytes(num, destination, destinationIndex, length);
				currentOffset = num + (uint)length;
			}
		}

		public byte[] ReadBytes(int length)
		{
			if (length < 0)
			{
				ThrowInvalidArgument("length");
			}
			if (length == 0)
			{
				return Array2.Empty<byte>();
			}
			byte[] array = new byte[length];
			ReadBytes(array, 0, length);
			return array;
		}

		public bool TryReadCompressedUInt32(out uint value)
		{
			uint num = currentOffset;
			uint num2 = endOffset - num;
			if (num2 == 0)
			{
				value = 0u;
				return false;
			}
			DataStream dataStream = stream;
			byte b = dataStream.ReadByte(num++);
			if ((b & 0x80) == 0)
			{
				value = b;
				currentOffset = num;
				return true;
			}
			if ((b & 0xC0) == 128)
			{
				if (num2 < 2)
				{
					value = 0u;
					return false;
				}
				value = (uint)(((b & 0x3F) << 8) | dataStream.ReadByte(num++));
				currentOffset = num;
				return true;
			}
			if (num2 < 4)
			{
				value = 0u;
				return false;
			}
			value = (uint)(((b & 0x1F) << 24) | (dataStream.ReadByte(num++) << 16) | (dataStream.ReadByte(num++) << 8) | dataStream.ReadByte(num++));
			currentOffset = num;
			return true;
		}

		public uint ReadCompressedUInt32()
		{
			if (!TryReadCompressedUInt32(out var value))
			{
				ThrowNoMoreBytesLeft();
			}
			return value;
		}

		public bool TryReadCompressedInt32(out int value)
		{
			uint num = currentOffset;
			uint num2 = endOffset - num;
			if (num2 == 0)
			{
				value = 0;
				return false;
			}
			DataStream dataStream = stream;
			byte b = dataStream.ReadByte(num++);
			if ((b & 0x80) == 0)
			{
				if (((uint)b & (true ? 1u : 0u)) != 0)
				{
					value = -64 | (b >> 1);
				}
				else
				{
					value = b >> 1;
				}
				currentOffset = num;
				return true;
			}
			if ((b & 0xC0) == 128)
			{
				if (num2 < 2)
				{
					value = 0;
					return false;
				}
				uint num3 = (uint)(((b & 0x3F) << 8) | dataStream.ReadByte(num++));
				if ((num3 & (true ? 1u : 0u)) != 0)
				{
					value = -8192 | (int)(num3 >> 1);
				}
				else
				{
					value = (int)(num3 >> 1);
				}
				currentOffset = num;
				return true;
			}
			if ((b & 0xE0) == 192)
			{
				if (num2 < 4)
				{
					value = 0;
					return false;
				}
				uint num4 = (uint)(((b & 0x1F) << 24) | (dataStream.ReadByte(num++) << 16) | (dataStream.ReadByte(num++) << 8) | dataStream.ReadByte(num++));
				if ((num4 & (true ? 1u : 0u)) != 0)
				{
					value = -268435456 | (int)(num4 >> 1);
				}
				else
				{
					value = (int)(num4 >> 1);
				}
				currentOffset = num;
				return true;
			}
			value = 0;
			return false;
		}

		public int ReadCompressedInt32()
		{
			if (!TryReadCompressedInt32(out var value))
			{
				ThrowNoMoreBytesLeft();
			}
			return value;
		}

		public uint Read7BitEncodedUInt32()
		{
			uint num = 0u;
			int num2 = 0;
			for (int i = 0; i < 5; i++)
			{
				byte b = ReadByte();
				num |= (uint)((b & 0x7F) << num2);
				if ((b & 0x80) == 0)
				{
					return num;
				}
				num2 += 7;
			}
			ThrowDataReaderException("Invalid encoded UInt32");
			return 0u;
		}

		public int Read7BitEncodedInt32()
		{
			return (int)Read7BitEncodedUInt32();
		}

		public string ReadSerializedString()
		{
			return ReadSerializedString(Encoding.UTF8);
		}

		public string ReadSerializedString(Encoding encoding)
		{
			if (encoding == null)
			{
				ThrowArgumentNullException("encoding");
			}
			int num = Read7BitEncodedInt32();
			if (num < 0)
			{
				ThrowNoMoreBytesLeft();
			}
			if (num == 0)
			{
				return string.Empty;
			}
			return ReadString(num, encoding);
		}

		public byte[] ToArray()
		{
			int length = (int)Length;
			if (length < 0)
			{
				ThrowInvalidOperationException();
			}
			if (length == 0)
			{
				return Array2.Empty<byte>();
			}
			byte[] array = new byte[length];
			stream.ReadBytes(startOffset, array, 0, array.Length);
			return array;
		}

		public byte[] ReadRemainingBytes()
		{
			int bytesLeft = (int)BytesLeft;
			if (bytesLeft < 0)
			{
				ThrowInvalidOperationException();
			}
			return ReadBytes(bytesLeft);
		}

		public byte[] TryReadBytesUntil(byte value)
		{
			uint num = currentOffset;
			uint num2 = endOffset;
			if (num == num2)
			{
				return null;
			}
			if (!stream.TryGetOffsetOf(num, num2, value, out var valueOffset))
			{
				return null;
			}
			int num3 = (int)(valueOffset - num);
			if (num3 < 0)
			{
				return null;
			}
			return ReadBytes(num3);
		}

		public string TryReadZeroTerminatedUtf8String()
		{
			return TryReadZeroTerminatedString(Encoding.UTF8);
		}

		public string TryReadZeroTerminatedString(Encoding encoding)
		{
			if (encoding == null)
			{
				ThrowArgumentNullException("encoding");
			}
			uint num = currentOffset;
			uint num2 = endOffset;
			if (num == num2)
			{
				return null;
			}
			if (!stream.TryGetOffsetOf(num, num2, 0, out var valueOffset))
			{
				return null;
			}
			int num3 = (int)(valueOffset - num);
			if (num3 < 0)
			{
				return null;
			}
			string result = ((num3 == 0) ? string.Empty : stream.ReadString(num, num3, encoding));
			currentOffset = valueOffset + 1;
			return result;
		}

		public string ReadUtf8String(int byteCount)
		{
			return ReadString(byteCount, Encoding.UTF8);
		}

		public string ReadString(int byteCount, Encoding encoding)
		{
			if (byteCount < 0)
			{
				ThrowInvalidArgument("byteCount");
			}
			if (encoding == null)
			{
				ThrowArgumentNullException("encoding");
			}
			if (byteCount == 0)
			{
				return string.Empty;
			}
			if ((uint)byteCount > Length)
			{
				ThrowInvalidArgument("byteCount");
			}
			uint num = currentOffset;
			string result = stream.ReadString(num, byteCount, encoding);
			currentOffset = num + (uint)byteCount;
			return result;
		}

		public Stream AsStream()
		{
			return new DataReaderStream(ref this);
		}

		private byte[] AllocTempBuffer()
		{
			return new byte[Math.Min(8192u, BytesLeft)];
		}

		public void CopyTo(DataWriter destination)
		{
			if (destination == null)
			{
				ThrowArgumentNullException("destination");
			}
			if (Position < Length)
			{
				CopyTo(destination.InternalStream, AllocTempBuffer());
			}
		}

		public void CopyTo(DataWriter destination, byte[] dataBuffer)
		{
			if (destination == null)
			{
				ThrowArgumentNullException("destination");
			}
			CopyTo(destination.InternalStream, dataBuffer);
		}

		public void CopyTo(BinaryWriter destination)
		{
			if (destination == null)
			{
				ThrowArgumentNullException("destination");
			}
			if (Position < Length)
			{
				CopyTo(destination.BaseStream, AllocTempBuffer());
			}
		}

		public void CopyTo(BinaryWriter destination, byte[] dataBuffer)
		{
			if (destination == null)
			{
				ThrowArgumentNullException("destination");
			}
			CopyTo(destination.BaseStream, dataBuffer);
		}

		public void CopyTo(Stream destination)
		{
			if (destination == null)
			{
				ThrowArgumentNullException("destination");
			}
			if (Position < Length)
			{
				CopyTo(destination, AllocTempBuffer());
			}
		}

		public void CopyTo(Stream destination, byte[] dataBuffer)
		{
			if (destination == null)
			{
				ThrowArgumentNullException("destination");
			}
			if (dataBuffer == null)
			{
				ThrowArgumentNullException("dataBuffer");
			}
			if (Position < Length)
			{
				if (dataBuffer.Length == 0)
				{
					ThrowInvalidArgument("dataBuffer");
				}
				uint num = BytesLeft;
				while (num != 0)
				{
					int num2 = (int)Math.Min((uint)dataBuffer.Length, num);
					num -= (uint)num2;
					ReadBytes(dataBuffer, 0, num2);
					destination.Write(dataBuffer, 0, num2);
				}
			}
		}
	}
	public abstract class DataReaderFactory : IDisposable
	{
		public abstract string Filename { get; }

		public abstract uint Length { get; }

		public virtual event EventHandler DataReaderInvalidated
		{
			add
			{
			}
			remove
			{
			}
		}

		public DataReader CreateReader()
		{
			return CreateReader(0u, Length);
		}

		public abstract DataReader CreateReader(uint offset, uint length);

		private static void ThrowArgumentOutOfRangeException(string paramName)
		{
			throw new ArgumentOutOfRangeException(paramName);
		}

		private static void Throw_CreateReader_2(int offset, int length)
		{
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			throw new ArgumentOutOfRangeException("length");
		}

		public DataReader CreateReader(uint offset, int length)
		{
			if (length < 0)
			{
				ThrowArgumentOutOfRangeException("length");
			}
			return CreateReader(offset, (uint)length);
		}

		public DataReader CreateReader(int offset, uint length)
		{
			if (offset < 0)
			{
				ThrowArgumentOutOfRangeException("offset");
			}
			return CreateReader((uint)offset, length);
		}

		public DataReader CreateReader(int offset, int length)
		{
			if (offset < 0 || length < 0)
			{
				Throw_CreateReader_2(offset, length);
			}
			return CreateReader((uint)offset, (uint)length);
		}

		protected DataReader CreateReader(DataStream stream, uint offset, uint length)
		{
			uint length2 = Length;
			if (offset > length2)
			{
				offset = length2;
			}
			if ((ulong)((long)offset + (long)length) > (ulong)length2)
			{
				length = length2 - offset;
			}
			return new DataReader(stream, offset, length);
		}

		public abstract void Dispose();
	}
	internal static class DataReaderFactoryFactory
	{
		private static readonly bool isUnix;

		static DataReaderFactoryFactory()
		{
			int platform = (int)Environment.OSVersion.Platform;
			if (platform == 4 || platform == 6 || platform == 128)
			{
				isUnix = true;
			}
		}

		public static DataReaderFactory Create(string fileName, bool mapAsImage)
		{
			DataReaderFactory dataReaderFactory = CreateDataReaderFactory(fileName, mapAsImage);
			if (dataReaderFactory != null)
			{
				return dataReaderFactory;
			}
			return ByteArrayDataReaderFactory.Create(File.ReadAllBytes(fileName), fileName);
		}

		private static DataReaderFactory CreateDataReaderFactory(string fileName, bool mapAsImage)
		{
			if (!isUnix)
			{
				return MemoryMappedDataReaderFactory.CreateWindows(fileName, mapAsImage);
			}
			return MemoryMappedDataReaderFactory.CreateUnix(fileName, mapAsImage);
		}
	}
	internal sealed class DataReaderStream : Stream
	{
		private DataReader reader;

		private long position;

		public override bool CanRead => true;

		public override bool CanSeek => true;

		public override bool CanWrite => false;

		public override long Length => reader.Length;

		public override long Position
		{
			get
			{
				return position;
			}
			set
			{
				position = value;
			}
		}

		public DataReaderStream(ref DataReader reader)
		{
			this.reader = reader;
			position = reader.Position;
		}

		public override void Flush()
		{
		}

		private bool CheckAndSetPosition()
		{
			if (position < 0 || position > reader.Length)
			{
				return false;
			}
			reader.Position = (uint)position;
			return true;
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			switch (origin)
			{
			case SeekOrigin.Begin:
				Position = offset;
				break;
			case SeekOrigin.Current:
				Position += offset;
				break;
			case SeekOrigin.End:
				Position = Length + offset;
				break;
			}
			return Position;
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			if (offset < 0)
			{
				throw new ArgumentOutOfRangeException("offset");
			}
			if (count < 0)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			if (!CheckAndSetPosition())
			{
				return 0;
			}
			int num = (int)Math.Min((uint)count, reader.BytesLeft);
			reader.ReadBytes(buffer, offset, num);
			Position += num;
			return num;
		}

		public override int ReadByte()
		{
			if (!CheckAndSetPosition() || !reader.CanRead(1u))
			{
				return -1;
			}
			Position++;
			return reader.ReadByte();
		}

		public override void SetLength(long value)
		{
			throw new NotSupportedException();
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			throw new NotSupportedException();
		}
	}
	public abstract class DataStream
	{
		public unsafe abstract void ReadBytes(uint offset, void* destination, int length);

		public abstract void ReadBytes(uint offset, byte[] destination, int destinationIndex, int length);

		public abstract byte ReadByte(uint offset);

		public abstract ushort ReadUInt16(uint offset);

		public abstract uint ReadUInt32(uint offset);

		public abstract ulong ReadUInt64(uint offset);

		public abstract float ReadSingle(uint offset);

		public abstract double ReadDouble(uint offset);

		public virtual Guid ReadGuid(uint offset)
		{
			return new Guid(ReadUInt32(offset), ReadUInt16(offset + 4), ReadUInt16(offset + 6), ReadByte(offset + 8), ReadByte(offset + 9), ReadByte(offset + 10), ReadByte(offset + 11), ReadByte(offset + 12), ReadByte(offset + 13), ReadByte(offset + 14), ReadByte(offset + 15));
		}

		public abstract string ReadUtf16String(uint offset, int chars);

		public abstract string ReadString(uint offset, int length, Encoding encoding);

		public abstract bool TryGetOffsetOf(uint offset, uint endOffset, byte value, out uint valueOffset);
	}
	public static class DataStreamFactory
	{
		private static bool supportsUnalignedAccesses = CalculateSupportsUnalignedAccesses();

		private static bool CalculateSupportsUnalignedAccesses()
		{
			switch (ProcessorArchUtils.GetProcessCpuArchitecture())
			{
			case Machine.I386:
			case Machine.AMD64:
				return true;
			case Machine.ARMNT:
			case Machine.ARM64:
				return false;
			default:
				return true;
			}
		}

		public unsafe static DataStream Create(byte* data)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			if (supportsUnali

UMM/Core/UnityModManager.dll

Decompiled 2 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml.Serialization;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TinyJson;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using UnityModManagerNet;
using dnlib.DotNet;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("newman55")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2019-2025")]
[assembly: AssemblyDescription("Mod manager for Unity games.")]
[assembly: AssemblyFileVersion("0.32.4")]
[assembly: AssemblyInformationalVersion("0.32.4+e166d51d08c558c16332a1fbfb6a207746110663")]
[assembly: AssemblyProduct("UnityModManager")]
[assembly: AssemblyTitle("UnityModManager")]
[assembly: NeutralResourcesLanguage("en-001")]
[assembly: AssemblyVersion("0.32.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TinyJson
{
	public static class JSONParser
	{
		[ThreadStatic]
		private static Stack<List<string>> splitArrayPool;

		[ThreadStatic]
		private static StringBuilder stringBuilder;

		[ThreadStatic]
		private static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache;

		[ThreadStatic]
		private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache;

		public static T FromJson<T>(this string json)
		{
			if (propertyInfoCache == null)
			{
				propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
			}
			if (fieldInfoCache == null)
			{
				fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>>();
			}
			if (stringBuilder == null)
			{
				stringBuilder = new StringBuilder();
			}
			if (splitArrayPool == null)
			{
				splitArrayPool = new Stack<List<string>>();
			}
			stringBuilder.Length = 0;
			for (int i = 0; i < json.Length; i++)
			{
				char c = json[i];
				if (c == '"')
				{
					i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json);
				}
				else if (!char.IsWhiteSpace(c))
				{
					stringBuilder.Append(c);
				}
			}
			return (T)ParseValue(typeof(T), stringBuilder.ToString());
		}

		private static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
		{
			stringBuilder.Append(json[startIdx]);
			for (int i = startIdx + 1; i < json.Length; i++)
			{
				if (json[i] == '\\')
				{
					if (appendEscapeCharacter)
					{
						stringBuilder.Append(json[i]);
					}
					stringBuilder.Append(json[i + 1]);
					i++;
				}
				else
				{
					if (json[i] == '"')
					{
						stringBuilder.Append(json[i]);
						return i;
					}
					stringBuilder.Append(json[i]);
				}
			}
			return json.Length - 1;
		}

		private static List<string> Split(string json)
		{
			List<string> list = ((splitArrayPool.Count > 0) ? splitArrayPool.Pop() : new List<string>());
			list.Clear();
			if (json.Length == 2)
			{
				return list;
			}
			int num = 0;
			stringBuilder.Length = 0;
			for (int i = 1; i < json.Length - 1; i++)
			{
				switch (json[i])
				{
				case '[':
				case '{':
					num++;
					break;
				case ']':
				case '}':
					num--;
					break;
				case '"':
					i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json);
					continue;
				case ',':
				case ':':
					if (num == 0)
					{
						list.Add(stringBuilder.ToString());
						stringBuilder.Length = 0;
						continue;
					}
					break;
				}
				stringBuilder.Append(json[i]);
			}
			list.Add(stringBuilder.ToString());
			return list;
		}

		internal static object ParseValue(Type type, string json)
		{
			if ((object)type == typeof(string))
			{
				if (json.Length <= 2)
				{
					return string.Empty;
				}
				StringBuilder stringBuilder = new StringBuilder(json.Length);
				for (int i = 1; i < json.Length - 1; i++)
				{
					if (json[i] == '\\' && i + 1 < json.Length - 1)
					{
						int num = "\"\\nrtbf/".IndexOf(json[i + 1]);
						if (num >= 0)
						{
							stringBuilder.Append("\"\\\n\r\t\b\f/"[num]);
							i++;
							continue;
						}
						if (json[i + 1] == 'u' && i + 5 < json.Length - 1)
						{
							uint result = 0u;
							if (uint.TryParse(json.Substring(i + 2, 4), NumberStyles.AllowHexSpecifier, null, out result))
							{
								stringBuilder.Append((char)result);
								i += 5;
								continue;
							}
						}
					}
					stringBuilder.Append(json[i]);
				}
				return stringBuilder.ToString();
			}
			if (type.IsPrimitive)
			{
				return Convert.ChangeType(json, type, CultureInfo.InvariantCulture);
			}
			if ((object)type == typeof(decimal))
			{
				decimal.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2);
				return result2;
			}
			if (json == "null")
			{
				return null;
			}
			if (type.IsEnum)
			{
				if (json[0] == '"')
				{
					json = json.Substring(1, json.Length - 2);
				}
				try
				{
					return Enum.Parse(type, json, ignoreCase: false);
				}
				catch
				{
					return 0;
				}
			}
			if (type.IsArray)
			{
				Type elementType = type.GetElementType();
				if (json[0] != '[' || json[json.Length - 1] != ']')
				{
					return null;
				}
				List<string> list = Split(json);
				Array array = Array.CreateInstance(elementType, list.Count);
				for (int j = 0; j < list.Count; j++)
				{
					array.SetValue(ParseValue(elementType, list[j]), j);
				}
				splitArrayPool.Push(list);
				return array;
			}
			if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(List<>))
			{
				Type type2 = type.GetGenericArguments()[0];
				if (json[0] != '[' || json[json.Length - 1] != ']')
				{
					return null;
				}
				List<string> list2 = Split(json);
				IList list3 = (IList)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list2.Count });
				for (int k = 0; k < list2.Count; k++)
				{
					list3.Add(ParseValue(type2, list2[k]));
				}
				splitArrayPool.Push(list2);
				return list3;
			}
			if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(Dictionary<, >))
			{
				Type[] genericArguments = type.GetGenericArguments();
				Type type3 = genericArguments[0];
				Type type4 = genericArguments[1];
				if ((object)type3 != typeof(string))
				{
					return null;
				}
				if (json[0] != '{' || json[json.Length - 1] != '}')
				{
					return null;
				}
				List<string> list4 = Split(json);
				if (list4.Count % 2 != 0)
				{
					return null;
				}
				IDictionary dictionary = (IDictionary)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list4.Count / 2 });
				for (int l = 0; l < list4.Count; l += 2)
				{
					if (list4[l].Length > 2)
					{
						string key = list4[l].Substring(1, list4[l].Length - 2);
						object value = ParseValue(type4, list4[l + 1]);
						dictionary.Add(key, value);
					}
				}
				return dictionary;
			}
			if ((object)type == typeof(object))
			{
				return ParseAnonymousValue(json);
			}
			if (json[0] == '{' && json[json.Length - 1] == '}')
			{
				return ParseObject(type, json);
			}
			return null;
		}

		private static object ParseAnonymousValue(string json)
		{
			if (json.Length == 0)
			{
				return null;
			}
			if (json[0] == '{' && json[json.Length - 1] == '}')
			{
				List<string> list = Split(json);
				if (list.Count % 2 != 0)
				{
					return null;
				}
				Dictionary<string, object> dictionary = new Dictionary<string, object>(list.Count / 2);
				for (int i = 0; i < list.Count; i += 2)
				{
					dictionary.Add(list[i].Substring(1, list[i].Length - 2), ParseAnonymousValue(list[i + 1]));
				}
				return dictionary;
			}
			if (json[0] == '[' && json[json.Length - 1] == ']')
			{
				List<string> list2 = Split(json);
				List<object> list3 = new List<object>(list2.Count);
				for (int j = 0; j < list2.Count; j++)
				{
					list3.Add(ParseAnonymousValue(list2[j]));
				}
				return list3;
			}
			if (json[0] == '"' && json[json.Length - 1] == '"')
			{
				return json.Substring(1, json.Length - 2).Replace("\\", string.Empty);
			}
			if (char.IsDigit(json[0]) || json[0] == '-')
			{
				if (json.Contains("."))
				{
					double.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result);
					return result;
				}
				int.TryParse(json, out var result2);
				return result2;
			}
			if (json == "true")
			{
				return true;
			}
			if (json == "false")
			{
				return false;
			}
			return null;
		}

		private static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members) where T : MemberInfo
		{
			Dictionary<string, T> dictionary = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
			foreach (T val in members)
			{
				string name = val.Name;
				if (val.GetCustomAttributes(typeof(IgnoreJsonAttribute), inherit: false).Length == 0)
				{
					dictionary.Add(name, val);
				}
			}
			return dictionary;
		}

		private static object ParseObject(Type type, string json)
		{
			object uninitializedObject = FormatterServices.GetUninitializedObject(type);
			List<string> list = Split(json);
			if (list.Count % 2 != 0)
			{
				return uninitializedObject;
			}
			if (!fieldInfoCache.TryGetValue(type, out var value))
			{
				value = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
				fieldInfoCache.Add(type, value);
			}
			if (!propertyInfoCache.TryGetValue(type, out var value2))
			{
				value2 = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
				propertyInfoCache.Add(type, value2);
			}
			for (int i = 0; i < list.Count; i += 2)
			{
				if (list[i].Length > 2)
				{
					string key = list[i].Substring(1, list[i].Length - 2);
					string json2 = list[i + 1];
					PropertyInfo value4;
					if (value.TryGetValue(key, out var value3))
					{
						value3.SetValue(uninitializedObject, ParseValue(value3.FieldType, json2));
					}
					else if (value2.TryGetValue(key, out value4))
					{
						value4.SetValue(uninitializedObject, ParseValue(value4.PropertyType, json2), null);
					}
				}
			}
			return uninitializedObject;
		}
	}
	public static class JSONWriter
	{
		public static string ToJson(this object item)
		{
			StringBuilder stringBuilder = new StringBuilder();
			AppendValue(stringBuilder, item);
			return stringBuilder.ToString();
		}

		private static void AppendValue(StringBuilder stringBuilder, object item)
		{
			if (item == null)
			{
				stringBuilder.Append("null");
				return;
			}
			Type type = item.GetType();
			if ((object)type == typeof(string))
			{
				stringBuilder.Append('"');
				string text = (string)item;
				for (int i = 0; i < text.Length; i++)
				{
					if (text[i] < ' ' || text[i] == '"' || text[i] == '\\')
					{
						stringBuilder.Append('\\');
						int num = "\"\\\n\r\t\b\f".IndexOf(text[i]);
						if (num >= 0)
						{
							stringBuilder.Append("\"\\nrtbf"[num]);
						}
						else
						{
							stringBuilder.AppendFormat("u{0:X4}", (uint)text[i]);
						}
					}
					else
					{
						stringBuilder.Append(text[i]);
					}
				}
				stringBuilder.Append('"');
				return;
			}
			if ((object)type == typeof(byte) || (object)type == typeof(int))
			{
				stringBuilder.Append(item.ToString());
				return;
			}
			if ((object)type == typeof(float))
			{
				stringBuilder.Append(((float)item).ToString(CultureInfo.InvariantCulture));
				return;
			}
			if ((object)type == typeof(double))
			{
				stringBuilder.Append(((double)item).ToString(CultureInfo.InvariantCulture));
				return;
			}
			if ((object)type == typeof(bool))
			{
				stringBuilder.Append(((bool)item) ? "true" : "false");
				return;
			}
			if (type.IsEnum)
			{
				stringBuilder.Append('"');
				stringBuilder.Append(item.ToString());
				stringBuilder.Append('"');
				return;
			}
			if (item is IList)
			{
				stringBuilder.Append('[');
				bool flag = true;
				IList list = item as IList;
				for (int j = 0; j < list.Count; j++)
				{
					if (flag)
					{
						flag = false;
					}
					else
					{
						stringBuilder.Append(',');
					}
					AppendValue(stringBuilder, list[j]);
				}
				stringBuilder.Append(']');
				return;
			}
			if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(Dictionary<, >))
			{
				if ((object)type.GetGenericArguments()[0] != typeof(string))
				{
					stringBuilder.Append("{}");
					return;
				}
				stringBuilder.Append('{');
				IDictionary dictionary = item as IDictionary;
				bool flag2 = true;
				foreach (object key in dictionary.Keys)
				{
					if (flag2)
					{
						flag2 = false;
					}
					else
					{
						stringBuilder.Append(',');
					}
					stringBuilder.Append('"');
					stringBuilder.Append((string)key);
					stringBuilder.Append("\":");
					AppendValue(stringBuilder, dictionary[key]);
				}
				stringBuilder.Append('}');
				return;
			}
			stringBuilder.Append('{');
			bool flag3 = true;
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
			for (int k = 0; k < fields.Length; k++)
			{
				if (fields[k].GetCustomAttributes(typeof(IgnoreJsonAttribute), inherit: false).Length != 0)
				{
					continue;
				}
				object value = fields[k].GetValue(item);
				if (value != null)
				{
					if (flag3)
					{
						flag3 = false;
					}
					else
					{
						stringBuilder.Append(',');
					}
					stringBuilder.Append('"');
					stringBuilder.Append(GetMemberName(fields[k]));
					stringBuilder.Append("\":");
					AppendValue(stringBuilder, value);
				}
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
			for (int l = 0; l < properties.Length; l++)
			{
				if (properties[l].GetCustomAttributes(typeof(IgnoreJsonAttribute), inherit: false).Length != 0)
				{
					continue;
				}
				object value2 = properties[l].GetValue(item, null);
				if (value2 != null)
				{
					if (flag3)
					{
						flag3 = false;
					}
					else
					{
						stringBuilder.Append(',');
					}
					stringBuilder.Append('"');
					stringBuilder.Append(GetMemberName(properties[l]));
					stringBuilder.Append("\":");
					AppendValue(stringBuilder, value2);
				}
			}
			stringBuilder.Append('}');
		}

		private static string GetMemberName(MemberInfo member)
		{
			return member.Name;
		}
	}
	public class IgnoreJsonAttribute : Attribute
	{
	}
}
namespace Doorstop
{
	public class Entrypoint
	{
		public static void Start()
		{
			UnityModManager.Main();
		}
	}
}
namespace UnityModManagerNet
{
	public class UnityModManager
	{
		public sealed class Param
		{
			[Serializable]
			public class Mod
			{
				[XmlAttribute]
				public string Id;

				[XmlAttribute]
				public bool Enabled = true;

				public KeyBinding Hotkey = new KeyBinding();
			}

			public static KeyBinding DefaultHotkey = new KeyBinding
			{
				keyCode = (KeyCode)291,
				modifiers = 1
			};

			public static KeyBinding EscapeHotkey = new KeyBinding
			{
				keyCode = (KeyCode)27
			};

			public KeyBinding Hotkey = new KeyBinding();

			public int ShowOnStart = 1;

			public float WindowWidth;

			public float WindowHeight;

			public float UIScale = 1f;

			public string UIFont;

			public bool ShownModToggleWarning;

			public List<Mod> ModParams = new List<Mod>();

			private static readonly string filepath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(Param).Assembly.Location), "../Config/UMM/Params.xml"));

			public void Save()
			{
				try
				{
					ModParams.Clear();
					foreach (ModEntry modEntry in modEntries)
					{
						ModParams.Add(new Mod
						{
							Id = modEntry.Info.Id,
							Enabled = modEntry.Enabled,
							Hotkey = modEntry.Hotkey
						});
					}
					Directory.CreateDirectory(Path.GetDirectoryName(filepath));
					using StreamWriter textWriter = new StreamWriter(filepath);
					new XmlSerializer(typeof(Param)).Serialize(textWriter, this);
				}
				catch (Exception ex)
				{
					Logger.Error("Can't write file '" + filepath + "'.");
					Debug.LogException(ex);
				}
			}

			public static Param Load()
			{
				if (File.Exists(filepath))
				{
					try
					{
						using FileStream stream = File.OpenRead(filepath);
						return new XmlSerializer(typeof(Param)).Deserialize(stream) as Param;
					}
					catch (Exception ex)
					{
						Logger.Error("Can't read file '" + filepath + "'.");
						Debug.LogException(ex);
					}
				}
				return new Param();
			}

			internal void ReadModParams()
			{
				foreach (Mod modParam in ModParams)
				{
					ModEntry modEntry = FindMod(modParam.Id);
					if (modEntry != null)
					{
						modEntry.Enabled = modParam.Enabled;
						modEntry.Hotkey = ((modParam.Hotkey != null) ? modParam.Hotkey : new KeyBinding());
					}
				}
			}
		}

		[XmlRoot("Param")]
		public sealed class InstallerParam
		{
			public string APIkey;

			public static InstallerParam Load()
			{
				string text = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnityModManagerNet"), "Params.xml");
				if (File.Exists(text))
				{
					try
					{
						using FileStream stream = File.OpenRead(text);
						return new XmlSerializer(typeof(InstallerParam)).Deserialize(stream) as InstallerParam;
					}
					catch (Exception ex)
					{
						Logger.Error("Can't read file '" + text + "'.");
						Debug.LogException(ex);
					}
				}
				return new InstallerParam();
			}
		}

		[XmlRoot("Config")]
		public class GameInfo
		{
			[XmlAttribute]
			public string ModsDirectory;

			public string RelativeModsDirectory = "../Mods";

			public string ModInfo = "Info.json";

			public string EntryPoint;

			public string StartingPoint;

			public string UIStartingPoint;

			public string TextureReplacingPoint;

			public string SessionStartPoint;

			public string SessionStopPoint;

			public string GameVersionPoint;

			public string MinimalManagerVersion;

			private static readonly string filepath = Path.Combine(Path.GetDirectoryName(typeof(GameInfo).Assembly.Location), "Config.xml");

			public static GameInfo Load()
			{
				try
				{
					if (File.Exists(filepath))
					{
						using (FileStream stream = File.OpenRead(filepath))
						{
							return new XmlSerializer(typeof(GameInfo)).Deserialize(stream) as GameInfo;
						}
					}
					return new GameInfo();
				}
				catch (Exception ex)
				{
					Logger.Error("Can't read file '" + filepath + "'.");
					Debug.LogException(ex);
					return null;
				}
			}
		}

		private class GameScripts
		{
			private class GameScript
			{
				public virtual void OnModToggle(ModEntry modEntry, bool value)
				{
				}

				public virtual void OnBeforeLoadMods()
				{
				}

				public virtual void OnAfterLoadMods()
				{
				}

				public virtual void OnToggleWindow(bool value)
				{
				}
			}

			private static readonly List<GameScript> scripts = new List<GameScript>();

			public static void Init()
			{
			}

			public static void OnBeforeLoadMods()
			{
				foreach (GameScript script in scripts)
				{
					try
					{
						script.OnBeforeLoadMods();
					}
					catch (Exception e)
					{
						Logger.LogException("OnBeforeLoadMods", e);
					}
				}
			}

			public static void OnAfterLoadMods()
			{
				foreach (GameScript script in scripts)
				{
					try
					{
						script.OnAfterLoadMods();
					}
					catch (Exception e)
					{
						Logger.LogException("OnAfterLoadMods", e);
					}
				}
			}

			public static void OnModToggle(ModEntry modEntry, bool value)
			{
				foreach (GameScript script in scripts)
				{
					try
					{
						script.OnModToggle(modEntry, value);
					}
					catch (Exception e)
					{
						Logger.LogException("OnModToggle", e);
					}
				}
			}

			public static void OnToggleWindow(bool value)
			{
				foreach (GameScript script in scripts)
				{
					try
					{
						script.OnToggleWindow(value);
					}
					catch (Exception e)
					{
						Logger.LogException("OnToggleWindow", e);
					}
				}
			}
		}

		private static class Textures
		{
			private static string WindowBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAEACAYAAACZCaebAAAAnElEQVRIS63MtQHDQADAwPdEZmaG/fdJCq2g7qqLvu/7hRBCZOF9X0ILz/MQWrjvm1DHdV3MFs7zJLRwHAehhX3fCS1s20ZoYV1XQgvLshDqmOeZ2cI0TYQWxnEktDAMA6GFvu8JLXRdR2ihbVtCHU3TMFuo65rQQlVVhBbKsiS0UBQFoYU8zwktZFlGqCNNU2YLSZIQWojjmFDCH22GtZAncD8TAAAAAElFTkSuQmCC";

			private static string SettingsNormalBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAJsmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTY6MTI6NTArMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE4OjMyOjQ2KzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE4LTA5LTA5VDE4OjMyOjQ2KzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpiZTNlYTRkYy0zYjU4LTIxNDctOWQzMi04NmRiYTFjNmM4MjMiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDoyMmYzNGE4Yy1jZjBiLTVkNDMtODRkYy05ODgyY2UyMTFhYTMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpiNjZhYTU5Ny1mODA5LTA0NGYtOWYzYi0wMTZlODdiODFkZjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmI2NmFhNTk3LWY4MDktMDQ0Zi05ZjNiLTAxNmU4N2I4MWRmMSIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNjoxMjo1MCswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL3BuZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyNGZjMTdlMS1jOWY3LTk5NDUtYmFkOC00NWZhNGI1MjgwNTgiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTg6MzI6MjcrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmZiYTVjMTY5LTkzNGItOGI0NS1hMjg3LTc2NzJkYjc1MjY2ZiIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxODozMjo0NiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6YmUzZWE0ZGMtM2I1OC0yMTQ3LTlkMzItODZkYmExYzZjODIzIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE4OjMyOjQ2KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpmYmE1YzE2OS05MzRiLThiNDUtYTI4Ny03NjcyZGI3NTI2NmYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIiBzdFJlZjpvcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+KBN97QAAAGtJREFUOI3FkTESgCAMBDcOhX6ZHr+snZZy4MRBUbcLmYS7nCWAkYMVIWpJAGDJXgyXwW/XWNraBgIG5EOFpNJDs6RwttWj+YebkhTnBN/l4EjqlIPipvJ+Dl08CHN2s2h/Bac8lXRpmknLHSshDz5/7DVxAAAAAElFTkSuQmCC";

			private static string SettingsActiveBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAJsmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTY6MTI6NTArMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE4OjMzOjAyKzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE4LTA5LTA5VDE4OjMzOjAyKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowNTVkNWY0My00MmViLTdiNDMtOTdkZi1mYjc2MWY2NzcyNjkiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDoyZjNlNWU4NC04NzM4LTdlNDEtYmExZi00MzljMWU3YjI2NTEiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpiNjZhYTU5Ny1mODA5LTA0NGYtOWYzYi0wMTZlODdiODFkZjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmI2NmFhNTk3LWY4MDktMDQ0Zi05ZjNiLTAxNmU4N2I4MWRmMSIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNjoxMjo1MCswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL3BuZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyNGZjMTdlMS1jOWY3LTk5NDUtYmFkOC00NWZhNGI1MjgwNTgiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTg6MzI6MjcrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjQ1NGEwNjIxLTQwZmMtNTU0Yy1hZDkzLWNkM2ZjMzIxMTdlYyIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxODozMzowMiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MDU1ZDVmNDMtNDJlYi03YjQzLTk3ZGYtZmI3NjFmNjc3MjY5IiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE4OjMzOjAyKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0NTRhMDYyMS00MGZjLTU1NGMtYWQ5My1jZDNmYzMyMTE3ZWMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIiBzdFJlZjpvcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+rc0l4AAAAF5JREFUOI3FkUsSgCAMQx+OC73/Zd3VpUYhTMcPb0chk9CUAFg42LCUAIjzxAsmf11ziP4jFcDXkZKCtENaMFdmdgV/9aC8Hek+api1I1nGFKdcdjamOOVppP6nVz3uep4WJ6dlbD4AAAAASUVORK5CYII=";

			private static string StatusActiveBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAIf2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTc6MDg6NTIrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMDlUMTc6MDk6MDErMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE3OjA5OjAxKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyOWQ1NWMzNi0xNzYxLTE1NDYtOTgyMC1kMWRkNjliZDE0NTciIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDplOTEwMGY5Yi00NTU4LWE2NDYtYTY3Ny0xY2I0NjY3YTRjYjciIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4NmEyNWY2LWU2ZTQtN2U0MS1hYjQwLTYzNmQzOWNkOTBmOCIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNzowODo1MiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NWYwNzJhODUtYjU4Zi1mMzQ4LTliOGQtZGQyZjE3NDQyOGY2IiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE3OjA5OjAxKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyOWQ1NWMzNi0xNzYxLTE1NDYtOTgyMC1kMWRkNjliZDE0NTciIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTc6MDk6MDErMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjVmMDcyYTg1LWI1OGYtZjM0OC05YjhkLWRkMmYxNzQ0MjhmNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7dzHWlAAAEt0lEQVRIiXWWW2xUVRSGv332OTPodFoGKC2osdAOCZFbgFhoSERHuRkgJhhFffEVePSG8mSClxh8UCFRY/RFaMQHRI0QDZEHi0QJKBE1NCQggpXeYC49M917Lx/OOdOLdE1W1pyZvf9//f9eZ86owoUnSXsp0ipN2kuRUgEpFRCogAPz9uaA7cBGYAnQCtSAq0Av8A1wCBhiilDrfn+alErVwdNeio/n75sOvADsnmrjpHgdeOt2RGr978/EwGlSKuDTjnd2APuTBT3FM1wML/HPaD9lV0GjafQbmKGbyE+bT1d2xXi8ncCB/xEEKiDtBXyef/9lYC/AiVs/cPLWjxRtGa00Hh6eUgA4ERwOK5YGneGBxk4KjWsSzFeA15ILPX/XIrTyOLLgo2eBdwA+G/iKo0PfEroqAIJEwMlLHAaDFUvJVjhf+YMRV+W+OxcAFIArwDkA9eCFJzixsLsJGAboHjjKl0PfESgfX/lopdF4aOWhUHVCKw4bqzBiGBXD5tzDPDlzS9J8Dhj2jRiAlwCODB2ne+AovvIjC7Bo0XjKwxMPbzwBDhHBYDBiGRVD98BR0l6Kx3IbAF4EdisRmQEMAGzv3cWgGSalArTSkYJ6996E6RBcXYWRyK6ajJLTTXTn6zMy0yeacw4Pfs3l6lV85TOqDIHy0ei6Nd4ki5y4cVZFCqxYrthrHB78msdnPAqw3QfWA5y8eYqyG8FXPj46VpBMz5g9SbiYxMVKjBgM0Xl8f7MnIdjgA8uMMZwt/UbZViYA+0rjKU3Uu5qgQJCYxNZVGLFYsZwrXcAYg+/7S32gpVgscuNmP1YZnGcY1Qq0QnmxNUoxXoPEIysSW+UEbJTi4Ib0UywWyeVyLT5QLZfLKV1WVMWAp1CaqHoK50XvURDfZ4gkLAKOiMAJYqPPrIJSqUQul8MHrodhmG2qNlCqlSKgGDBSMUYwgUFAbFSJq7ioNvlNhGEI0OcDf4rIgpbRmfxV/jvarGJgpcBjImnsUQKGiwjFJdLgnmxrMgu/+MDxTCazeSHt/FQ+i8TdRZbEoN647us3QmxPsn7cnoXZDjKZDMAxHzjU3Nz83trMKr4YPcZQdThppB5qCgJxk9YpmJ6eztrMKpqbmwEOeXM/WDQYBMEbbW1trEmtxIUOGbFIeSxd0eKKBleKs2hwxYlrZMTiQsea1Era2toIguANYNAj6uLNfD7PptYCXanlSOhwocWNWFxlXC3HWZn0XWiR0NGVWs6m1gL5fB7gTQAPgdZ9C4e11jsKhQJbZq/j/vQypCZIzUVZjXOq65rQmV7G1pb1FAoFtNY7iX+ddXbzbMQIb5149+c9jzxn29vbH+KaoVaqMlAdomprY4fokqkZy6xqYHXDcrbO28i2bdtobGzcA7xdP5c5Hy5CKpFcqTj+ffXiDmPM/tOnT9PT08Op/jNcrl6l3wxStiMAZPQdzPJncG/6blbPWkFXVxednZ34vv//R+bcT5bUCVwl8vLG3t4c8HwYhrvPnz9Pb28vfX19FItFALLZLC0tLXR0dLB48WKmTZs29UP/roNLkRGHSyZhxCGhRWpC/75LOeApYAPR35Y58b7rwK/AMeDg7YCT+A96mKaYuYno5AAAAABJRU5ErkJggg==";

			private static string StatusInactiveBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAIf2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTc6MDg6NTIrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMDlUMTc6NTg6MzErMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE3OjU4OjMxKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDphYjJiZWI3Ni0wY2JiLWIyNDctYjdhYS0zMWI1NjYzYjJjNDEiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpiNzRkODNkZC03NmM0LWQ1NDYtYWEyNi02N2Y3YjMyMGNlYzgiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4NmEyNWY2LWU2ZTQtN2U0MS1hYjQwLTYzNmQzOWNkOTBmOCIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNzowODo1MiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZThjZTMxMGEtODRkYi1lNjQyLWEyYWYtOWQyNDQ0OWUwOTBkIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE3OjU4OjMxKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphYjJiZWI3Ni0wY2JiLWIyNDctYjdhYS0zMWI1NjYzYjJjNDEiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTc6NTg6MzErMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4Y2UzMTBhLTg0ZGItZTY0Mi1hMmFmLTlkMjQ0NDllMDkwZCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6CJz7aAAAD3UlEQVRIiaWWS0grVxzGf2dmjIYQm/iKWRhEr6UQrQXRhXTVLHqr9QVxobhxewUXQttr6baPS6GL0nZ53VUkGxeF3m677sJ2fKT4SNCSaywSIYnJvDJdmBkmqba39MDHOcOc833/1/nPiK2tLWRZRlGUhlmSJGZmZsLAEvAe8CbQC+jAH8AJ8COwDRR4YChCCCRJQgjhYm5uLgR8CGzec8YHvFHH+8C3wOfAl/cJKUIIAJd8YWHhSf0QAOfn51xfX1MqlTAMAyEEra2t+P1+Ojs7icVi1A3ZBNaA7xoEnIVt2ySTyY+BTwHOzs7IZrNomtbgIYBhGBSLRS4vLzk+Pqa/v5/BwUHqhoWAzxxeeX5+HiEEy8vLq8DXAPv7+6TTaUzTdMWd2UGtVsO2bXRdJ5/PY5omPT09AAngHNgDkGq1GisrK68BzwFUVSWdTmNZ1n9COp1GVVXH8Od1T+4EgKcAR0dHqKqKaZqYpollWe7aMAx37YV3j6qqHB4eOiIfAQjbtjuAa4BUKkWlUkGSpAZ44+/NmRMqL/x+P4uLi862ToW7Oufg4ICbm5sHyR8SaBbRNI2DgwPi8TjAkgK8C5DJZNB1/X8L1Go1MpmMI/BYAd4yTZNcLtcgcN8FfEigWSSXy2GaJoqijCpApFgsUigUqNVqf7P+VXLQLKDrOsVikXA4HFEArVwu+wzDcG9qM7kkSQCuiHMvvOTeWZIkSqUS4XAYBXhZrVaDQggqlUpDSP6tipqJHQQCAarVKkBeAX63bfv1lpYWNE3Dtu0GkWbcF38vALq6uhw7flWAnwKBwEwoFOL09NTd5ITkVZPsPRMKhQgEAgAvFGC7u7v7m1gsxt7eHuVyuSHO95E3i3jJA4EAsViM7u5ugG356uqqMjs722aa5tsXFxdu42puA95nb9twepGTh4GBASYnJ4lEIl8APyh1C54NDQ09jcfjFAoFstks9R7l5uQhD5x3kiTR399PPB5naGgI4BmAZNs2q6urN7IsP0kkEsTjcaLRaIOlTgk3w7snGo0yPDxMIpFAluU14AZAHh8fx7IsUqnUL0tLS9bg4OA7hUKB29tbyuUyhmH8Y9X4fD76+voYGxsjmUzS3t7+CfCV46U8MTGBbdtYlsXOzs7PKysrf46MjEx3dHQghGi4VJZlAeDz+QgGg/T29jI6OsrU1BTT09P4/f41LzmAWF9fR9M0F4ZhkEqlwsAH1Wp1U1VVTk5OyOfzFItFAILBIJFIhEePHjEyMkJbW9uDH32xsbHhkuu67sKyLHZ3d8PAMvCYu9+WaP3cS+A34AXw/X3EzvgLFKrw+QQN6BEAAAAASUVORK5CYII=";

			private static string StatusNeedRestartBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAIf2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTc6MDg6NTIrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMDlUMTc6NTc6MTArMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE3OjU3OjEwKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDphYjljYTE2MS01NTA1LTM2NDItYjBmZi04NWM2YTQ4OTQzOTMiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpkZjAzYzgxNS01ZGFhLTZjNDUtOWU4ZC03NWJhYWViNWY0OGEiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4NmEyNWY2LWU2ZTQtN2U0MS1hYjQwLTYzNmQzOWNkOTBmOCIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNzowODo1MiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MGE1N2VhNDUtMjc3ZC01MjQxLWE2MjktYjlmYTFhYTNlNTk0IiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE3OjU3OjEwKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphYjljYTE2MS01NTA1LTM2NDItYjBmZi04NWM2YTQ4OTQzOTMiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTc6NTc6MTArMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjBhNTdlYTQ1LTI3N2QtNTI0MS1hNjI5LWI5ZmExYWEzZTU5NCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz58w4sCAAAEb0lEQVRIiY2WT2gUdxTHP7/5t1vWTXc2bhNblQhuvbi2RaqyGonsQXuIqNFDCh5Kb3run7Q9FEqrYiltQduLJ0P2opKLVEW9SCIRFFtPQiAojWmi0U12NjuZnfn9etiZdLJG6YPHzG/mve/3fd/7Mb8RI8UiWiKBlkigJxKIRALNstAsiy3nztlAP/ARsAXoBDzgb2Ac+AMoAy94hYnRXbvQkskmiWWhJZN8MDSUAT4HBl6V2GIngNMrEYnR3buXgDXLYuvFi8eAM1HA81u3cB4+xJuawq/VELqO0daG2d7Oqk2byHZ3x/GOA2dXJrAsPrx8+Svge4Bn167x7OZN/GoVoesITQNNa2ZJiZISFQQY6TSr9+xh9d69EebXwA/RQv907VqErrPt6tVPgF8BJoeGmL50Cem6oFTTQ+DIle+jfJ/AcZi/f5+gXqetUAAoAY+B+wBiZMcOirdvvwlUACbPn+ef4WE000QYRtMjBUI0iZRaUhARyUaDzgMHeOfo0ah4G6gYstEA+BJg6sIFJgcHEaYJQYAwTYTvg6YhQm/iK1QQNIl8H9VoIH2fycFBtGSSNUeOAHwBDAilVBaYBbh78CDe7CyaZTWrNs2X+x9ZbA6q0UAFAdLzsLJZtg4PR1HtBs19zpNymYWJCYRhoBqNZe1BiBVbRKgkapPyfRYePeJJuczb/f0A/QawF2D2xg2CWg1hGMh47/+PghaSZ9evRwT7DOB93/d5cfcuvuMsBzaM/3ovxDIFS4OODzu8Vu7dw/d9DMN4zwA6qtUqlZkZkBLN89AAXQg0QAurFy0ESimQEiklEgiUQgISWJiZoVqtYtt2hwEs1mo1q26aSM9DhMC6UmiAUAotCBBACI8KXYY7SgJBbC2UwnEcbNvGAKZc1003bBvXcSACjlQohQBaJrBUrQqrjwgBrEwG13UBpg3goVLqXdXZSe3x4yWApepDMk2IZQpkDDQODmCtXx/d/mkAV1OpVK+xeTP1sTFk9FmIgQpAiz2PFMTbFM95q1AglUoBXNGAci6Xwy6VCDIZ6kqxoBQ1pahKSVVKHCmZb3En9q4WxteVIshksEslcrkcQFk7nc0+N03zZFdXF+meHhbDwMgXlMIJAeLuhO+iOFcpFpUi3dNDV1cXpmmeBJ5rYe9O5fN51vX2kuruxguD3VhyvcXdFmBPKVLd3azr7SWfzwOcimbJt7Zd0XX9WKlUYt2hQ6wqFvHCpIhs8TVrTylWFYus7+ujVCqh6/pxwq+zEQ1xIJP57USl0n748OHvLgBBMsmLO3fwq1VeZ2Y6jb1tG/n9++nr66Otre0bYqea+NG2l0n/aW7umO/7Z8bGxhgdHWVqZIT6xATe06f4tRoARiqFlcvxxoYNrNm5k2KxyPbt2zEM4+Uj8+dsFjcamJQsAr/MzdnAZ67rDjx48IDx8XGmp6ephmrS6TQdHR1s3LiRQqFAMpl89aF/NkbgxocG/D4/bwMfA/to/rasCfOmgL+AK8DQSsCR/QsjSb1FKvuN9QAAAABJRU5ErkJggg==";

			private static string WWWBase64 = "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAfCAYAAAAfrhY5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGjWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxOC0wOS0xOFQyMDowMjo0OSswMzowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTgtMDktMTlUMTI6MjE6MDkrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMTlUMTI6MjE6MDkrMDM6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjllZWQwYzk5LWQ4YmItMTk0Yi1hOTU2LWI0Mzg4MzZiNGE1NyIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjE0YmE2MTBjLTcxMzMtM2E0Yy05NDkyLWUwNTczZDE5YmUxOCIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjRlYjUxNDViLTY5YjEtODE0Zi1hNmEyLWRhNGU3ZDliMjlmMyI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NGViNTE0NWItNjliMS04MTRmLWE2YTItZGE0ZTdkOWIyOWYzIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTE4VDIwOjAyOjQ5KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDozYWU1NzdiOS00MWEwLTU1NGUtYTU1NC0zMmViZmI1ZDFjNzMiIHN0RXZ0OndoZW49IjIwMTgtMDktMThUMjA6MDY6MTErMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjllZWQwYzk5LWQ4YmItMTk0Yi1hOTU2LWI0Mzg4MzZiNGE1NyIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0xOVQxMjoyMTowOSswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5HbzubAAAEM0lEQVRIicWXTWwVVRTHf2doQUKnMWkhgOK7o2gMoiCGHZBoQozs+LCyMOwq8T2iW1pJCCZQjStiZxpwZ4wp5WslCxdScFUaJMpHjBrmloABeWxmXiFt6RwXnfcYXqcfiTY9izfz7v3N+Z+cuffMuaKqiAgzWp8uKJSH3xC0U9DVCi2itKjwQOAByh+JOF8M3VvyK4ckmcmdqiKzEff86DOEdpDCzFHqEHA8LDYfmUncmVIwiHZ6fvS3F8SKyDpN2INqr6JXaWR5WHQFICy6kiSyQtGrqPZqwh5V2eAFsXpBdKfQE22fSiNX3PhxF8pJRFag2h8W3TYHeQ6R3Q1jC7aF7e69LD+0r+luw9iCbYjsRmSFLbm7gAsgK52E08aPD89KfE2fLhRhvwqjoMWw6L6zpk8XqnAE4K9Pl9zOc1QdF6HrrWPaGH7c9DawT2FMhM41fbpwWnEviL56VK6MoKyzxeZnwmJzDyL66H7lCoIR1Z35CaxZG+A9GI8vI6Jh0fVtqXmRiqx/VK6MGD/uysK1BVcIKu856LkZnP83U1DkXVtq+vGpBSckx+dUeEIESL55EowqAOnq/AnVSfsunZuUci+INWfs/bxxVMX48cXqnKpO/JggOmCC+GResF5PvNX40WDuXJ4IYPxo0OuJt+bPxae8IOqsic+H1SrcfFmDtfYMsJ2J5dAGnAB2p9cy0JLOAZwBNgHLsqwx5oS1tgxcNMbsALDWKnDfGLPMWlvPKnDWAQZSx8+mjgG2pKItdcEOAEvrWWttlb1Uxy+11uaxAJccoLqYXgE2p/ebgVdzMjUTWy8+LSthGAJcAx4CG4HvgA+B31PwOrA240zTIDYC3wJ7qqwxprZNrbXXgNemYMeNMWurRWYgBQD602s1wrxtVmXP17FZG5iGHYQntT2brvM8bQNMbf3TzNW/giw7kCd+C7gJ2AyYW2BS1taxU4nfMsZk2UFgfvf5vFY4ByZ6NOPHp/KguarttQiqjrwg7p/Tr1oQ/5z9qtWaCeNHQyLyQl60/7OFYdF9sa57ddrnfAEoIOx98j+jZ/y4ywtiLXRX1mefMX501Qti9bqjXdnx+vQaP/7AC2I1QfRbdrwQVN70glizPdykvt2W3I7FrU2LHEevGD8a8YK4hKq0NLgbUCyO5DYcVROhF+Vm4Z67IX3Hnxg/GnXQXxa3Ni2yJbcjy09qnW+0yajCYYFGoNvrqfRf3itjidABsPro8PN5wi/5D1dNRMD+C4fksempXBQ4KtAAfH6jTUbrn8k9NNiieyCBHajeAbaYID6NcBfV3seN4+cK3ZXlWX7V18Mrx+XxD6r6faKUvSA+K7BJ0dsJ7AiL7sHcTM3yrNYB8hGCmRacsFBVj9lS85fTQbM+KAJwUB2zfPh10aQDeFmVVoFWhbIIZeBPVI6E/zRdm+0p9V+lFDjVQcCm0AAAAABJRU5ErkJggg==";

			private static string UpdatesBase64 = "iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAYAAADjVADoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFwmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxOC0wOS0xOFQyMDozNjo0NSswMzowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTgtMDktMTlUMTE6MDY6NTkrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMTlUMTE6MDY6NTkrMDM6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmE1Zjg4NDg3LWU0MmUtMDc0OS04MDYwLWE5YmMwNWM2Yzg2NCIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOmY1M2Q1NTJhLWNiMDgtZDc0ZS1hOGE2LTI0YjQ2MzRlZWEyMyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjQxMDdiYjQ2LWRmYzEtNWI0Mi05ZDIxLTViZGM4YmVjMjE5ZCI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NDEwN2JiNDYtZGZjMS01YjQyLTlkMjEtNWJkYzhiZWMyMTlkIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTE4VDIwOjM2OjQ1KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWY4ODQ4Ny1lNDJlLTA3NDktODA2MC1hOWJjMDVjNmM4NjQiIHN0RXZ0OndoZW49IjIwMTgtMDktMTlUMTE6MDY6NTkrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+1SDzqQAAB2dJREFUeJztnG1sFMcdxp//7jl+OdsBjO00ChEmCTZqSAkJDqSlrutgjI9KNCIpTUKlVC2IM3yI+hKp+UDzqY3UqFLBl1hqFClJK6JKAZL4JdiOZacNoDa1jZTIEKilFBUwNdjGZ4x9u08/mNucz3tmd293D9T8Ps3O7sw8+3hm7r+zsxaS+ApAybSAm4VAPCEinjWypX1f0RSVKgoeAFAOyHIRFJPMF2ABABAYEZFxEhcBngJwUhGlP4uxnkMb9gx7pS0+IsRIuGzE5ramCj2g/YhkPURWisPeR0AXsJ+UFlVT33q/bueAmzo9MeKhfzRl3XFZe0oHwyJSmXaFpvCYUF4dD1z4U3f1i7G0a3PTiKquvYE8rXSnkD+HyNJ0xVmBwKBAXoqq519LxxDXjAh1RNbrYEQg9zsVkxbECeoSbt2462+OiqdrxNaPX86NRnN+L8AOT2daK5AEpCkayH2uu/rZSdtF4dCIzW1NFVog9peM9YIUEOgDtR+0bthzynIZp0bUHdlfIyIHRaTAgVY/GAO4peWxhi4rF8fv39ZPWl3H/q2KojTfxCYAQCEgrXUd+7faKWTZiFBn5AmBHACQbVua/2QL5ECo45XvWy1gaWhs6ox8F2SrQG5LX6N/EJyCyKbWmvCHKa+xOkfMRIixY4Dc7oFWH+AoqVemmkAtzRGb323K01Xtba9MKMjKxrriMqxadBdU8er5T24XUQ5Udb2eM99VgflO6rnay5h5UHKdewqK8ZvV30MwMDPlDI4P4/lPDiMau+ZBa/JgMDbxOwC7U12R8s8Q6oisB7jTA1UAgO3L1hgmAEBZfhE23/V1r5oDgHB9Z+OjqU6aGlHVtTeggxEvI8a7gwvn5C0xyXMNESGlsaprr+koMDUiGCvZ4XXUqJjMCQJvI3UBVuXHSn9sqic547pjv/BUUQbRhc+b9Yo5RgS14mf8epTOBAJZFtRKtiXnmwwNJeyHoAzTkJwxy4j6I40rAKzxTU7GkLWhI6/cl5gzu0cInvFVTwahom9PPJ5lBIGQv3IyByn1iceGEVva9xVBZKX/kjKEcFXoo4gRuBg/I1NUqkTcfeFzR24hau9cAdUkLgsG5j7ILitYjGfvXTsnX6OOD/4zgAtXx1zTJhCVk/q3ARwGEoyg4AG3w5mNd67Ak0tXW77+7uBC04hzBsEbZ467I8yoUr6B60Yk9ABZ7m4rwMEv+vGvK/9Nu57B8WEc/vcJFxTNwbhnwwgRVrjdytj0JF7ofS8tMwbHh/FC73sYnbrqojKD8njCMIJAkRctpWOGxyaAQEk8/WWPADxbgXJihtcmAAAohfFkQo/wdmXajhm+mAAAQuOefd0fYcUM30xIImFo8IofDY5NT+JXKczw3QSKcc+Jk+WoP60DV0zMyEhPEBoRWuJk6dmuFDPiZnw6cg6fjZzPyHAQYCie/jKypAyI4EG7lW1fVolHipei/9JZ/PH0UdjZnHZlehK//OSQ3SYNshQVeyqqUJZfhI5zJ50EXSfjiYQlK56CzTXDewuKsa3sIQAzq9B9l87i78Nf2BXjmO+U3oear83ERD8tWIyjFwcxNGlrqjNe+hhDQxGl366Qhdl5s45Lcv19N7wgO9dIC4DinHx7FZDGPRtGZDHWQ0BPX96tAUFNcpSe+LFhxKENe4YFtN0rblUE6G1eH74cP569QkVp8V9SZki+11lGqJr6lr9yMocW0N9MPJ71ouP9up0Dm9ojx0XwiJPK1xaXoSTHvwmzvLDUUTmCR49U7z6dmGfyHpARQBwZsXrREqxetMSROD8hlcbkvDkPXROBoT8TGLRS4dXYtBu6XGNs2sLOQvLM1cD5t5Oz5xjRXf1iTCAvWWn4s9FzvgZQ89Fz4TTORi/f8DqK/NZsp67pK/Koev61YKw0fKNNIjqJX/c1Y8FtuchRsyyLdpuJ2JSl3kCgL//S4tfNzqXcQ1XXvv9bCqQn47tqXYKATh3fbKsNH5uVf6M9VG0bdv8Vglc91ucnjckmJDLvClVe3uTPyFs/2iTxT05Nz7vn44bbCzd2RspV8vitvL0wpvLh5LjBOGt1C/IHNeGTFHmc4JTLCv3gGkUeT2VCIpYWb1trwh+Kjh8S1NLX5g8ENRE8Od+u20Qsr2K31Da8Q3AbAC82QroLOalAeaK5Jvyu1SK2P1Oo72isBnDwZp0zSIyQ3NJW29Bt7XoHnykAQMtjDV2iK2sI9Nkt6z3sVSiVVk1IxNELnubaXZ9PqLnrCERsrdZ6BAGd4B/0qdi65tpdnzupI+2P2+o7Gx+ljojM7DXIAOzVdQnPFyzNW9rp0Eimpabh44nA0MPU9R1Wn1pdgTwD8CdRdajSqQmJuPoBbFXX3kBQK9lGICyQdWlXaALBowJEourQgZvuA1gzNrXvWw6oTwMIQbhKIKqTeghqAvSS0qIF9DetBEe26vfaiERCH0UW6tdYBcpKEVaQUg5gMcBCyPWfYXIUkDERXgRwipQBgX4iKzDdfbj6uRGvtM0x4v+dr/5/xHX+BywfMF35GGAAAAAAAElFTkSuQmCC";

			private static string QuestionBase64 = "iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAYAAADAQbwGAAABN2lDQ1BBZG9iZSBSR0IgKDE5OTgpAAAokZWPv0rDUBSHvxtFxaFWCOLgcCdRUGzVwYxJW4ogWKtDkq1JQ5ViEm6uf/oQjm4dXNx9AidHwUHxCXwDxamDQ4QMBYvf9J3fORzOAaNi152GUYbzWKt205Gu58vZF2aYAoBOmKV2q3UAECdxxBjf7wiA10277jTG+38yH6ZKAyNguxtlIYgK0L/SqQYxBMygn2oQD4CpTto1EE9AqZf7G1AKcv8ASsr1fBBfgNlzPR+MOcAMcl8BTB1da4Bakg7UWe9Uy6plWdLuJkEkjweZjs4zuR+HiUoT1dFRF8jvA2AxH2w3HblWtay99X/+PRHX82Vun0cIQCw9F1lBeKEuf1UYO5PrYsdwGQ7vYXpUZLs3cLcBC7dFtlqF8hY8Dn8AwMZP/fNTP8gAAAAJcEhZcwAACxMAAAsTAQCanBgAAAj9aVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzE0MiA3OS4xNjA5MjQsIDIwMTcvMDcvMTMtMDE6MDY6MzkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMi0xMC0wOFQxMDowNzoxNiswMzowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMi0xMC0wOFQxMjowOTo0NiswMzowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjItMTAtMDhUMTI6MDk6NDYrMDM6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjFlYmE4Yjg0LWZhMGEtOWY0MS05OTE3LWIwN2U0ZjMxMTlhMiIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjFiZDVlYzRmLTNjOGQtN2M0NS1hZWMzLTI2NzE4YTZhNGI0YiIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjcwZTcwODU1LWE2NzMtNDY0NC04MmMxLTE5MmVhNWM5YTJjZiIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NzBlNzA4NTUtYTY3My00NjQ0LTgyYzEtMTkyZWE1YzlhMmNmIiBzdEV2dDp3aGVuPSIyMDIyLTEwLTA4VDEwOjA3OjE2KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo0Y2QwZDZjOC1hZjJiLTQ3NGYtYThlZS04NDQyYWIzMzMxNGQiIHN0RXZ0OndoZW49IjIwMjItMTAtMDhUMTI6MDk6NDYrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNvbnZlcnRlZCIgc3RFdnQ6cGFyYW1ldGVycz0iZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iZGVyaXZlZCIgc3RFdnQ6cGFyYW1ldGVycz0iY29udmVydGVkIGZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjFlYmE4Yjg0LWZhMGEtOWY0MS05OTE3LWIwN2U0ZjMxMTlhMiIgc3RFdnQ6d2hlbj0iMjAyMi0xMC0wOFQxMjowOTo0NiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NGNkMGQ2YzgtYWYyYi00NzRmLWE4ZWUtODQ0MmFiMzMzMTRkIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjcwZTcwODU1LWE2NzMtNDY0NC04MmMxLTE5MmVhNWM5YTJjZiIgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjcwZTcwODU1LWE2NzMtNDY0NC04MmMxLTE5MmVhNWM5YTJjZiIvPiA8cGhvdG9zaG9wOlRleHRMYXllcnM+IDxyZGY6QmFnPiA8cmRmOmxpIHBob3Rvc2hvcDpMYXllck5hbWU9Ij8iIHBob3Rvc2hvcDpMYXllclRleHQ9Ij8iLz4gPC9yZGY6QmFnPiA8L3Bob3Rvc2hvcDpUZXh0TGF5ZXJzPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pm3hzHgAAAEiSURBVDiNrZXhbYMwEEafrSxAR2AFOkI6Ah0hmcBihuAJwgh0hGaEsEJHgA3s/DCoBIxt0n4SEtadH3dn3yGstXilZQacgArIZpYG+EKZm2+b3IAdgR4ogHeUESgjgDNQAt9oWfm2ilWEWhbAHRhG2M/CfgKu4+qMMk0swunLU8rPcoBh4RsEzutVeOzMgDla5jFgs/GepHUNU6Rlj8tkQJm3ucl/ymFYyW9ZLn+L0N3NO5ADN5T5WLrsjbANwfYBtbwCR+CyBQPAWht/alHZWlhbiyrmmwrsbS3aFN94yq4VMzwn6lNKDd0VUab7L6ADuSsT1WudEtD+TonoEPXQssUN1Q74XM3HhcIRuqlcjqsC33zcBXxBMWADTD+jjoT5+AD4rb8zjOF5rwAAAABJRU5ErkJggg==";

			private static string TooltipBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABRJREFUGFdjTE5O/s/AwMDACGMAAC3JBFO8wVSyAAAAAElFTkSuQmCC";

			public static Texture2D Window = null;

			public static Texture2D SettingsNormal = null;

			public static Texture2D SettingsActive = null;

			public static Texture2D StatusActive = null;

			public static Texture2D StatusInactive = null;

			public static Texture2D StatusNeedRestart = null;

			public static Texture2D WWW = null;

			public static Texture2D Updates = null;

			public static Texture2D Question = null;

			public static Texture2D Tooltip = null;

			public static void Init()
			{
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Expected O, but got Unknown
				FieldInfo[] source = (from x in typeof(Textures).GetFields(BindingFlags.Static | BindingFlags.NonPublic)
					where (object)x.FieldType == typeof(string)
					select x).ToArray();
				FieldInfo[] array = (from x in typeof(Textures).GetFields(BindingFlags.Static | BindingFlags.Public)
					where (object)x.FieldType == typeof(Texture2D)
					select x).ToArray();
				foreach (FieldInfo f in array)
				{
					Texture2D val = new Texture2D(2, 2, (TextureFormat)5, false, true);
					f.SetValue(null, val);
					Utils.LoadImage(val, Convert.FromBase64String(((string)source.FirstOrDefault((FieldInfo x) => x.Name == f.Name + "Base64")?.GetValue(null)) ?? ""));
				}
				int size = 128;
				SettingsNormal.ResizeToIfLess(size);
				SettingsActive.ResizeToIfLess(size);
				WWW.ResizeToIfLess(size);
				Updates.ResizeToIfLess(size);
			}
		}

		public class ModEntry
		{
			public class ModLogger
			{
				protected readonly string Prefix;

				protected readonly string PrefixError;

				protected readonly string PrefixCritical;

				protected readonly string PrefixWarning;

				protected readonly string PrefixException;

				public ModLogger(string Id)
				{
					Prefix = "[" + Id + "] ";
					PrefixError = "[" + Id + "] [Error] ";
					PrefixCritical = "[" + Id + "] [Critical] ";
					PrefixWarning = "[" + Id + "] [Warning] ";
					PrefixException = "[" + Id + "] [Exception] ";
				}

				public void Log(string str)
				{
					UnityModManager.Logger.Log(str, Prefix);
				}

				public void Error(string str)
				{
					UnityModManager.Logger.Log(str, PrefixError);
				}

				public void Critical(string str)
				{
					UnityModManager.Logger.Log(str, PrefixCritical);
				}

				public void Warning(string str)
				{
					UnityModManager.Logger.Log(str, PrefixWarning);
				}

				public void NativeLog(string str)
				{
					UnityModManager.Logger.NativeLog(str, Prefix);
				}

				public void LogException(string key, Exception e)
				{
					UnityModManager.Logger.LogException(key, e, PrefixException);
				}

				public void LogException(Exception e)
				{
					UnityModManager.Logger.LogException(null, e, PrefixException);
				}
			}

			public readonly ModInfo Info;

			public readonly string Path;

			public readonly string ConfigPath;

			private Assembly mAssembly;

			public readonly Version Version;

			public readonly Version ManagerVersion;

			public readonly Version GameVersion;

			public Version NewestVersion;

			public readonly Dictionary<string, Version> Requirements = new Dictionary<string, Version>();

			public readonly List<string> LoadAfter = new List<string>();

			public string CustomRequirements = string.Empty;

			public readonly ModLogger Logger;

			public KeyBinding Hotkey = new KeyBinding();

			public bool HasUpdate;

			public Func<ModEntry, bool> OnUnload;

			public Func<ModEntry, bool, bool> OnToggle;

			public Action<ModEntry> OnGUI;

			public Action<ModEntry> OnFixedGUI;

			public Action<ModEntry> OnShowGUI;

			public Action<ModEntry> OnHideGUI;

			public Action<ModEntry> OnSaveGUI;

			public Action<ModEntry, float> OnUpdate;

			public Action<ModEntry, float> OnLateUpdate;

			public Action<ModEntry, float> OnFixedUpdate;

			public Action<ModEntry> OnSessionStart;

			public Action<ModEntry> OnSessionStop;

			private Dictionary<long, MethodInfo> mCache = new Dictionary<long, MethodInfo>();

			internal readonly List<TextureReplacer.Skin> Skins = new List<TextureReplacer.Skin>();

			private bool mStarted;

			private bool mErrorOnLoading;

			public bool Enabled = true;

			private bool mFirstLoading = true;

			private int mReloaderCount;

			private bool mActive;

			public Assembly Assembly => mAssembly;

			public bool HasAssembly
			{
				get
				{
					if (string.IsNullOrEmpty(Info.AssemblyName))
					{
						return !string.IsNullOrEmpty(Info.EntryMethod);
					}
					return true;
				}
			}

			public bool CanReload { get; private set; }

			public bool Started => mStarted;

			public bool ErrorOnLoading => mErrorOnLoading;

			public bool Toggleable
			{
				get
				{
					if (OnToggle == null)
					{
						return !HasAssembly;
					}
					return true;
				}
			}

			public bool Loaded
			{
				get
				{
					if ((object)Assembly == null)
					{
						if (!HasAssembly)
						{
							return mStarted;
						}
						return false;
					}
					return true;
				}
			}

			public bool Active
			{
				get
				{
					return mActive;
				}
				set
				{
					if (value && !Loaded)
					{
						Stopwatch stopwatch = Stopwatch.StartNew();
						Load();
						Logger.NativeLog($"Loading time {(float)stopwatch.ElapsedMilliseconds / 1000f:f2} s.");
					}
					else
					{
						if (!mStarted || mErrorOnLoading)
						{
							return;
						}
						try
						{
							if (value)
							{
								if (mActive)
								{
									return;
								}
								if (OnToggle == null || OnToggle(this, arg2: true))
								{
									mActive = true;
									Logger.Log("Active.");
									GameScripts.OnModToggle(this, value: true);
									if (UnityModManager.toggleModsListen != null)
									{
										UnityModManager.toggleModsListen(this, result: true);
									}
								}
								else
								{
									Logger.Log("Unsuccessfully.");
									Logger.NativeLog("OnToggle(true) failed.");
								}
							}
							else
							{
								if (forbidDisableMods || !mActive)
								{
									return;
								}
								if ((OnToggle != null && OnToggle(this, arg2: false)) || !HasAssembly)
								{
									mActive = false;
									Logger.Log("Inactive.");
									GameScripts.OnModToggle(this, value: false);
									if (UnityModManager.toggleModsListen != null)
									{
										UnityModManager.toggleModsListen(this, result: false);
									}
								}
								else if (OnToggle != null)
								{
									Logger.NativeLog("OnToggle(false) failed.");
								}
							}
						}
						catch (Exception e)
						{
							Logger.LogException("OnToggle", e);
						}
					}
				}
			}

			public ModEntry(ModInfo info, string path)
			{
				Info = info;
				Path = path;
				ConfigPath = System.IO.Path.Combine(configPath, Info.Id);
				Logger = new ModLogger(Info.Id);
				Version = ParseVersion(info.Version);
				ManagerVersion = ((!string.IsNullOrEmpty(info.ManagerVersion)) ? ParseVersion(info.ManagerVersion) : ((!string.IsNullOrEmpty(Config.MinimalManagerVersion)) ? ParseVersion(Config.MinimalManagerVersion) : new Version()));
				GameVersion = ((!string.IsNullOrEmpty(info.GameVersion)) ? ParseVersion(info.GameVersion) : new Version());
				if (info.Requirements != null && info.Requirements.Length != 0)
				{
					Regex regex = new Regex("(.*)-(\\d+\\.\\d+\\.\\d+).*");
					string[] requirements = info.Requirements;
					foreach (string text in requirements)
					{
						Match match = regex.Match(text);
						if (match.Success)
						{
							Requirements.Add(match.Groups[1].Value, ParseVersion(match.Groups[2].Value));
						}
						else if (!Requirements.ContainsKey(text))
						{
							Requirements.Add(text, null);
						}
					}
				}
				if (info.LoadAfter != null && info.LoadAfter.Length != 0)
				{
					LoadAfter.AddRange(info.LoadAfter);
				}
			}

			public bool Load()
			{
				//IL_06cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_06d7: Expected O, but got Unknown
				if (Loaded)
				{
					return !mErrorOnLoading;
				}
				mErrorOnLoading = false;
				Logger.Log("Version '" + Info.Version + "'. Loading.");
				if (string.IsNullOrEmpty(Info.AssemblyName) && !string.IsNullOrEmpty(Info.EntryMethod))
				{
					mErrorOnLoading = true;
					Logger.Error("AssemblyName is null.");
				}
				if (!string.IsNullOrEmpty(Info.AssemblyName) && string.IsNullOrEmpty(Info.EntryMethod))
				{
					mErrorOnLoading = true;
					Logger.Error("EntryMethod is null.");
				}
				if (!string.IsNullOrEmpty(Info.ManagerVersion) && ManagerVersion > GetVersion())
				{
					mErrorOnLoading = true;
					Logger.Error("Mod Manager must be version '" + Info.ManagerVersion + "' or higher.");
				}
				if (!string.IsNullOrEmpty(Info.GameVersion) && gameVersion != VER_0 && GameVersion > gameVersion)
				{
					mErrorOnLoading = true;
					Logger.Error("Game must be version '" + Info.GameVersion + "' or higher.");
				}
				if (Requirements.Count > 0)
				{
					foreach (KeyValuePair<string, Version> requirement in Requirements)
					{
						string key = requirement.Key;
						ModEntry modEntry = FindMod(key);
						if (modEntry == null)
						{
							mErrorOnLoading = true;
							Logger.Error("Required mod '" + key + "' missing.");
						}
						else if (requirement.Value != null && requirement.Value > modEntry.Version)
						{
							mErrorOnLoading = true;
							Logger.Error($"Required mod '{key}' must be version '{requirement.Value}' or higher.");
						}
						else if (!modEntry.Active)
						{
							modEntry.Enabled = true;
							modEntry.Active = true;
							if (!modEntry.Active)
							{
								Logger.Log("Required mod '" + key + "' inactive.");
							}
						}
					}
				}
				if (LoadAfter.Count > 0)
				{
					foreach (string item in LoadAfter)
					{
						ModEntry modEntry2 = FindMod(item);
						if (modEntry2 == null)
						{
							Logger.Log("Optional mod '" + item + "' not found.");
						}
						else if (!modEntry2.Active && modEntry2.Enabled)
						{
							modEntry2.Active = true;
							if (!modEntry2.Active)
							{
								Logger.Log("Optional mod '" + item + "' enabled, but inactive.");
							}
						}
					}
				}
				if (mErrorOnLoading)
				{
					return false;
				}
				if (!HasAssembly)
				{
					mStarted = true;
					Active = true;
					return true;
				}
				string text = System.IO.Path.Combine(Path, Info.AssemblyName);
				string text2 = text.Replace(".dll", ".pdb");
				string value = string.Empty;
				string[] commandLineArgs = Environment.GetCommandLineArgs();
				int num = Array.IndexOf(commandLineArgs, "--umm-" + Info.Id + "-assembly-path");
				if (num != -1 && commandLineArgs.Length > num + 1)
				{
					value = (text = commandLineArgs[num + 1]);
				}
				if (File.Exists(text))
				{
					if (!string.IsNullOrEmpty(value))
					{
						try
						{
							mAssembly = Assembly.LoadFrom(text);
							mFirstLoading = false;
						}
						catch (Exception e)
						{
							mErrorOnLoading = true;
							Logger.Error("Error loading file '" + text + "'.");
							Logger.LogException(e);
							return false;
						}
					}
					else
					{
						try
						{
							string text3 = text;
							string destFileName = text2;
							bool flag = false;
							if (mFirstLoading)
							{
								ushort num2 = (ushort)((long)new FileInfo(text).LastWriteTimeUtc.GetHashCode() + (long)version.GetHashCode() + ManagerVersion.GetHashCode()).GetHashCode();
								text3 = text + $".{num2}.cache";
								destFileName = text3 + ".pdb";
								flag = File.Exists(text3);
								if (!flag)
								{
									string[] files = Directory.GetFiles(Path, "*.cache*");
									foreach (string path in files)
									{
										try
										{
											File.Delete(path);
										}
										catch (Exception)
										{
										}
									}
								}
							}
							if (ManagerVersion >= VER_0_13)
							{
								if (mFirstLoading)
								{
									if (!flag)
									{
										bool flag2 = false;
										ModuleDefMD val = ModuleDefMD.Load(File.ReadAllBytes(text), (ModuleCreationOptions)null);
										foreach (AssemblyRef assemblyRef in ((ModuleDef)val).GetAssemblyRefs())
										{
											if (assemblyRef.FullName.StartsWith("0Harmony, Version=1."))
											{
												assemblyRef.Name = UTF8String.op_Implicit("0Harmony-1.2");
												flag2 = true;
											}
										}
										if (flag2)
										{
											((ModuleDef)val).Write(text3);
										}
										else
										{
											File.Copy(text, text3, overwrite: true);
										}
										if (File.Exists(text2))
										{
											File.Copy(text2, destFileName, overwrite: true);
										}
									}
									mAssembly = Assembly.LoadFrom(text3);
									Type[] types = mAssembly.GetTypes();
									for (int i = 0; i < types.Length; i++)
									{
										if (types[i].GetCustomAttributes(typeof(EnableReloadingAttribute), inherit: true).Any())
										{
											CanReload = true;
											break;
										}
									}
								}
								else
								{
									ModuleDefMD val2 = ModuleDefMD.Load(File.ReadAllBytes(text), (ModuleCreationOptions)null);
									AssemblyDef assembly = ((ModuleDef)val2).Assembly;
									string text4 = UTF8String.op_Implicit(assembly.Name);
									int i = ++mReloaderCount;
									assembly.Name = UTF8String.op_Implicit(text4 + i);
									using MemoryStream memoryStream = new MemoryStream();
									((ModuleDef)val2).Write((Stream)memoryStream);
									if (File.Exists(text2))
									{
										mAssembly = Assembly.Load(memoryStream.ToArray(), File.ReadAllBytes(text2));
									}
									else
									{
										mAssembly = Assembly.Load(memoryStream.ToArray());
									}
								}
							}
							else
							{
								if (!flag)
								{
									bool flag3 = false;
									ModuleDefMD val3 = ModuleDefMD.Load(File.ReadAllBytes(text), (ModuleCreationOptions)null);
									foreach (TypeRef typeRef in ((ModuleDef)val3).GetTypeRefs())
									{
										if (typeRef.FullName == "UnityModManagerNet.UnityModManager")
										{
											typeRef.ResolutionScope = (IResolutionScope)new AssemblyRefUser((IAssembly)(object)((ModuleDef)thisModuleDef).Assembly);
											flag3 = true;
										}
									}
									foreach (MemberRef item2 in from member in ((ModuleDef)val3).GetMemberRefs()
										where member.IsFieldRef
										select member)
									{
										if (item2.Name == "modsPath" && ((IFullName)item2.Class).FullName == "UnityModManagerNet.UnityModManager")
										{
											item2.Name = UTF8String.op_Implicit("OldModsPath");
											flag3 = true;
										}
									}
									foreach (AssemblyRef assemblyRef2 in ((ModuleDef)val3).GetAssemblyRefs())
									{
										if (assemblyRef2.FullName.StartsWith("0Harmony, Version=1."))
										{
											assemblyRef2.Name = UTF8String.op_Implicit("0Harmony-1.2");
											flag3 = true;
										}
									}
									if (flag3)
									{
										((ModuleDef)val3).Write(text3);
									}
									else
									{
										File.Copy(text, text3, overwrite: true);
									}
								}
								mAssembly = Assembly.LoadFile(text3);
							}
							mFirstLoading = false;
						}
						catch (Exception e2)
						{
							mErrorOnLoading = true;
							Logger.Error("Error loading file '" + text + "'.");
							Logger.LogException(e2);
							return false;
						}
					}
					try
					{
						object[] param = new object[1] { this };
						Type[] types2 = new Type[1] { typeof(ModEntry) };
						if ((object)FindMethod(Info.EntryMethod, types2, showLog: false) == null)
						{
							param = null;
							types2 = null;
						}
						if (!Invoke(Info.EntryMethod, out var result, param, types2) || (result != null && !(bool)result))
						{
							mErrorOnLoading = true;
							Logger.Log("Not loaded.");
						}
					}
					catch (Exception ex2)
					{
						mErrorOnLoading = true;
						Logger.Log(ex2.ToString());
						return false;
					}
					mStarted = true;
					if (!mErrorOnLoading)
					{
						Active = true;
						return true;
					}
				}
				else
				{
					mErrorOnLoading = true;
					Logger.Error("File '" + text + "' not found.");
				}
				return false;
			}

			internal void LoadSkins()
			{
				foreach (TextureReplacer.Skin skin in Skins)
				{
					if (!allSkins.Contains(skin))
					{
						allSkins.Add(skin);
					}
					foreach (KeyValuePair<string, TextureReplacer.Skin.texture> texture2 in skin.textures)
					{
						Texture2D texture = Utils.LoadTexture(texture2.Value.Path);
						texture2.Value.Texture = texture;
					}
				}
			}

			internal void Reload()
			{
				if (!mStarted || !CanReload)
				{
					return;
				}
				if (OnSaveGUI != null)
				{
					OnSaveGUI(this);
				}
				Logger.Log("Reloading...");
				if (Toggleable)
				{
					bool forbidDisableMods = UnityModManager.forbidDisableMods;
					UnityModManager.forbidDisableMods = false;
					Active = false;
					UnityModManager.forbidDisableMods = forbidDisableMods;
				}
				else
				{
					mActive = false;
				}
				try
				{
					if (!Active && (OnUnload == null || OnUnload(this)))
					{
						mCache.Clear();
						Type type = typeof(Traverse).Assembly.GetType("HarmonyLib.AccessCache");
						object value = typeof(Traverse).GetField("Cache", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
						string[] array = new string[6] { "declaredFields", "declaredProperties", "declaredMethods", "inheritedFields", "inheritedProperties", "inheritedMethods" };
						foreach (string name in array)
						{
							((IDictionary)type.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(value)).Clear();
						}
						Assembly assembly = Assembly;
						mAssembly = null;
						mStarted = false;
						mErrorOnLoading = false;
						OnToggle = null;
						OnGUI = null;
						OnFixedGUI = null;
						OnShowGUI = null;
						OnHideGUI = null;
						OnSaveGUI = null;
						OnUnload = null;
						OnUpdate = null;
						OnFixedUpdate = null;
						OnLateUpdate = null;
						CustomRequirements = null;
						if (!Load())
						{
							return;
						}
						Type[] types = assembly.GetTypes();
						foreach (Type type2 in types)
						{
							Type type3 = Assembly.GetType(type2.FullName);
							if ((object)type3 == null)
							{
								continue;
							}
							FieldInfo[] fields = type2.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
							foreach (FieldInfo fieldInfo in fields)
							{
								if (!fieldInfo.GetCustomAttributes(typeof(SaveOnReloadAttribute), inherit: true).Any())
								{
									continue;
								}
								FieldInfo field = type3.GetField(fieldInfo.Name);
								if ((object)field == null)
								{
									continue;
								}
								Logger.Log("Copying field '" + fieldInfo.DeclaringType.Name + "." + fieldInfo.Name + "'");
								try
								{
									if ((object)fieldInfo.FieldType != field.FieldType)
									{
										if (fieldInfo.FieldType.IsEnum && field.FieldType.IsEnum)
										{
											field.SetValue(null, Convert.ToInt32(fieldInfo.GetValue(null)));
										}
										else if ((!fieldInfo.FieldType.IsClass || !field.FieldType.IsClass) && fieldInfo.FieldType.IsValueType && !field.FieldType.IsValueType)
										{
										}
									}
									else
									{
										field.SetValue(null, fieldInfo.GetValue(null));
									}
								}
								catch (Exception ex)
								{
									Logger.Error(ex.ToString());
								}
							}
						}
						return;
					}
					if (Active)
					{
						Logger.Log("Must be deactivated.");
					}
				}
				catch (Exception ex2)
				{
					Logger.Error(ex2.ToString());
				}
				Logger.Log("Reloading canceled.");
			}

			public bool Invoke(string namespaceClassnameMethodname, out object result, object[] param = null, Type[] types = null)
			{
				result = null;
				try
				{
					MethodInfo methodInfo = FindMethod(namespaceClassnameMethodname, types);
					if ((object)methodInfo != null)
					{
						result = methodInfo.Invoke(null, param);
						return true;
					}
				}
				catch (Exception e)
				{
					Logger.Error("Error trying to call '" + namespaceClassnameMethodname + "'.");
					Logger.LogException(e);
				}
				return false;
			}

			private MethodInfo FindMethod(string namespaceClassnameMethodname, Type[] types, bool showLog = true)
			{
				long num = namespaceClassnameMethodname.GetHashCode();
				if (types != null)
				{
					Type[] array = types;
					foreach (Type type in array)
					{
						num += type.GetHashCode();
					}
				}
				if (!mCache.TryGetValue(num, out var value))
				{
					if ((object)mAssembly != null)
					{
						string text = null;
						string text2 = null;
						int num2 = namespaceClassnameMethodname.LastIndexOf('.');
						if (num2 != -1)
						{
							text = namespaceClassnameMethodname.Substring(0, num2);
							text2 = namespaceClassnameMethodname.Substring(num2 + 1);
							Type type2 = mAssembly.GetType(text);
							if ((object)type2 != null)
							{
								if (types == null)
								{
									types = new Type[0];
								}
								value = type2.GetMethod(text2, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, types, null);
								if ((object)value == null && showLog)
								{
									if (types.Length != 0)
									{
										Logger.Log("Method '" + namespaceClassnameMethodname + "[" + string.Join(", ", types.Select((Type x) => x.Name).ToArray()) + "]' not found.");
									}
									else
									{
										Logger.Log("Method '" + namespaceClassnameMethodname + "' not found.");
									}
								}
							}
							else if (showLog)
							{
								Logger.Error("Class '" + text + "' not found.");
							}
						}
						else if (showLog)
						{
							Logger.Error("Function name error '" + namespaceClassnameMethodname + "'.");
						}
					}
					else if (showLog)
					{
						UnityModManager.Logger.Error("Can't find method '" + namespaceClassnameMethodname + "'. Mod '" + Info.Id + "' is not loaded.");
					}
					mCache[num] = value;
				}
				return value;
			}

			public bool HasContentType(string str)
			{
				if (!string.IsNullOrEmpty(Info.ContentType))
				{
					return new Regex("\\b" + str + "\\b", RegexOptions.IgnoreCase).IsMatch(Info.ContentType);
				}
				return false;
			}
		}

		public static class Logger
		{
			private const string Prefix = "[Manager] ";

			private const string PrefixError = "[Manager] [Error] ";

			private const string PrefixException = "[Manager] [Exception] ";

			public static readonly string filepath = Path.Combine(Path.GetDirectoryName(typeof(GameInfo).Assembly.Location), "Log.txt");

			private static bool hasErrors;

			private static int bufferCapacity = 100;

			private static List<string> buffer = new List<string>(bufferCapacity);

			internal static int historyCapacity = 200;

			internal static List<string> history = new List<string>(historyCapacity * 2);

			private static float timer;

			public static void NativeLog(string str)
			{
				NativeLog(str, "[Manager] ");
			}

			public static void NativeLog(string str, string prefix)
			{
				Write(prefix + str, onlyNative: true);
			}

			public static void Log(string str)
			{
				Log(str, "[Manager] ");
			}

			public static void Log(string str, string prefix)
			{
				Write(prefix + str);
			}

			public static void Error(string str)
			{
				Error(str, "[Manager] [Error] ");
			}

			public static void Error(string str, string prefix)
			{
				Write(prefix + str);
			}

			public static void LogException(Exception e)
			{
				LogException(null, e, "[Manager] [Exception] ");
			}

			public static void LogException(string key, Exception e)
			{
				LogException(key, e, "[Manager] [Exception] ");
			}

			public static void LogException(string key, Exception e, string prefix)
			{
				if (string.IsNullOrEmpty(key))
				{
					Write(prefix + e.GetType().Name + " - " + e.Message);
				}
				else
				{
					Write(prefix + key + ": " + e.GetType().Name + " - " + e.Message);
				}
				Console.WriteLine(e.ToString());
			}

			private static void Write(string str, bool onlyNative = false)
			{
				if (str == null)
				{
					return;
				}
				Console.WriteLine(str);
				if (!onlyNative)
				{
					buffer.Add(str);
					history.Add(str);
					if (history.Count >= historyCapacity * 2)
					{
						string[] collection = history.Skip(historyCapacity).ToArray();
						history.Clear();
						history.AddRange(collection);
					}
				}
			}

			internal static void Watcher(float dt)
			{
				if (buffer.Count >= bufferCapacity || timer > 0.5f)
				{
					WriteBuffers();
				}
				else
				{
					timer += dt;
				}
			}

			internal static void WriteBuffers()
			{
				try
				{
					if (buffer.Count > 0 && !hasErrors)
					{
						if (!File.Exists(filepath))
						{
							using (File.Create(filepath))
							{
							}
						}
						using StreamWriter streamWriter = File.AppendText(filepath);
						foreach (string item in buffer)
						{
							streamWriter.WriteLine(item);
						}
					}
				}
				catch (UnauthorizedAccessException ex)
				{
					hasErrors = true;
					Console.WriteLine("[Manager] [Exception] " + ex.ToString());
					Console.WriteLine("[Manager] Uncheck the read-only box from the UnityModManager folder.");
					history.Add("[Manager] [Exception] " + ex.ToString());
					history.Add("[Manager] Uncheck the read-only box from the UnityModManager folder.");
				}
				catch (Exception ex2)
				{
					hasErrors = true;
					Console.WriteLine("[Manager] [Exception] " + ex2.ToString());
					history.Add("[Manager] [Exception] " + ex2.ToString());
				}
				buffer.Clear();
				timer = 0f;
			}

			public static void Clear()
			{
				buffer.Clear();
				history.Clear();
				if (File.Exists(filepath) && !hasErrors)
				{
					try
					{
						File.Delete(filepath);
					}
					catch (UnauthorizedAccessException ex)
					{
						hasErrors = true;
						Console.WriteLine("[Manager] [Exception] " + ex.ToString());
						Console.WriteLine("[Manager] Uncheck the read-only box from the UnityModManager folder.");
						history.Add("[Manager] [Exception] " + ex.ToString());
						history.Add("[Manager] Uncheck the read-only box from the UnityModManager folder.");
					}
					catch (Exception ex2)
					{
						hasErrors = true;
						Console.WriteLine("[Manager] [Exception] " + ex2.ToString());
						history.Add("[Manager] [Exception] " + ex2.ToString());
					}
				}
			}
		}

		public class ModInfo : IEquatable<ModInfo>
		{
			public string Id;

			public string DisplayName;

			public string Author;

			public string Version;

			public string ManagerVersion;

			public string GameVersion;

			public string[] Requirements;

			public string[] LoadAfter;

			public string AssemblyName;

			public string EntryMethod;

			public string HomePage;

			public string Repository;

			public string ContentType;

			[NonSerialized]
			public bool IsCheat = true;

			public static implicit operator bool(ModInfo exists)
			{
				return exists != null;
			}

			public bool Equals(ModInfo other)
			{
				return Id.Equals(other.Id);
			}

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

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

		public delegate void ToggleModsListen(ModEntry modEntry, bool result);

		public class ModSettings
		{
			public virtual void Save(ModEntry modEntry)
			{
				Save(this, modEntry);
			}

			public virtual string GetPath(ModEntry modEntry)
			{
				return Path.Combine(modEntry.ConfigPath, "Settings.xml");
			}

			public static void Save<T>(T data, ModEntry modEntry) where T : ModSettings, new()
			{
				Save(data, modEntry, null);
			}

			public static void Save<T>(T data, ModEntry modEntry, XmlAttributeOverrides attributes) where T : ModSettings, new()
			{
				Directory.CreateDirectory(modEntry.ConfigPath);
				string path = data.GetPath(modEntry);
				try
				{
					using StreamWriter textWriter = new StreamWriter(path);
					new XmlSerializer(data.GetType(), attributes).Serialize(textWriter, data);
				}
				catch (Exception e)
				{
					modEntry.Logger.Error("Can't save " + path + ".");
					modEntry.Logger.LogException(e);
				}
			}

			public static T Load<T>(ModEntry modEntry) where T : ModSettings, new()
			{
				T val = new T();
				string path = val.GetPath(modEntry);
				if (File.Exists(path))
				{
					try
					{
						using FileStream stream = File.OpenRead(path);
						return (T)new XmlSerializer(typeof(T)).Deserialize(stream);
					}
					catch (Exception e)
					{
						modEntry.Logger.Error("Can't read " + path + ".");
						modEntry.Logger.LogException(e);
					}
				}
				return val;
			}

			public static T Load<T>(ModEntry modEntry, XmlAttributeOverrides attributes) where T : ModSettings, new()
			{
				T val = new T();
				string path = val.GetPath(modEntry);
				if (File.Exists(path))
				{
					try
					{
						using FileStream stream = File.OpenRead(path);
						return (T)new XmlSerializer(typeof(T), attributes).Deserialize(stream);
					}
					catch (Exception e)
					{
						modEntry.Logger.Error("Can't read " + path + ".");
						modEntry.Logger.LogException(e);
					}
				}
				return val;
			}
		}

		public class Repository
		{
			[Serializable]
			public class Release : IEquatable<Release>
			{
				public string Id;

				public string Version;

				public string DownloadUrl;

				public bool Equals(Release other)
				{
					return Id.Equals(other.Id);
				}

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

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

			public Release[] Releases;
		}

		internal class TextureReplacer
		{
			public class Skin
			{
				public struct conditions
				{
					public string MaterialName;

					public string ObjectName;

					public string ObjectComponent;

					public string Custom;

					[IgnoreJson]
					public bool IsEmpty
					{
						get
						{
							if (string.IsNullOrEmpty(MaterialName) && string.IsNullOrEmpty(ObjectName) && string.IsNullOrEmpty(ObjectComponent))
							{
								return string.IsNullOrEmpty(Custom);
							}
							return false;
						}
					}
				}

				public class texture
				{
					public string Path;

					public Texture2D Texture;

					public Texture2D Previous;
				}

				[IgnoreJson]
				public ModEntry modEntry;

				public string Name;

				public string Tags;

				public conditions Conditions;

				[IgnoreJson]
				public Dictionary<string, texture> textures;

				public override string ToString()
				{
					return Name + " (" + modEntry.Info.DisplayName + ")";
				}

				public void WriteFile(string filePath)
				{
					try
					{
						File.WriteAllText(filePath, this.ToJson());
					}
					catch (Exception ex)
					{
						Logger.Error(ex.ToString());
						Logger.Error("Error file creating '" + filePath + "'.");
					}
				}

				public static Skin ReadFile(string filePath)
				{
					try
					{
						return File.ReadAllText(filePath).FromJson<Skin>();
					}
					catch (Exception ex)
					{
						Logger.Error(ex.ToString());
						Logger.Error("Can't read file '" + filePath + "'.");
						return null;
					}
				}

				public static implicit operator bool(Skin exists)
				{
					return exists != null;
				}

				public bool Equals(Skin other)
				{
					if (Name.Equals(other.Name))
					{
						return modEntry.Info.Equals(other.modEntry.Info);
					}
					return false;
				}

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

				public override int GetHashCode()
				{
					return Name.GetHashCode() + modEntry.Info.GetHashCode();
				}
			}

			public static void Start()
			{
			}
		}

		public class UI : MonoBehaviour
		{
			private class PopupWindow
			{
				internal const int MARGIN = 100;

				internal int mId;

				internal Rect mWindowRect;

				internal Vector2 mScrollPosition;

				internal int mWidth;

				internal int mHeight;

				internal int mRecalculateFrame;

				internal bool mOpened;

				public HashSet<int> DestroyCounter { get; set; } = new HashSet<int>();


				internal bool Recalculating => mRecalculateFrame == Time.frameCount;

				public bool Opened
				{
					get
					{
						return mOpened;
					}
					set
					{
						mOpened = value;
						if (value)
						{
							Reset();
						}
					}
				}

				public PopupWindow()
				{
					mId = GetNextWindowId();
					mPopupList.Add(this);
				}

				public void Reset()
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					mRecalculateFrame = Time.frameCount;
					mWindowRect = new Rect(-9000f, 0f, 0f, 0f);
				}

				public virtual void Render()
				{
					//IL_00e7: 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_012f: Expected O, but got Unknown
					//IL_012a: Unknown result type (might be due to invalid IL or missing references)
					//IL_012f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_003a: Expected O, but got Unknown
					//IL_0035: Unknown result type (might be due to invalid IL or missing references)
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					if (Recalculating)
					{
						mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[0]);
						if (((Rect)(ref mWindowRect)).width > 0f)
						{
							mWidth = (int)Math.Min(Math.Max(((Rect)(ref mWindowRect)).width, 250f), Screen.width - 100);
							mHeight = (int)Math.Min(((Rect)(ref mWindowRect)).height, Screen.height - 100);
							((Rect)(ref mWindowRect)).x = Math.Max(Screen.width - mWidth, 0) / 2;
							((Rect)(ref mWindowRect)).y = Math.Max(Screen.height - mHeight, 0) / 2;
						}
					}
					else
					{
						mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[2]
						{
							GUILayout.Width((float)mWidth),
							GUILayout.Height((float)(mHeight + 20))
						});
						GUI.BringWindowToFront(mId);
					}
				}

				public virtual void WindowFunction(int windowId)
				{
					throw new NotImplementedException();
				}
			}

			private class PopupToggleGroup_GUI : PopupWindow
			{
				public int? newSelected;

				public int selected;

				public readonly string[] values;

				public string title;

				public int unique;

				public PopupToggleGroup_GUI(string[] values)
				{
					this.values = values;
				}

				public void Button(string text = null, GUIStyle style = null, params GUILayoutOption[] option)
				{
					base.DestroyCounter.Clear();
					if (!GUILayout.Button(text ?? values[selected], style ?? GUI.skin.button, option))
					{
						return;
					}
					if (!base.Opened)
					{
						foreach (PopupWindow mPopup in mPopupList)
						{
							mPopup.Opened = false;
						}
						base.Opened = true;
					}
					else
					{
						base.Opened = false;
					}
				}

				public override void WindowFunction(int windowId)
				{
					//IL_0028: Unknown result type (might be due to invalid IL or missing references)
					//IL_0033: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Unknown result type (might be due to invalid IL or missing references)
					if (title != null)
					{
						GUILayout.Label(title, h1, (GUILayoutOption[])(object)new GUILayoutOption[0]);
					}
					if (!base.Recalculating)
					{
						mScrollPosition = GUILayout.BeginScrollView(mScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[0]);
					}
					if (values != null)
					{
						int num = 0;
						string[] array = values;
						foreach (string text in array)
						{
							if (GUILayout.Button((num == selected) ? ("<b>" + text + "</b>") : text, (GUILayoutOption[])(object)new GUILayoutOption[0]))
							{
								newSelected = num;
								base.Opened = false;
							}
							num++;
						}
					}
					if (!base.Recalculating)
					{
						GUILayout.EndScrollView();
					}
				}
			}

			private class PopupToggleMulti_GUI : PopupWindow
			{
				public int? newSelected;

				public int selected;

				public readonly string[] values;

				public readonly int[] flags;

				public string title;

				public int unique;

				public PopupToggleMulti_GUI(string[] values, int[] flags)
				{
					this.values = values;
					this.flags = flags;
				}

				public void Button(string text = null, GUIStyle style = null, params GUILayoutOption[] option)
				{
					base.DestroyCounter.Clear();
					int num = -1;
					int num2 = 0;
					int num3 = 0;
					int[] array = flags;
					foreach (int num4 in array)
					{
						if ((selected & num4) == num4)
						{
							num = ((num >= 0) ? num : num3);
							num2++;
						}
						num3++;
					}
					if (!GUILayout.Button(text ?? ((num2 >= 2) ? $"{values[num]} and {num2 - 1} more" : ((num2 == 1) ? values[num] : "None")), style ?? GUI.skin.button, option))
					{
						return;
					}
					if (!base.Opened)
					{
						foreach (PopupWindow mPopup in mPopupList)
						{
							mPopup.Opened = false;
						}
						base.Opened = true;
					}
					else
					{
						base.Opened = false;
					}
				}

				public override void WindowFunction(int windowId)
				{
					//IL_0028: Unknown result type (might be due to invalid IL or missing references)
					//IL_0033: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Unknown result type (might be due to invalid IL or missing references)
					if (title != null)
					{
						GUILayout.Label(title, h1, (GUILayoutOption[])(object)new GUILayoutOption[0]);
					}
					if (!base.Recalculating)
					{
						mScrollPosition = GUILayout.BeginScrollView(mScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[0]);
					}
					if (values != null && flags != null)
					{
						int num = 0;
						string[] array = values;
						foreach (string text in array)
						{
							bool flag = (selected & flags[num]) == flags[num];
							if (GUILayout.Toggle(flag, text, (GUILayoutOption[])(object)new GUILayoutOption[0]) != flag)
							{
								if ((selected & flags[num]) == flags[num])
								{
									newSelected = selected ^ flags[num];
								}
								else
								{
									newSelected = selected | flags[num];
								}
							}
							num++;
						}
					}
					if (!base.Recalculating)
					{
						GUILayout.EndScrollView();
					}
					if (GUILayout.Button("Close", button, (GUILayoutOption[])(object)new GUILayoutOption[0]))
					{
						base.Opened = false;
					}
				}
			}

			private class Column
			{
				public string name;

				public float width;

				public bool expand;

				public bool skip;
			}

			internal class WindowParams
			{
				public int? Width { get; set; }

				public int? Height { get; set; }
			}

			internal class Window_GUI
			{
				internal static readonly List<Window_GUI> mList = new List<Window_GUI>();

				internal readonly HashSet<int> mDestroyCounter = new HashSet<int>();

				private const int MARGIN = 50;

				private int mId;

				private Rect mWindowRect;

				private Vector2 mScrollPosition;

				private int mWidth;

				private int mHeight;

				private int mRecalculateFrame;

				private bool mOpened;

				internal string title;

				internal int unique;

				internal Action<Window_GUI> onGui;

				internal Action onClose;

				private bool Recalculating => mRecalculateFrame == Time.frameCount;

				public bool Opened
				{
					get
					{
						return mOpened;
					}
					internal set
					{
						mOpened = value;
						if (value)
						{
							Reset();
						}
					}
				}

				public WindowParams Params { get; internal set; }

				public Window_GUI(Action<Window_GUI> onGui, Action onClose, string title, int unique, WindowParams @params = null)
				{
					mId = GetNextWindowId();
					mList.Add(this);
					this.onGui = onGui;
					this.onClose = onClose;
					this.unique = unique;
					this.title = title;
					Params = @params ?? new WindowParams();
				}

				public void Render()
				{
					//IL_011a: Unknown result type (might be due to invalid IL or missing references)
					//IL_0126: Unknown result type (might be due to invalid IL or missing references)
					//IL_0161: Expected O, but got Unknown
					//IL_015c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0161: Unknown result type (might be due to invalid IL or missing references)
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0039: Expected O, but got Unknown
					//IL_0034: Unknown result type (might be due to invalid IL or missing references)
					//IL_0039: Unknown result type (might be due to invalid IL or missing references)
					if (Recalculating)
					{
						mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[0]);
						if (((Rect)(ref mWindowRect)).width > 0f)
						{
							mWidth = (int)Math.Min(((float?)Params.Width) ?? ((Rect)(ref mWindowRect)).width, Screen.width - 100);
							mHeight = (int)Math.Min(((float?)Params.Height) ?? ((Rect)(ref mWindowRect)).height, Screen.height - 100);
							((Rect)(ref mWindowRect)).x = Math.Max(Screen.width - mWidth, 0) / 2;
							((Rect)(ref mWindowRect)).y = Math.Max(Screen.height - mHeight, 0) / 2;
						}
					}
					else
					{
						mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[2]
						{
							GUILayout.Width((float)mWidth),
							GUILayout.Height((float)(mHeight + 10))
						});
						GUI.BringWindowToFront(mId);
					}
				}

				private void WindowFunction(int windowId)
				{
					//IL_0028: Unknown result type (might be due to invalid IL or missing references)
					//IL_0033: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Unknown result type (might be due to invalid IL or missing references)
					if (title != null)
					{
						GUILayout.Label(title, h1, (GUILayoutOption[])(object)new GUILayoutOption[0]);
					}
					if (!Recalculating)
					{
						mScrollPosition = GUILayout.BeginScrollView(mScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[0]);
					}
					onGui(this);
					if (!Recalculating)
					{
						GUILayout.EndScrollView();
					}
				}

				internal void Reset()
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					mRecalculateFrame = Time.frameCount;
					mWindowRect = new Rect(-9000f, 0f, 0f, 0f);
				}

				public void Close()
				{
					if (!Opened)
					{
						return;
					}
					Opened = false;
					if (onClose == null)
					{
						return;
					}
					try
					{
						onClose();
					}
					catch (Exception ex)
					{
						Logger.Error("Window.OnClose: " + ex.GetType()?.ToString() + " - " + ex.Message);
						Console.WriteLine(ex.ToString());
					}
				}
			}

			[Serializable]
			[CompilerGenerated]
			private sealed class <>c
			{
				public static readonly <>c <>9 = new <>c();

				public static Func<Color32, Color32> <>9__68_0;

				public static Action<ModEntry> <>9__82_0;

				public static Action<ModEntry> <>9__82_1;

				public static UnityAction <>9__87_0;

				public static Func<Column, bool> <>9__89_0;

				public static Func<Column, float> <>9__89_1;

				public static Func<Column, bool> <>9__89_2;

				public static Func<Column, float> <>9__89_3;

				public static UnityAction <>9__89_5;

				public static Action<int> <>9__89_6;

				public static Func<ModEntry, bool> <>9__100_0;

				public static Func<object, bool> <>9__147_4;

				public static Func<PropertyAttribute, int> <>9__147_5;

				public static Converter<object, float> <>9__147_8;

				public static Converter<object, int> <>9__147_9;

				public static Converter<object, long> <>9__147_10;

				public static Converter<object, double> <>9__147_11;

				public static Converter<object, string> <>9__147_12;

				internal Color32 <PrepareGUI>b__68_0(Color32 x)
				{
					//IL_0012: Unknown result type (might be due to invalid IL or missing references)
					((Color32)(ref x))..ctor((byte)30, (byte)30, (byte)30, byte.MaxValue);
					return x;
				}

				internal void <set_ShowModSettings>b__82_0(ModEntry mod)
				{
					if (mod.Active && mod.OnHideGUI != null && mod.OnGUI != null)
					{
						try
						{
							mod.OnHideGUI(mod);
						}
						catch (ExitGUIException)
						{
						}
						catch (Exception e)
						{
							mod.Logger.LogException("OnHideGUI", e);
						}
					}
				}

				internal void <set_ShowModSettings>b__82_1(ModEntry mod)
				{
					if (mod.Active && mod.OnShowGUI != null && mod.OnGUI != null)
					{
						try
						{
							mod.OnShowGUI(mod);
						}
						catch (ExitGUIException)
						{
						}
						catch (Exception e)
						{
							mod.Logger.LogException("OnShowGUI", e);
						}
					}
				}

				internal void <WindowFunction>b__87_0()
				{
				}

				internal bool <DrawTab>b__89_0(Column x)
				{
					return !x.skip;
				}

				internal float <DrawTab>b__89_1(Column x)
				{
					return x.width;
				}

				internal bool <DrawTab>b__89_2(Column x)
				{
					if (x.expand)
					{
						return !x.skip;
					}
					return false;
				}

				internal float <DrawTab>b__89_3(Column x)
				{
					return x.width;
				}

				internal void <DrawTab>b__89_5()
				{
					if (GUILayout.Button("Clear", button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
					{
						Logger.Clear();
					}
					if (GUILayout.Button("Open Unity log", button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
					{
						OpenUnityFileLog();
					}
					if (GUILayout.Button("Open UMM log", button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
					{
						OpenUMMLog();
					}
				}

				internal void <DrawTab>b__89_6(int i)
				{
					Params.ShowOnStart = i;
				}

				internal bool <FirstLaunch>b__100_0(ModEntry x)
				{
					return !x.ErrorOnLoading;
				}

				internal bool <Draw>b__147_4(object x)
				{
					return x is PropertyAttribute;
				}

				internal int <Draw>b__147_5(PropertyAttribute x)
				{
					return x.order;
				}

				internal float <Draw>b__147_8(object x)
				{
					return (float)x;
				}

				internal int <Draw>