Decompiled source of CityMonitor v0.3.0

System.Collections.Immutable.dll

Decompiled a year ago
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using FxResources.System.Collections.Immutable;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("System.Collections.Immutable.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")]
[assembly: AssemblyDefaultAlias("System.Collections.Immutable")]
[assembly: AssemblyMetadata(".NETFrameworkAssembly", "")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("PreferInbox", "True")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyDescription("System.Collections.Immutable")]
[assembly: AssemblyFileVersion("4.700.20.21406")]
[assembly: AssemblyInformationalVersion("3.1.4+c4164928b270ee2369808ab347d33423ef765216")]
[assembly: AssemblyProduct("Microsoft® .NET Core")]
[assembly: AssemblyTitle("System.Collections.Immutable")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyVersion("1.2.5.0")]
[module: System.Runtime.CompilerServices.NullablePublicOnly(true)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class NullablePublicOnlyAttribute : Attribute
	{
		public readonly bool IncludesInternals;

		public NullablePublicOnlyAttribute(bool P_0)
		{
			IncludesInternals = P_0;
		}
	}
}
namespace FxResources.System.Collections.Immutable
{
	internal static class SR
	{
	}
}
namespace System
{
	internal static class SR
	{
		private static ResourceManager s_resourceManager;

		internal static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(typeof(SR)));

		internal static string Arg_KeyNotFoundWithKey => GetResourceString("Arg_KeyNotFoundWithKey");

		internal static string ArrayInitializedStateNotEqual => GetResourceString("ArrayInitializedStateNotEqual");

		internal static string ArrayLengthsNotEqual => GetResourceString("ArrayLengthsNotEqual");

		internal static string CannotFindOldValue => GetResourceString("CannotFindOldValue");

		internal static string CapacityMustBeGreaterThanOrEqualToCount => GetResourceString("CapacityMustBeGreaterThanOrEqualToCount");

		internal static string CapacityMustEqualCountOnMove => GetResourceString("CapacityMustEqualCountOnMove");

		internal static string CollectionModifiedDuringEnumeration => GetResourceString("CollectionModifiedDuringEnumeration");

		internal static string DuplicateKey => GetResourceString("DuplicateKey");

		internal static string InvalidEmptyOperation => GetResourceString("InvalidEmptyOperation");

		internal static string InvalidOperationOnDefaultArray => GetResourceString("InvalidOperationOnDefaultArray");

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool UsingResourceKeys()
		{
			return false;
		}

		internal static string GetResourceString(string resourceKey, string? defaultString = null)
		{
			if (UsingResourceKeys())
			{
				return defaultString ?? resourceKey;
			}
			string text = null;
			try
			{
				text = ResourceManager.GetString(resourceKey);
			}
			catch (MissingManifestResourceException)
			{
			}
			if (defaultString != null && resourceKey.Equals(text))
			{
				return defaultString;
			}
			return text;
		}

		internal static string Format(string resourceFormat, object? p1)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1);
			}
			return string.Format(resourceFormat, p1);
		}

		internal static string Format(string resourceFormat, object? p1, object? p2)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1, p2);
			}
			return string.Format(resourceFormat, p1, p2);
		}

		internal static string Format(string resourceFormat, object? p1, object? p2, object? p3)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1, p2, p3);
			}
			return string.Format(resourceFormat, p1, p2, p3);
		}

		internal static string Format(string resourceFormat, params object?[]? args)
		{
			if (args != null)
			{
				if (UsingResourceKeys())
				{
					return resourceFormat + ", " + string.Join(", ", args);
				}
				return string.Format(resourceFormat, args);
			}
			return resourceFormat;
		}

		internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1);
			}
			return string.Format(provider, resourceFormat, p1);
		}

		internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1, p2);
			}
			return string.Format(provider, resourceFormat, p1, p2);
		}

		internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2, object? p3)
		{
			if (UsingResourceKeys())
			{
				return string.Join(", ", resourceFormat, p1, p2, p3);
			}
			return string.Format(provider, resourceFormat, p1, p2, p3);
		}

		internal static string Format(IFormatProvider? provider, string resourceFormat, params object?[]? args)
		{
			if (args != null)
			{
				if (UsingResourceKeys())
				{
					return resourceFormat + ", " + string.Join(", ", args);
				}
				return string.Format(provider, resourceFormat, args);
			}
			return resourceFormat;
		}
	}
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
	internal sealed class NonVersionableAttribute : Attribute
	{
	}
}
namespace System.Linq
{
	public static class ImmutableArrayExtensions
	{
		public static IEnumerable<TResult> Select<T, TResult>(this ImmutableArray<T> immutableArray, Func<T, TResult> selector)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			return immutableArray.array.Select(selector);
		}

		public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this ImmutableArray<TSource> immutableArray, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			if (collectionSelector == null || resultSelector == null)
			{
				return Enumerable.SelectMany(immutableArray, collectionSelector, resultSelector);
			}
			if (immutableArray.Length != 0)
			{
				return immutableArray.SelectManyIterator(collectionSelector, resultSelector);
			}
			return Enumerable.Empty<TResult>();
		}

		public static IEnumerable<T> Where<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			return immutableArray.array.Where(predicate);
		}

		public static bool Any<T>(this ImmutableArray<T> immutableArray)
		{
			return immutableArray.Length > 0;
		}

		public static bool Any<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			Requires.NotNull(predicate, "predicate");
			T[] array = immutableArray.array;
			foreach (T arg in array)
			{
				if (predicate(arg))
				{
					return true;
				}
			}
			return false;
		}

		public static bool All<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			Requires.NotNull(predicate, "predicate");
			T[] array = immutableArray.array;
			foreach (T arg in array)
			{
				if (!predicate(arg))
				{
					return false;
				}
			}
			return true;
		}

		public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, ImmutableArray<TDerived> items, IEqualityComparer<TBase> comparer = null) where TDerived : TBase
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			items.ThrowNullRefIfNotInitialized();
			if (immutableArray.array == items.array)
			{
				return true;
			}
			if (immutableArray.Length != items.Length)
			{
				return false;
			}
			if (comparer == null)
			{
				comparer = EqualityComparer<TBase>.Default;
			}
			for (int i = 0; i < immutableArray.Length; i++)
			{
				if (!comparer.Equals(immutableArray.array[i], (TBase)(object)items.array[i]))
				{
					return false;
				}
			}
			return true;
		}

		public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, IEnumerable<TDerived> items, IEqualityComparer<TBase> comparer = null) where TDerived : TBase
		{
			Requires.NotNull(items, "items");
			if (comparer == null)
			{
				comparer = EqualityComparer<TBase>.Default;
			}
			int num = 0;
			int length = immutableArray.Length;
			foreach (TDerived item in items)
			{
				if (num == length)
				{
					return false;
				}
				if (!comparer.Equals(immutableArray[num], (TBase)(object)item))
				{
					return false;
				}
				num++;
			}
			return num == length;
		}

		public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, ImmutableArray<TDerived> items, Func<TBase, TBase, bool> predicate) where TDerived : TBase
		{
			Requires.NotNull(predicate, "predicate");
			immutableArray.ThrowNullRefIfNotInitialized();
			items.ThrowNullRefIfNotInitialized();
			if (immutableArray.array == items.array)
			{
				return true;
			}
			if (immutableArray.Length != items.Length)
			{
				return false;
			}
			int i = 0;
			for (int length = immutableArray.Length; i < length; i++)
			{
				if (!predicate(immutableArray[i], (TBase)(object)items[i]))
				{
					return false;
				}
			}
			return true;
		}

		public static T Aggregate<T>(this ImmutableArray<T> immutableArray, Func<T, T, T> func)
		{
			Requires.NotNull(func, "func");
			if (immutableArray.Length == 0)
			{
				return default(T);
			}
			T val = immutableArray[0];
			int i = 1;
			for (int length = immutableArray.Length; i < length; i++)
			{
				val = func(val, immutableArray[i]);
			}
			return val;
		}

		public static TAccumulate Aggregate<TAccumulate, T>(this ImmutableArray<T> immutableArray, TAccumulate seed, Func<TAccumulate, T, TAccumulate> func)
		{
			Requires.NotNull(func, "func");
			TAccumulate val = seed;
			T[] array = immutableArray.array;
			foreach (T arg in array)
			{
				val = func(val, arg);
			}
			return val;
		}

		public static TResult Aggregate<TAccumulate, TResult, T>(this ImmutableArray<T> immutableArray, TAccumulate seed, Func<TAccumulate, T, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
		{
			Requires.NotNull(resultSelector, "resultSelector");
			return resultSelector(immutableArray.Aggregate(seed, func));
		}

		public static T ElementAt<T>(this ImmutableArray<T> immutableArray, int index)
		{
			return immutableArray[index];
		}

		public static T ElementAtOrDefault<T>(this ImmutableArray<T> immutableArray, int index)
		{
			if (index < 0 || index >= immutableArray.Length)
			{
				return default(T);
			}
			return immutableArray[index];
		}

		public static T First<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			Requires.NotNull(predicate, "predicate");
			T[] array = immutableArray.array;
			foreach (T val in array)
			{
				if (predicate(val))
				{
					return val;
				}
			}
			return Enumerable.Empty<T>().First();
		}

		public static T First<T>(this ImmutableArray<T> immutableArray)
		{
			if (immutableArray.Length <= 0)
			{
				return immutableArray.array.First();
			}
			return immutableArray[0];
		}

		public static T FirstOrDefault<T>(this ImmutableArray<T> immutableArray)
		{
			if (immutableArray.array.Length == 0)
			{
				return default(T);
			}
			return immutableArray.array[0];
		}

		public static T FirstOrDefault<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			Requires.NotNull(predicate, "predicate");
			T[] array = immutableArray.array;
			foreach (T val in array)
			{
				if (predicate(val))
				{
					return val;
				}
			}
			return default(T);
		}

		public static T Last<T>(this ImmutableArray<T> immutableArray)
		{
			if (immutableArray.Length <= 0)
			{
				return immutableArray.array.Last();
			}
			return immutableArray[immutableArray.Length - 1];
		}

		public static T Last<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			Requires.NotNull(predicate, "predicate");
			for (int num = immutableArray.Length - 1; num >= 0; num--)
			{
				if (predicate(immutableArray[num]))
				{
					return immutableArray[num];
				}
			}
			return Enumerable.Empty<T>().Last();
		}

		public static T LastOrDefault<T>(this ImmutableArray<T> immutableArray)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			return immutableArray.array.LastOrDefault();
		}

		public static T LastOrDefault<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			Requires.NotNull(predicate, "predicate");
			for (int num = immutableArray.Length - 1; num >= 0; num--)
			{
				if (predicate(immutableArray[num]))
				{
					return immutableArray[num];
				}
			}
			return default(T);
		}

		public static T Single<T>(this ImmutableArray<T> immutableArray)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			return immutableArray.array.Single();
		}

		public static T Single<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			Requires.NotNull(predicate, "predicate");
			bool flag = true;
			T result = default(T);
			T[] array = immutableArray.array;
			foreach (T val in array)
			{
				if (predicate(val))
				{
					if (!flag)
					{
						ImmutableArray.TwoElementArray.Single();
					}
					flag = false;
					result = val;
				}
			}
			if (flag)
			{
				Enumerable.Empty<T>().Single();
			}
			return result;
		}

		public static T SingleOrDefault<T>(this ImmutableArray<T> immutableArray)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			return immutableArray.array.SingleOrDefault();
		}

		public static T SingleOrDefault<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate)
		{
			Requires.NotNull(predicate, "predicate");
			bool flag = true;
			T result = default(T);
			T[] array = immutableArray.array;
			foreach (T val in array)
			{
				if (predicate(val))
				{
					if (!flag)
					{
						ImmutableArray.TwoElementArray.Single();
					}
					flag = false;
					result = val;
				}
			}
			return result;
		}

		public static Dictionary<TKey, T> ToDictionary<TKey, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector)
		{
			return immutableArray.ToDictionary(keySelector, EqualityComparer<TKey>.Default);
		}

		public static Dictionary<TKey, TElement> ToDictionary<TKey, TElement, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector, Func<T, TElement> elementSelector)
		{
			return immutableArray.ToDictionary(keySelector, elementSelector, EqualityComparer<TKey>.Default);
		}

		public static Dictionary<TKey, T> ToDictionary<TKey, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector, IEqualityComparer<TKey> comparer)
		{
			Requires.NotNull(keySelector, "keySelector");
			Dictionary<TKey, T> dictionary = new Dictionary<TKey, T>(immutableArray.Length, comparer);
			ImmutableArray<T>.Enumerator enumerator = immutableArray.GetEnumerator();
			while (enumerator.MoveNext())
			{
				T current = enumerator.Current;
				dictionary.Add(keySelector(current), current);
			}
			return dictionary;
		}

		public static Dictionary<TKey, TElement> ToDictionary<TKey, TElement, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector, Func<T, TElement> elementSelector, IEqualityComparer<TKey> comparer)
		{
			Requires.NotNull(keySelector, "keySelector");
			Requires.NotNull(elementSelector, "elementSelector");
			Dictionary<TKey, TElement> dictionary = new Dictionary<TKey, TElement>(immutableArray.Length, comparer);
			T[] array = immutableArray.array;
			foreach (T arg in array)
			{
				dictionary.Add(keySelector(arg), elementSelector(arg));
			}
			return dictionary;
		}

		public static T[] ToArray<T>(this ImmutableArray<T> immutableArray)
		{
			immutableArray.ThrowNullRefIfNotInitialized();
			if (immutableArray.array.Length == 0)
			{
				return ImmutableArray<T>.Empty.array;
			}
			return (T[])immutableArray.array.Clone();
		}

		public static T First<T>(this ImmutableArray<T>.Builder builder)
		{
			Requires.NotNull(builder, "builder");
			if (!builder.Any())
			{
				throw new InvalidOperationException();
			}
			return builder[0];
		}

		public static T FirstOrDefault<T>(this ImmutableArray<T>.Builder builder)
		{
			Requires.NotNull(builder, "builder");
			if (!builder.Any())
			{
				return default(T);
			}
			return builder[0];
		}

		public static T Last<T>(this ImmutableArray<T>.Builder builder)
		{
			Requires.NotNull(builder, "builder");
			if (!builder.Any())
			{
				throw new InvalidOperationException();
			}
			return builder[builder.Count - 1];
		}

		public static T LastOrDefault<T>(this ImmutableArray<T>.Builder builder)
		{
			Requires.NotNull(builder, "builder");
			if (!builder.Any())
			{
				return default(T);
			}
			return builder[builder.Count - 1];
		}

		public static bool Any<T>(this ImmutableArray<T>.Builder builder)
		{
			Requires.NotNull(builder, "builder");
			return builder.Count > 0;
		}

		private static IEnumerable<TResult> SelectManyIterator<TSource, TCollection, TResult>(this ImmutableArray<TSource> immutableArray, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
		{
			TSource[] array = immutableArray.array;
			foreach (TSource item in array)
			{
				foreach (TCollection item2 in collectionSelector(item))
				{
					yield return resultSelector(item, item2);
				}
			}
		}
	}
}
namespace System.Collections.Immutable
{
	internal static class AllocFreeConcurrentStack<T>
	{
		private const int MaxSize = 35;

		private static readonly Type s_typeOfT = typeof(T);

		private static Stack<RefAsValueType<T>> ThreadLocalStack
		{
			get
			{
				Dictionary<Type, object> dictionary = AllocFreeConcurrentStack.t_stacks;
				if (dictionary == null)
				{
					dictionary = (AllocFreeConcurrentStack.t_stacks = new Dictionary<Type, object>());
				}
				if (!dictionary.TryGetValue(s_typeOfT, out var value))
				{
					value = new Stack<RefAsValueType<T>>(35);
					dictionary.Add(s_typeOfT, value);
				}
				return (Stack<RefAsValueType<T>>)value;
			}
		}

		public static void TryAdd(T item)
		{
			Stack<RefAsValueType<T>> threadLocalStack = ThreadLocalStack;
			if (threadLocalStack.Count < 35)
			{
				threadLocalStack.Push(new RefAsValueType<T>(item));
			}
		}

		public static bool TryTake(out T item)
		{
			Stack<RefAsValueType<T>> threadLocalStack = ThreadLocalStack;
			if (threadLocalStack != null && threadLocalStack.Count > 0)
			{
				item = threadLocalStack.Pop().Value;
				return true;
			}
			item = default(T);
			return false;
		}
	}
	internal static class AllocFreeConcurrentStack
	{
		[ThreadStatic]
		internal static Dictionary<Type, object> t_stacks;
	}
	internal sealed class DictionaryEnumerator<TKey, TValue> : IDictionaryEnumerator, IEnumerator
	{
		private readonly IEnumerator<KeyValuePair<TKey, TValue>> _inner;

		public DictionaryEntry Entry => new DictionaryEntry(_inner.Current.Key, _inner.Current.Value);

		public object Key => _inner.Current.Key;

		public object Value => _inner.Current.Value;

		public object Current => Entry;

		internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> inner)
		{
			Requires.NotNull(inner, "inner");
			_inner = inner;
		}

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

		public void Reset()
		{
			_inner.Reset();
		}
	}
	internal struct DisposableEnumeratorAdapter<T, TEnumerator> : IDisposable where TEnumerator : struct, IEnumerator<T>
	{
		private readonly IEnumerator<T> _enumeratorObject;

		private TEnumerator _enumeratorStruct;

		public T Current
		{
			get
			{
				if (_enumeratorObject == null)
				{
					return _enumeratorStruct.Current;
				}
				return _enumeratorObject.Current;
			}
		}

		internal DisposableEnumeratorAdapter(TEnumerator enumerator)
		{
			_enumeratorStruct = enumerator;
			_enumeratorObject = null;
		}

		internal DisposableEnumeratorAdapter(IEnumerator<T> enumerator)
		{
			_enumeratorStruct = default(TEnumerator);
			_enumeratorObject = enumerator;
		}

		public bool MoveNext()
		{
			if (_enumeratorObject == null)
			{
				return _enumeratorStruct.MoveNext();
			}
			return _enumeratorObject.MoveNext();
		}

		public void Dispose()
		{
			if (_enumeratorObject != null)
			{
				_enumeratorObject.Dispose();
			}
			else
			{
				_enumeratorStruct.Dispose();
			}
		}

		public DisposableEnumeratorAdapter<T, TEnumerator> GetEnumerator()
		{
			return this;
		}
	}
	internal interface IBinaryTree
	{
		int Height { get; }

		bool IsEmpty { get; }

		int Count { get; }

		IBinaryTree Left { get; }

		IBinaryTree Right { get; }
	}
	internal interface IBinaryTree<out T> : IBinaryTree
	{
		T Value { get; }

		new IBinaryTree<T> Left { get; }

		new IBinaryTree<T> Right { get; }
	}
	internal interface IImmutableArray
	{
		Array Array { get; }
	}
	public interface IImmutableDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IReadOnlyCollection<KeyValuePair<TKey, TValue>>
	{
		IImmutableDictionary<TKey, TValue> Clear();

		IImmutableDictionary<TKey, TValue> Add(TKey key, TValue value);

		IImmutableDictionary<TKey, TValue> AddRange(IEnumerable<KeyValuePair<TKey, TValue>> pairs);

		IImmutableDictionary<TKey, TValue> SetItem(TKey key, TValue value);

		IImmutableDictionary<TKey, TValue> SetItems(IEnumerable<KeyValuePair<TKey, TValue>> items);

		IImmutableDictionary<TKey, TValue> RemoveRange(IEnumerable<TKey> keys);

		IImmutableDictionary<TKey, TValue> Remove(TKey key);

		bool Contains(KeyValuePair<TKey, TValue> pair);

		bool TryGetKey(TKey equalKey, out TKey actualKey);
	}
	internal interface IImmutableDictionaryInternal<TKey, TValue>
	{
		bool ContainsValue(TValue value);
	}
	public interface IImmutableList<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>
	{
		IImmutableList<T> Clear();

		int IndexOf(T item, int index, int count, IEqualityComparer<T> equalityComparer);

		int LastIndexOf(T item, int index, int count, IEqualityComparer<T> equalityComparer);

		IImmutableList<T> Add(T value);

		IImmutableList<T> AddRange(IEnumerable<T> items);

		IImmutableList<T> Insert(int index, T element);

		IImmutableList<T> InsertRange(int index, IEnumerable<T> items);

		IImmutableList<T> Remove(T value, IEqualityComparer<T> equalityComparer);

		IImmutableList<T> RemoveAll(Predicate<T> match);

		IImmutableList<T> RemoveRange(IEnumerable<T> items, IEqualityComparer<T> equalityComparer);

		IImmutableList<T> RemoveRange(int index, int count);

		IImmutableList<T> RemoveAt(int index);

		IImmutableList<T> SetItem(int index, T value);

		IImmutableList<T> Replace(T oldValue, T newValue, IEqualityComparer<T> equalityComparer);
	}
	internal interface IImmutableListQueries<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>
	{
		ImmutableList<TOutput> ConvertAll<TOutput>(Func<T, TOutput> converter);

		void ForEach(Action<T> action);

		ImmutableList<T> GetRange(int index, int count);

		void CopyTo(T[] array);

		void CopyTo(T[] array, int arrayIndex);

		void CopyTo(int index, T[] array, int arrayIndex, int count);

		bool Exists(Predicate<T> match);

		T Find(Predicate<T> match);

		ImmutableList<T> FindAll(Predicate<T> match);

		int FindIndex(Predicate<T> match);

		int FindIndex(int startIndex, Predicate<T> match);

		int FindIndex(int startIndex, int count, Predicate<T> match);

		T FindLast(Predicate<T> match);

		int FindLastIndex(Predicate<T> match);

		int FindLastIndex(int startIndex, Predicate<T> match);

		int FindLastIndex(int startIndex, int count, Predicate<T> match);

		bool TrueForAll(Predicate<T> match);

		int BinarySearch(T item);

		int BinarySearch(T item, IComparer<T> comparer);

		int BinarySearch(int index, int count, T item, IComparer<T> comparer);
	}
	public interface IImmutableQueue<T> : IEnumerable<T>, IEnumerable
	{
		bool IsEmpty { get; }

		IImmutableQueue<T> Clear();

		T Peek();

		IImmutableQueue<T> Enqueue(T value);

		IImmutableQueue<T> Dequeue();
	}
	public interface IImmutableSet<T> : IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
	{
		IImmutableSet<T> Clear();

		bool Contains(T value);

		IImmutableSet<T> Add(T value);

		IImmutableSet<T> Remove(T value);

		bool TryGetValue(T equalValue, out T actualValue);

		IImmutableSet<T> Intersect(IEnumerable<T> other);

		IImmutableSet<T> Except(IEnumerable<T> other);

		IImmutableSet<T> SymmetricExcept(IEnumerable<T> other);

		IImmutableSet<T> Union(IEnumerable<T> other);

		bool SetEquals(IEnumerable<T> other);

		bool IsProperSubsetOf(IEnumerable<T> other);

		bool IsProperSupersetOf(IEnumerable<T> other);

		bool IsSubsetOf(IEnumerable<T> other);

		bool IsSupersetOf(IEnumerable<T> other);

		bool Overlaps(IEnumerable<T> other);
	}
	public interface IImmutableStack<T> : IEnumerable<T>, IEnumerable
	{
		bool IsEmpty { get; }

		IImmutableStack<T> Clear();

		IImmutableStack<T> Push(T value);

		IImmutableStack<T> Pop();

		T Peek();
	}
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))]
	public sealed class ImmutableHashSet<T> : IImmutableSet<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable, IHashKeyCollection<T>, ICollection<T>, ISet<T>, ICollection, IStrongEnumerable<T, ImmutableHashSet<T>.Enumerator>
	{
		private class HashBucketByValueEqualityComparer : IEqualityComparer<HashBucket>
		{
			private static readonly IEqualityComparer<HashBucket> s_defaultInstance = new HashBucketByValueEqualityComparer(EqualityComparer<T>.Default);

			private readonly IEqualityComparer<T> _valueComparer;

			internal static IEqualityComparer<HashBucket> DefaultInstance => s_defaultInstance;

			internal HashBucketByValueEqualityComparer(IEqualityComparer<T> valueComparer)
			{
				Requires.NotNull(valueComparer, "valueComparer");
				_valueComparer = valueComparer;
			}

			public bool Equals(HashBucket x, HashBucket y)
			{
				return x.EqualsByValue(y, _valueComparer);
			}

			public int GetHashCode(HashBucket obj)
			{
				throw new NotSupportedException();
			}
		}

		private class HashBucketByRefEqualityComparer : IEqualityComparer<HashBucket>
		{
			private static readonly IEqualityComparer<HashBucket> s_defaultInstance = new HashBucketByRefEqualityComparer();

			internal static IEqualityComparer<HashBucket> DefaultInstance => s_defaultInstance;

			private HashBucketByRefEqualityComparer()
			{
			}

			public bool Equals(HashBucket x, HashBucket y)
			{
				return x.EqualsByRef(y);
			}

			public int GetHashCode(HashBucket obj)
			{
				throw new NotSupportedException();
			}
		}

		[DebuggerDisplay("Count = {Count}")]
		public sealed class Builder : IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable, ISet<T>, ICollection<T>
		{
			private SortedInt32KeyNode<HashBucket> _root = SortedInt32KeyNode<HashBucket>.EmptyNode;

			private IEqualityComparer<T> _equalityComparer;

			private IEqualityComparer<HashBucket> _hashBucketEqualityComparer;

			private int _count;

			private ImmutableHashSet<T> _immutable;

			private int _version;

			public int Count => _count;

			bool ICollection<T>.IsReadOnly => false;

			public IEqualityComparer<T> KeyComparer
			{
				get
				{
					return _equalityComparer;
				}
				set
				{
					Requires.NotNull(value, "value");
					if (value != _equalityComparer)
					{
						MutationResult mutationResult = ImmutableHashSet<T>.Union((IEnumerable<T>)this, new MutationInput(SortedInt32KeyNode<HashBucket>.EmptyNode, value, _hashBucketEqualityComparer, 0));
						_immutable = null;
						_equalityComparer = value;
						Root = mutationResult.Root;
						_count = mutationResult.Count;
					}
				}
			}

			internal int Version => _version;

			private MutationInput Origin => new MutationInput(Root, _equalityComparer, _hashBucketEqualityComparer, _count);

			private SortedInt32KeyNode<HashBucket> Root
			{
				get
				{
					return _root;
				}
				set
				{
					_version++;
					if (_root != value)
					{
						_root = value;
						_immutable = null;
					}
				}
			}

			internal Builder(ImmutableHashSet<T> set)
			{
				Requires.NotNull(set, "set");
				_root = set._root;
				_count = set._count;
				_equalityComparer = set._equalityComparer;
				_hashBucketEqualityComparer = set._hashBucketEqualityComparer;
				_immutable = set;
			}

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

			public ImmutableHashSet<T> ToImmutable()
			{
				if (_immutable == null)
				{
					_immutable = ImmutableHashSet<T>.Wrap(_root, _equalityComparer, _count);
				}
				return _immutable;
			}

			public bool Add(T item)
			{
				MutationResult result = ImmutableHashSet<T>.Add(item, Origin);
				Apply(result);
				return result.Count != 0;
			}

			public bool Remove(T item)
			{
				MutationResult result = ImmutableHashSet<T>.Remove(item, Origin);
				Apply(result);
				return result.Count != 0;
			}

			public bool Contains(T item)
			{
				return ImmutableHashSet<T>.Contains(item, Origin);
			}

			public void Clear()
			{
				_count = 0;
				Root = SortedInt32KeyNode<HashBucket>.EmptyNode;
			}

			public void ExceptWith(IEnumerable<T> other)
			{
				MutationResult result = ImmutableHashSet<T>.Except(other, _equalityComparer, _hashBucketEqualityComparer, _root);
				Apply(result);
			}

			public void IntersectWith(IEnumerable<T> other)
			{
				MutationResult result = ImmutableHashSet<T>.Intersect(other, Origin);
				Apply(result);
			}

			public bool IsProperSubsetOf(IEnumerable<T> other)
			{
				return ImmutableHashSet<T>.IsProperSubsetOf(other, Origin);
			}

			public bool IsProperSupersetOf(IEnumerable<T> other)
			{
				return ImmutableHashSet<T>.IsProperSupersetOf(other, Origin);
			}

			public bool IsSubsetOf(IEnumerable<T> other)
			{
				return ImmutableHashSet<T>.IsSubsetOf(other, Origin);
			}

			public bool IsSupersetOf(IEnumerable<T> other)
			{
				return ImmutableHashSet<T>.IsSupersetOf(other, Origin);
			}

			public bool Overlaps(IEnumerable<T> other)
			{
				return ImmutableHashSet<T>.Overlaps(other, Origin);
			}

			public bool SetEquals(IEnumerable<T> other)
			{
				if (this == other)
				{
					return true;
				}
				return ImmutableHashSet<T>.SetEquals(other, Origin);
			}

			public void SymmetricExceptWith(IEnumerable<T> other)
			{
				MutationResult result = ImmutableHashSet<T>.SymmetricExcept(other, Origin);
				Apply(result);
			}

			public void UnionWith(IEnumerable<T> other)
			{
				MutationResult result = ImmutableHashSet<T>.Union(other, Origin);
				Apply(result);
			}

			void ICollection<T>.Add(T item)
			{
				Add(item);
			}

			void ICollection<T>.CopyTo(T[] array, int arrayIndex)
			{
				Requires.NotNull(array, "array");
				Requires.Range(arrayIndex >= 0, "arrayIndex");
				Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex");
				using Enumerator enumerator = GetEnumerator();
				while (enumerator.MoveNext())
				{
					T current = enumerator.Current;
					array[arrayIndex++] = current;
				}
			}

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

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

			private void Apply(MutationResult result)
			{
				Root = result.Root;
				if (result.CountType == CountType.Adjustment)
				{
					_count += result.Count;
				}
				else
				{
					_count = result.Count;
				}
			}
		}

		public struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable, IStrongEnumerator<T>
		{
			private readonly Builder _builder;

			private SortedInt32KeyNode<HashBucket>.Enumerator _mapEnumerator;

			private HashBucket.Enumerator _bucketEnumerator;

			private int _enumeratingBuilderVersion;

			public T Current
			{
				get
				{
					_mapEnumerator.ThrowIfDisposed();
					return _bucketEnumerator.Current;
				}
			}

			object IEnumerator.Current => Current;

			internal Enumerator(SortedInt32KeyNode<HashBucket> root, Builder builder = null)
			{
				_builder = builder;
				_mapEnumerator = new SortedInt32KeyNode<HashBucket>.Enumerator(root);
				_bucketEnumerator = default(HashBucket.Enumerator);
				_enumeratingBuilderVersion = builder?.Version ?? (-1);
			}

			public bool MoveNext()
			{
				ThrowIfChanged();
				if (_bucketEnumerator.MoveNext())
				{
					return true;
				}
				if (_mapEnumerator.MoveNext())
				{
					_bucketEnumerator = new HashBucket.Enumerator(_mapEnumerator.Current.Value);
					return _bucketEnumerator.MoveNext();
				}
				return false;
			}

			public void Reset()
			{
				_enumeratingBuilderVersion = ((_builder != null) ? _builder.Version : (-1));
				_mapEnumerator.Reset();
				_bucketEnumerator.Dispose();
				_bucketEnumerator = default(HashBucket.Enumerator);
			}

			public void Dispose()
			{
				_mapEnumerator.Dispose();
				_bucketEnumerator.Dispose();
			}

			private void ThrowIfChanged()
			{
				if (_builder != null && _builder.Version != _enumeratingBuilderVersion)
				{
					throw new InvalidOperationException(System.SR.CollectionModifiedDuringEnumeration);
				}
			}
		}

		internal enum OperationResult
		{
			SizeChanged,
			NoChangeRequired
		}

		internal readonly struct HashBucket
		{
			internal struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable
			{
				private enum Position
				{
					BeforeFirst,
					First,
					Additional,
					End
				}

				private readonly HashBucket _bucket;

				private bool _disposed;

				private Position _currentPosition;

				private ImmutableList<T>.Enumerator _additionalEnumerator;

				object IEnumerator.Current => Current;

				public T Current
				{
					get
					{
						ThrowIfDisposed();
						return _currentPosition switch
						{
							Position.First => _bucket._firstValue, 
							Position.Additional => _additionalEnumerator.Current, 
							_ => throw new InvalidOperationException(), 
						};
					}
				}

				internal Enumerator(HashBucket bucket)
				{
					_disposed = false;
					_bucket = bucket;
					_currentPosition = Position.BeforeFirst;
					_additionalEnumerator = default(ImmutableList<T>.Enumerator);
				}

				public bool MoveNext()
				{
					ThrowIfDisposed();
					if (_bucket.IsEmpty)
					{
						_currentPosition = Position.End;
						return false;
					}
					switch (_currentPosition)
					{
					case Position.BeforeFirst:
						_currentPosition = Position.First;
						return true;
					case Position.First:
						if (_bucket._additionalElements.IsEmpty)
						{
							_currentPosition = Position.End;
							return false;
						}
						_currentPosition = Position.Additional;
						_additionalEnumerator = new ImmutableList<T>.Enumerator(_bucket._additionalElements);
						return _additionalEnumerator.MoveNext();
					case Position.Additional:
						return _additionalEnumerator.MoveNext();
					case Position.End:
						return false;
					default:
						throw new InvalidOperationException();
					}
				}

				public void Reset()
				{
					ThrowIfDisposed();
					_additionalEnumerator.Dispose();
					_currentPosition = Position.BeforeFirst;
				}

				public void Dispose()
				{
					_disposed = true;
					_additionalEnumerator.Dispose();
				}

				private void ThrowIfDisposed()
				{
					if (_disposed)
					{
						Requires.FailObjectDisposed(this);
					}
				}
			}

			private readonly T _firstValue;

			private readonly ImmutableList<T>.Node _additionalElements;

			internal bool IsEmpty => _additionalElements == null;

			private HashBucket(T firstElement, ImmutableList<T>.Node additionalElements = null)
			{
				_firstValue = firstElement;
				_additionalElements = additionalElements ?? ImmutableList<T>.Node.EmptyNode;
			}

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

			public override bool Equals(object obj)
			{
				throw new NotSupportedException();
			}

			public override int GetHashCode()
			{
				throw new NotSupportedException();
			}

			internal bool EqualsByRef(HashBucket other)
			{
				if ((object)_firstValue == (object)other._firstValue)
				{
					return _additionalElements == other._additionalElements;
				}
				return false;
			}

			internal bool EqualsByValue(HashBucket other, IEqualityComparer<T> valueComparer)
			{
				if (valueComparer.Equals(_firstValue, other._firstValue))
				{
					return _additionalElements == other._additionalElements;
				}
				return false;
			}

			internal HashBucket Add(T value, IEqualityComparer<T> valueComparer, out OperationResult result)
			{
				if (IsEmpty)
				{
					result = OperationResult.SizeChanged;
					return new HashBucket(value);
				}
				if (valueComparer.Equals(value, _firstValue) || _additionalElements.IndexOf(value, valueComparer) >= 0)
				{
					result = OperationResult.NoChangeRequired;
					return this;
				}
				result = OperationResult.SizeChanged;
				return new HashBucket(_firstValue, _additionalElements.Add(value));
			}

			internal bool Contains(T value, IEqualityComparer<T> valueComparer)
			{
				if (IsEmpty)
				{
					return false;
				}
				if (!valueComparer.Equals(value, _firstValue))
				{
					return _additionalElements.IndexOf(value, valueComparer) >= 0;
				}
				return true;
			}

			internal bool TryExchange(T value, IEqualityComparer<T> valueComparer, out T existingValue)
			{
				if (!IsEmpty)
				{
					if (valueComparer.Equals(value, _firstValue))
					{
						existingValue = _firstValue;
						return true;
					}
					int num = _additionalElements.IndexOf(value, valueComparer);
					if (num >= 0)
					{
						existingValue = _additionalElements.ItemRef(num);
						return true;
					}
				}
				existingValue = value;
				return false;
			}

			internal HashBucket Remove(T value, IEqualityComparer<T> equalityComparer, out OperationResult result)
			{
				if (IsEmpty)
				{
					result = OperationResult.NoChangeRequired;
					return this;
				}
				if (equalityComparer.Equals(_firstValue, value))
				{
					if (_additionalElements.IsEmpty)
					{
						result = OperationResult.SizeChanged;
						return default(HashBucket);
					}
					int count = _additionalElements.Left.Count;
					result = OperationResult.SizeChanged;
					return new HashBucket(_additionalElements.Key, _additionalElements.RemoveAt(count));
				}
				int num = _additionalElements.IndexOf(value, equalityComparer);
				if (num < 0)
				{
					result = OperationResult.NoChangeRequired;
					return this;
				}
				result = OperationResult.SizeChanged;
				return new HashBucket(_firstValue, _additionalElements.RemoveAt(num));
			}

			internal void Freeze()
			{
				if (_additionalElements != null)
				{
					_additionalElements.Freeze();
				}
			}
		}

		private readonly struct MutationInput
		{
			private readonly SortedInt32KeyNode<HashBucket> _root;

			private readonly IEqualityComparer<T> _equalityComparer;

			private readonly int _count;

			private readonly IEqualityComparer<HashBucket> _hashBucketEqualityComparer;

			internal SortedInt32KeyNode<HashBucket> Root => _root;

			internal IEqualityComparer<T> EqualityComparer => _equalityComparer;

			internal int Count => _count;

			internal IEqualityComparer<HashBucket> HashBucketEqualityComparer => _hashBucketEqualityComparer;

			internal MutationInput(ImmutableHashSet<T> set)
			{
				Requires.NotNull(set, "set");
				_root = set._root;
				_equalityComparer = set._equalityComparer;
				_count = set._count;
				_hashBucketEqualityComparer = set._hashBucketEqualityComparer;
			}

			internal MutationInput(SortedInt32KeyNode<HashBucket> root, IEqualityComparer<T> equalityComparer, IEqualityComparer<HashBucket> hashBucketEqualityComparer, int count)
			{
				Requires.NotNull(root, "root");
				Requires.NotNull(equalityComparer, "equalityComparer");
				Requires.Range(count >= 0, "count");
				Requires.NotNull(hashBucketEqualityComparer, "hashBucketEqualityComparer");
				_root = root;
				_equalityComparer = equalityComparer;
				_count = count;
				_hashBucketEqualityComparer = hashBucketEqualityComparer;
			}
		}

		private enum CountType
		{
			Adjustment,
			FinalValue
		}

		private readonly struct MutationResult
		{
			private readonly SortedInt32KeyNode<HashBucket> _root;

			private readonly int _count;

			private readonly CountType _countType;

			internal SortedInt32KeyNode<HashBucket> Root => _root;

			internal int Count => _count;

			internal CountType CountType => _countType;

			internal MutationResult(SortedInt32KeyNode<HashBucket> root, int count, CountType countType = CountType.Adjustment)
			{
				Requires.NotNull(root, "root");
				_root = root;
				_count = count;
				_countType = countType;
			}

			internal ImmutableHashSet<T> Finalize(ImmutableHashSet<T> priorSet)
			{
				Requires.NotNull(priorSet, "priorSet");
				int num = Count;
				if (CountType == CountType.Adjustment)
				{
					num += priorSet._count;
				}
				return priorSet.Wrap(Root, num);
			}
		}

		private readonly struct NodeEnumerable : IEnumerable<T>, IEnumerable
		{
			private readonly SortedInt32KeyNode<HashBucket> _root;

			internal NodeEnumerable(SortedInt32KeyNode<HashBucket> root)
			{
				Requires.NotNull(root, "root");
				_root = root;
			}

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

			[ExcludeFromCodeCoverage]
			IEnumerator<T> IEnumerable<T>.GetEnumerator()
			{
				return GetEnumerator();
			}

			[ExcludeFromCodeCoverage]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}
		}

		public static readonly ImmutableHashSet<T> Empty = new ImmutableHashSet<T>(SortedInt32KeyNode<HashBucket>.EmptyNode, EqualityComparer<T>.Default, 0);

		private static readonly Action<KeyValuePair<int, HashBucket>> s_FreezeBucketAction = delegate(KeyValuePair<int, HashBucket> kv)
		{
			kv.Value.Freeze();
		};

		private readonly IEqualityComparer<T> _equalityComparer;

		private readonly int _count;

		private readonly SortedInt32KeyNode<HashBucket> _root;

		private readonly IEqualityComparer<HashBucket> _hashBucketEqualityComparer;

		public int Count => _count;

		public bool IsEmpty => Count == 0;

		public IEqualityComparer<T> KeyComparer => _equalityComparer;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		object ICollection.SyncRoot => this;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		bool ICollection.IsSynchronized => true;

		internal IBinaryTree Root => _root;

		private MutationInput Origin => new MutationInput(this);

		bool ICollection<T>.IsReadOnly => true;

		internal ImmutableHashSet(IEqualityComparer<T> equalityComparer)
			: this(SortedInt32KeyNode<HashBucket>.EmptyNode, equalityComparer, 0)
		{
		}

		private ImmutableHashSet(SortedInt32KeyNode<HashBucket> root, IEqualityComparer<T> equalityComparer, int count)
		{
			Requires.NotNull(root, "root");
			Requires.NotNull(equalityComparer, "equalityComparer");
			root.Freeze(s_FreezeBucketAction);
			_root = root;
			_count = count;
			_equalityComparer = equalityComparer;
			_hashBucketEqualityComparer = GetHashBucketEqualityComparer(equalityComparer);
		}

		public ImmutableHashSet<T> Clear()
		{
			if (!IsEmpty)
			{
				return Empty.WithComparer(_equalityComparer);
			}
			return this;
		}

		[ExcludeFromCodeCoverage]
		IImmutableSet<T> IImmutableSet<T>.Clear()
		{
			return Clear();
		}

		public Builder ToBuilder()
		{
			return new Builder(this);
		}

		public ImmutableHashSet<T> Add(T item)
		{
			return Add(item, Origin).Finalize(this);
		}

		public ImmutableHashSet<T> Remove(T item)
		{
			return Remove(item, Origin).Finalize(this);
		}

		public bool TryGetValue(T equalValue, out T actualValue)
		{
			int hashCode = _equalityComparer.GetHashCode(equalValue);
			if (_root.TryGetValue(hashCode, out var value))
			{
				return value.TryExchange(equalValue, _equalityComparer, out actualValue);
			}
			actualValue = equalValue;
			return false;
		}

		public ImmutableHashSet<T> Union(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return Union(other, avoidWithComparer: false);
		}

		public ImmutableHashSet<T> Intersect(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return Intersect(other, Origin).Finalize(this);
		}

		public ImmutableHashSet<T> Except(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return Except(other, _equalityComparer, _hashBucketEqualityComparer, _root).Finalize(this);
		}

		public ImmutableHashSet<T> SymmetricExcept(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return SymmetricExcept(other, Origin).Finalize(this);
		}

		public bool SetEquals(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			if (this == other)
			{
				return true;
			}
			return SetEquals(other, Origin);
		}

		public bool IsProperSubsetOf(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return IsProperSubsetOf(other, Origin);
		}

		public bool IsProperSupersetOf(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return IsProperSupersetOf(other, Origin);
		}

		public bool IsSubsetOf(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return IsSubsetOf(other, Origin);
		}

		public bool IsSupersetOf(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return IsSupersetOf(other, Origin);
		}

		public bool Overlaps(IEnumerable<T> other)
		{
			Requires.NotNull(other, "other");
			return Overlaps(other, Origin);
		}

		[ExcludeFromCodeCoverage]
		IImmutableSet<T> IImmutableSet<T>.Add(T item)
		{
			return Add(item);
		}

		[ExcludeFromCodeCoverage]
		IImmutableSet<T> IImmutableSet<T>.Remove(T item)
		{
			return Remove(item);
		}

		[ExcludeFromCodeCoverage]
		IImmutableSet<T> IImmutableSet<T>.Union(IEnumerable<T> other)
		{
			return Union(other);
		}

		[ExcludeFromCodeCoverage]
		IImmutableSet<T> IImmutableSet<T>.Intersect(IEnumerable<T> other)
		{
			return Intersect(other);
		}

		[ExcludeFromCodeCoverage]
		IImmutableSet<T> IImmutableSet<T>.Except(IEnumerable<T> other)
		{
			return Except(other);
		}

		[ExcludeFromCodeCoverage]
		IImmutableSet<T> IImmutableSet<T>.SymmetricExcept(IEnumerable<T> other)
		{
			return SymmetricExcept(other);
		}

		public bool Contains(T item)
		{
			return Contains(item, Origin);
		}

		public ImmutableHashSet<T> WithComparer(IEqualityComparer<T> equalityComparer)
		{
			if (equalityComparer == null)
			{
				equalityComparer = EqualityComparer<T>.Default;
			}
			if (equalityComparer == _equalityComparer)
			{
				return this;
			}
			ImmutableHashSet<T> immutableHashSet = new ImmutableHashSet<T>(equalityComparer);
			return immutableHashSet.Union(this, avoidWithComparer: true);
		}

		bool ISet<T>.Add(T item)
		{
			throw new NotSupportedException();
		}

		void ISet<T>.ExceptWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		void ISet<T>.IntersectWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		void ISet<T>.SymmetricExceptWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		void ISet<T>.UnionWith(IEnumerable<T> other)
		{
			throw new NotSupportedException();
		}

		void ICollection<T>.CopyTo(T[] array, int arrayIndex)
		{
			Requires.NotNull(array, "array");
			Requires.Range(arrayIndex >= 0, "arrayIndex");
			Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex");
			using Enumerator enumerator = GetEnumerator();
			while (enumerator.MoveNext())
			{
				T current = enumerator.Current;
				array[arrayIndex++] = current;
			}
		}

		void ICollection<T>.Add(T item)
		{
			throw new NotSupportedException();
		}

		void ICollection<T>.Clear()
		{
			throw new NotSupportedException();
		}

		bool ICollection<T>.Remove(T item)
		{
			throw new NotSupportedException();
		}

		void ICollection.CopyTo(Array array, int arrayIndex)
		{
			Requires.NotNull(array, "array");
			Requires.Range(arrayIndex >= 0, "arrayIndex");
			Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex");
			using Enumerator enumerator = GetEnumerator();
			while (enumerator.MoveNext())
			{
				T current = enumerator.Current;
				array.SetValue(current, arrayIndex++);
			}
		}

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

		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			if (!IsEmpty)
			{
				return GetEnumerator();
			}
			return Enumerable.Empty<T>().GetEnumerator();
		}

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

		private static bool IsSupersetOf(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			foreach (T item in other.GetEnumerableDisposable<T, Enumerator>())
			{
				if (!Contains(item, origin))
				{
					return false;
				}
			}
			return true;
		}

		private static MutationResult Add(T item, MutationInput origin)
		{
			int hashCode = origin.EqualityComparer.GetHashCode(item);
			OperationResult result;
			HashBucket newBucket = origin.Root.GetValueOrDefault(hashCode).Add(item, origin.EqualityComparer, out result);
			if (result == OperationResult.NoChangeRequired)
			{
				return new MutationResult(origin.Root, 0);
			}
			SortedInt32KeyNode<HashBucket> root = UpdateRoot(origin.Root, hashCode, origin.HashBucketEqualityComparer, newBucket);
			return new MutationResult(root, 1);
		}

		private static MutationResult Remove(T item, MutationInput origin)
		{
			OperationResult result = OperationResult.NoChangeRequired;
			int hashCode = origin.EqualityComparer.GetHashCode(item);
			SortedInt32KeyNode<HashBucket> root = origin.Root;
			if (origin.Root.TryGetValue(hashCode, out var value))
			{
				HashBucket newBucket = value.Remove(item, origin.EqualityComparer, out result);
				if (result == OperationResult.NoChangeRequired)
				{
					return new MutationResult(origin.Root, 0);
				}
				root = UpdateRoot(origin.Root, hashCode, origin.HashBucketEqualityComparer, newBucket);
			}
			return new MutationResult(root, (result == OperationResult.SizeChanged) ? (-1) : 0);
		}

		private static bool Contains(T item, MutationInput origin)
		{
			int hashCode = origin.EqualityComparer.GetHashCode(item);
			if (origin.Root.TryGetValue(hashCode, out var value))
			{
				return value.Contains(item, origin.EqualityComparer);
			}
			return false;
		}

		private static MutationResult Union(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			int num = 0;
			SortedInt32KeyNode<HashBucket> sortedInt32KeyNode = origin.Root;
			foreach (T item in other.GetEnumerableDisposable<T, Enumerator>())
			{
				int hashCode = origin.EqualityComparer.GetHashCode(item);
				OperationResult result;
				HashBucket newBucket = sortedInt32KeyNode.GetValueOrDefault(hashCode).Add(item, origin.EqualityComparer, out result);
				if (result == OperationResult.SizeChanged)
				{
					sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, hashCode, origin.HashBucketEqualityComparer, newBucket);
					num++;
				}
			}
			return new MutationResult(sortedInt32KeyNode, num);
		}

		private static bool Overlaps(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			if (origin.Root.IsEmpty)
			{
				return false;
			}
			foreach (T item in other.GetEnumerableDisposable<T, Enumerator>())
			{
				if (Contains(item, origin))
				{
					return true;
				}
			}
			return false;
		}

		private static bool SetEquals(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			HashSet<T> hashSet = new HashSet<T>(other, origin.EqualityComparer);
			if (origin.Count != hashSet.Count)
			{
				return false;
			}
			foreach (T item in hashSet)
			{
				if (!Contains(item, origin))
				{
					return false;
				}
			}
			return true;
		}

		private static SortedInt32KeyNode<HashBucket> UpdateRoot(SortedInt32KeyNode<HashBucket> root, int hashCode, IEqualityComparer<HashBucket> hashBucketEqualityComparer, HashBucket newBucket)
		{
			bool mutated;
			if (newBucket.IsEmpty)
			{
				return root.Remove(hashCode, out mutated);
			}
			bool replacedExistingValue;
			return root.SetItem(hashCode, newBucket, hashBucketEqualityComparer, out replacedExistingValue, out mutated);
		}

		private static MutationResult Intersect(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			SortedInt32KeyNode<HashBucket> root = SortedInt32KeyNode<HashBucket>.EmptyNode;
			int num = 0;
			foreach (T item in other.GetEnumerableDisposable<T, Enumerator>())
			{
				if (Contains(item, origin))
				{
					MutationResult mutationResult = Add(item, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num));
					root = mutationResult.Root;
					num += mutationResult.Count;
				}
			}
			return new MutationResult(root, num, CountType.FinalValue);
		}

		private static MutationResult Except(IEnumerable<T> other, IEqualityComparer<T> equalityComparer, IEqualityComparer<HashBucket> hashBucketEqualityComparer, SortedInt32KeyNode<HashBucket> root)
		{
			Requires.NotNull(other, "other");
			Requires.NotNull(equalityComparer, "equalityComparer");
			Requires.NotNull(root, "root");
			int num = 0;
			SortedInt32KeyNode<HashBucket> sortedInt32KeyNode = root;
			foreach (T item in other.GetEnumerableDisposable<T, Enumerator>())
			{
				int hashCode = equalityComparer.GetHashCode(item);
				if (sortedInt32KeyNode.TryGetValue(hashCode, out var value))
				{
					OperationResult result;
					HashBucket newBucket = value.Remove(item, equalityComparer, out result);
					if (result == OperationResult.SizeChanged)
					{
						num--;
						sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, hashCode, hashBucketEqualityComparer, newBucket);
					}
				}
			}
			return new MutationResult(sortedInt32KeyNode, num);
		}

		private static MutationResult SymmetricExcept(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			ImmutableHashSet<T> immutableHashSet = ImmutableHashSet.CreateRange(origin.EqualityComparer, other);
			int num = 0;
			SortedInt32KeyNode<HashBucket> root = SortedInt32KeyNode<HashBucket>.EmptyNode;
			foreach (T item in new NodeEnumerable(origin.Root))
			{
				if (!immutableHashSet.Contains(item))
				{
					MutationResult mutationResult = Add(item, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num));
					root = mutationResult.Root;
					num += mutationResult.Count;
				}
			}
			foreach (T item2 in immutableHashSet)
			{
				if (!Contains(item2, origin))
				{
					MutationResult mutationResult2 = Add(item2, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num));
					root = mutationResult2.Root;
					num += mutationResult2.Count;
				}
			}
			return new MutationResult(root, num, CountType.FinalValue);
		}

		private static bool IsProperSubsetOf(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			if (origin.Root.IsEmpty)
			{
				return other.Any();
			}
			HashSet<T> hashSet = new HashSet<T>(other, origin.EqualityComparer);
			if (origin.Count >= hashSet.Count)
			{
				return false;
			}
			int num = 0;
			bool flag = false;
			foreach (T item in hashSet)
			{
				if (Contains(item, origin))
				{
					num++;
				}
				else
				{
					flag = true;
				}
				if (num == origin.Count && flag)
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsProperSupersetOf(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			if (origin.Root.IsEmpty)
			{
				return false;
			}
			int num = 0;
			foreach (T item in other.GetEnumerableDisposable<T, Enumerator>())
			{
				num++;
				if (!Contains(item, origin))
				{
					return false;
				}
			}
			return origin.Count > num;
		}

		private static bool IsSubsetOf(IEnumerable<T> other, MutationInput origin)
		{
			Requires.NotNull(other, "other");
			if (origin.Root.IsEmpty)
			{
				return true;
			}
			HashSet<T> hashSet = new HashSet<T>(other, origin.EqualityComparer);
			int num = 0;
			foreach (T item in hashSet)
			{
				if (Contains(item, origin))
				{
					num++;
				}
			}
			return num == origin.Count;
		}

		private static ImmutableHashSet<T> Wrap(SortedInt32KeyNode<HashBucket> root, IEqualityComparer<T> equalityComparer, int count)
		{
			Requires.NotNull(root, "root");
			Requires.NotNull(equalityComparer, "equalityComparer");
			Requires.Range(count >= 0, "count");
			return new ImmutableHashSet<T>(root, equalityComparer, count);
		}

		private static IEqualityComparer<HashBucket> GetHashBucketEqualityComparer(IEqualityComparer<T> valueComparer)
		{
			if (!ImmutableExtensions.IsValueType<T>())
			{
				return HashBucketByRefEqualityComparer.DefaultInstance;
			}
			if (valueComparer == EqualityComparer<T>.Default)
			{
				return HashBucketByValueEqualityComparer.DefaultInstance;
			}
			return new HashBucketByValueEqualityComparer(valueComparer);
		}

		private ImmutableHashSet<T> Wrap(SortedInt32KeyNode<HashBucket> root, int adjustedCountIfDifferentRoot)
		{
			if (root == _root)
			{
				return this;
			}
			return new ImmutableHashSet<T>(root, _equalityComparer, adjustedCountIfDifferentRoot);
		}

		private ImmutableHashSet<T> Union(IEnumerable<T> items, bool avoidWithComparer)
		{
			Requires.NotNull(items, "items");
			if (IsEmpty && !avoidWithComparer && items is ImmutableHashSet<T> immutableHashSet)
			{
				return immutableHashSet.WithComparer(KeyComparer);
			}
			return Union(items, Origin).Finalize(this);
		}
	}
	internal interface IStrongEnumerable<out T, TEnumerator> where TEnumerator : struct, IStrongEnumerator<T>
	{
		TEnumerator GetEnumerator();
	}
	internal interface IStrongEnumerator<T>
	{
		T Current { get; }

		bool MoveNext();
	}
	internal interface IOrderedCollection<out T> : IEnumerable<T>, IEnumerable
	{
		int Count { get; }

		T this[int index] { get; }
	}
	public static class ImmutableArray
	{
		internal static readonly byte[] TwoElementArray = new byte[2];

		public static ImmutableArray<T> Create<T>()
		{
			return ImmutableArray<T>.Empty;
		}

		public static ImmutableArray<T> Create<T>(T item)
		{
			T[] items = new T[1] { item };
			return new ImmutableArray<T>(items);
		}

		public static ImmutableArray<T> Create<T>(T item1, T item2)
		{
			T[] items = new T[2] { item1, item2 };
			return new ImmutableArray<T>(items);
		}

		public static ImmutableArray<T> Create<T>(T item1, T item2, T item3)
		{
			T[] items = new T[3] { item1, item2, item3 };
			return new ImmutableArray<T>(items);
		}

		public static ImmutableArray<T> Create<T>(T item1, T item2, T item3, T item4)
		{
			T[] items = new T[4] { item1, item2, item3, item4 };
			return new ImmutableArray<T>(items);
		}

		public static ImmutableArray<T> CreateRange<T>(IEnumerable<T> items)
		{
			Requires.NotNull(items, "items");
			if (items is IImmutableArray immutableArray)
			{
				Array array = immutableArray.Array;
				if (array == null)
				{
					throw new InvalidOperationException(System.SR.InvalidOperationOnDefaultArray);
				}
				return new ImmutableArray<T>((T[])array);
			}
			if (items.TryGetCount(out var count))
			{
				return new ImmutableArray<T>(items.ToArray(count));
			}
			return new ImmutableArray<T>(items.ToArray());
		}

		public static ImmutableArray<T> Create<T>(params T[] items)
		{
			if (items == null)
			{
				return Create<T>();
			}
			return CreateDefensiveCopy(items);
		}

		public static ImmutableArray<T> Create<T>(T[] items, int start, int length)
		{
			Requires.NotNull(items, "items");
			Requires.Range(start >= 0 && start <= items.Length, "start");
			Requires.Range(length >= 0 && start + length <= items.Length, "length");
			if (length == 0)
			{
				return Create<T>();
			}
			T[] array = new T[length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = items[start + i];
			}
			return new ImmutableArray<T>(array);
		}

		public static ImmutableArray<T> Create<T>(ImmutableArray<T> items, int start, int length)
		{
			Requires.Range(start >= 0 && start <= items.Length, "start");
			Requires.Range(length >= 0 && start + length <= items.Length, "length");
			if (length == 0)
			{
				return Create<T>();
			}
			if (start == 0 && length == items.Length)
			{
				return items;
			}
			T[] array = new T[length];
			Array.Copy(items.array, start, array, 0, length);
			return new ImmutableArray<T>(array);
		}

		public static ImmutableArray<TResult> CreateRange<TSource, TResult>(ImmutableArray<TSource> items, Func<TSource, TResult> selector)
		{
			Requires.NotNull(selector, "selector");
			int length = items.Length;
			if (length == 0)
			{
				return Create<TResult>();
			}
			TResult[] array = new TResult[length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = selector(items[i]);
			}
			return new ImmutableArray<TResult>(array);
		}

		public static ImmutableArray<TResult> CreateRange<TSource, TResult>(ImmutableArray<TSource> items, int start, int length, Func<TSource, TResult> selector)
		{
			int length2 = items.Length;
			Requires.Range(start >= 0 && start <= length2, "start");
			Requires.Range(length >= 0 && start + length <= length2, "length");
			Requires.NotNull(selector, "selector");
			if (length == 0)
			{
				return Create<TResult>();
			}
			TResult[] array = new TResult[length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = selector(items[i + start]);
			}
			return new ImmutableArray<TResult>(array);
		}

		public static ImmutableArray<TResult> CreateRange<TSource, TArg, TResult>(ImmutableArray<TSource> items, Func<TSource, TArg, TResult> selector, TArg arg)
		{
			Requires.NotNull(selector, "selector");
			int length = items.Length;
			if (length == 0)
			{
				return Create<TResult>();
			}
			TResult[] array = new TResult[length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = selector(items[i], arg);
			}
			return new ImmutableArray<TResult>(array);
		}

		public static ImmutableArray<TResult> CreateRange<TSource, TArg, TResult>(ImmutableArray<TSource> items, int start, int length, Func<TSource, TArg, TResult> selector, TArg arg)
		{
			int length2 = items.Length;
			Requires.Range(start >= 0 && start <= length2, "start");
			Requires.Range(length >= 0 && start + length <= length2, "length");
			Requires.NotNull(selector, "selector");
			if (length == 0)
			{
				return Create<TResult>();
			}
			TResult[] array = new TResult[length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = selector(items[i + start], arg);
			}
			return new ImmutableArray<TResult>(array);
		}

		public static ImmutableArray<T>.Builder CreateBuilder<T>()
		{
			return Create<T>().ToBuilder();
		}

		public static ImmutableArray<T>.Builder CreateBuilder<T>(int initialCapacity)
		{
			return new ImmutableArray<T>.Builder(initialCapacity);
		}

		public static ImmutableArray<TSource> ToImmutableArray<TSource>(this IEnumerable<TSource> items)
		{
			if (items is ImmutableArray<TSource>)
			{
				return (ImmutableArray<TSource>)(object)items;
			}
			return CreateRange(items);
		}

		public static ImmutableArray<TSource> ToImmutableArray<TSource>(this ImmutableArray<TSource>.Builder builder)
		{
			Requires.NotNull(builder, "builder");
			return builder.ToImmutable();
		}

		public static int BinarySearch<T>(this ImmutableArray<T> array, T value)
		{
			return Array.BinarySearch(array.array, value);
		}

		public static int BinarySearch<T>(this ImmutableArray<T> array, T value, IComparer<T> comparer)
		{
			return Array.BinarySearch(array.array, value, comparer);
		}

		public static int BinarySearch<T>(this ImmutableArray<T> array, int index, int length, T value)
		{
			return Array.BinarySearch(array.array, index, length, value);
		}

		public static int BinarySearch<T>(this ImmutableArray<T> array, int index, int length, T value, IComparer<T> comparer)
		{
			return Array.BinarySearch(array.array, index, length, value, comparer);
		}

		internal static ImmutableArray<T> CreateDefensiveCopy<T>(T[] items)
		{
			if (items.Length == 0)
			{
				return ImmutableArray<T>.Empty;
			}
			T[] array = new T[items.Length];
			Array.Copy(items, 0, array, 0, items.Length);
			return new ImmutableArray<T>(array);
		}
	}
	[DebuggerDisplay("{DebuggerDisplay,nq}")]
	[System.Runtime.Versioning.NonVersionable]
	public struct ImmutableArray<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>, IList<T>, ICollection<T>, IEquatable<ImmutableArray<T>>, IList, ICollection, IImmutableArray, IStructuralComparable, IStructuralEquatable, IImmutableList<T>
	{
		[DebuggerDisplay("Count = {Count}")]
		[DebuggerTypeProxy(typeof(ImmutableArrayBuilderDebuggerProxy<>))]
		public sealed class Builder : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IReadOnlyList<T>, IReadOnlyCollection<T>
		{
			private T[] _elements;

			private int _count;

			public int Capacity
			{
				get
				{
					return _elements.Length;
				}
				set
				{
					if (value < _count)
					{
						throw new ArgumentException(System.SR.CapacityMustBeGreaterThanOrEqualToCount, "value");
					}
					if (value == _elements.Length)
					{
						return;
					}
					if (value > 0)
					{
						T[] array = new T[value];
						if (_count > 0)
						{
							Array.Copy(_elements, 0, array, 0, _count);
						}
						_elements = array;
					}
					else
					{
						_elements = ImmutableArray<T>.Empty.array;
					}
				}
			}

			public int Count
			{
				get
				{
					return _count;
				}
				set
				{
					Requires.Range(value >= 0, "value");
					if (value < _count)
					{
						if (_count - value > 64)
						{
							Array.Clear(_elements, value, _count - value);
						}
						else
						{
							for (int i = value; i < Count; i++)
							{
								_elements[i] = default(T);
							}
						}
					}
					else if (value > _count)
					{
						EnsureCapacity(value);
					}
					_count = value;
				}
			}

			public T this[int index]
			{
				get
				{
					if (index >= Count)
					{
						ThrowIndexOutOfRangeException();
					}
					return _elements[index];
				}
				set
				{
					if (index >= Count)
					{
						ThrowIndexOutOfRangeException();
					}
					_elements[index] = value;
				}
			}

			bool ICollection<T>.IsReadOnly => false;

			internal Builder(int capacity)
			{
				Requires.Range(capacity >= 0, "capacity");
				_elements = new T[capacity];
				_count = 0;
			}

			internal Builder()
				: this(8)
			{
			}

			private static void ThrowIndexOutOfRangeException()
			{
				throw new IndexOutOfRangeException();
			}

			public ref readonly T ItemRef(int index)
			{
				if (index >= Count)
				{
					ThrowIndexOutOfRangeException();
				}
				return ref _elements[index];
			}

			public ImmutableArray<T> ToImmutable()
			{
				return new ImmutableArray<T>(ToArray());
			}

			public ImmutableArray<T> MoveToImmutable()
			{
				if (Capacity != Count)
				{
					throw new InvalidOperationException(System.SR.CapacityMustEqualCountOnMove);
				}
				T[] elements = _elements;
				_elements = ImmutableArray<T>.Empty.array;
				_count = 0;
				return new ImmutableArray<T>(elements);
			}

			public void Clear()
			{
				Count = 0;
			}

			public void Insert(int index, T item)
			{
				Requires.Range(index >= 0 && index <= Count, "index");
				EnsureCapacity(Count + 1);
				if (index < Count)
				{
					Array.Copy(_elements, index, _elements, index + 1, Count - index);
				}
				_count++;
				_elements[index] = item;
			}

			public void Add(T item)
			{
				int num = _count + 1;
				EnsureCapacity(num);
				_elements[_count] = item;
				_count = num;
			}

			public void AddRange(IEnumerable<T> items)
			{
				Requires.NotNull(items, "items");
				if (items.TryGetCount(out var count))
				{
					EnsureCapacity(Count + count);
					if (items.TryCopyTo(_elements, _count))
					{
						_count += count;
						return;
					}
				}
				foreach (T item in items)
				{
					Add(item);
				}
			}

			public void AddRange(params T[] items)
			{
				Requires.NotNull(items, "items");
				int count = Count;
				Count += items.Length;
				Array.Copy(items, 0, _elements, count, items.Length);
			}

			public void AddRange<TDerived>(TDerived[] items) where TDerived : T
			{
				Requires.NotNull(items, "items");
				int count = Count;
				Count += items.Length;
				Array.Copy(items, 0, _elements, count, items.Length);
			}

			public void AddRange(T[] items, int length)
			{
				Requires.NotNull(items, "items");
				Requires.Range(length >= 0 && length <= items.Length, "length");
				int count = Count;
				Count += length;
				Array.Copy(items, 0, _elements, count, length);
			}

			public void AddRange(ImmutableArray<T> items)
			{
				AddRange(items, items.Length);
			}

			public void AddRange(ImmutableArray<T> items, int length)
			{
				Requires.Range(length >= 0, "length");
				if (items.array != null)
				{
					AddRange(items.array, length);
				}
			}

			public void AddRange<TDerived>(ImmutableArray<TDerived> items) where TDerived : T
			{
				if (items.array != null)
				{
					AddRange(items.array);
				}
			}

			public void AddRange(Builder items)
			{
				Requires.NotNull(items, "items");
				AddRange(items._elements, items.Count);
			}

			public void AddRange<TDerived>(ImmutableArray<TDerived>.Builder items) where TDerived : T
			{
				Requires.NotNull(items, "items");
				AddRange(items._elements, items.Count);
			}

			public bool Remove(T element)
			{
				int num = IndexOf(element);
				if (num >= 0)
				{
					RemoveAt(num);
					return true;
				}
				return false;
			}

			public void RemoveAt(int index)
			{
				Requires.Range(index >= 0 && index < Count, "index");
				if (index < Count - 1)
				{
					Array.Copy(_elements, index + 1, _elements, index, Count - index - 1);
				}
				Count--;
			}

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

			public T[] ToArray()
			{
				if (Count == 0)
				{
					return ImmutableArray<T>.Empty.array;
				}
				T[] array = new T[Count];
				Array.Copy(_elements, 0, array, 0, Count);
				return array;
			}

			public void CopyTo(T[] array, int index)
			{
				Requires.NotNull(array, "array");
				Requires.Range(index >= 0 && index + Count <= array.Length, "index");
				Array.Copy(_elements, 0, array, index, Count);
			}

			private void EnsureCapacity(int capacity)
			{
				if (_elements.Length < capacity)
				{
					int newSize = Math.Max(_elements.Length * 2, capacity);
					Array.Resize(ref _elements, newSize);
				}
			}

			public int IndexOf(T item)
			{
				return IndexOf(item, 0, _count, EqualityComparer<T>.Default);
			}

			public int IndexOf(T item, int startIndex)
			{
				return IndexOf(item, startIndex, Count - startIndex, EqualityComparer<T>.Default);
			}

			public int IndexOf(T item, int startIndex, int count)
			{
				return IndexOf(item, startIndex, count, EqualityComparer<T>.Default);
			}

			public int IndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer)
			{
				if (count == 0 && startIndex == 0)
				{
					return -1;
				}
				Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex");
				Requires.Range(count >= 0 && startIndex + count <= Count, "count");
				equalityComparer = equalityComparer ?? EqualityComparer<T>.Default;
				if (equalityComparer == EqualityComparer<T>.Default)
				{
					return Array.IndexOf(_elements, item, startIndex, count);
				}
				for (int i = startIndex; i < startIndex + count; i++)
				{
					if (equalityComparer.Equals(_elements[i], item))
					{
						return i;
					}
				}
				return -1;
			}

			public int LastIndexOf(T item)
			{
				if (Count == 0)
				{
					return -1;
				}
				return LastIndexOf(item, Count - 1, Count, EqualityComparer<T>.Default);
			}

			public int LastIndexOf(T item, int startIndex)
			{
				if (Count == 0 && startIndex == 0)
				{
					return -1;
				}
				Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex");
				return LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer<T>.Default);
			}

			public int LastIndexOf(T item, int startIndex, int count)
			{
				return LastIndexOf(item, startIndex, count, EqualityComparer<T>.Default);
			}

			public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer)
			{
				if (count == 0 && startIndex == 0)
				{
					return -1;
				}
				Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex");
				Requires.Range(count >= 0 && startIndex - count + 1 >= 0, "count");
				equalityComparer = equalityComparer ?? EqualityComparer<T>.Default;
				if (equalityComparer == EqualityComparer<T>.Default)
				{
					return Array.LastIndexOf(_elements, item, startIndex, count);
				}
				for (int num = startIndex; num >= startIndex - count + 1; num--)
				{
					if (equalityComparer.Equals(item, _elements[num]))
					{
						return num;
					}
				}
				return -1;
			}

			public void Reverse()
			{
				int num = 0;
				int num2 = _count - 1;
				T[] elements = _elements;
				while (num < num2)
				{
					T val = elements[num];
					elements[num] = elements[num2];
					elements[num2] = val;
					num++;
					num2--;
				}
			}

			public void Sort()
			{
				if (Count > 1)
				{
					Array.Sort(_elements, 0, Count, Comparer<T>.Default);
				}
			}

			public void Sort(Comparison<T> comparison)
			{
				Requires.NotNull(comparison, "comparison");
				if (Count > 1)
				{
					Array.Sort(_elements, 0, _count, Comparer<T>.Create(comparison));
				}
			}

			public void Sort(IComparer<T> comparer)
			{
				if (Count > 1)
				{
					Array.Sort(_elements, 0, _count, comparer);
				}
			}

			public void Sort(int index, int count, IComparer<T> comparer)
			{
				Requires.Range(index >= 0, "index");
				Requires.Range(count >= 0 && index + count <= Count, "count");
				if (count > 1)
				{
					Array.Sort(_elements, index, count, comparer);
				}
			}

			public IEnumerator<T> GetEnumerator()
			{
				for (int i = 0; i < Count; i++)
				{
					yield return this[i];
				}
			}

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

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

			private void AddRange<TDerived>(TDerived[] items, int length) where TDerived : T
			{
				EnsureCapacity(Count + length);
				int count = Count;
				Count += length;
				T[] elements = _elements;
				for (int i = 0; i < length; i++)
				{
					elements[count + i] = (T)(object)items[i];
				}
			}
		}

		public struct Enumerator
		{
			private readonly T[] _array;

			private int _index;

			public T Current => _array[_index];

			internal Enumerator(T[] array)
			{
				_array = array;
				_index = -1;
			}

			public bool MoveNext()
			{
				return ++_index < _array.Length;
			}
		}

		private class EnumeratorObject : IEnumerator<T>, IEnumerator, IDisposable
		{
			private static readonly IEnumerator<T> s_EmptyEnumerator = new EnumeratorObject(ImmutableArray<T>.Empty.array);

			private readonly T[] _array;

			private int _index;

			public T Current
			{
				get
				{
					if ((uint)_index < (uint)_array.Length)
					{
						return _array[_index];
					}
					throw new InvalidOperationException();
				}
			}

			object IEnumerator.Current => Current;

			private EnumeratorObject(T[] array)
			{
				_index = -1;
				_array = array;
			}

			public bool MoveNext()
			{
				int num = _index + 1;
				int num2 = _array.Length;
				if ((uint)num <= (uint)num2)
				{
					_index = num;
					return (uint)num < (uint)num2;
				}
				return false;
			}

			void IEnumerator.Reset()
			{
				_index = -1;
			}

			public void Dispose()
			{
			}

			internal static IEnumerator<T> Create(T[] array)
			{
				if (array.Length != 0)
				{
					return new EnumeratorObject(array);
				}
				return s_EmptyEnumerator;
			}
		}

		public static readonly ImmutableArray<T> Empty = new ImmutableArray<T>(new T[0]);

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		internal T[] array;

		T IList<T>.this[int index]
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				immutableArray.ThrowInvalidOperationIfNotInitialized();
				return immutableArray[index];
			}
			set
			{
				throw new NotSupportedException();
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		bool ICollection<T>.IsReadOnly => true;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		int ICollection<T>.Count
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				immutableArray.ThrowInvalidOperationIfNotInitialized();
				return immutableArray.Length;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		int IReadOnlyCollection<T>.Count
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				immutableArray.ThrowInvalidOperationIfNotInitialized();
				return immutableArray.Length;
			}
		}

		T IReadOnlyList<T>.this[int index]
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				immutableArray.ThrowInvalidOperationIfNotInitialized();
				return immutableArray[index];
			}
		}

		[ExcludeFromCodeCoverage]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		bool IList.IsFixedSize => true;

		[ExcludeFromCodeCoverage]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		bool IList.IsReadOnly => true;

		[ExcludeFromCodeCoverage]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		int ICollection.Count
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				immutableArray.ThrowInvalidOperationIfNotInitialized();
				return immutableArray.Length;
			}
		}

		[ExcludeFromCodeCoverage]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		bool ICollection.IsSynchronized => true;

		[ExcludeFromCodeCoverage]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		object ICollection.SyncRoot
		{
			get
			{
				throw new NotSupportedException();
			}
		}

		[ExcludeFromCodeCoverage]
		object IList.this[int index]
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				immutableArray.ThrowInvalidOperationIfNotInitialized();
				return immutableArray[index];
			}
			set
			{
				throw new NotSupportedException();
			}
		}

		public T this[int index]
		{
			[System.Runtime.Versioning.NonVersionable]
			get
			{
				return array[index];
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public bool IsEmpty
		{
			[System.Runtime.Versioning.NonVersionable]
			get
			{
				return Length == 0;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int Length
		{
			[System.Runtime.Versioning.NonVersionable]
			get
			{
				return array.Length;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public bool IsDefault => array == null;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public bool IsDefaultOrEmpty
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				if (immutableArray.array != null)
				{
					return immutableArray.array.Length == 0;
				}
				return true;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		Array IImmutableArray.Array => array;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private string DebuggerDisplay
		{
			get
			{
				ImmutableArray<T> immutableArray = this;
				if (!immutableArray.IsDefault)
				{
					return string.Format(CultureInfo.CurrentCulture, "Length = {0}", immutableArray.Length);
				}
				return "Uninitialized";
			}
		}

		public ReadOnlySpan<T> AsSpan()
		{
			return new ReadOnlySpan<T>(array);
		}

		public ReadOnlyMemory<T> AsMemory()
		{
			return new ReadOnlyMemory<T>(array);
		}

		public int IndexOf(T item)
		{
			ImmutableArray<T> immutableArray = this;
			return immutableArray.IndexOf(item, 0, immutableArray.Length, EqualityComparer<T>.Default);
		}

		public int IndexOf(T item, int startIndex, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			return immutableArray.IndexOf(item, startIndex, immutableArray.Length - startIndex, equalityComparer);
		}

		public int IndexOf(T item, int startIndex)
		{
			ImmutableArray<T> immutableArray = this;
			return immutableArray.IndexOf(item, startIndex, immutableArray.Length - startIndex, EqualityComparer<T>.Default);
		}

		public int IndexOf(T item, int startIndex, int count)
		{
			return IndexOf(item, startIndex, count, EqualityComparer<T>.Default);
		}

		public int IndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			if (count == 0 && startIndex == 0)
			{
				return -1;
			}
			Requires.Range(startIndex >= 0 && startIndex < immutableArray.Length, "startIndex");
			Requires.Range(count >= 0 && startIndex + count <= immutableArray.Length, "count");
			equalityComparer = equalityComparer ?? EqualityComparer<T>.Default;
			if (equalityComparer == EqualityComparer<T>.Default)
			{
				return Array.IndexOf(immutableArray.array, item, startIndex, count);
			}
			for (int i = startIndex; i < startIndex + count; i++)
			{
				if (equalityComparer.Equals(immutableArray.array[i], item))
				{
					return i;
				}
			}
			return -1;
		}

		public int LastIndexOf(T item)
		{
			ImmutableArray<T> immutableArray = this;
			if (immutableArray.Length == 0)
			{
				return -1;
			}
			return immutableArray.LastIndexOf(item, immutableArray.Length - 1, immutableArray.Length, EqualityComparer<T>.Default);
		}

		public int LastIndexOf(T item, int startIndex)
		{
			ImmutableArray<T> immutableArray = this;
			if (immutableArray.Length == 0 && startIndex == 0)
			{
				return -1;
			}
			return immutableArray.LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer<T>.Default);
		}

		public int LastIndexOf(T item, int startIndex, int count)
		{
			return LastIndexOf(item, startIndex, count, EqualityComparer<T>.Default);
		}

		public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			if (startIndex == 0 && count == 0)
			{
				return -1;
			}
			Requires.Range(startIndex >= 0 && startIndex < immutableArray.Length, "startIndex");
			Requires.Range(count >= 0 && startIndex - count + 1 >= 0, "count");
			equalityComparer = equalityComparer ?? EqualityComparer<T>.Default;
			if (equalityComparer == EqualityComparer<T>.Default)
			{
				return Array.LastIndexOf(immutableArray.array, item, startIndex, count);
			}
			for (int num = startIndex; num >= startIndex - count + 1; num--)
			{
				if (equalityComparer.Equals(item, immutableArray.array[num]))
				{
					return num;
				}
			}
			return -1;
		}

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

		public ImmutableArray<T> Insert(int index, T item)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			Requires.Range(index >= 0 && index <= immutableArray.Length, "index");
			if (immutableArray.Length == 0)
			{
				return ImmutableArray.Create(item);
			}
			T[] array = new T[immutableArray.Length + 1];
			array[index] = item;
			if (index != 0)
			{
				Array.Copy(immutableArray.array, 0, array, 0, index);
			}
			if (index != immutableArray.Length)
			{
				Array.Copy(immutableArray.array, index, array, index + 1, immutableArray.Length - index);
			}
			return new ImmutableArray<T>(array);
		}

		public ImmutableArray<T> InsertRange(int index, IEnumerable<T> items)
		{
			ImmutableArray<T> result = this;
			result.ThrowNullRefIfNotInitialized();
			Requires.Range(index >= 0 && index <= result.Length, "index");
			Requires.NotNull(items, "items");
			if (result.Length == 0)
			{
				return ImmutableArray.CreateRange(items);
			}
			int count = ImmutableExtensions.GetCount(ref items);
			if (count == 0)
			{
				return result;
			}
			T[] array = new T[result.Length + count];
			if (index != 0)
			{
				Array.Copy(result.array, 0, array, 0, index);
			}
			if (index != result.Length)
			{
				Array.Copy(result.array, index, array, index + count, result.Length - index);
			}
			if (!items.TryCopyTo(array, index))
			{
				int num = index;
				foreach (T item in items)
				{
					array[num++] = item;
				}
			}
			return new ImmutableArray<T>(array);
		}

		public ImmutableArray<T> InsertRange(int index, ImmutableArray<T> items)
		{
			ImmutableArray<T> result = this;
			result.ThrowNullRefIfNotInitialized();
			items.ThrowNullRefIfNotInitialized();
			Requires.Range(index >= 0 && index <= result.Length, "index");
			if (result.IsEmpty)
			{
				return items;
			}
			if (items.IsEmpty)
			{
				return result;
			}
			T[] array = new T[result.Length + items.Length];
			if (index != 0)
			{
				Array.Copy(result.array, 0, array, 0, index);
			}
			if (index != result.Length)
			{
				Array.Copy(result.array, index, array, index + items.Length, result.Length - index);
			}
			Array.Copy(items.array, 0, array, index, items.Length);
			return new ImmutableArray<T>(array);
		}

		public ImmutableArray<T> Add(T item)
		{
			ImmutableArray<T> immutableArray = this;
			if (immutableArray.Length == 0)
			{
				return ImmutableArray.Create(item);
			}
			return immutableArray.Insert(immutableArray.Length, item);
		}

		public ImmutableArray<T> AddRange(IEnumerable<T> items)
		{
			ImmutableArray<T> immutableArray = this;
			return immutableArray.InsertRange(immutableArray.Length, items);
		}

		public ImmutableArray<T> AddRange(ImmutableArray<T> items)
		{
			ImmutableArray<T> immutableArray = this;
			return immutableArray.InsertRange(immutableArray.Length, items);
		}

		public ImmutableArray<T> SetItem(int index, T item)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			Requires.Range(index >= 0 && index < immutableArray.Length, "index");
			T[] array = new T[immutableArray.Length];
			Array.Copy(immutableArray.array, 0, array, 0, immutableArray.Length);
			array[index] = item;
			return new ImmutableArray<T>(array);
		}

		public ImmutableArray<T> Replace(T oldValue, T newValue)
		{
			return Replace(oldValue, newValue, EqualityComparer<T>.Default);
		}

		public ImmutableArray<T> Replace(T oldValue, T newValue, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			int num = immutableArray.IndexOf(oldValue, 0, immutableArray.Length, equalityComparer);
			if (num < 0)
			{
				throw new ArgumentException(System.SR.CannotFindOldValue, "oldValue");
			}
			return immutableArray.SetItem(num, newValue);
		}

		public ImmutableArray<T> Remove(T item)
		{
			return Remove(item, EqualityComparer<T>.Default);
		}

		public ImmutableArray<T> Remove(T item, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> result = this;
			result.ThrowNullRefIfNotInitialized();
			int num = result.IndexOf(item, 0, result.Length, equalityComparer);
			if (num >= 0)
			{
				return result.RemoveAt(num);
			}
			return result;
		}

		public ImmutableArray<T> RemoveAt(int index)
		{
			return RemoveRange(index, 1);
		}

		public ImmutableArray<T> RemoveRange(int index, int length)
		{
			ImmutableArray<T> result = this;
			result.ThrowNullRefIfNotInitialized();
			Requires.Range(index >= 0 && index <= result.Length, "index");
			Requires.Range(length >= 0 && index + length <= result.Length, "length");
			if (length == 0)
			{
				return result;
			}
			T[] array = new T[result.Length - length];
			Array.Copy(result.array, 0, array, 0, index);
			Array.Copy(result.array, index + length, array, index, result.Length - index - length);
			return new ImmutableArray<T>(array);
		}

		public ImmutableArray<T> RemoveRange(IEnumerable<T> items)
		{
			return RemoveRange(items, EqualityComparer<T>.Default);
		}

		public ImmutableArray<T> RemoveRange(IEnumerable<T> items, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			Requires.NotNull(items, "items");
			SortedSet<int> sortedSet = new SortedSet<int>();
			foreach (T item in items)
			{
				int num = immutableArray.IndexOf(item, 0, immutableArray.Length, equalityComparer);
				while (num >= 0 && !sortedSet.Add(num) && num + 1 < immutableArray.Length)
				{
					num = immutableArray.IndexOf(item, num + 1, equalityComparer);
				}
			}
			return immutableArray.RemoveAtRange(sortedSet);
		}

		public ImmutableArray<T> RemoveRange(ImmutableArray<T> items)
		{
			return RemoveRange(items, EqualityComparer<T>.Default);
		}

		public ImmutableArray<T> RemoveRange(ImmutableArray<T> items, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> result = this;
			Requires.NotNull(items.array, "items");
			if (items.IsEmpty)
			{
				result.ThrowNullRefIfNotInitialized();
				return result;
			}
			if (items.Length == 1)
			{
				return result.Remove(items[0], equalityComparer);
			}
			return result.RemoveRange(items.array, equalityComparer);
		}

		public ImmutableArray<T> RemoveAll(Predicate<T> match)
		{
			ImmutableArray<T> result = this;
			result.ThrowNullRefIfNotInitialized();
			Requires.NotNull(match, "match");
			if (result.IsEmpty)
			{
				return result;
			}
			List<int> list = null;
			for (int i = 0; i < result.array.Length; i++)
			{
				if (match(result.array[i]))
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(i);
				}
			}
			if (list == null)
			{
				return result;
			}
			return result.RemoveAtRange(list);
		}

		public ImmutableArray<T> Clear()
		{
			return Empty;
		}

		public ImmutableArray<T> Sort()
		{
			ImmutableArray<T> immutableArray = this;
			return immutableArray.Sort(0, immutableArray.Length, Comparer<T>.Default);
		}

		public ImmutableArray<T> Sort(Comparison<T> comparison)
		{
			Requires.NotNull(comparison, "comparison");
			ImmutableArray<T> immutableArray = this;
			return immutableArray.Sort(Comparer<T>.Create(comparison));
		}

		public ImmutableArray<T> Sort(IComparer<T> comparer)
		{
			ImmutableArray<T> immutableArray = this;
			return immutableArray.Sort(0, immutableArray.Length, comparer);
		}

		public ImmutableArray<T> Sort(int index, int count, IComparer<T> comparer)
		{
			ImmutableArray<T> result = this;
			result.ThrowNullRefIfNotInitialized();
			Requires.Range(index >= 0, "index");
			Requires.Range(count >= 0 && index + count <= result.Length, "count");
			if (count > 1)
			{
				if (comparer == null)
				{
					comparer = Comparer<T>.Default;
				}
				bool flag = false;
				for (int i = index + 1; i < index + count; i++)
				{
					if (comparer.Compare(result.array[i - 1], result.array[i]) > 0)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					T[] array = new T[result.Length];
					Array.Copy(result.array, 0, array, 0, result.Length);
					Array.Sort(array, index, count, comparer);
					return new ImmutableArray<T>(array);
				}
			}
			return result;
		}

		public IEnumerable<TResult> OfType<TResult>()
		{
			ImmutableArray<T> immutableArray = this;
			if (immutableArray.array == null || immutableArray.array.Length == 0)
			{
				return Enumerable.Empty<TResult>();
			}
			return immutableArray.array.OfType<TResult>();
		}

		void IList<T>.Insert(int index, T item)
		{
			throw new NotSupportedException();
		}

		void IList<T>.RemoveAt(int index)
		{
			throw new NotSupportedException();
		}

		void ICollection<T>.Add(T item)
		{
			throw new NotSupportedException();
		}

		void ICollection<T>.Clear()
		{
			throw new NotSupportedException();
		}

		bool ICollection<T>.Remove(T item)
		{
			throw new NotSupportedException();
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.Clear()
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.Clear();
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.Add(T value)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.Add(value);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.AddRange(IEnumerable<T> items)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.AddRange(items);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.Insert(int index, T element)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.Insert(index, element);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.InsertRange(int index, IEnumerable<T> items)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.InsertRange(index, items);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.Remove(T value, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.Remove(value, equalityComparer);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.RemoveAll(Predicate<T> match)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.RemoveAll(match);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.RemoveRange(IEnumerable<T> items, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.RemoveRange(items, equalityComparer);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.RemoveRange(int index, int count)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.RemoveRange(index, count);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.RemoveAt(int index)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.RemoveAt(index);
		}

		[ExcludeFromCodeCoverage]
		IImmutableList<T> IImmutableList<T>.SetItem(int index, T value)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.SetItem(index, value);
		}

		IImmutableList<T> IImmutableList<T>.Replace(T oldValue, T newValue, IEqualityComparer<T> equalityComparer)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.Replace(oldValue, newValue, equalityComparer);
		}

		[ExcludeFromCodeCoverage]
		int IList.Add(object value)
		{
			throw new NotSupportedException();
		}

		[ExcludeFromCodeCoverage]
		void IList.Clear()
		{
			throw new NotSupportedException();
		}

		[ExcludeFromCodeCoverage]
		bool IList.Contains(object value)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.Contains((T)value);
		}

		[ExcludeFromCodeCoverage]
		int IList.IndexOf(object value)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			return immutableArray.IndexOf((T)value);
		}

		[ExcludeFromCodeCoverage]
		void IList.Insert(int index, object value)
		{
			throw new NotSupportedException();
		}

		[ExcludeFromCodeCoverage]
		void IList.Remove(object value)
		{
			throw new NotSupportedException();
		}

		[ExcludeFromCodeCoverage]
		void IList.RemoveAt(int index)
		{
			throw new NotSupportedException();
		}

		[ExcludeFromCodeCoverage]
		void ICollection.CopyTo(Array array, int index)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowInvalidOperationIfNotInitialized();
			Array.Copy(immutableArray.array, 0, array, index, immutableArray.Length);
		}

		bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer)
		{
			ImmutableArray<T> immutableArray = this;
			Array array = other as Array;
			if (array == null && other is IImmutableArray immutableArray2)
			{
				array = immutableArray2.Array;
				if (immutableArray.array == null && array == null)
				{
					return true;
				}
				if (immutableArray.array == null)
				{
					return false;
				}
			}
			IStructuralEquatable structuralEquatable = immutableArray.array;
			return structuralEquatable.Equals(array, comparer);
		}

		int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
		{
			ImmutableArray<T> immutableArray = this;
			return ((IStructuralEquatable)immutableArray.array)?.GetHashCode(comparer) ?? immutableArray.GetHashCode();
		}

		int IStructuralComparable.CompareTo(object other, IComparer comparer)
		{
			ImmutableArray<T> immutableArray = this;
			Array array = other as Array;
			if (array == null && other is IImmutableArray immutableArray2)
			{
				array = immutableArray2.Array;
				if (immutableArray.array == null && array == null)
				{
					return 0;
				}
				if ((immutableArray.array == null) ^ (array == null))
				{
					throw new ArgumentException(System.SR.ArrayInitializedStateNotEqual, "other");
				}
			}
			if (array != null)
			{
				IStructuralComparable structuralComparable = immutableArray.array;
				return structuralComparable.CompareTo(array, comparer);
			}
			throw new ArgumentException(System.SR.ArrayLengthsNotEqual, "other");
		}

		private ImmutableArray<T> RemoveAtRange(ICollection<int> indicesToRemove)
		{
			ImmutableArray<T> result = this;
			result.ThrowNullRefIfNotInitialized();
			Requires.NotNull(indicesToRemove, "indicesToRemove");
			if (indicesToRemove.Count == 0)
			{
				return result;
			}
			T[] array = new T[result.Length - indicesToRemove.Count];
			int num = 0;
			int num2 = 0;
			int num3 = -1;
			foreach (int item in indicesToRemove)
			{
				int num4 = ((num3 == -1) ? item : (item - num3 - 1));
				Array.Copy(result.array, num + num2, array, num, num4);
				num2++;
				num += num4;
				num3 = item;
			}
			Array.Copy(result.array, num + num2, array, num, result.Length - (num + num2));
			return new ImmutableArray<T>(array);
		}

		internal ImmutableArray(T[] items)
		{
			array = items;
		}

		[System.Runtime.Versioning.NonVersionable]
		public static bool operator ==(ImmutableArray<T> left, ImmutableArray<T> right)
		{
			return left.Equals(right);
		}

		[System.Runtime.Versioning.NonVersionable]
		public static bool operator !=(ImmutableArray<T> left, ImmutableArray<T> right)
		{
			return !left.Equals(right);
		}

		public static bool operator ==(ImmutableArray<T>? left, ImmutableArray<T>? right)
		{
			return left.GetValueOrDefault().Equals(right.GetValueOrDefault());
		}

		public static bool operator !=(ImmutableArray<T>? left, ImmutableArray<T>? right)
		{
			return !left.GetValueOrDefault().Equals(right.GetValueOrDefault());
		}

		public ref readonly T ItemRef(int index)
		{
			return ref array[index];
		}

		public void CopyTo(T[] destination)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			Array.Copy(immutableArray.array, 0, destination, 0, immutableArray.Length);
		}

		public void CopyTo(T[] destination, int destinationIndex)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			Array.Copy(immutableArray.array, 0, destination, destinationIndex, immutableArray.Length);
		}

		public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length)
		{
			ImmutableArray<T> immutableArray = this;
			immutableArray.ThrowNullRefIfNotInitialized();
			Array.Copy(immutableArray.array, sourceIndex, destination, destinationIndex, length);
		}

		public Builder ToBuilder()
		{
			ImmutableArray<T> items = this;
			if (items.Length == 0)
			{
				return new Builder();
			}
			Builder builder = new Builder(items.Length);
			builder.AddRange(items);
			return builder;
		}

		p

0Harmony.dll

Decompiled a year ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
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 HarmonyLib.Internal.Patching;
using HarmonyLib.Internal.RuntimeFixes;
using HarmonyLib.Internal.Util;
using HarmonyLib.Public.Patching;
using HarmonyLib.Tools;
using JetBrains.Annotations;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using MonoMod.Utils;
using MonoMod.Utils.Cil;

[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: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("BepInEx")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © BepInEx 2022")]
[assembly: AssemblyDescription("A library for patching, replacing and decorating .NET and Mono methods during runtime powered by MonoMod.")]
[assembly: AssemblyFileVersion("2.10.2.0")]
[assembly: AssemblyInformationalVersion("2.10.2")]
[assembly: AssemblyProduct("HarmonyX")]
[assembly: AssemblyTitle("0Harmony")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.10.2.0")]
[module: UnverifiableCode]
namespace JetBrains.Annotations
{
	[AttributeUsage(AttributeTargets.All)]
	internal sealed class UsedImplicitlyAttribute : Attribute
	{
		public ImplicitUseKindFlags UseKindFlags { get; }

		public ImplicitUseTargetFlags TargetFlags { get; }

		public UsedImplicitlyAttribute()
			: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
			: this(useKindFlags, ImplicitUseTargetFlags.Default)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
			: this(ImplicitUseKindFlags.Default, targetFlags)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
		{
			UseKindFlags = useKindFlags;
			TargetFlags = targetFlags;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter | AttributeTargets.GenericParameter)]
	internal sealed class MeansImplicitUseAttribute : Attribute
	{
		[UsedImplicitly]
		public ImplicitUseKindFlags UseKindFlags { get; }

		[UsedImplicitly]
		public ImplicitUseTargetFlags TargetFlags { get; }

		public MeansImplicitUseAttribute()
			: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags)
			: this(useKindFlags, ImplicitUseTargetFlags.Default)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags)
			: this(ImplicitUseKindFlags.Default, targetFlags)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
		{
			UseKindFlags = useKindFlags;
			TargetFlags = targetFlags;
		}
	}
	[Flags]
	internal enum ImplicitUseKindFlags
	{
		Default = 7,
		Access = 1,
		Assign = 2,
		InstantiatedWithFixedConstructorSignature = 4,
		InstantiatedNoFixedConstructorSignature = 8
	}
	[Flags]
	internal enum ImplicitUseTargetFlags
	{
		Default = 1,
		Itself = 1,
		Members = 2,
		WithInheritors = 4,
		WithMembers = 3
	}
}
namespace HarmonyLib
{
	public class DelegateTypeFactory
	{
		private class DelegateEntry
		{
			public CallingConvention? callingConvention;

			public Type delegateType;
		}

		private static int counter;

		private static readonly Dictionary<MethodInfo, List<DelegateEntry>> TypeCache = new Dictionary<MethodInfo, List<DelegateEntry>>();

		private static readonly MethodBase CallingConvAttr = AccessTools.Constructor(typeof(UnmanagedFunctionPointerAttribute), new Type[1] { typeof(CallingConvention) });

		public static readonly DelegateTypeFactory instance = new DelegateTypeFactory();

		public Type CreateDelegateType(Type returnType, Type[] argTypes)
		{
			return CreateDelegateType(returnType, argTypes, null);
		}

		public Type CreateDelegateType(Type returnType, Type[] argTypes, CallingConvention? convention)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			counter++;
			AssemblyDefinition val = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition($"HarmonyDTFAssembly{counter}", new Version(1, 0)), $"HarmonyDTFModule{counter}", (ModuleKind)0);
			ModuleDefinition module = val.MainModule;
			TypeDefinition val2 = new TypeDefinition("", $"HarmonyDTFType{counter}", (TypeAttributes)257)
			{
				BaseType = module.ImportReference(typeof(MulticastDelegate))
			};
			module.Types.Add(val2);
			if (convention.HasValue)
			{
				CustomAttribute val3 = new CustomAttribute(module.ImportReference(CallingConvAttr));
				val3.ConstructorArguments.Add(new CustomAttributeArgument(module.ImportReference(typeof(CallingConvention)), (object)convention.Value));
				val2.CustomAttributes.Add(val3);
			}
			MethodDefinition val4 = new MethodDefinition(".ctor", (MethodAttributes)4230, module.ImportReference(typeof(void)))
			{
				ImplAttributes = (MethodImplAttributes)3
			};
			Extensions.AddRange<ParameterDefinition>(((MethodReference)val4).Parameters, (IEnumerable<ParameterDefinition>)(object)new ParameterDefinition[2]
			{
				new ParameterDefinition(module.ImportReference(typeof(object))),
				new ParameterDefinition(module.ImportReference(typeof(IntPtr)))
			});
			val2.Methods.Add(val4);
			MethodDefinition val5 = new MethodDefinition("Invoke", (MethodAttributes)198, module.ImportReference(returnType))
			{
				ImplAttributes = (MethodImplAttributes)3
			};
			Extensions.AddRange<ParameterDefinition>(((MethodReference)val5).Parameters, ((IEnumerable<Type>)argTypes).Select((Func<Type, ParameterDefinition>)((Type t) => new ParameterDefinition(module.ImportReference(t)))));
			val2.Methods.Add(val5);
			return ReflectionHelper.Load(val.MainModule).GetType($"HarmonyDTFType{counter}");
		}

		public Type CreateDelegateType(MethodInfo method)
		{
			return CreateDelegateType(method, null);
		}

		public Type CreateDelegateType(MethodInfo method, CallingConvention? convention)
		{
			DelegateEntry delegateEntry;
			if (TypeCache.TryGetValue(method, out var value) && (delegateEntry = value.FirstOrDefault((DelegateEntry e) => e.callingConvention == convention)) != null)
			{
				return delegateEntry.delegateType;
			}
			if (value == null)
			{
				value = (TypeCache[method] = new List<DelegateEntry>());
			}
			delegateEntry = new DelegateEntry
			{
				delegateType = CreateDelegateType(method.ReturnType, method.GetParameters().Types().ToArray(), convention),
				callingConvention = convention
			};
			value.Add(delegateEntry);
			return delegateEntry.delegateType;
		}
	}
	[Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Func<T, S>> for property getters")]
	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")]
	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>()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			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 val = new DynamicMethodDefinition("InstantiateObject_" + typeof(T).Name, typeof(T), (Type[])null);
			ILGenerator iLGenerator = val.GetILGenerator();
			iLGenerator.Emit(OpCodes.Newobj, constructor);
			iLGenerator.Emit(OpCodes.Ret);
			return (InstantiationHandler<T>)val.Generate().CreateDelegate(typeof(InstantiationHandler<T>));
		}

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

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

		[Obsolete("Use AccessTools.FieldRefAccess<T, S>(name) for fields and AccessTools.MethodDelegate<Func<T, S>>(AccessTools.PropertyGetter(typeof(T), name)) for properties")]
		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))")]
		public static SetterHandler<T, S> CreateSetterHandler<T, S>(PropertyInfo propertyInfo)
		{
			MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true);
			DynamicMethodDefinition obj = CreateSetDynamicMethod<T, S>(propertyInfo.DeclaringType);
			ILGenerator iLGenerator = obj.GetILGenerator();
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Ldarg_1);
			iLGenerator.Emit(OpCodes.Call, setMethod);
			iLGenerator.Emit(OpCodes.Ret);
			return (SetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(SetterHandler<T, S>));
		}

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

		private static DynamicMethodDefinition CreateGetDynamicMethod<T, S>(Type type)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			return new DynamicMethodDefinition("DynamicGet_" + type.Name, typeof(S), new Type[1] { typeof(T) });
		}

		private static DynamicMethodDefinition CreateSetDynamicMethod<T, S>(Type type)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			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)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastInvoke_" + methodInfo.Name + "_" + (directBoxValueAccess ? "direct" : "indirect"), typeof(object), new Type[2]
			{
				typeof(object),
				typeof(object[])
			});
			ILGenerator iLGenerator = val.GetILGenerator();
			if (!methodInfo.IsStatic)
			{
				Emit(iLGenerator, 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, OpCodes.Ldarg_1);
					EmitFastInt(iLGenerator, i);
				}
				Emit(iLGenerator, OpCodes.Ldarg_1);
				EmitFastInt(iLGenerator, i);
				if (isByRef && !isValueType)
				{
					Emit(iLGenerator, OpCodes.Ldelema, typeof(object));
					continue;
				}
				Emit(iLGenerator, OpCodes.Ldelem_Ref);
				if (!isValueType)
				{
					continue;
				}
				if (!isByRef || !directBoxValueAccess)
				{
					Emit(iLGenerator, OpCodes.Unbox_Any, type);
					if (isByRef)
					{
						Emit(iLGenerator, OpCodes.Box, type);
						Emit(iLGenerator, OpCodes.Dup);
						if (flag)
						{
							flag = false;
							iLGenerator.DeclareLocal(typeof(object), pinned: false);
						}
						Emit(iLGenerator, OpCodes.Stloc_0);
						Emit(iLGenerator, OpCodes.Stelem_Ref);
						Emit(iLGenerator, OpCodes.Ldloc_0);
						Emit(iLGenerator, OpCodes.Unbox, type);
					}
				}
				else
				{
					Emit(iLGenerator, OpCodes.Unbox, type);
				}
			}
			if (methodInfo.IsStatic)
			{
				EmitCall(iLGenerator, OpCodes.Call, methodInfo);
			}
			else
			{
				EmitCall(iLGenerator, OpCodes.Callvirt, methodInfo);
			}
			if (methodInfo.ReturnType == typeof(void))
			{
				Emit(iLGenerator, OpCodes.Ldnull);
			}
			else
			{
				EmitBoxIfNeeded(iLGenerator, methodInfo.ReturnType);
			}
			Emit(iLGenerator, OpCodes.Ret);
			return (FastInvokeHandler)val.Generate().CreateDelegate(typeof(FastInvokeHandler));
		}

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

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

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

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

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

		internal static void EmitFastInt(ILGenerator il, int value)
		{
			switch (value)
			{
			case -1:
				il.Emit(OpCodes.Ldc_I4_M1);
				return;
			case 0:
				il.Emit(OpCodes.Ldc_I4_0);
				return;
			case 1:
				il.Emit(OpCodes.Ldc_I4_1);
				return;
			case 2:
				il.Emit(OpCodes.Ldc_I4_2);
				return;
			case 3:
				il.Emit(OpCodes.Ldc_I4_3);
				return;
			case 4:
				il.Emit(OpCodes.Ldc_I4_4);
				return;
			case 5:
				il.Emit(OpCodes.Ldc_I4_5);
				return;
			case 6:
				il.Emit(OpCodes.Ldc_I4_6);
				return;
			case 7:
				il.Emit(OpCodes.Ldc_I4_7);
				return;
			case 8:
				il.Emit(OpCodes.Ldc_I4_8);
				return;
			}
			if (value > -129 && value < 128)
			{
				il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
			}
			else
			{
				il.Emit(OpCodes.Ldc_I4, value);
			}
		}
	}
	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 static class PatchArgumentExtensions
	{
		private static HarmonyArgument[] AllHarmonyArguments(object[] attributes)
		{
			return (from attr in attributes
				select (attr.GetType().Name != "HarmonyArgument") ? null : AccessTools.MakeDeepCopy<HarmonyArgument>(attr) into harg
				where harg != null
				select harg).ToArray();
		}

		private static HarmonyArgument GetArgumentAttribute(this ParameterInfo parameter)
		{
			return AllHarmonyArguments(parameter.GetCustomAttributes(inherit: false)).FirstOrDefault();
		}

		private static HarmonyArgument[] GetArgumentAttributes(this MethodInfo method)
		{
			if ((object)method == null || method is DynamicMethod)
			{
				return null;
			}
			return AllHarmonyArguments(method.GetCustomAttributes(inherit: false));
		}

		private static HarmonyArgument[] GetArgumentAttributes(this Type type)
		{
			return AllHarmonyArguments(type.GetCustomAttributes(inherit: false));
		}

		private static string GetOriginalArgumentName(this ParameterInfo parameter, string[] originalParameterNames)
		{
			HarmonyArgument argumentAttribute = parameter.GetArgumentAttribute();
			if (argumentAttribute == null)
			{
				return null;
			}
			if (!string.IsNullOrEmpty(argumentAttribute.OriginalName))
			{
				return argumentAttribute.OriginalName;
			}
			if (argumentAttribute.Index >= 0 && argumentAttribute.Index < originalParameterNames.Length)
			{
				return originalParameterNames[argumentAttribute.Index];
			}
			return null;
		}

		private static string GetOriginalArgumentName(HarmonyArgument[] attributes, string name, string[] originalParameterNames)
		{
			if (((attributes != null && attributes.Length != 0) ? 1 : 0) <= (false ? 1 : 0))
			{
				return null;
			}
			HarmonyArgument harmonyArgument = attributes.SingleOrDefault((HarmonyArgument p) => p.NewName == name);
			if (harmonyArgument == null)
			{
				return null;
			}
			if (!string.IsNullOrEmpty(harmonyArgument.OriginalName))
			{
				return harmonyArgument.OriginalName;
			}
			if (originalParameterNames != null && harmonyArgument.Index >= 0 && harmonyArgument.Index < originalParameterNames.Length)
			{
				return originalParameterNames[harmonyArgument.Index];
			}
			return null;
		}

		private static string GetOriginalArgumentName(this MethodInfo method, string[] originalParameterNames, string name)
		{
			string originalArgumentName = GetOriginalArgumentName(((object)method != null) ? method.GetArgumentAttributes() : null, name, originalParameterNames);
			if (originalArgumentName != null)
			{
				return originalArgumentName;
			}
			object attributes;
			if ((object)method == null)
			{
				attributes = null;
			}
			else
			{
				Type? declaringType = method.DeclaringType;
				attributes = (((object)declaringType != null) ? declaringType.GetArgumentAttributes() : null);
			}
			originalArgumentName = GetOriginalArgumentName((HarmonyArgument[])attributes, name, originalParameterNames);
			if (originalArgumentName != null)
			{
				return originalArgumentName;
			}
			return name;
		}

		internal static int GetArgumentIndex(this MethodInfo patch, string[] originalParameterNames, ParameterInfo patchParam)
		{
			if (patch is DynamicMethod)
			{
				return Array.IndexOf<string>(originalParameterNames, patchParam.Name);
			}
			string originalArgumentName = patchParam.GetOriginalArgumentName(originalParameterNames);
			if (originalArgumentName != null)
			{
				return Array.IndexOf(originalParameterNames, originalArgumentName);
			}
			originalArgumentName = patch.GetOriginalArgumentName(originalParameterNames, patchParam.Name);
			if (originalArgumentName != null)
			{
				return Array.IndexOf(originalParameterNames, originalArgumentName);
			}
			return -1;
		}
	}
	internal static class PatchFunctions
	{
		internal static List<MethodInfo> GetSortedPatchMethods(MethodBase original, Patch[] patches, bool debug)
		{
			return new PatchSorter(patches, debug).Sort(original);
		}

		internal static Patch[] GetSortedPatchMethodsAsPatches(MethodBase original, Patch[] patches, bool debug)
		{
			return new PatchSorter(patches, debug).SortAsPatches(original);
		}

		internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			MethodPatcher methodPatcher = original.GetMethodPatcher();
			DynamicMethodDefinition val = methodPatcher.PrepareOriginal();
			if (val != null)
			{
				ILContext ctx = new ILContext(val.Definition);
				HarmonyManipulator.Manipulate(original, patchInfo, ctx);
			}
			try
			{
				return methodPatcher.DetourTo((val != null) ? val.Generate() : null) as MethodInfo;
			}
			catch (Exception ex)
			{
				object body;
				if (val == null)
				{
					body = null;
				}
				else
				{
					MethodDefinition definition = val.Definition;
					body = ((definition != null) ? definition.Body : null);
				}
				throw HarmonyException.Create(ex, (MethodBody)body);
			}
		}

		internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler, MethodInfo postManipulator)
		{
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			if (standin == null)
			{
				throw new ArgumentNullException("standin");
			}
			if ((object)standin.method == null)
			{
				throw new ArgumentNullException("standin", "standin.method is NULL");
			}
			if (!standin.method.IsStatic)
			{
				throw new ArgumentException("standin", "standin.method is not static");
			}
			bool debug = standin.debug.GetValueOrDefault();
			List<MethodInfo> transpilers = new List<MethodInfo>();
			List<MethodInfo> ilmanipulators = new List<MethodInfo>();
			if (standin.reversePatchType == HarmonyReversePatchType.Snapshot)
			{
				Patches patchInfo = Harmony.GetPatchInfo(original);
				transpilers.AddRange(GetSortedPatchMethods(original, patchInfo.Transpilers.ToArray(), debug));
				ilmanipulators.AddRange(GetSortedPatchMethods(original, patchInfo.ILManipulators.ToArray(), debug));
			}
			if ((object)postTranspiler != null)
			{
				transpilers.Add(postTranspiler);
			}
			if ((object)postManipulator != null)
			{
				ilmanipulators.Add(postManipulator);
			}
			Logger.Log(Logger.LogChannel.Info, delegate
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Reverse patching " + standin.method.FullDescription() + " with " + original.FullDescription());
				PrintInfo(stringBuilder, transpilers, "Transpiler");
				PrintInfo(stringBuilder, ilmanipulators, "Manipulators");
				return stringBuilder.ToString();
			}, debug);
			MethodBody patchBody = null;
			ILHook val = new ILHook((MethodBase)standin.method, (Manipulator)delegate(ILContext ctx)
			{
				//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: Expected O, but got Unknown
				//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
				if (original is MethodInfo methodInfo2)
				{
					patchBody = ctx.Body;
					MethodPatcher methodPatcher = methodInfo2.GetMethodPatcher();
					DynamicMethodDefinition val2 = methodPatcher.CopyOriginal();
					if (val2 == null)
					{
						throw new NullReferenceException("Cannot reverse patch " + methodInfo2.FullDescription() + ": method patcher (" + methodPatcher.GetType().FullDescription() + ") can't copy original method body");
					}
					ILManipulator iLManipulator = new ILManipulator(val2.Definition.Body, debug);
					ctx.Body.Variables.Clear();
					Enumerator<VariableDefinition> enumerator2 = iLManipulator.Body.Variables.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							VariableDefinition current2 = enumerator2.Current;
							ctx.Body.Variables.Add(new VariableDefinition(ctx.Module.ImportReference(((VariableReference)current2).VariableType)));
						}
					}
					finally
					{
						((IDisposable)enumerator2).Dispose();
					}
					foreach (MethodInfo item in transpilers)
					{
						iLManipulator.AddTranspiler(item);
					}
					iLManipulator.WriteTo(ctx.Body, standin.method);
					HarmonyManipulator.ApplyManipulators(ctx, original, ilmanipulators, null);
					Instruction val3 = null;
					foreach (Instruction item2 in ((IEnumerable<Instruction>)ctx.Instrs).Where((Instruction i) => i.OpCode == OpCodes.Ret))
					{
						if (val3 == null)
						{
							val3 = ctx.IL.Create(OpCodes.Ret);
						}
						item2.OpCode = OpCodes.Br;
						item2.Operand = val3;
					}
					if (val3 != null)
					{
						ctx.IL.Append(val3);
					}
					Logger.Log(Logger.LogChannel.IL, () => "Generated reverse patcher (" + ((MemberReference)ctx.Method).FullName + "):\n" + ctx.Body.ToILDasmString(), debug);
				}
			}, new ILHookConfig
			{
				ManualApply = true
			});
			try
			{
				val.Apply();
			}
			catch (Exception ex)
			{
				throw HarmonyException.Create(ex, patchBody);
			}
			MethodInfo methodInfo = val.GetCurrentTarget() as MethodInfo;
			PatchTools.RememberObject(standin.method, methodInfo);
			return methodInfo;
			static void PrintInfo(StringBuilder sb, ICollection<MethodInfo> methods, string name)
			{
				if (methods.Count <= 0)
				{
					return;
				}
				sb.AppendLine(name + ":");
				foreach (MethodInfo method in methods)
				{
					sb.AppendLine("  * " + method.FullDescription());
				}
			}
		}

		internal static IEnumerable<CodeInstruction> ApplyTranspilers(MethodBase methodBase, ILGenerator generator, int maxTranspilers = 0)
		{
			MethodPatcher methodPatcher = methodBase.GetMethodPatcher();
			DynamicMethodDefinition val = methodPatcher.CopyOriginal();
			if (val == null)
			{
				throw new NullReferenceException("Cannot reverse patch " + methodBase.FullDescription() + ": method patcher (" + methodPatcher.GetType().FullDescription() + ") can't copy original method body");
			}
			ILManipulator iLManipulator = new ILManipulator(val.Definition.Body, debug: false);
			PatchInfo patchInfo = methodBase.GetPatchInfo();
			if (patchInfo != null)
			{
				List<MethodInfo> sortedPatchMethods = GetSortedPatchMethods(methodBase, patchInfo.transpilers, debug: false);
				for (int i = 0; i < maxTranspilers && i < sortedPatchMethods.Count; i++)
				{
					iLManipulator.AddTranspiler(sortedPatchMethods[i]);
				}
			}
			return iLManipulator.GetInstructions(generator, methodBase);
		}

		internal static void UnpatchConditional(Func<Patch, bool> executionCondition)
		{
			foreach (MethodBase item in PatchProcessor.GetAllPatchedMethods().ToList())
			{
				bool num = item.HasMethodBody();
				Patches patchInfo2 = PatchProcessor.GetPatchInfo(item);
				PatchProcessor patchProcessor = new PatchProcessor(null, item);
				if (num)
				{
					patchInfo2.Postfixes.DoIf(executionCondition, delegate(Patch patchInfo)
					{
						patchProcessor.Unpatch(patchInfo.PatchMethod);
					});
					patchInfo2.Prefixes.DoIf(executionCondition, delegate(Patch patchInfo)
					{
						patchProcessor.Unpatch(patchInfo.PatchMethod);
					});
				}
				patchInfo2.ILManipulators.DoIf(executionCondition, delegate(Patch patchInfo)
				{
					patchProcessor.Unpatch(patchInfo.PatchMethod);
				});
				patchInfo2.Transpilers.DoIf(executionCondition, delegate(Patch patchInfo)
				{
					patchProcessor.Unpatch(patchInfo.PatchMethod);
				});
				if (num)
				{
					patchInfo2.Finalizers.DoIf(executionCondition, delegate(Patch patchInfo)
					{
						patchProcessor.Unpatch(patchInfo.PatchMethod);
					});
				}
			}
		}
	}
	internal class PatchJobs<T>
	{
		internal class Job
		{
			internal MethodBase original;

			internal T replacement;

			internal List<HarmonyMethod> prefixes = new List<HarmonyMethod>();

			internal List<HarmonyMethod> postfixes = new List<HarmonyMethod>();

			internal List<HarmonyMethod> transpilers = new List<HarmonyMethod>();

			internal List<HarmonyMethod> finalizers = new List<HarmonyMethod>();

			internal List<HarmonyMethod> ilmanipulators = new List<HarmonyMethod>();

			internal void AddPatch(AttributePatch patch)
			{
				HarmonyPatchType? type = patch.type;
				if (type.HasValue)
				{
					switch (type.GetValueOrDefault())
					{
					case HarmonyPatchType.Prefix:
						prefixes.Add(patch.info);
						break;
					case HarmonyPatchType.Postfix:
						postfixes.Add(patch.info);
						break;
					case HarmonyPatchType.Transpiler:
						transpilers.Add(patch.info);
						break;
					case HarmonyPatchType.Finalizer:
						finalizers.Add(patch.info);
						break;
					case HarmonyPatchType.ILManipulator:
						ilmanipulators.Add(patch.info);
						break;
					case HarmonyPatchType.ReversePatch:
						break;
					}
				}
			}
		}

		internal Dictionary<MethodBase, Job> state = new Dictionary<MethodBase, Job>();

		internal Job GetJob(MethodBase method)
		{
			if ((object)method == null)
			{
				return null;
			}
			if (!state.TryGetValue(method, out var value))
			{
				value = new Job
				{
					original = method
				};
				state[method] = value;
			}
			return value;
		}

		internal List<Job> GetJobs()
		{
			return state.Values.Where((Job job) => job.prefixes.Count + job.postfixes.Count + job.transpilers.Count + job.finalizers.Count + job.ilmanipulators.Count > 0).ToList();
		}

		internal List<T> GetReplacements()
		{
			return state.Values.Select((Job job) => job.replacement).ToList();
		}
	}
	internal class AttributePatch
	{
		private static readonly HarmonyPatchType[] allPatchTypes = new HarmonyPatchType[6]
		{
			HarmonyPatchType.Prefix,
			HarmonyPatchType.Postfix,
			HarmonyPatchType.Transpiler,
			HarmonyPatchType.Finalizer,
			HarmonyPatchType.ReversePatch,
			HarmonyPatchType.ILManipulator
		};

		internal HarmonyMethod info;

		internal HarmonyPatchType? type;

		private static readonly string harmonyAttributeName = typeof(HarmonyAttribute).FullName;

		internal static IEnumerable<AttributePatch> Create(MethodInfo patch, bool collectIncomplete = false)
		{
			if ((object)patch == null)
			{
				throw new NullReferenceException("Patch method cannot be null");
			}
			object[] customAttributes = patch.GetCustomAttributes(inherit: true);
			string name = patch.Name;
			HarmonyPatchType? type = GetPatchType(name, customAttributes);
			if (!type.HasValue)
			{
				return Enumerable.Empty<AttributePatch>();
			}
			if (type != HarmonyPatchType.ReversePatch && !patch.IsStatic)
			{
				throw new ArgumentException("Patch method " + patch.FullDescription() + " must be static");
			}
			List<HarmonyMethod> list = (from attr in customAttributes
				where attr.GetType().BaseType.FullName == harmonyAttributeName
				select AccessTools.Field(attr.GetType(), "info").GetValue(attr) into harmonyInfo
				select AccessTools.MakeDeepCopy<HarmonyMethod>(harmonyInfo)).ToList();
			List<HarmonyMethod> list2 = new List<HarmonyMethod>();
			ILookup<bool, HarmonyMethod> lookup = list.ToLookup((HarmonyMethod m) => IsComplete(m, collectIncomplete));
			List<HarmonyMethod> incomplete = lookup[false].ToList();
			HarmonyMethod info = HarmonyMethod.Merge(incomplete);
			List<HarmonyMethod> list3 = lookup[true].Where((HarmonyMethod m) => !Same(m, info)).ToList();
			if (list3.Count > 1)
			{
				list2.AddRange(list3.Select((HarmonyMethod m) => HarmonyMethod.Merge(incomplete.AddItem(m))));
			}
			else
			{
				list2.Add(HarmonyMethod.Merge(list));
			}
			foreach (HarmonyMethod item in list2)
			{
				item.method = patch;
			}
			return list2.Select((HarmonyMethod i) => new AttributePatch
			{
				info = i,
				type = type
			}).ToList();
			static bool IsComplete(HarmonyMethod m, bool collectIncomplete)
			{
				if (collectIncomplete || m.GetDeclaringType() != null)
				{
					return m.methodName != null;
				}
				return false;
			}
			static bool Same(HarmonyMethod m1, HarmonyMethod m2)
			{
				if (m1.GetDeclaringType() == m2.GetDeclaringType() && m1.methodName == m2.methodName)
				{
					return m1.GetArgumentList().SequenceEqual(m2.GetArgumentList());
				}
				return false;
			}
		}

		private static HarmonyPatchType? GetPatchType(string methodName, object[] allAttributes)
		{
			HashSet<string> hashSet = new HashSet<string>(from attr in allAttributes
				select attr.GetType().FullName into name
				where name.StartsWith("Harmony")
				select name);
			HarmonyPatchType? result = null;
			HarmonyPatchType[] array = allPatchTypes;
			for (int i = 0; i < array.Length; i++)
			{
				HarmonyPatchType value = array[i];
				string text = value.ToString();
				if (text == methodName || hashSet.Contains("HarmonyLib.Harmony" + text))
				{
					result = value;
					break;
				}
			}
			return result;
		}
	}
	internal class PatchSorter
	{
		private class PatchSortingWrapper : IComparable
		{
			internal readonly HashSet<PatchSortingWrapper> after;

			internal readonly HashSet<PatchSortingWrapper> before;

			internal readonly Patch innerPatch;

			internal PatchSortingWrapper(Patch patch)
			{
				innerPatch = patch;
				before = new HashSet<PatchSortingWrapper>();
				after = new HashSet<PatchSortingWrapper>();
			}

			public int CompareTo(object obj)
			{
				return PatchInfoSerialization.PriorityComparer((obj as PatchSortingWrapper)?.innerPatch, innerPatch.index, innerPatch.priority);
			}

			public override bool Equals(object obj)
			{
				if (obj is PatchSortingWrapper patchSortingWrapper)
				{
					return innerPatch.PatchMethod == patchSortingWrapper.innerPatch.PatchMethod;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return innerPatch.PatchMethod.GetHashCode();
			}

			internal void AddBeforeDependency(IEnumerable<PatchSortingWrapper> dependencies)
			{
				foreach (PatchSortingWrapper dependency in dependencies)
				{
					before.Add(dependency);
					dependency.after.Add(this);
				}
			}

			internal void AddAfterDependency(IEnumerable<PatchSortingWrapper> dependencies)
			{
				foreach (PatchSortingWrapper dependency in dependencies)
				{
					after.Add(dependency);
					dependency.before.Add(this);
				}
			}

			internal void RemoveAfterDependency(PatchSortingWrapper afterNode)
			{
				after.Remove(afterNode);
				afterNode.before.Remove(this);
			}

			internal void RemoveBeforeDependency(PatchSortingWrapper beforeNode)
			{
				before.Remove(beforeNode);
				beforeNode.after.Remove(this);
			}
		}

		internal class PatchDetailedComparer : IEqualityComparer<Patch>
		{
			public bool Equals(Patch x, Patch y)
			{
				if (y != null && x != null && x.owner == y.owner && x.PatchMethod == y.PatchMethod && x.index == y.index && x.priority == y.priority && x.before.Length == y.before.Length && x.after.Length == y.after.Length && x.before.All(((IEnumerable<string>)y.before).Contains<string>))
				{
					return x.after.All(((IEnumerable<string>)y.after).Contains<string>);
				}
				return false;
			}

			public int GetHashCode(Patch obj)
			{
				return obj.GetHashCode();
			}
		}

		private List<PatchSortingWrapper> patches;

		private HashSet<PatchSortingWrapper> handledPatches;

		private List<PatchSortingWrapper> result;

		private List<PatchSortingWrapper> waitingList;

		internal Patch[] sortedPatchArray;

		private readonly bool debug;

		internal PatchSorter(Patch[] patches, bool debug = false)
		{
			this.patches = patches.Select((Patch x) => new PatchSortingWrapper(x)).ToList();
			this.debug = debug;
			foreach (PatchSortingWrapper node in this.patches)
			{
				node.AddBeforeDependency(this.patches.Where((PatchSortingWrapper x) => node.innerPatch.before.Contains(x.innerPatch.owner)));
				node.AddAfterDependency(this.patches.Where((PatchSortingWrapper x) => node.innerPatch.after.Contains(x.innerPatch.owner)));
			}
			this.patches.Sort();
		}

		internal List<MethodInfo> Sort(MethodBase original)
		{
			return (from x in SortAsPatches(original)
				select x.GetMethod(original)).ToList();
		}

		internal Patch[] SortAsPatches(MethodBase original)
		{
			if (sortedPatchArray != null)
			{
				return sortedPatchArray;
			}
			handledPatches = new HashSet<PatchSortingWrapper>();
			waitingList = new List<PatchSortingWrapper>();
			result = new List<PatchSortingWrapper>(patches.Count);
			Queue<PatchSortingWrapper> queue = new Queue<PatchSortingWrapper>(patches);
			while (queue.Count != 0)
			{
				foreach (PatchSortingWrapper item in queue)
				{
					if (item.after.All((PatchSortingWrapper x) => handledPatches.Contains(x)))
					{
						AddNodeToResult(item);
						if (item.before.Count != 0)
						{
							ProcessWaitingList();
						}
					}
					else
					{
						waitingList.Add(item);
					}
				}
				CullDependency();
				queue = new Queue<PatchSortingWrapper>(waitingList);
				waitingList.Clear();
			}
			sortedPatchArray = result.Select((PatchSortingWrapper x) => x.innerPatch).ToArray();
			handledPatches = null;
			waitingList = null;
			patches = null;
			return sortedPatchArray;
		}

		internal bool ComparePatchLists(Patch[] patches)
		{
			if (sortedPatchArray == null)
			{
				Sort(null);
			}
			if (patches != null && sortedPatchArray.Length == patches.Length)
			{
				return sortedPatchArray.All((Patch x) => patches.Contains(x, new PatchDetailedComparer()));
			}
			return false;
		}

		private void CullDependency()
		{
			for (int i = waitingList.Count - 1; i >= 0; i--)
			{
				foreach (PatchSortingWrapper afterNode in waitingList[i].after)
				{
					if (!handledPatches.Contains(afterNode))
					{
						waitingList[i].RemoveAfterDependency(afterNode);
						Logger.Log(Logger.LogChannel.Debug, delegate
						{
							string text = afterNode.innerPatch.PatchMethod.FullDescription();
							string text2 = waitingList[i].innerPatch.PatchMethod.FullDescription();
							return "Breaking dependence between " + text + " and " + text2;
						}, debug);
						return;
					}
				}
			}
		}

		private void ProcessWaitingList()
		{
			int num = waitingList.Count;
			int num2 = 0;
			while (num2 < num)
			{
				PatchSortingWrapper patchSortingWrapper = waitingList[num2];
				if (patchSortingWrapper.after.All(handledPatches.Contains))
				{
					waitingList.Remove(patchSortingWrapper);
					AddNodeToResult(patchSortingWrapper);
					num--;
					num2 = 0;
				}
				else
				{
					num2++;
				}
			}
		}

		private void AddNodeToResult(PatchSortingWrapper node)
		{
			result.Add(node);
			handledPatches.Add(node);
		}
	}
	internal static class PatchTools
	{
		[ThreadStatic]
		private static Dictionary<object, object> objectReferences;

		internal static void RememberObject(object key, object value)
		{
			if (objectReferences == null)
			{
				objectReferences = new Dictionary<object, object>();
			}
			objectReferences[key] = value;
		}

		internal static MethodInfo GetPatchMethod(Type patchType, string attributeName)
		{
			MethodInfo methodInfo = patchType.GetMethods(AccessTools.all).FirstOrDefault((MethodInfo m) => m.GetCustomAttributes(inherit: true).Any((object a) => a.GetType().FullName == attributeName));
			if ((object)methodInfo == null)
			{
				string name = attributeName.Replace("HarmonyLib.Harmony", "");
				methodInfo = patchType.GetMethod(name, AccessTools.all);
			}
			return methodInfo;
		}

		internal static AssemblyBuilder DefineDynamicAssembly(string name)
		{
			return AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.Run);
		}

		internal static List<AttributePatch> GetPatchMethods(Type type, bool collectIncomplete = false)
		{
			return (from attributePatch in AccessTools.GetDeclaredMethods(type).SelectMany((MethodInfo m) => AttributePatch.Create(m, collectIncomplete))
				where attributePatch != null
				select attributePatch).ToList();
		}

		internal static MethodBase GetOriginalMethod(this HarmonyMethod attr)
		{
			try
			{
				MethodType? methodType = attr.methodType;
				if (methodType.HasValue)
				{
					switch (methodType.GetValueOrDefault())
					{
					case MethodType.Normal:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes);
					case MethodType.Getter:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.DeclaredProperty(attr.GetDeclaringType(), attr.methodName).GetGetMethod(nonPublic: true);
					case MethodType.Setter:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.DeclaredProperty(attr.GetDeclaringType(), attr.methodName).GetSetMethod(nonPublic: true);
					case MethodType.Constructor:
						return AccessTools.DeclaredConstructor(attr.GetDeclaringType(), attr.argumentTypes);
					case MethodType.StaticConstructor:
						return AccessTools.GetDeclaredConstructors(attr.GetDeclaringType()).FirstOrDefault((ConstructorInfo c) => c.IsStatic);
					case MethodType.Enumerator:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes));
					}
				}
			}
			catch (AmbiguousMatchException ex)
			{
				throw new HarmonyException("Ambiguous match for HarmonyMethod[" + attr.Description() + "]", ex.InnerException ?? ex);
			}
			return null;
		}
	}
	public enum MethodType
	{
		Normal,
		Getter,
		Setter,
		Constructor,
		StaticConstructor,
		Enumerator
	}
	public enum ArgumentType
	{
		Normal,
		Ref,
		Out,
		Pointer
	}
	public enum HarmonyPatchType
	{
		All,
		Prefix,
		Postfix,
		Transpiler,
		Finalizer,
		ReversePatch,
		ILManipulator
	}
	public enum HarmonyReversePatchType
	{
		Original,
		Snapshot
	}
	public enum MethodDispatchType
	{
		VirtualCall,
		Call
	}
	[MeansImplicitUse]
	public class HarmonyAttribute : Attribute
	{
		public HarmonyMethod info = new HarmonyMethod();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Delegate, AllowMultiple = true)]
	public class HarmonyPatch : HarmonyAttribute
	{
		public HarmonyPatch()
		{
		}

		public HarmonyPatch(Type declaringType)
		{
			info.declaringType = declaringType;
		}

		public HarmonyPatch(Type declaringType, Type[] argumentTypes)
		{
			info.declaringType = declaringType;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type declaringType, string methodName)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
		}

		public HarmonyPatch(Type declaringType, string methodName, params Type[] argumentTypes)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(string typeName, string methodName)
		{
			info.declaringType = AccessTools.TypeByName(typeName);
			info.methodName = methodName;
		}

		public HarmonyPatch(string typeName, string methodName, MethodType methodType, Type[] argumentTypes = null, ArgumentType[] argumentVariations = null)
		{
			info.declaringType = AccessTools.TypeByName(typeName);
			info.methodName = methodName;
			info.methodType = methodType;
			if (argumentTypes != null)
			{
				ParseSpecialArguments(argumentTypes, argumentVariations);
			}
		}

		public HarmonyPatch(Type declaringType, MethodType methodType)
		{
			info.declaringType = declaringType;
			info.methodType = methodType;
		}

		public HarmonyPatch(Type declaringType, MethodType methodType, params Type[] argumentTypes)
		{
			info.declaringType = declaringType;
			info.methodType = methodType;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type declaringType, MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.declaringType = declaringType;
			info.methodType = methodType;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(Type declaringType, string methodName, MethodType methodType)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
			info.methodType = methodType;
		}

		public HarmonyPatch(string methodName)
		{
			info.methodName = methodName;
		}

		public HarmonyPatch(string methodName, params Type[] argumentTypes)
		{
			info.methodName = methodName;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.methodName = methodName;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(string methodName, MethodType methodType)
		{
			info.methodName = methodName;
			info.methodType = methodType;
		}

		public HarmonyPatch(MethodType methodType)
		{
			info.methodType = methodType;
		}

		public HarmonyPatch(MethodType methodType, params Type[] argumentTypes)
		{
			info.methodType = methodType;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.methodType = methodType;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(Type[] argumentTypes)
		{
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(string typeName, string methodName, MethodType methodType = MethodType.Normal)
		{
			info.declaringType = AccessTools.TypeByName(typeName);
			info.methodName = methodName;
			info.methodType = methodType;
		}

		private void ParseSpecialArguments(Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			if (argumentVariations == null || argumentVariations.Length == 0)
			{
				info.argumentTypes = argumentTypes;
				return;
			}
			if (argumentTypes.Length < argumentVariations.Length)
			{
				throw new ArgumentException("argumentVariations contains more elements than argumentTypes", "argumentVariations");
			}
			List<Type> list = new List<Type>();
			for (int i = 0; i < argumentTypes.Length; i++)
			{
				Type type = argumentTypes[i];
				switch (argumentVariations[i])
				{
				case ArgumentType.Ref:
				case ArgumentType.Out:
					type = type.MakeByRefType();
					break;
				case ArgumentType.Pointer:
					type = type.MakePointerType();
					break;
				}
				list.Add(type);
			}
			info.argumentTypes = list.ToArray();
		}
	}
	[AttributeUsage(AttributeTargets.Delegate, AllowMultiple = true)]
	public class HarmonyDelegate : HarmonyPatch
	{
		public HarmonyDelegate(Type declaringType)
			: base(declaringType)
		{
		}

		public HarmonyDelegate(Type declaringType, Type[] argumentTypes)
			: base(declaringType, argumentTypes)
		{
		}

		public HarmonyDelegate(Type declaringType, string methodName)
			: base(declaringType, methodName)
		{
		}

		public HarmonyDelegate(Type declaringType, string methodName, params Type[] argumentTypes)
			: base(declaringType, methodName, argumentTypes)
		{
		}

		public HarmonyDelegate(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(declaringType, methodName, argumentTypes, argumentVariations)
		{
		}

		public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType)
			: base(declaringType, MethodType.Normal)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, params Type[] argumentTypes)
			: base(declaringType, MethodType.Normal, argumentTypes)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(declaringType, MethodType.Normal, argumentTypes, argumentVariations)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type declaringType, string methodName, MethodDispatchType methodDispatchType)
			: base(declaringType, methodName, MethodType.Normal)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(string methodName)
			: base(methodName)
		{
		}

		public HarmonyDelegate(string methodName, params Type[] argumentTypes)
			: base(methodName, argumentTypes)
		{
		}

		public HarmonyDelegate(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(methodName, argumentTypes, argumentVariations)
		{
		}

		public HarmonyDelegate(string methodName, MethodDispatchType methodDispatchType)
			: base(methodName, MethodType.Normal)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(MethodDispatchType methodDispatchType)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(MethodDispatchType methodDispatchType, params Type[] argumentTypes)
			: base(MethodType.Normal, argumentTypes)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(MethodType.Normal, argumentTypes, argumentVariations)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type[] argumentTypes)
			: base(argumentTypes)
		{
		}

		public HarmonyDelegate(Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(argumentTypes, argumentVariations)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
	public class HarmonyReversePatch : HarmonyAttribute
	{
		public HarmonyReversePatch(HarmonyReversePatchType type = HarmonyReversePatchType.Original)
		{
			info.reversePatchType = type;
		}
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class HarmonyPatchAll : HarmonyAttribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyPriority : HarmonyAttribute
	{
		public HarmonyPriority(int priority)
		{
			info.priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyBefore : HarmonyAttribute
	{
		public HarmonyBefore(params string[] before)
		{
			info.before = before;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyAfter : HarmonyAttribute
	{
		public HarmonyAfter(params string[] after)
		{
			info.after = after;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyDebug : HarmonyAttribute
	{
		public HarmonyDebug()
		{
			info.debug = true;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyEmitIL : HarmonyAttribute
	{
		public HarmonyEmitIL()
		{
			info.debugEmitPath = "./";
		}

		public HarmonyEmitIL(string dir)
		{
			info.debugEmitPath = dir;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyWrapSafe : HarmonyAttribute
	{
		public HarmonyWrapSafe()
		{
			info.wrapTryCatch = true;
		}
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyPrepare : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyCleanup : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyTargetMethod : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyTargetMethods : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyPrefix : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyPostfix : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyTranspiler : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyILManipulator : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyFinalizer : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)]
	public class HarmonyArgument : Attribute
	{
		public string OriginalName { get; private set; }

		public int Index { get; private set; }

		public string NewName { get; private set; }

		public HarmonyArgument(string originalName)
			: this(originalName, null)
		{
		}

		public HarmonyArgument(int index)
			: this(index, null)
		{
		}

		public HarmonyArgument(string originalName, string newName)
		{
			OriginalName = originalName;
			Index = -1;
			NewName = newName;
		}

		public HarmonyArgument(int index, string name)
		{
			OriginalName = null;
			Index = index;
			NewName = name;
		}
	}
	public class CodeInstruction
	{
		public OpCode opcode;

		public object operand;

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

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

		internal CodeInstruction()
		{
		}

		public CodeInstruction(OpCode opcode, object operand = null)
		{
			this.opcode = opcode;
			this.operand = operand;
		}

		public CodeInstruction(CodeInstruction instruction)
		{
			opcode = instruction.opcode;
			operand = instruction.operand;
			labels = instruction.labels.ToList();
			blocks = instruction.blocks.ToList();
		}

		public CodeInstruction Clone()
		{
			return new CodeInstruction(this)
			{
				labels = new List<Label>(),
				blocks = new List<ExceptionBlock>()
			};
		}

		public CodeInstruction Clone(OpCode opcode)
		{
			CodeInstruction codeInstruction = Clone();
			codeInstruction.opcode = opcode;
			return codeInstruction;
		}

		public CodeInstruction Clone(object operand)
		{
			CodeInstruction codeInstruction = Clone();
			codeInstruction.operand = operand;
			return codeInstruction;
		}

		public static CodeInstruction Call(Type type, string name, Type[] parameters = null, Type[] generics = null)
		{
			MethodInfo methodInfo = AccessTools.Method(type, name, parameters, generics);
			if ((object)methodInfo == null)
			{
				throw new ArgumentException($"No method found for type={type}, name={name}, parameters={parameters.Description()}, generics={generics.Description()}");
			}
			return new CodeInstruction(OpCodes.Call, methodInfo);
		}

		public static CodeInstruction Call(string typeColonMethodname, Type[] parameters = null, Type[] generics = null)
		{
			MethodInfo methodInfo = AccessTools.Method(typeColonMethodname, parameters, generics);
			if ((object)methodInfo == null)
			{
				throw new ArgumentException("No method found for " + typeColonMethodname + ", parameters=" + parameters.Description() + ", generics=" + generics.Description());
			}
			return new CodeInstruction(OpCodes.Call, methodInfo);
		}

		public static CodeInstruction Call(Expression<Action> expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction Call<T>(Expression<Action<T>> expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction Call<T, TResult>(Expression<Func<T, TResult>> expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction Call(LambdaExpression expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction CallClosure<T>(T closure) where T : Delegate
		{
			return Transpilers.EmitDelegate(closure);
		}

		public static CodeInstruction LoadField(Type type, string name, bool useAddress = false)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if ((object)fieldInfo == null)
			{
				throw new ArgumentException($"No field found for {type} and {name}");
			}
			return new CodeInstruction((!useAddress) ? (fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld) : (fieldInfo.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldflda), fieldInfo);
		}

		public static CodeInstruction StoreField(Type type, string name)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if ((object)fieldInfo == null)
			{
				throw new ArgumentException($"No field found for {type} and {name}");
			}
			return new CodeInstruction(fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
		}

		public override string ToString()
		{
			List<string> list = new List<string>();
			foreach (Label label in labels)
			{
				list.Add($"Label{label.GetHashCode()}");
			}
			foreach (ExceptionBlock block in blocks)
			{
				list.Add("EX_" + block.blockType.ToString().Replace("Block", ""));
			}
			string text = ((list.Count > 0) ? (" [" + string.Join(", ", list.ToArray()) + "]") : "");
			string text2 = FormatArgument(operand);
			if (text2.Length > 0)
			{
				text2 = " " + text2;
			}
			OpCode opCode = opcode;
			return opCode.ToString() + text2 + text;
		}

		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 (type == typeof(Label))
			{
				return $"Label{((Label)argument).GetHashCode()}";
			}
			if (type == typeof(Label[]))
			{
				return "Labels" + string.Join(",", ((Label[])argument).Select((Label l) => l.GetHashCode().ToString()).ToArray());
			}
			if (type == typeof(LocalBuilder))
			{
				return $"{((LocalBuilder)argument).LocalIndex} ({((LocalBuilder)argument).LocalType})";
			}
			if (type == typeof(string))
			{
				return argument.ToString().ToLiteral();
			}
			return argument.ToString().Trim();
		}
	}
	public enum ExceptionBlockType
	{
		BeginExceptionBlock,
		BeginCatchBlock,
		BeginExceptFilterBlock,
		BeginFaultBlock,
		BeginFinallyBlock,
		EndExceptionBlock
	}
	public class ExceptionBlock
	{
		public ExceptionBlockType blockType;

		public Type catchType;

		public ExceptionBlock(ExceptionBlockType blockType, Type catchType = null)
		{
			this.blockType = blockType;
			this.catchType = catchType ?? typeof(object);
		}
	}
	public class InvalidHarmonyPatchArgumentException : Exception
	{
		public MethodBase Original { get; }

		public MethodInfo Patch { get; }

		public override string Message => "(" + Patch.FullDescription() + "): " + base.Message;

		public InvalidHarmonyPatchArgumentException(string message, MethodBase original, MethodInfo patch)
			: base(message)
		{
			Original = original;
			Patch = patch;
		}
	}
	public class MemberNotFoundException : Exception
	{
		public MemberNotFoundException(string message)
			: base(message)
		{
		}
	}
	public class Harmony : IDisposable
	{
		[Obsolete("Use HarmonyFileLog.Enabled instead")]
		public static bool DEBUG;

		public string Id { get; }

		static Harmony()
		{
			StackTraceFixes.Install();
		}

		public Harmony(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				throw new ArgumentException("id cannot be null or empty");
			}
			try
			{
				string environmentVariable = Environment.GetEnvironmentVariable("HARMONY_DEBUG");
				if (environmentVariable != null && environmentVariable.Length > 0)
				{
					environmentVariable = environmentVariable.Trim();
					DEBUG = environmentVariable == "1" || bool.Parse(environmentVariable);
				}
			}
			catch
			{
			}
			if (DEBUG)
			{
				HarmonyFileLog.Enabled = true;
			}
			MethodBase callingMethod = (Logger.IsEnabledFor(Logger.LogChannel.Info) ? AccessTools.GetOutsideCaller() : null);
			Logger.Log(Logger.LogChannel.Info, delegate
			{
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				StringBuilder stringBuilder = new StringBuilder();
				Assembly assembly = typeof(Harmony).Assembly;
				Version version = assembly.GetName().Version;
				string text = assembly.Location;
				string text2 = Environment.Version.ToString();
				string text3 = Environment.OSVersion.Platform.ToString();
				if (string.IsNullOrEmpty(text))
				{
					text = new Uri(assembly.CodeBase).LocalPath;
				}
				int size = IntPtr.Size;
				Platform current = PlatformHelper.Current;
				stringBuilder.AppendLine($"### Harmony id={id}, version={version}, location={text}, env/clr={text2}, platform={text3}, ptrsize:runtime/env={size}/{current}");
				if ((object)callingMethod?.DeclaringType != null)
				{
					Assembly assembly2 = callingMethod.DeclaringType.Assembly;
					text = assembly2.Location;
					if (string.IsNullOrEmpty(text))
					{
						text = new Uri(assembly2.CodeBase).LocalPath;
					}
					stringBuilder.AppendLine("### Started from " + callingMethod.FullDescription() + ", location " + text);
					stringBuilder.Append($"### At {DateTime.Now:yyyy-MM-dd hh.mm.ss}");
				}
				return stringBuilder.ToString();
			});
			Id = id;
		}

		public void PatchAll()
		{
			Assembly assembly = new StackTrace().GetFrame(1).GetMethod().ReflectedType.Assembly;
			PatchAll(assembly);
		}

		public PatchProcessor CreateProcessor(MethodBase original)
		{
			return new PatchProcessor(this, original);
		}

		public PatchClassProcessor CreateClassProcessor(Type type)
		{
			return new PatchClassProcessor(this, type);
		}

		public PatchClassProcessor CreateClassProcessor(Type type, bool allowUnannotatedType)
		{
			return new PatchClassProcessor(this, type, allowUnannotatedType);
		}

		public ReversePatcher CreateReversePatcher(MethodBase original, HarmonyMethod standin)
		{
			return new ReversePatcher(this, original, standin);
		}

		public void PatchAll(Assembly assembly)
		{
			AccessTools.GetTypesFromAssembly(assembly).Do(delegate(Type type)
			{
				CreateClassProcessor(type).Patch();
			});
		}

		public void PatchAll(Type type)
		{
			CreateClassProcessor(type, allowUnannotatedType: true).Patch();
		}

		public MethodInfo Patch(MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null, HarmonyMethod ilmanipulator = null)
		{
			PatchProcessor patchProcessor = CreateProcessor(original);
			patchProcessor.AddPrefix(prefix);
			patchProcessor.AddPostfix(postfix);
			patchProcessor.AddTranspiler(transpiler);
			patchProcessor.AddFinalizer(finalizer);
			patchProcessor.AddILManipulator(ilmanipulator);
			return patchProcessor.Patch();
		}

		[Obsolete("Use newer Patch() instead", true)]
		public MethodInfo Patch(MethodBase original, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer)
		{
			return Patch(original, prefix, postfix, transpiler, finalizer, null);
		}

		public static MethodInfo ReversePatch(MethodBase original, HarmonyMethod standin, MethodInfo transpiler = null, MethodInfo ilmanipulator = null)
		{
			return PatchFunctions.ReversePatch(standin, original, transpiler, ilmanipulator);
		}

		[Obsolete("Use newer ReversePatch() instead", true)]
		public static MethodInfo ReversePatch(MethodBase original, HarmonyMethod standin, MethodInfo transpiler)
		{
			return PatchFunctions.ReversePatch(standin, original, transpiler, null);
		}

		public static void UnpatchID(string harmonyID)
		{
			if (string.IsNullOrEmpty(harmonyID))
			{
				throw new ArgumentNullException("harmonyID", "UnpatchID was called with a null or empty harmonyID.");
			}
			PatchFunctions.UnpatchConditional((Patch patchInfo) => patchInfo.owner == harmonyID);
		}

		void IDisposable.Dispose()
		{
			UnpatchSelf();
		}

		public void UnpatchSelf()
		{
			UnpatchID(Id);
		}

		public static void UnpatchAll()
		{
			Logger.Log(Logger.LogChannel.Warn, () => "UnpatchAll has been called - This will remove ALL HARMONY PATCHES.");
			PatchFunctions.UnpatchConditional((Patch _) => true);
		}

		[Obsolete("Use UnpatchSelf() to unpatch the current instance. The functionality to unpatch either other ids or EVERYTHING has been moved the static methods UnpatchID() and UnpatchAll() respectively", true)]
		public void UnpatchAll(string harmonyID = null)
		{
			if (harmonyID == null)
			{
				if (HarmonyGlobalSettings.DisallowLegacyGlobalUnpatchAll)
				{
					Logger.Log(Logger.LogChannel.Warn, () => "Legacy UnpatchAll has been called AND DisallowLegacyGlobalUnpatchAll=true. Skipping execution of UnpatchAll");
				}
				else
				{
					UnpatchAll();
				}
			}
			else if (harmonyID.Length == 0)
			{
				Logger.Log(Logger.LogChannel.Warn, () => "Legacy UnpatchAll was called with harmonyID=\"\" which is an invalid id. Skipping execution of UnpatchAll");
			}
			else
			{
				UnpatchID(harmonyID);
			}
		}

		public void Unpatch(MethodBase original, HarmonyPatchType type, string harmonyID = "*")
		{
			CreateProcessor(original).Unpatch(type, harmonyID);
		}

		public void Unpatch(MethodBase original, MethodInfo patch)
		{
			CreateProcessor(original).Unpatch(patch);
		}

		public static bool HasAnyPatches(string harmonyID)
		{
			return (from original in GetAllPatchedMethods()
				select GetPatchInfo(original)).Any((Patches info) => info.Owners.Contains(harmonyID));
		}

		public static Patches GetPatchInfo(MethodBase method)
		{
			return PatchProcessor.GetPatchInfo(method);
		}

		public IEnumerable<MethodBase> GetPatchedMethods()
		{
			return from original in GetAllPatchedMethods()
				where GetPatchInfo(original).Owners.Contains(Id)
				select original;
		}

		public static IEnumerable<MethodBase> GetAllPatchedMethods()
		{
			return PatchProcessor.GetAllPatchedMethods();
		}

		public static MethodBase GetOriginalMethod(MethodInfo replacement)
		{
			if (replacement == null)
			{
				throw new ArgumentNullException("replacement");
			}
			return PatchManager.GetOriginal(replacement);
		}

		public static MethodBase GetMethodFromStackframe(StackFrame frame)
		{
			if (frame == null)
			{
				throw new ArgumentNullException("frame");
			}
			return PatchManager.FindReplacement(frame) ?? frame.GetMethod();
		}

		public static MethodBase GetOriginalMethodFromStackframe(StackFrame frame)
		{
			MethodBase methodBase = GetMethodFromStackframe(frame);
			if (methodBase is MethodInfo replacement)
			{
				methodBase = GetOriginalMethod(replacement) ?? methodBase;
			}
			return methodBase;
		}

		public static Dictionary<string, Version> VersionInfo(out Version currentVersion)
		{
			return PatchProcessor.VersionInfo(out currentVersion);
		}

		public static Harmony CreateAndPatchAll(Type type, string harmonyInstanceId = null)
		{
			Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}");
			harmony.PatchAll(type);
			return harmony;
		}

		public static Harmony CreateAndPatchAll(Assembly assembly, string harmonyInstanceId = null)
		{
			Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}");
			harmony.PatchAll(assembly);
			return harmony;
		}
	}
	[Serializable]
	public class HarmonyException : Exception
	{
		private Dictionary<int, CodeInstruction> instructions = new Dictionary<int, CodeInstruction>();

		private int errorOffset = -1;

		internal HarmonyException()
		{
		}

		internal HarmonyException(string message)
			: base(message)
		{
		}

		internal HarmonyException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected HarmonyException(SerializationInfo serializationInfo, StreamingContext streamingContext)
		{
			throw new NotImplementedException();
		}

		internal HarmonyException(Exception innerException, Dictionary<int, CodeInstruction> instructions, int errorOffset)
			: base("IL Compile Error", innerException)
		{
			this.instructions = instructions;
			this.errorOffset = errorOffset;
		}

		internal static Exception Create(Exception ex, MethodBody body)
		{
			if (ex is HarmonyException ex2)
			{
				Dictionary<int, CodeInstruction> dictionary = ex2.instructions;
				if (dictionary != null && dictionary.Count > 0 && ex2.errorOffset >= 0)
				{
					return ex;
				}
			}
			Match match = Regex.Match(ex.Message.TrimEnd(Array.Empty<char>()), "(?:Reason: )?Invalid IL code in.+: IL_(\\d{4}): (.+)$");
			if (!match.Success)
			{
				return new HarmonyException("IL Compile Error (unknown location)", ex);
			}
			Dictionary<int, CodeInstruction> dictionary2 = ILManipulator.GetInstructions(body) ?? new Dictionary<int, CodeInstruction>();
			int num = int.Parse(match.Groups[1].Value, NumberStyles.HexNumber);
			Regex.Replace(match.Groups[2].Value, " {2,}", " ");
			if (ex is HarmonyException ex3)
			{
				if (dictionary2.Count != 0)
				{
					ex3.instructions = dictionary2;
					ex3.errorOffset = num;
				}
				return ex3;
			}
			return new HarmonyException(ex, dictionary2, num);
		}

		public List<KeyValuePair<int, CodeInstruction>> GetInstructionsWithOffsets()
		{
			return instructions.OrderBy((KeyValuePair<int, CodeInstruction> ins) => ins.Key).ToList();
		}

		public List<CodeInstruction> GetInstructions()
		{
			return (from ins in instructions
				orderby ins.Key
				select ins.Value).ToList();
		}

		public int GetErrorOffset()
		{
			return errorOffset;
		}

		public int GetErrorIndex()
		{
			if (instructions.TryGetValue(errorOffset, out var value))
			{
				return GetInstructions().IndexOf(value);
			}
			return -1;
		}
	}
	public static class HarmonyGlobalSettings
	{
		public static bool DisallowLegacyGlobalUnpatchAll { get; set; }
	}
	public class HarmonyMethod
	{
		public MethodInfo method;

		public Type declaringType;

		public string methodName;

		public MethodType? methodType;

		public Type[] argumentTypes;

		public int priority = -1;

		public string[] before;

		public string[] after;

		public HarmonyReversePatchType? reversePatchType;

		public bool? debug;

		public string debugEmitPath;

		public bool nonVirtualDelegate;

		public bool? wrapTryCatch;

		public HarmonyMethod()
		{
		}

		private void ImportMethod(MethodInfo theMethod)
		{
			if ((object)theMethod == null)
			{
				throw new ArgumentNullException("theMethod", "Harmony method is null (did you target a wrong or missing method?)");
			}
			if (!theMethod.IsStatic)
			{
				throw new ArgumentException("Harmony method must be static", "theMethod");
			}
			method = theMethod;
			List<HarmonyMethod> fromMethod = HarmonyMethodExtensions.GetFromMethod(method);
			if (fromMethod != null)
			{
				Merge(fromMethod).CopyTo(this);
			}
		}

		public HarmonyMethod(MethodInfo method)
		{
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			ImportMethod(method);
		}

		public HarmonyMethod(MethodInfo method, int priority = -1, string[] before = null, string[] after = null, bool? debug = null)
		{
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			ImportMethod(method);
			this.priority = priority;
			this.before = before;
			this.after = after;
			this.debug = debug;
		}

		public HarmonyMethod(Type methodType, string methodName, Type[] argumentTypes = null)
		{
			MethodInfo methodInfo = AccessTools.Method(methodType, methodName, argumentTypes);
			if ((object)methodInfo == null)
			{
				throw new ArgumentException($"Cannot not find method for type {methodType} and name {methodName} and parameters {argumentTypes?.Description()}");
			}
			ImportMethod(methodInfo);
		}

		public static List<string> HarmonyFields()
		{
			return (from s in AccessTools.GetFieldNames(typeof(HarmonyMethod))
				where s != "method"
				select s).ToList();
		}

		public static HarmonyMethod Merge(List<HarmonyMethod> attributes)
		{
			return Merge((IEnumerable<HarmonyMethod>)attributes);
		}

		internal static HarmonyMethod Merge(IEnumerable<HarmonyMethod> attributes)
		{
			HarmonyMethod harmonyMethod = new HarmonyMethod();
			if (attributes == null)
			{
				return harmonyMethod;
			}
			Traverse resultTrv = Traverse.Create(harmonyMethod);
			attributes.Do(delegate(HarmonyMethod attribute)
			{
				Traverse trv = Traverse.Create(attribute);
				HarmonyFields().ForEach(delegate(string f)
				{
					object value = trv.Field(f).GetValue();
					if (value != null && (f != "priority" || (int)value != -1))
					{
						HarmonyMethodExtensions.SetValue(resultTrv, f, value);
					}
				});
			});
			return harmonyMethod;
		}

		public override string ToString()
		{
			string result = "";
			Traverse trv = Traverse.Create(this);
			HarmonyFields().ForEach(delegate(string f)
			{
				if (result.Length > 0)
				{
					result += ", ";
				}
				result += $"{f}={trv.Field(f).GetValue()}";
			});
			return "HarmonyMethod[" + result + "]";
		}

		internal string Description()
		{
			string text = (((object)declaringType != null) ? declaringType.FullDescription() : "undefined");
			string text2 = methodName ?? "undefined";
			string text3 = (methodType.HasValue ? methodType.Value.ToString() : "undefined");
			string text4 = ((argumentTypes != null) ? argumentTypes.Description() : "undefined");
			return "(class=" + text + ", methodname=" + text2 + ", type=" + text3 + ", args=" + text4 + ")";
		}

		internal Type GetDeclaringType()
		{
			return declaringType;
		}

		internal Type[] GetArgumentList()
		{
			return argumentTypes ?? EmptyType.NoArgs;
		}
	}
	internal static class EmptyType
	{
		internal static readonly Type[] NoArgs = new Type[0];
	}
	public static class HarmonyMethodExtensions
	{
		internal static void SetValue(Traverse trv, string name, object val)
		{
			if (val != null)
			{
				Traverse traverse = trv.Field(name);
				if (name == "methodType" || name == "reversePatchType")
				{
					val = Enum.ToObject(Nullable.GetUnderlyingType(traverse.GetValueType()), (int)val);
				}
				traverse.SetValue(val);
			}
		}

		public static void CopyTo(this HarmonyMethod from, HarmonyMethod to)
		{
			if (to == null)
			{
				return;
			}
			Traverse fromTrv = Traverse.Create(from);
			Traverse toTrv = Traverse.Create(to);
			HarmonyMethod.HarmonyFields().ForEach(delegate(string f)
			{
				object value = fromTrv.Field(f).GetValue();
				if (value != null)
				{
					SetValue(toTrv, f, value);
				}
			});
		}

		public static HarmonyMethod Clone(this HarmonyMethod original)
		{
			HarmonyMethod harmonyMethod = new HarmonyMethod();
			original.CopyTo(harmonyMethod);
			return harmonyMethod;
		}

		public static HarmonyMethod Merge(this HarmonyMethod master, HarmonyMethod detail)
		{
			if (detail == null)
			{
				return master;
			}
			HarmonyMethod harmonyMethod = new HarmonyMethod();
			Traverse resultTrv = Traverse.Create(harmonyMethod);
			Traverse masterTrv = Traverse.Create(master);
			Traverse detailTrv = Traverse.Create(detail);
			HarmonyMethod.HarmonyFields().ForEach(delegate(string f)
			{
				object value = masterTrv.Field(f).GetValue();
				object value2 = detailTrv.Field(f).GetValue();
				if (f != "priority" || (int)value2 != -1)
				{
					SetValue(resultTrv, f, value2 ?? value);
				}
			});
			return harmonyMethod;
		}

		private static HarmonyMethod GetHarmonyMethodInfo(object attribute)
		{
			FieldInfo field = attribute.GetType().GetField("info", AccessTools.all);
			if ((object)field == null)
			{
				return null;
			}
			if (field.FieldType.FullName != typeof(HarmonyMethod).FullName)
			{
				return null;
			}
			return AccessTools.MakeDeepCopy<HarmonyMethod>(field.GetValue(attribute));
		}

		public static List<HarmonyMethod> GetFromType(Type type)
		{
			return (from attr in type.GetCustomAttributes(inherit: true)
				select GetHarmonyMethodInfo(attr) into info
				where info != null
				select info).ToList();
		}

		public static HarmonyMethod GetMergedFromType(Type type)
		{
			return HarmonyMethod.Merge(GetFromType(type));
		}

		public static List<HarmonyMethod> GetFromMethod(MethodBase method)
		{
			return (from attr in method.GetCustomAttributes(inherit: true)
				select GetHarmonyMethodInfo(attr) into info
				where info != null
				select info).ToList();
		}

		public static HarmonyMethod GetMergedFromMethod(MethodBase method)
		{
			return HarmonyMethod.Merge(GetFromMethod(method));
		}
	}
	public class InlineSignature : ICallSiteGenerator
	{
		public class ModifierType
		{
			public bool IsOptional;

			public Type Modifier;

			public object Type;

			public override string ToString()
			{
				return ((Type is Type type) ? type.FullDescription() : Type?.ToString()) + " mod" + (IsOptional ? "opt" : "req") + "(" + Modifier?.FullDescription() + ")";
			}

			internal TypeReference ToTypeReference(ModuleDefinition module)
			{
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Expected O, but got Unknown
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Expected O, but got Unknown
				if (!IsOptional)
				{
					return (TypeReference)new RequiredModifierType(module.ImportReference(Modifier), GetTypeReference(module, Type));
				}
				return (TypeReference)new OptionalModifierType(module.ImportReference(Modifier), GetTypeReference(module, Type));
			}
		}

		public bool HasThis { get; set; }

		public bool ExplicitThis { get; set; }

		public CallingConvention CallingConvention { get; set; } = CallingConvention.Winapi;


		public List<object> Parameters { get; set; } = new List<object>();


		public object ReturnType { get; set; } = typeof(void);


		public override string ToString()
		{
			return ((ReturnType is Type type) ? type.FullDescription() : ReturnType?.ToString()) + " (" + Parameters.Join((object p) => (!(p is Type type2)) ? p?.ToString() : type2.FullDescription()) + ")";
		}

		internal static TypeReference GetTypeReference(ModuleDefinition module, object param)
		{
			if (!(param is Type type))
			{
				if (!(param is InlineSignature inlineSignature))
				{
					if (param is ModifierType modifierType)
					{
						return modifierType.ToTypeReference(module);
					}
					throw new NotSupportedException($"Unsupported inline signature parameter type: {param} ({param?.GetType().FullDescription()})");
				}
				return (TypeReference)(object)inlineSignature.ToFunctionPointer(module);
			}
			return module.ImportReference(type);
		}

		CallSite ICallSiteGenerator.ToCallSite(ModuleDefinition module)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			CallSite val = new CallSite(GetTypeReference(module, ReturnType))
			{
				HasThis = HasThis,
				ExplicitThis = ExplicitThis,
				CallingConvention = (MethodCallingConvention)(byte)((byte)CallingConvention - 1)
			};
			foreach (object parameter in Parameters)
			{
				val.Parameters.Add(new ParameterDefinition(GetTypeReference(module, parameter)));
			}
			return val;
		}

		private FunctionPointerType ToFunctionPointer(ModuleDefinition module)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			FunctionPointerType val = new FunctionPointerType
			{
				ReturnType = GetTypeReference(module, ReturnType),
				HasThis = HasThis,
				ExplicitThis = ExplicitThis,
				CallingConvention = (MethodCallingConvention)(byte)((byte)CallingConvention - 1)
			};
			foreach (object parameter in Parameters)
			{
				val.Parameters.Add(new ParameterDefinition(GetTypeReference(module, parameter)));
			}
			return val;
		}
	}
	internal static class PatchInfoSerialization
	{
		private class Binder : SerializationBinder
		{
			public override Type BindToType(string assemblyName, string typeName)
			{
				Type[] array = new Type[3]
				{
					typeof(PatchInfo),
					typeof(Patch[]),
					typeof(Patch)
				};
				foreach (Type type in array)
				{
					if (typeName == type.FullName)
					{
						return type;
					}
				}
				return Type.GetType($"{typeName}, {assemblyName}");
			}
		}

		internal static byte[] Serialize(this PatchInfo patchInfo)
		{
			using MemoryStream memoryStream = new MemoryStream();
			new BinaryFormatter().Serialize(memoryStream, patchInfo);
			return memoryStream.GetBuffer();
		}

		internal static PatchInfo Deserialize(byte[] bytes)
		{
			BinaryFormatter obj = new BinaryFormatter
			{
				Binder = new Binder()
			};
			MemoryStream serializationStream = new MemoryStream(bytes);
			return (PatchInfo)obj.Deserialize(serializationStream);
		}

		internal static int PriorityComparer(object obj, int index, int priority)
		{
			Traverse traverse = Traverse.Create(obj);
			int value = traverse.Field("priority").GetValue<int>();
			int value2 = traverse.Field("index").GetValue<int>();
			if (priority != value)
			{
				return -priority.CompareTo(value);
			}
			return index.CompareTo(value2);
		}
	}
	[Serializable]
	public class PatchInfo
	{
		public Patch[] prefixes = new Patch[0];

		public Patch[] postfixes = new Patch[0];

		public Patch[] transpilers = new Patch[0];

		public Patch[] finalizers = new Patch[0];

		public Patch[] ilmanipulators = new Patch[0];

		public bool Debugging
		{
			get
			{
				if (!prefixes.Any((Patch p) => p.debug) && !postfixes.Any((Patch p) => p.debug) && !transpilers.Any((Patch p) => p.debug) && !finalizers.Any((Patch p) => p.debug))
				{
					return ilmanipulators.Any((Patch p) => p.debug);
				}
				return true;
			}
		}

		public string[] DebugEmitPaths => (from p in prefixes.Concat(postfixes).Concat(transpilers).Concat(finalizers)
				.Concat(ilmanipulators)
			select p.debugEmitPath into p
			where p != null
			select p).ToArray();

		internal void AddPrefixes(string owner, params HarmonyMethod[] methods)
		{
			prefixes = Add(owner, methods, prefixes);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddPrefix(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddPrefixes(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemovePrefix(string owner)
		{
			prefixes = Remove(owner, prefixes);
		}

		internal void AddPostfixes(string owner, params HarmonyMethod[] methods)
		{
			postfixes = Add(owner, methods, postfixes);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddPostfix(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddPostfixes(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemovePostfix(string owner)
		{
			postfixes = Remove(owner, postfixes);
		}

		internal void AddTranspilers(string owner, params HarmonyMethod[] methods)
		{
			transpilers = Add(owner, methods, transpilers);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddTranspiler(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddTranspilers(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemoveTranspiler(string owner)
		{
			transpilers = Remove(owner, transpilers);
		}

		internal void AddFinalizers(string owner, params HarmonyMethod[] methods)
		{
			finalizers = Add(owner, methods, finalizers);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddFinalizer(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddFinalizers(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemoveFinalizer(string owner)
		{
			finalizers = Remove(owner, finalizers);
		}

		internal void AddILManipulators(string owner, params HarmonyMethod[] methods)
		{
			ilmanipulators = Add(owner, methods, ilmanipulators);
		}

		public void RemoveILManipulator(string owner)
		{
			ilmanipulators = Remove(owner, ilmanipulators);
		}

		public void RemovePatch(MethodInfo patch)
		{
			prefixes = prefixes.Where((Patch p) => p.PatchMethod != patch).ToArray();
			postfixes = postfixes.Where((Patch p) => p.PatchMethod != patch).ToArray();
			transpilers = transpilers.Where((Patch p) => p.PatchMethod != patch).ToArray();
			finalizers = finalizers.Where((Patch p) => p.PatchMethod != patch).ToArray();
			ilmanipulators = ilmanipulators.Where((Patch p) => p.PatchMethod != patch).ToArray();
		}

		private static Patch[] Add(string owner, HarmonyMethod[] add, Patch[] current)
		{
			if (add.Length == 0)
			{
				return current;
			}
			int initialIndex = current.Length;
			return current.Concat(add.Where((HarmonyMethod method) => method != null).Select((HarmonyMethod method, int i) => new Patch(method, i + initialIndex, owner))).ToArray();
		}

		private static Patch[] Remove(string owner, Patch[] current)
		{
			if (!(owner == "*"))
			{
				return current.Where((Patch patch) => patch.owner != owner).ToArray();
			}
			return new Patch[0];
		}
	}
	[Serializable]
	public class Patch : IComparable
	{
		public readonly int index;

		public readonly string owner;

		public readonly int priority;

		public readonly string[] before;

		public readonly string[] after;

		public readonly bool debug;

		public readonly string debugEmitPath;

		public readonly bool wrapTryCatch;

		[NonSerialized]
		private MethodInfo patchMethod;

		private int methodToken;

		private string moduleGUID;

		public MethodInfo PatchMethod
		{
			get
			{
				if ((object)patchMethod == null)
				{
					Module module = (from a in AppDomain.CurrentDomain.GetAssemblies()
						where !a.FullName.StartsWith("Microsoft.VisualStudio")
						select a).SelectMany((Assembly a) => a.GetLoadedModules()).First((Module m) => m.ModuleVersionId.ToString() == moduleGUID);
					patchMethod = (MethodInfo)module.ResolveMethod(methodToken);
				}
				return patchMethod;
			}
			set
			{
				patchMethod = value;
				methodToken = patchMethod.MetadataToken;
				moduleGUID = patchMethod.Module.ModuleVersionId.ToString();
			}
		}

		public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug)
		{
			if (patch is DynamicMethod)
			{
				throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method.");
			}
			this.index = index;
			this.owner = owner;
			this.priority = ((priority == -1) ? 400 : priority);
			this.before = before ?? new string[0];
			this.after = after ?? new string[0];
			this.debug = debug;
			PatchMethod = patch;
		}

		public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug, bool wrapTryCatch)
		{
			if (patch is DynamicMethod)
			{
				throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method.");
			}
			this.index = index;
			this.owner = owner;
			this.priority = ((priority == -1) ? 400 : priority);
			this.before = before ?? new string[0];
			this.after = after ?? new string[0];
			this.debug = debug;
			this.wrapTryCatch = wrapTryCatch;
			PatchMethod = patch;
		}

		public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug, bool wrapTryCatch, string debugEmitPath)
		{
			if (patch is DynamicMethod)
			{
				throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method.");
			}
			this.index = index;
			this.owner = owner;
			this.priority = ((priority == -1) ? 400 : priority);
			this.before = before ?? new string[0];
			this.after = after ?? new string[0];
			this.debug = debug;
			this.debugEmitPath = debugEmitPath;
			this.wrapTryCatch = wrapTryCatch;
			PatchMethod = patch;
		}

		public Patch(HarmonyMethod method, int index, string owner)
			: this(method.method, index, owner, method.priority, method.before, method.after, method.debug.GetValueOrDefault(), method.wrapTryCatch.GetValueOrDefault(), method.debugEmitPath)
		{
		}

		public MethodInfo GetMethod(MethodBase original)
		{
			MethodInfo methodInfo = PatchMethod;
			if (methodInfo.ReturnType != typeof(DynamicMethod) && methodInfo.ReturnType != typeof(MethodInfo))
			{
				return methodInfo;
			}
			if (!methodInfo.IsStatic)
			{
				return methodInfo;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			if (parameters.Length != 1)
			{
				return methodInfo;
			}
			if (parameters[0].ParameterType != typeof(MethodBase))
			{
				return methodInfo;
			}
			return methodInfo.Invoke(null, new object[1] { original }) as MethodInfo;
		}

		public override bool Equals(object obj)
		{
			if (obj != null && obj is Patch)
			{
				return PatchMethod == ((Patch)obj).PatchMethod;
			}
			return false;
		}

		public int CompareTo(object obj)
		{
			return PatchInfoSerialization.PriorityComparer(obj, index, priority);
		}

		public override int GetHashCode()
		{
			return PatchMethod.GetHashCode();
		}
	}
	public class PatchClassProcessor
	{
		private readonly Harmony instance;

		private readonly Type containerType;

		private readonly HarmonyMethod containerAttributes;

		private readonly Dictionary<Type, MethodInfo> auxilaryMethods;

		private readonly List<AttributePatch> patchMethods;

		private static readonly List<Type> auxilaryTypes = new List<Type>
		{
			typeof(HarmonyPrepare),
			typeof(HarmonyCleanup),
			typeof(HarmonyTargetMethod),
			typeof(HarmonyTargetMethods)
		};

		public PatchClassProcessor(Harmony instance, Type type)
			: this(instance, type, allowUnannotatedType: false)
		{
		}

		public PatchClassProcessor(Harmony instance, Type type, bool allowUnannotatedType)
		{
			if (instance == null)
			{
				throw new ArgumentNullException("instance");
			}
			if ((object)type == null)
			{
				throw new ArgumentNullException("type");
			}
			this.instance = instance;
			containerType = type;
			List<HarmonyMethod> fromType = HarmonyMethodExtensions.GetFromType(type);
			if (!allowUnannotatedType && (fromType == null || fromType.Count == 0))
			{
				return;
			}
			containerAttributes = HarmonyMethod.Merge(fromType);
			MethodType? methodType = containerAttributes.methodType;
			if (!methodType.HasValue)
			{
				containerAttributes.methodType = MethodType.Normal;
			}
			auxilaryMethods = new Dictionary<Type, MethodInfo>();
			foreach (Type auxilaryType in auxilaryTypes)
			{
				MethodInfo patchMethod = PatchTools.GetPatchMethod(containerType, auxilaryType.FullName);
				if ((object)patchMethod != null)
				{
					auxilaryMethods[auxilaryType] = patchMethod;
				}
			}
			patchMethods = PatchTools.GetPatchMethods(containerType, containerAttributes.GetDeclaringType() != null);
			foreach (AttributePatch patchMethod2 in patchMethods)
			{
				MethodInfo method = patchMethod2.info.method;
				patchMethod2.info = containerAttributes.Merge(patchMethod2.info);
				patchMethod2.info.method = method;
			}
		}

		public List<MethodInfo> Patch()
		{
			if (containerAttributes == null)
			{
				return null;
			}
			Exception exception = null;
			if (!RunMethod<HarmonyPrepare, bool>(defaultIfNotExisting: true, defaultIfFailing: false, null, Array.Empty<object>()))
			{
				RunMethod<HarmonyCleanup>(ref exception, Array.Empty<object>());
				ReportException(exception, null);
				return new List<MethodInfo>();
			}
			List<MethodInfo> result = new List<MethodInfo>();
			MethodBase lastOriginal = null;
			try
			{
				List<MethodBase> bulkMethods = GetBulkMethods();
				if (bulkMethods.Count == 1)
				{
					lastOriginal = bulkMethods[0];
				}
				ReversePatch(ref lastOriginal);
				result = ((bulkMethods.Count > 0) ? BulkPatch(bulkMethods, ref lastOriginal) : PatchWithAttributes(ref lastOriginal));
			}
			catch (Exception ex)
			{
				exception = ex;
			}
			RunMethod<HarmonyCleanup>(ref exception, new object[1] { exception });
			ReportException(exception, lastOriginal);
			return result;
		}

		private void ReversePatch(ref MethodBase lastOriginal)
		{
			for (int i = 0; i < patchMethods.Count; i++)
			{
				AttributePatch attributePatch = patchMethods[i];
				if (attributePatch.type == HarmonyPatchType.ReversePatch)
				{
					MethodBase originalMethod = attributePatch.info.GetOriginalMethod();
					if ((object)originalMethod != null)
					{
						lastOriginal = originalMethod;
					}
					ReversePatcher reversePatcher = instance.CreateReversePatcher(lastOriginal, attributePatch.info);
					lock (PatchProcessor.locker)
					{
						reversePatcher.Patch();
					}
				}
			}
		}

		private List<MethodInfo> BulkPatch(List<MethodBase> originals, ref MethodBase lastOriginal)
		{
			PatchJobs<MethodInfo> patchJobs = new PatchJobs<MethodInfo>();
			for (int i = 0; i < originals.Count; i++)
			{
				lastOriginal = originals[i];
				PatchJobs<MethodInfo>.Job job = patchJobs.GetJob(lastOriginal);
				foreach (AttributePatch patchMethod in patchMethods)
				{
					string text = "You cannot combine TargetMethod, TargetMethods or [HarmonyPatchAll] with individual annotations";
					HarmonyMethod info = patchMethod.info;
					if (info.methodName != null)
					{
						throw new ArgumentException(text + " [" + info.methodName + "]");
					}
					if (info.methodType.HasValue && info.methodType.Value != 0)
					{
						throw new ArgumentException($"{text} [{info.methodType}]");
					}
					if (info.argumentTypes != null)
					{
						throw new ArgumentException(text + " [" + info.argumentTypes.Description() + "]");
					}
					job.AddPatch(patchMethod);
				}
			}
			foreach (PatchJobs<MethodInfo>.Job job2 in patchJobs.GetJobs())
			{
				lastOriginal = job2.original;
				ProcessPatchJob(job2);
			}
			return patchJobs.GetReplacements();
		}

		private List<MethodInfo> PatchWithAttributes(ref MethodBase lastOriginal)
		{
			PatchJobs<MethodInfo> patchJobs = new PatchJobs<MethodInfo>();
			foreach (AttributePatch patchMethod in patchMethods)
			{
				lastOriginal = patchMethod.info.GetOriginalMethod();
				if ((object)lastOriginal == null)
				{
					throw new ArgumentException("Undefined targ

CityMonitor.dll

Decompiled a year ago
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using CityMonitor.Systems;
using Colossal.Annotations;
using Colossal.UI.Binding;
using Game;
using Game.Common;
using Game.UI;
using HarmonyLib;
using HookUILib.Core;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CityMonitor")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A little panel with the most important metrics of your city without having to browse around")]
[assembly: AssemblyFileVersion("0.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0+4ff59b1edff402446d171bb9b6ff1ced204af784")]
[assembly: AssemblyProduct("CityMonitor")]
[assembly: AssemblyTitle("CityMonitor")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CityMonitor
{
	[BepInPlugin("CityMonitor", "CityMonitor", "0.3.0")]
	public class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin CityMonitor is loaded!");
			Harmony val = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "CityMonitor_Cities2Harmony");
			MethodBase[] array = val.GetPatchedMethods().ToArray();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin CityMonitor made patches! Patched methods: " + array.Length));
			MethodBase[] array2 = array;
			foreach (MethodBase methodBase in array2)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched method: " + methodBase.Module.Name + ":" + methodBase.Name));
			}
		}
	}
	public class CityMonitorUI : UIExtension
	{
		public readonly string extensionID = "example.city_monitor";

		public readonly string extensionContent;

		public readonly ExtensionType extensionType = (ExtensionType)0;

		public CityMonitorUI()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			extensionContent = ((UIExtension)this).LoadEmbeddedResource("CityMonitor.dist.bundle.js");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "CityMonitor";

		public const string PLUGIN_NAME = "CityMonitor";

		public const string PLUGIN_VERSION = "0.3.0";
	}
}
namespace CityMonitor.Systems
{
	public record MeterSetting : IJsonWritable
	{
		public string label;

		public string eventName;

		public int index;

		public string gradientName;

		public bool isEnabled;

		public void Write(IJsonWriter writer)
		{
			writer.TypeBegin(GetType().FullName);
			writer.PropertyName("label");
			writer.Write(label);
			writer.PropertyName("eventName");
			writer.Write(eventName);
			writer.PropertyName("index");
			writer.Write(index);
			writer.PropertyName("gradientName");
			writer.Write(gradientName);
			writer.PropertyName("isEnabled");
			writer.Write(isEnabled);
			writer.TypeEnd();
		}
	}
	internal class CityMonitorUISystem : UISystemBase
	{
		private ImmutableDictionary<string, MeterSetting> meters;

		private string kGroup = "city_monitor";

		protected override void OnCreate()
		{
			((UISystemBase)this).OnCreate();
			ImmutableDictionary<string, MeterSetting>.Builder builder = ImmutableDictionary.CreateBuilder<string, MeterSetting>();
			AddMeter(builder, 0, "electricity", "Electricity Availability", "electricityInfo.electricityAvailability", "maxGood");
			AddMeter(builder, 1, "water", "Water Availability", "waterInfo.waterAvailability", "maxGood");
			AddMeter(builder, 2, "sewage", "Sewage", "waterInfo.sewageAvailability", "maxGood");
			AddMeter(builder, 3, "landfill", "Landfill Usage", "garbageInfo.landfillAvailability", "maxGood");
			AddMeter(builder, 4, "healthcare", "Healthcare Availability", "healthcareInfo.healthcareAvailability", "maxGood");
			AddMeter(builder, 5, "health", "Average Health", "healthcareInfo.averageHealth", "maxGood");
			AddMeter(builder, 6, "cemetery", "Cemetery Availability", "healthcareInfo.cemeteryAvailability", "maxGood");
			AddMeter(builder, 7, "fire_hazard", "Fire Hazard", "fireAndRescueInfo.averageFireHazard", "minGood");
			AddMeter(builder, 8, "crime", "Crime Rate", "policeInfo.averageCrimeProbability", "minGood");
			AddMeter(builder, 9, "jail", "Jail Availability", "policeInfo.jailAvailability", "maxGood");
			AddMeter(builder, 10, "elementary", "Elementary School Availability", "educationInfo.elementaryAvailability", "maxGood");
			AddMeter(builder, 11, "highschool", "High School Availability", "educationInfo.highSchoolAvailability", "maxGood");
			AddMeter(builder, 12, "collage", "College Availability", "educationInfo.collegeAvailability", "maxGood");
			AddMeter(builder, 13, "university", "University Availability", "educationInfo.universityAvailability", "maxGood");
			meters = builder.ToImmutableDictionary();
			((UISystemBase)this).AddUpdateBinding((IUpdateBinding)(object)new GetterValueBinding<ImmutableDictionary<string, MeterSetting>>(kGroup, "meters", (Func<ImmutableDictionary<string, MeterSetting>>)(() => meters), (IWriter<ImmutableDictionary<string, MeterSetting>>)(object)new MyDictionaryWriter<string, MeterSetting>(), (EqualityComparer<ImmutableDictionary<string, MeterSetting>>)null));
			((UISystemBase)this).AddBinding((IBinding)(object)new TriggerBinding<string, bool>(kGroup, "toggle_visibility", (Action<string, bool>)ToggleVisibility, (IReader<string>)null, (IReader<bool>)null));
		}

		private void AddMeter(ImmutableDictionary<string, MeterSetting>.Builder builder, int index, string key, string label, string eventName, string gradient)
		{
			builder.Add(key, new MeterSetting
			{
				label = label,
				eventName = eventName,
				index = index,
				gradientName = gradient,
				isEnabled = true
			});
		}

		private void ToggleVisibility(string key, bool newValue)
		{
			MeterSetting meterSetting = meters[key];
			meterSetting.isEnabled = newValue;
			ImmutableDictionary<string, MeterSetting> immutableDictionary = meters.Remove(key).Add(key, meterSetting);
			meters = immutableDictionary;
		}
	}
	public class MyDictionaryWriter<K, V> : IWriter<IDictionary<K, V>>
	{
		[NotNull]
		private readonly IWriter<K> m_KeyWriter;

		[NotNull]
		private readonly IWriter<V> m_ValueWriter;

		public MyDictionaryWriter(IWriter<K> keyWriter = null, IWriter<V> valueWriter = null)
		{
			m_KeyWriter = keyWriter ?? ValueWriters.Create<K>();
			m_ValueWriter = valueWriter ?? ValueWriters.Create<V>();
		}

		public void Write(IJsonWriter writer, IDictionary<K, V> value)
		{
			if (value != null)
			{
				JsonWriterExtensions.MapBegin(writer, value.Count);
				foreach (KeyValuePair<K, V> item in value)
				{
					m_KeyWriter.Write(writer, item.Key);
					if ((object)item.Value is IDictionary<K, V> value2)
					{
						Write(writer, value2);
					}
					else
					{
						((IWriter<?>)(object)m_ValueWriter).Write(writer, item.Value);
					}
				}
				writer.MapEnd();
				return;
			}
			writer.WriteNull();
			throw new ArgumentNullException("value", "Null passed to non-nullable dictionary writer");
		}
	}
}
namespace CityMonitor.Patches
{
	[HarmonyPatch(typeof(SystemOrder))]
	public static class SystemOrderPatch
	{
		[HarmonyPatch("Initialize")]
		[HarmonyPostfix]
		public static void Postfix(UpdateSystem updateSystem)
		{
			updateSystem.UpdateAt<CityMonitorUISystem>((SystemUpdatePhase)22);
		}
	}
}