Decompiled source of RepoRPG RU v0.2.1

patchers/RepoRPG_RU.Patcher.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("RepoRPG RU - patcher")]
[assembly: AssemblyVersion("0.2.1.0")]
namespace RepoRPG_RU;

internal enum Use
{
	Unknown,
	Display,
	Keep,
	Id
}
internal struct Consumer
{
	public Instruction Ins;

	public int FromTop;

	public int Pops;

	public bool IsCall
	{
		get
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			if (Ins == null)
			{
				return false;
			}
			OpCode opCode = Ins.OpCode;
			Code code = ((OpCode)(ref opCode)).Code;
			if ((int)code != 39 && (int)code != 110)
			{
				return (int)code == 114;
			}
			return true;
		}
	}

	public MethodReference Method
	{
		get
		{
			if (!IsCall)
			{
				return null;
			}
			object operand = Ins.Operand;
			return (MethodReference)((operand is MethodReference) ? operand : null);
		}
	}

	public int Param
	{
		get
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			MethodReference method = Method;
			if (method == null)
			{
				return -2;
			}
			int num = Pops - 1 - FromTop;
			if (method.HasThis && !method.ExplicitThis)
			{
				OpCode opCode = Ins.OpCode;
				if ((int)((OpCode)(ref opCode)).Code != 114)
				{
					return num - 1;
				}
			}
			return num;
		}
	}
}
internal enum ProbeKind
{
	Prefix,
	Suffix,
	Inside
}
internal sealed class Probe
{
	public string Text;

	public ProbeKind Kind;

	public bool IgnoreCase;

	public string Where;

	public string Key
	{
		get
		{
			int kind = (int)Kind;
			return kind + (IgnoreCase ? "i" : "c") + Text;
		}
	}

	public bool Hits(string s)
	{
		if (s == null || s.Length < Text.Length)
		{
			return false;
		}
		StringComparison comparisonType = (IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
		return Kind switch
		{
			ProbeKind.Prefix => s.StartsWith(Text, comparisonType), 
			ProbeKind.Suffix => s.EndsWith(Text, comparisonType), 
			_ => s.IndexOf(Text, comparisonType) >= 0, 
		};
	}

	public override string ToString()
	{
		return ((Kind == ProbeKind.Prefix) ? "StartsWith" : ((Kind == ProbeKind.Suffix) ? "EndsWith" : "Contains")) + "(\"" + Builder.Escape(Text) + "\")";
	}
}
internal static class Analysis
{
	public static bool IsProbe(Consumer c, out ProbeKind kind, out bool ignoreCase)
	{
		kind = ProbeKind.Inside;
		ignoreCase = false;
		MethodReference method = c.Method;
		if (method == null || c.Param != 0 || method.Parameters.Count == 0)
		{
			return false;
		}
		if (TypeName(((MemberReference)method).DeclaringType) != "System.String" || ((MemberReference)((ParameterReference)method.Parameters[0]).ParameterType).FullName != "System.String")
		{
			return false;
		}
		switch (((MemberReference)method).Name)
		{
		case "StartsWith":
			kind = ProbeKind.Prefix;
			break;
		case "EndsWith":
			kind = ProbeKind.Suffix;
			break;
		case "Contains":
		case "IndexOf":
		case "LastIndexOf":
			kind = ProbeKind.Inside;
			break;
		case "Replace":
			kind = ProbeKind.Inside;
			break;
		default:
			return false;
		}
		if (!method.HasThis)
		{
			return false;
		}
		for (int i = 1; i < method.Parameters.Count; i++)
		{
			string fullName = ((MemberReference)((ParameterReference)method.Parameters[i]).ParameterType).FullName;
			if (fullName == "System.StringComparison" && i == method.Parameters.Count - 1)
			{
				if (c.Ins != null && Constant(c.Ins.Previous, out var value))
				{
					if ((value & 1) != 0)
					{
						ignoreCase = true;
					}
				}
				else
				{
					ignoreCase = true;
				}
			}
			else
			{
				switch (fullName)
				{
				case "System.StringComparison":
				case "System.Boolean":
				case "System.Globalization.CultureInfo":
					ignoreCase = true;
					break;
				}
			}
		}
		return true;
	}

	private static bool Constant(Instruction ins, out int value)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: 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_0016: 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_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected I4, but got Unknown
		value = 0;
		if (ins == null)
		{
			return false;
		}
		OpCode opCode = ins.OpCode;
		Code code = ((OpCode)(ref opCode)).Code;
		switch (code - 21)
		{
		case 0:
			value = -1;
			return true;
		case 1:
			value = 0;
			return true;
		case 2:
			value = 1;
			return true;
		case 3:
			value = 2;
			return true;
		case 4:
			value = 3;
			return true;
		case 5:
			value = 4;
			return true;
		case 6:
			value = 5;
			return true;
		case 7:
			value = 6;
			return true;
		case 8:
			value = 7;
			return true;
		case 9:
			value = 8;
			return true;
		case 10:
			value = (sbyte)ins.Operand;
			return true;
		case 11:
			value = (int)ins.Operand;
			return true;
		default:
			return false;
		}
	}

	public static bool ProbeMatters(Probe p, Rules rules)
	{
		if (rules.ProbeIgnore.Contains(p.Text))
		{
			return false;
		}
		if (rules.ProbeProtect.Contains(p.Text))
		{
			return true;
		}
		if (p.Text.Length >= 3 && p.Text[0] == '{' && p.Text[p.Text.Length - 1] == '}')
		{
			return false;
		}
		bool flag = false;
		bool flag2 = true;
		string text = p.Text;
		foreach (char c in text)
		{
			if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
			{
				flag = true;
			}
			else if (c < '0' || c > '9')
			{
				flag2 = false;
			}
		}
		if (!flag)
		{
			return false;
		}
		if (p.Kind == ProbeKind.Inside && flag2)
		{
			return false;
		}
		return true;
	}

	public static string TypeKey(TypeDefinition t)
	{
		List<string> list = new List<string>();
		for (TypeDefinition val = t; val != null; val = val.DeclaringType)
		{
			string text = ((MemberReference)val).Name;
			if (text.Length <= 0 || text[0] != '<')
			{
				int num = text.IndexOf('`');
				if (num > 0)
				{
					text = text.Substring(0, num);
				}
				list.Add(text);
			}
		}
		list.Reverse();
		return string.Join(".", list.ToArray());
	}

	public static string MemberName(MethodDefinition m)
	{
		string text = Angle(((MemberReference)m).Name);
		if (text == null)
		{
			TypeDefinition declaringType = m.DeclaringType;
			while (declaringType != null && ((MemberReference)declaringType).Name.Length > 0 && ((MemberReference)declaringType).Name[0] == '<')
			{
				string text2 = Angle(((MemberReference)declaringType).Name);
				if (!string.IsNullOrEmpty(text2))
				{
					text = text2;
					break;
				}
				declaringType = declaringType.DeclaringType;
			}
		}
		if (text == null)
		{
			text = ((MemberReference)m).Name;
		}
		if (text != ".ctor" && text != ".cctor")
		{
			int num = text.LastIndexOf('.');
			if (num >= 0 && num + 1 < text.Length)
			{
				text = text.Substring(num + 1);
			}
		}
		if (text.StartsWith("get_", StringComparison.Ordinal) || text.StartsWith("set_", StringComparison.Ordinal))
		{
			text = text.Substring(4);
		}
		else if (text.StartsWith("add_", StringComparison.Ordinal))
		{
			text = text.Substring(4);
		}
		else if (text.StartsWith("remove_", StringComparison.Ordinal))
		{
			text = text.Substring(7);
		}
		return text;
	}

	private static string Angle(string n)
	{
		if (n.Length < 3 || n[0] != '<')
		{
			return null;
		}
		int num = n.IndexOf('>');
		if (num <= 1)
		{
			return null;
		}
		return n.Substring(1, num - 1);
	}

	public static string Scope(MethodDefinition m)
	{
		return TypeKey(m.DeclaringType) + "::" + MemberName(m);
	}

	public static string TypeName(TypeReference t)
	{
		if (t == null)
		{
			return "";
		}
		return ((MemberReference)t.GetElementType()).FullName.Replace('/', '.');
	}

	private static bool Effect(MethodDefinition owner, Instruction ins, out int pop, out int push)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Expected I4, but got Unknown
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Invalid comparison between Unknown and I4
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Expected I4, but got Unknown
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Invalid comparison between Unknown and I4
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Invalid comparison between Unknown and I4
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Invalid comparison between Unknown and I4
		OpCode opCode = ins.OpCode;
		pop = 0;
		push = 0;
		StackBehaviour stackBehaviourPop = ((OpCode)(ref opCode)).StackBehaviourPop;
		switch ((int)stackBehaviourPop)
		{
		case 0:
			pop = 0;
			break;
		case 1:
		case 3:
		case 10:
			pop = 1;
			break;
		case 2:
		case 4:
		case 5:
		case 6:
		case 8:
		case 9:
		case 11:
		case 12:
			pop = 2;
			break;
		case 7:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
			pop = 3;
			break;
		case 18:
			return false;
		case 27:
		{
			if ((int)((OpCode)(ref opCode)).Code == 41)
			{
				pop = ((!(((MemberReference)((MethodReference)owner).ReturnType).FullName == "System.Void")) ? 1 : 0);
				break;
			}
			if ((int)((OpCode)(ref opCode)).Code == 40)
			{
				object operand = ins.Operand;
				CallSite val = (CallSite)((operand is CallSite) ? operand : null);
				if (val == null)
				{
					return false;
				}
				pop = val.Parameters.Count + 1 + ((val.HasThis && !val.ExplicitThis) ? 1 : 0);
				break;
			}
			object operand2 = ins.Operand;
			MethodReference val2 = (MethodReference)((operand2 is MethodReference) ? operand2 : null);
			if (val2 == null)
			{
				return false;
			}
			pop = val2.Parameters.Count;
			if (val2.HasThis && !val2.ExplicitThis && (int)((OpCode)(ref opCode)).Code != 114)
			{
				pop++;
			}
			break;
		}
		default:
			return false;
		}
		stackBehaviourPop = ((OpCode)(ref opCode)).StackBehaviourPush;
		switch (stackBehaviourPop - 19)
		{
		case 0:
			push = 0;
			break;
		case 1:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
			push = 1;
			break;
		case 2:
			push = 2;
			break;
		case 9:
			if ((int)((OpCode)(ref opCode)).Code == 40)
			{
				object operand3 = ins.Operand;
				CallSite val3 = (CallSite)((operand3 is CallSite) ? operand3 : null);
				if (val3 == null)
				{
					return false;
				}
				push = ((!(((MemberReference)val3.ReturnType).FullName == "System.Void")) ? 1 : 0);
			}
			else
			{
				object operand4 = ins.Operand;
				MethodReference val4 = (MethodReference)((operand4 is MethodReference) ? operand4 : null);
				if (val4 == null)
				{
					return false;
				}
				push = ((!(((MemberReference)val4.ReturnType).FullName == "System.Void")) ? 1 : 0);
			}
			break;
		default:
			return false;
		}
		return true;
	}

	public static Consumer Find(MethodDefinition owner, Instruction start)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Invalid comparison between Unknown and I4
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Invalid comparison between Unknown and I4
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Invalid comparison between Unknown and I4
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Invalid comparison between Unknown and I4
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Invalid comparison between Unknown and I4
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Invalid comparison between Unknown and I4
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Invalid comparison between Unknown and I4
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		Consumer result = default(Consumer);
		Instruction val = start;
		int num = 0;
		int num2 = 0;
		while (val != null && num2 < 4000)
		{
			OpCode opCode = val.OpCode;
			Code code = ((OpCode)(ref opCode)).Code;
			if ((int)code == 187 || (int)code == 188 || (int)code == 186 || (int)code == 206 || (int)code == 215)
			{
				return result;
			}
			if (!Effect(owner, val, out var pop, out var push))
			{
				return result;
			}
			if (num < pop)
			{
				return new Consumer
				{
					Ins = val,
					FromTop = num,
					Pops = pop
				};
			}
			num += push - pop;
			if ((int)code == 41 || (int)code == 119)
			{
				return result;
			}
			opCode = val.OpCode;
			val = (Instruction)(((int)((OpCode)(ref opCode)).FlowControl != 0) ? ((object)val.Next) : ((object)/*isinst with value type is only supported in some contexts*/));
			num2++;
		}
		return result;
	}

	public static Consumer Final(MethodDefinition owner, Instruction afterValue, Rules rules)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: 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_0022: 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_0026: Invalid comparison between Unknown and I4
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Invalid comparison between Unknown and I4
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Invalid comparison between Unknown and I4
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Invalid comparison between Unknown and I4
		Consumer result = Find(owner, afterValue);
		for (int i = 0; i < 12; i++)
		{
			if (result.Ins == null)
			{
				break;
			}
			OpCode opCode = result.Ins.OpCode;
			Code code = ((OpCode)(ref opCode)).Code;
			if ((int)code == 115 || (int)code == 116)
			{
				result = Find(owner, result.Ins.Next);
				continue;
			}
			if ((int)code != 39 && (int)code != 110)
			{
				break;
			}
			MethodReference method = result.Method;
			if (method == null || !(((MemberReference)method.ReturnType).FullName != "System.Void") || !IsThrough(method, result.Param, rules))
			{
				break;
			}
			result = Find(owner, result.Ins.Next);
		}
		return result;
	}

	private static bool IsThrough(MethodReference m, int param, Rules rules)
	{
		string text = TypeName(((MemberReference)m).DeclaringType);
		string name = ((MemberReference)m).Name;
		if (text == "System.String")
		{
			switch (name)
			{
			case "Concat":
			case "Format":
			case "Join":
				return true;
			case "ToUpper":
			case "ToUpperInvariant":
			case "ToLower":
			case "ToLowerInvariant":
			case "Trim":
			case "TrimStart":
			case "TrimEnd":
			case "PadLeft":
			case "PadRight":
			case "Substring":
			case "Insert":
			case "Remove":
			case "Replace":
			case "ToString":
			case "Normalize":
				return param == -1;
			default:
				return false;
			}
		}
		if (text == "System.Object" && name == "ToString")
		{
			return param == -1;
		}
		for (int i = 0; i < rules.Through.Count; i++)
		{
			if (Match(rules.Through[i], m, text, name, param))
			{
				return true;
			}
		}
		return false;
	}

	public static bool Match(CallRule rule, MethodReference m, string dt, string name, int param)
	{
		if (rule.Args != null && Array.IndexOf(rule.Args, param) < 0)
		{
			return false;
		}
		if (!Rules.Glob(rule.Method, name))
		{
			return false;
		}
		if (rule.External)
		{
			return Rules.Glob(rule.Type, dt);
		}
		if (!(((MemberReference)m).DeclaringType.GetElementType() is TypeDefinition))
		{
			return false;
		}
		return TypeMatches(rule.Type, dt);
	}

	public static bool TypeMatches(string pattern, string fullName)
	{
		if (pattern == "*")
		{
			return true;
		}
		if (Rules.Glob(pattern, fullName))
		{
			return true;
		}
		if (pattern.IndexOf('*') < 0)
		{
			if (fullName.Length > pattern.Length && fullName.EndsWith(pattern, StringComparison.Ordinal))
			{
				return fullName[fullName.Length - pattern.Length - 1] == '.';
			}
			return false;
		}
		return Rules.Glob("*." + pattern, fullName);
	}

	public static Use Classify(MethodDefinition owner, Consumer c, Rules rules, Dictionary<MethodDefinition, HashSet<int>> hooked, int depth, out string why)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		why = null;
		if (c.Ins == null)
		{
			return Use.Unknown;
		}
		OpCode opCode = c.Ins.OpCode;
		Code code = ((OpCode)(ref opCode)).Code;
		int num = LocalIndex(c.Ins, store: true);
		if (num >= 0)
		{
			if (depth > 0)
			{
				return Use.Unknown;
			}
			bool flag = false;
			bool flag2 = true;
			string text = null;
			Enumerator<Instruction> enumerator = owner.Body.Instructions.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					Instruction current = enumerator.Current;
					if (LocalIndex(current, store: false) != num)
					{
						continue;
					}
					flag = true;
					string why2;
					Use use = Classify(owner, Final(owner, current.Next, rules), rules, hooked, depth + 1, out why2);
					switch (use)
					{
					case Use.Id:
						why = "local -> " + why2;
						return Use.Id;
					case Use.Keep:
						if (text == null)
						{
							text = why2;
						}
						break;
					}
					if (use != Use.Display)
					{
						flag2 = false;
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			if (text != null)
			{
				why = "local -> " + text;
				return Use.Keep;
			}
			if (!(flag && flag2))
			{
				return Use.Unknown;
			}
			return Use.Display;
		}
		if (!c.IsCall)
		{
			return Use.Unknown;
		}
		MethodReference method = c.Method;
		if (method == null)
		{
			return Use.Unknown;
		}
		string text2 = TypeName(((MemberReference)method).DeclaringType);
		string name = ((MemberReference)method).Name;
		int param = c.Param;
		MethodReference elementMethod = method.GetElementMethod();
		MethodDefinition val = (MethodDefinition)(object)((elementMethod is MethodDefinition) ? elementMethod : null);
		if (val != null && hooked != null && hooked.TryGetValue(val, out var value) && value.Contains(param))
		{
			return Use.Display;
		}
		for (int i = 0; i < rules.Display.Count; i++)
		{
			if (Match(rules.Display[i], method, text2, name, param))
			{
				return Use.Display;
			}
		}
		for (int j = 0; j < rules.Keep.Count; j++)
		{
			if (Match(rules.Keep[j], method, text2, name, param))
			{
				why = text2 + "::" + name;
				return Use.Keep;
			}
		}
		for (int k = 0; k < rules.Veto.Count; k++)
		{
			if (Match(rules.Veto[k], method, text2, name, param))
			{
				why = text2 + "::" + name;
				return Use.Id;
			}
		}
		Use use2 = Builtin(method, text2, name, param, code);
		if (use2 == Use.Id || use2 == Use.Keep)
		{
			why = text2 + "::" + name;
		}
		return use2;
	}

	private static int LocalIndex(Instruction ins, bool store)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: 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_004f: Expected I4, but got Unknown
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Invalid comparison between Unknown and I4
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Invalid comparison between Unknown and I4
		OpCode opCode = ins.OpCode;
		Code code = ((OpCode)(ref opCode)).Code;
		switch (code - 6)
		{
		default:
			if ((int)code != 202)
			{
				if ((int)code != 204)
				{
					break;
				}
				goto case 13;
			}
			goto case 11;
		case 4:
			if (!store)
			{
				return -1;
			}
			return 0;
		case 5:
			if (!store)
			{
				return -1;
			}
			return 1;
		case 6:
			if (!store)
			{
				return -1;
			}
			return 2;
		case 7:
			if (!store)
			{
				return -1;
			}
			return 3;
		case 13:
			if (!store)
			{
				return -1;
			}
			return Index(ins.Operand);
		case 0:
			if (!store)
			{
				return 0;
			}
			return -1;
		case 1:
			if (!store)
			{
				return 1;
			}
			return -1;
		case 2:
			if (!store)
			{
				return 2;
			}
			return -1;
		case 3:
			if (!store)
			{
				return 3;
			}
			return -1;
		case 11:
			if (!store)
			{
				return Index(ins.Operand);
			}
			return -1;
		case 8:
		case 9:
		case 10:
		case 12:
			break;
		}
		return -1;
	}

	private static int Index(object operand)
	{
		VariableDefinition val = (VariableDefinition)((operand is VariableDefinition) ? operand : null);
		if (val != null)
		{
			return ((VariableReference)val).Index;
		}
		return -1;
	}

	private static Use Builtin(MethodReference m, string dt, string name, int param, Code code)
	{
		//IL_0530: Unknown result type (might be due to invalid IL or missing references)
		//IL_0534: Invalid comparison between Unknown and I4
		if (dt == "System.String")
		{
			switch (name)
			{
			case "op_Equality":
			case "op_Inequality":
			case "Equals":
			case "StartsWith":
			case "EndsWith":
			case "Contains":
			case "IndexOf":
			case "LastIndexOf":
			case "IndexOfAny":
			case "Compare":
			case "CompareOrdinal":
			case "CompareTo":
			case "Split":
			case "IsNullOrEmpty":
			case "IsNullOrWhiteSpace":
			case "Intern":
				return Use.Id;
			case "Replace":
				if (param != 0)
				{
					return Use.Unknown;
				}
				return Use.Id;
			case "Trim":
			case "TrimStart":
			case "TrimEnd":
				if (param < 0)
				{
					return Use.Unknown;
				}
				return Use.Id;
			default:
				return Use.Unknown;
			}
		}
		if (dt.StartsWith("System.Collections.", StringComparison.Ordinal))
		{
			switch (name)
			{
			case "ContainsKey":
			case "TryGetValue":
			case "get_Item":
			case "Contains":
			case "IndexOf":
			case "LastIndexOf":
			case "Remove":
			case "TryRemove":
			case "GetValueOrDefault":
			case "ContainsValue":
				return Use.Id;
			case "set_Item":
			case "Add":
			case "TryAdd":
			case ".ctor":
				if (dt.IndexOf("Dictionary", StringComparison.Ordinal) >= 0 || dt.IndexOf("SortedList", StringComparison.Ordinal) >= 0 || dt.IndexOf("Hashtable", StringComparison.Ordinal) >= 0 || dt.IndexOf("KeyValuePair", StringComparison.Ordinal) >= 0)
				{
					if (param != 0)
					{
						return Use.Unknown;
					}
					return Use.Id;
				}
				if (dt.IndexOf("Set`", StringComparison.Ordinal) >= 0)
				{
					return Use.Id;
				}
				return Use.Unknown;
			default:
				return Use.Unknown;
			}
		}
		if (dt.StartsWith("System.", StringComparison.Ordinal))
		{
			if ((int)code == 114 && dt.EndsWith("Exception", StringComparison.Ordinal))
			{
				return Use.Keep;
			}
			switch (dt)
			{
			case "System.Array":
			case "System.Linq.Enumerable":
				switch (name)
				{
				default:
					return Use.Unknown;
				case "IndexOf":
				case "LastIndexOf":
				case "Contains":
				case "BinarySearch":
					return Use.Id;
				}
			case "System.Console":
				return Use.Keep;
			case "System.Enum":
			case "System.Type":
			case "System.Activator":
			case "System.Convert":
			case "System.Environment":
			case "System.Guid":
			case "System.Version":
			case "System.Uri":
			case "System.AppDomain":
			case "System.Text.Encoding":
			case "System.StringComparer":
			case "System.Int16":
			case "System.Int32":
			case "System.Int64":
			case "System.UInt16":
			case "System.UInt32":
			case "System.UInt64":
			case "System.Byte":
			case "System.SByte":
			case "System.Single":
			case "System.Double":
			case "System.Decimal":
			case "System.Boolean":
			case "System.Char":
			case "System.DateTime":
			case "System.TimeSpan":
			case "System.Math":
				return Use.Id;
			case "System.Text.StringBuilder":
				if (!(name == "Replace") || param != 0)
				{
					return Use.Unknown;
				}
				return Use.Id;
			default:
				if (dt.StartsWith("System.Diagnostics.", StringComparison.Ordinal))
				{
					return Use.Keep;
				}
				if (dt.StartsWith("System.Reflection.", StringComparison.Ordinal) || dt.StartsWith("System.IO.", StringComparison.Ordinal) || dt.StartsWith("System.Text.RegularExpressions.", StringComparison.Ordinal) || dt.StartsWith("System.Net.", StringComparison.Ordinal) || dt.StartsWith("System.Threading.", StringComparison.Ordinal) || dt.StartsWith("System.Globalization.", StringComparison.Ordinal) || dt.StartsWith("System.Runtime.", StringComparison.Ordinal) || dt.StartsWith("System.Security.", StringComparison.Ordinal) || dt.StartsWith("System.Xml.", StringComparison.Ordinal))
				{
					return Use.Id;
				}
				return Use.Unknown;
			}
		}
		if (dt.StartsWith("BepInEx.Configuration.", StringComparison.Ordinal))
		{
			if (name == "Bind")
			{
				if (m.Parameters.Count != 4 || param != 3 || !(((MemberReference)((ParameterReference)m.Parameters[3]).ParameterType).FullName == "System.String"))
				{
					return Use.Id;
				}
				return Use.Display;
			}
			if (dt == "BepInEx.Configuration.ConfigDescription" && name == ".ctor")
			{
				if (param != 0)
				{
					return Use.Id;
				}
				return Use.Display;
			}
			return Use.Id;
		}
		if (dt.StartsWith("BepInEx.Logging.", StringComparison.Ordinal))
		{
			return Use.Keep;
		}
		if (dt.StartsWith("BepInEx.", StringComparison.Ordinal))
		{
			return Use.Id;
		}
		if (dt.StartsWith("HarmonyLib.", StringComparison.Ordinal) || dt.StartsWith("MonoMod.", StringComparison.Ordinal) || dt.StartsWith("Mono.", StringComparison.Ordinal) || dt.StartsWith("Photon.", StringComparison.Ordinal) || dt.StartsWith("ExitGames.", StringComparison.Ordinal) || dt.StartsWith("Steamworks.", StringComparison.Ordinal))
		{
			return Use.Id;
		}
		if (dt.StartsWith("UnityEngine.", StringComparison.Ordinal))
		{
			if (IsUnityText(dt, name))
			{
				return Use.Display;
			}
			switch (dt)
			{
			case "UnityEngine.Debug":
			case "UnityEngine.Logger":
				return Use.Keep;
			case "UnityEngine.GUIUtility":
				if (name == "set_systemCopyBuffer")
				{
					return Use.Keep;
				}
				break;
			}
			return Use.Id;
		}
		if (dt.StartsWith("TMPro.", StringComparison.Ordinal))
		{
			if (!(name == "set_text") && !(name == "SetText"))
			{
				return Use.Id;
			}
			return Use.Display;
		}
		return Use.Unknown;
	}

	private static bool IsUnityText(string dt, string name)
	{
		switch (dt)
		{
		case "UnityEngine.GUI":
		case "UnityEngine.GUILayout":
			return true;
		case "UnityEngine.GUIContent":
			if (!(name == ".ctor") && !(name == "set_text"))
			{
				return name == "set_tooltip";
			}
			return true;
		case "UnityEngine.TextMesh":
		case "UnityEngine.UI.Text":
			return name == "set_text";
		default:
			return false;
		}
	}

	public static bool IsTokenLike(string s)
	{
		if (s.Length == 0 || s.Length > 40)
		{
			return false;
		}
		bool result = false;
		foreach (char c in s)
		{
			if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
			{
				result = true;
			}
			else if ((c < '0' || c > '9') && c != '_' && c != '.' && c != '-' && c != '+' && c != '/' && c != ':' && c != '#' && c != '%')
			{
				return false;
			}
		}
		return result;
	}

	public static string Describe(Consumer c)
	{
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		if (c.Ins == null)
		{
			return "?";
		}
		MethodReference method = c.Method;
		if (method != null)
		{
			return TypeName(((MemberReference)method).DeclaringType) + "::" + ((MemberReference)method).Name + "#" + c.Param;
		}
		OpCode opCode = c.Ins.OpCode;
		return ((OpCode)(ref opCode)).Name;
	}
}
internal sealed class Report
{
	public string OriginalVersion = "?";

	public string NewVersion = "?";

	public int Methods;

	public int Literals;

	public int Replaced;

	public int ReplacedScoped;

	public int SkippedVeto;

	public int SkippedToken;

	public int SkippedType;

	public int SkippedProbe;

	public int SkippedSentence;

	public int Probes;

	public int HooksApplied;

	public int CallHooks;

	public int HookRulesMissed;

	public int FontHooks;

	public int FontRulesMissed;

	public int DataReplaced;

	public int DataFiles;

	public int EnumsKnown;

	public int EnumsAnswered;

	public int AssemblyRequests;

	public readonly HashSet<string> UsedGlobal = new HashSet<string>(StringComparer.Ordinal);

	public readonly HashSet<string> UsedScoped = new HashSet<string>(StringComparer.Ordinal);

	public readonly HashSet<string> UsedData = new HashSet<string>(StringComparer.Ordinal);

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

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

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

	public readonly Dictionary<string, byte[]> Resources = new Dictionary<string, byte[]>(StringComparer.Ordinal);
}
internal sealed class BuildOptions
{
	public Settings Settings;

	public Lang Lang;

	public Rules Rules;

	public string RuntimeAssemblyName = "RepoRPG_RU";

	public Version RuntimeVersion = new Version(0, 0, 0, 0);

	public bool HaveRuntime;

	public bool Dump;

	public string Stamp;

	public bool RequirePlugin = true;

	public List<string> SearchDirs = new List<string>();
}
internal static class Builder
{
	private sealed class Edit
	{
		public int Index;

		public string Value;
	}

	private sealed class Plan
	{
		public readonly Dictionary<uint, List<Edit>> Edits = new Dictionary<uint, List<Edit>>();

		public readonly Dictionary<uint, List<int>> Hooks = new Dictionary<uint, List<int>>();

		public readonly Dictionary<uint, List<int>> Shims = new Dictionary<uint, List<int>>();

		public readonly Dictionary<uint, int> Fonts = new Dictionary<uint, int>();

		public readonly Dictionary<uint, int> FontAdded = new Dictionary<uint, int>();

		public readonly Dictionary<uint, int> Counts = new Dictionary<uint, int>();

		public readonly Dictionary<uint, string> Names = new Dictionary<uint, string>();

		public readonly List<Probe> Probes = new List<Probe>();

		public HashSet<string> Free;
	}

	private sealed class Occurrence
	{
		public uint Token;

		public int Index;

		public string Scope;

		public string TypeKey;

		public string Value;

		public string Translated;

		public string Why;

		public bool Scoped;

		public bool Skipped;

		public Use Use;
	}

	private sealed class Expect
	{
		public int Count;

		public int Shift;

		public int Font;

		public List<int> Shims;

		public List<Edit> Edits;

		public bool Seen;

		public int Moved(int index)
		{
			int num = index + Shift;
			if (Shims != null)
			{
				for (int i = 0; i < Shims.Count; i++)
				{
					if (Shims[i] < index)
					{
						num++;
					}
				}
			}
			return num;
		}
	}

	private const string GuardType = "<RepoRPG_RU>";

	public static byte[] Build(byte[] original, BuildOptions o, Report report)
	{
		Plan plan = MakePlan(original, o, report);
		byte[] result = Apply(original, o, plan, report);
		Verify(result, plan, report);
		return result;
	}

	private static AssemblyDefinition Read(byte[] bytes)
	{
		return Read(bytes, null, null);
	}

	private static AssemblyDefinition Read(byte[] bytes, IAssemblyResolver assemblies, IMetadataResolver metadata)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		ReaderParameters val = new ReaderParameters();
		val.ReadingMode = (ReadingMode)2;
		val.InMemory = true;
		val.ReadSymbols = false;
		if (assemblies != null)
		{
			val.AssemblyResolver = assemblies;
		}
		if (metadata != null)
		{
			val.MetadataResolver = metadata;
		}
		return AssemblyDefinition.ReadAssembly((Stream)new MemoryStream(bytes, writable: false), val);
	}

	private static IEnumerable<TypeDefinition> AllTypes(ModuleDefinition module)
	{
		Stack<TypeDefinition> todo = new Stack<TypeDefinition>();
		for (int num = module.Types.Count - 1; num >= 0; num--)
		{
			todo.Push(module.Types[num]);
		}
		while (todo.Count > 0)
		{
			TypeDefinition t = todo.Pop();
			yield return t;
			if (t.HasNestedTypes)
			{
				for (int num2 = t.NestedTypes.Count - 1; num2 >= 0; num2--)
				{
					todo.Push(t.NestedTypes[num2]);
				}
			}
		}
	}

	private static Plan MakePlan(byte[] original, BuildOptions o, Report report)
	{
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_032b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0330: Unknown result type (might be due to invalid IL or missing references)
		//IL_0504: Unknown result type (might be due to invalid IL or missing references)
		//IL_0509: Unknown result type (might be due to invalid IL or missing references)
		//IL_053e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0543: Unknown result type (might be due to invalid IL or missing references)
		//IL_068e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0693: Unknown result type (might be due to invalid IL or missing references)
		//IL_0697: Unknown result type (might be due to invalid IL or missing references)
		//IL_069e: Invalid comparison between Unknown and I4
		//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Invalid comparison between Unknown and I4
		//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e0: Invalid comparison between Unknown and I4
		//IL_0606: Unknown result type (might be due to invalid IL or missing references)
		//IL_060b: Unknown result type (might be due to invalid IL or missing references)
		//IL_060f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0615: Invalid comparison between Unknown and I4
		Plan plan = new Plan();
		plan.Free = ((o.Rules != null) ? o.Rules.ProbeFree : null);
		AssemblyDefinition val = Read(original);
		try
		{
			ModuleDefinition mainModule = val.MainModule;
			Rules rules = o.Rules;
			Lang lang = o.Lang;
			Dictionary<MethodDefinition, HashSet<int>> dictionary = new Dictionary<MethodDefinition, HashSet<int>>();
			foreach (HookRule hook in rules.Hooks)
			{
				int num = 0;
				foreach (TypeDefinition item in AllTypes(mainModule))
				{
					if (!Analysis.TypeMatches(hook.Type, ((MemberReference)item).FullName.Replace('/', '.')))
					{
						continue;
					}
					Enumerator<MethodDefinition> enumerator3 = item.Methods.GetEnumerator();
					try
					{
						while (enumerator3.MoveNext())
						{
							MethodDefinition current3 = enumerator3.Current;
							if (((MemberReference)current3).Name != hook.Method || !current3.HasBody)
							{
								continue;
							}
							Enumerator<ParameterDefinition> enumerator4 = ((MethodReference)current3).Parameters.GetEnumerator();
							try
							{
								while (enumerator4.MoveNext())
								{
									ParameterDefinition current4 = enumerator4.Current;
									if (Array.IndexOf(hook.Params, ((ParameterReference)current4).Name) >= 0 && !(((MemberReference)((ParameterReference)current4).ParameterType).FullName != "System.String"))
									{
										if (!dictionary.TryGetValue(current3, out var value))
										{
											value = (dictionary[current3] = new HashSet<int>());
										}
										if (value.Add(((ParameterReference)current4).Index))
										{
											num++;
										}
									}
								}
							}
							finally
							{
								((IDisposable)enumerator4/*cast due to .constrained prefix*/).Dispose();
							}
						}
					}
					finally
					{
						((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
					}
				}
				if (num == 0)
				{
					report.HookRulesMissed++;
					report.Notes.Add("hook not found: " + hook.Type + "::" + hook.Method + "(" + string.Join(", ", hook.Params) + ")  [" + hook.Source + "]");
				}
			}
			bool flag = o.Settings.DisplayHooks && o.HaveRuntime;
			MetadataToken metadataToken;
			if (flag)
			{
				foreach (KeyValuePair<MethodDefinition, HashSet<int>> item2 in dictionary)
				{
					List<int> list = new List<int>(item2.Value);
					list.Sort();
					Dictionary<uint, List<int>> hooks = plan.Hooks;
					metadataToken = ((MemberReference)item2.Key).MetadataToken;
					hooks[((MetadataToken)(ref metadataToken)).ToUInt32()] = list;
				}
			}
			foreach (HookRule font in rules.Fonts)
			{
				int num2 = 0;
				foreach (TypeDefinition item3 in AllTypes(mainModule))
				{
					if (!Analysis.TypeMatches(font.Type, ((MemberReference)item3).FullName.Replace('/', '.')))
					{
						continue;
					}
					Enumerator<MethodDefinition> enumerator3 = item3.Methods.GetEnumerator();
					try
					{
						while (enumerator3.MoveNext())
						{
							MethodDefinition current8 = enumerator3.Current;
							if (!(((MemberReference)current8).Name != font.Method) && current8.HasBody && !((MethodReference)current8).HasParameters && current8.Body.Instructions.Count != 0 && !(((MemberReference)((MethodReference)current8).ReturnType).FullName != "UnityEngine.Font"))
							{
								num2++;
								if (flag)
								{
									int num3 = FontSetting(current8.Body);
									Dictionary<uint, int> fonts = plan.Fonts;
									metadataToken = ((MemberReference)current8).MetadataToken;
									fonts[((MetadataToken)(ref metadataToken)).ToUInt32()] = num3;
									Dictionary<uint, int> fontAdded = plan.FontAdded;
									metadataToken = ((MemberReference)current8).MetadataToken;
									fontAdded[((MetadataToken)(ref metadataToken)).ToUInt32()] = FontAdded(current8.Body, 0, num3);
								}
							}
						}
					}
					finally
					{
						((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
					}
				}
				if (num2 == 0)
				{
					report.FontRulesMissed++;
					report.Notes.Add("font method not found: " + font.Type + "::" + font.Method + "  [" + font.Source + "]");
				}
			}
			bool translateStrings = o.Settings.TranslateStrings;
			List<Occurrence> list2 = new List<Occurrence>();
			HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal);
			HashSet<string> hashSet3 = new HashSet<string>(StringComparer.Ordinal);
			foreach (TypeDefinition item4 in AllTypes(mainModule))
			{
				string text = Analysis.TypeKey(item4);
				Enumerator<MethodDefinition> enumerator3 = item4.Methods.GetEnumerator();
				try
				{
					while (enumerator3.MoveNext())
					{
						MethodDefinition current10 = enumerator3.Current;
						if (!current10.HasBody)
						{
							continue;
						}
						report.Methods++;
						MethodBody body = current10.Body;
						metadataToken = ((MemberReference)current10).MetadataToken;
						uint num4 = ((MetadataToken)(ref metadataToken)).ToUInt32();
						plan.Counts[num4] = body.Instructions.Count;
						plan.Names[num4] = ((MemberReference)current10).FullName;
						string text2 = null;
						Dictionary<string, string> value2 = null;
						Dictionary<string, string> value3 = null;
						bool skipped = false;
						OpCode opCode;
						if (flag && rules.Calls.Count > 0)
						{
							List<int> list3 = null;
							for (int i = 0; i < body.Instructions.Count; i++)
							{
								Instruction val2 = body.Instructions[i];
								opCode = val2.OpCode;
								if ((int)((OpCode)(ref opCode)).Code != 39)
								{
									opCode = val2.OpCode;
									if ((int)((OpCode)(ref opCode)).Code != 110)
									{
										continue;
									}
								}
								object operand = val2.Operand;
								if (!IsCallHook(rules, (MethodReference)((operand is MethodReference) ? operand : null)))
								{
									continue;
								}
								if (val2.Previous != null)
								{
									opCode = val2.Previous.OpCode;
									if ((int)((OpCode)(ref opCode)).OpCodeType == 4)
									{
										continue;
									}
								}
								if (list3 == null)
								{
									if (IsSkipped(rules, text, text + "::" + Analysis.MemberName(current10)))
									{
										break;
									}
									list3 = new List<int>();
								}
								list3.Add(i);
							}
							if (list3 != null)
							{
								plan.Shims[num4] = list3;
							}
						}
						for (int j = 0; j < body.Instructions.Count; j++)
						{
							Instruction val3 = body.Instructions[j];
							opCode = val3.OpCode;
							if ((int)((OpCode)(ref opCode)).Code != 113 || !(val3.Operand is string text3))
							{
								continue;
							}
							report.Literals++;
							if (text3.Length == 0)
							{
								continue;
							}
							if (text2 == null)
							{
								text2 = text + "::" + Analysis.MemberName(current10);
								lang.Scoped.TryGetValue(text2, out value2);
								lang.Scoped.TryGetValue(text + "::*", out value3);
								skipped = IsSkipped(rules, text, text2);
							}
							string value4 = null;
							bool flag2 = (value2 != null && value2.TryGetValue(text3, out value4)) || (value3?.TryGetValue(text3, out value4) ?? false);
							bool flag3 = !flag2 && lang.Global.TryGetValue(text3, out value4);
							Consumer c = Analysis.Final(current10, val3.Next, rules);
							if (Analysis.IsProbe(c, out var kind, out var ignoreCase))
							{
								Probe probe = new Probe();
								probe.Text = text3;
								probe.Kind = kind;
								probe.IgnoreCase = ignoreCase;
								probe.Where = text2;
								if (hashSet3.Add(probe.Key) && Analysis.ProbeMatters(probe, rules))
								{
									plan.Probes.Add(probe);
								}
							}
							if (o.Dump || flag2 || flag3 || lang.Terms.ContainsKey(text3))
							{
								string why;
								Use use = Analysis.Classify(current10, c, rules, dictionary, 0, out why);
								if (use == Use.Id)
								{
									hashSet2.Add(text3);
								}
								if (o.Dump)
								{
									report.Dump.Add(text2 + "\t" + use.ToString() + "\t" + Analysis.Describe(c) + "\t" + Escape(text3));
								}
								if (flag2 || flag3)
								{
									Occurrence occurrence = new Occurrence();
									occurrence.Token = num4;
									occurrence.Index = j;
									occurrence.Scope = text2;
									occurrence.TypeKey = text;
									occurrence.Value = text3;
									occurrence.Translated = value4;
									occurrence.Scoped = flag2;
									occurrence.Skipped = skipped;
									occurrence.Use = use;
									occurrence.Why = why ?? Analysis.Describe(c);
									list2.Add(occurrence);
								}
							}
						}
					}
				}
				finally
				{
					((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
				}
			}
			report.Probes = plan.Probes.Count;
			if (!translateStrings)
			{
				return plan;
			}
			List<Occurrence> list4 = new List<Occurrence>();
			Dictionary<string, HashSet<string>> dictionary2 = new Dictionary<string, HashSet<string>>(StringComparer.Ordinal);
			foreach (KeyValuePair<string, HashSet<string>> item5 in lang.Unsafe)
			{
				dictionary2[item5.Key] = new HashSet<string>(item5.Value, StringComparer.Ordinal);
			}
			foreach (Occurrence item6 in list2)
			{
				string text4 = Refusal(item6, plan, hashSet2, report);
				if (text4 == null)
				{
					list4.Add(item6);
					continue;
				}
				report.Notes.Add(text4 + ": " + item6.Scope + "  \"" + Escape(item6.Value) + "\"");
				if (item6.Scoped)
				{
					if (!dictionary2.TryGetValue(item6.Scope, out var value5))
					{
						value5 = new HashSet<string>(StringComparer.Ordinal);
						dictionary2[item6.Scope] = value5;
					}
					value5.Add(item6.Value);
				}
			}
			foreach (KeyValuePair<string, HashSet<string>> item7 in dictionary2)
			{
				if (!lang.Sentences.TryGetValue(item7.Key, out var value6))
				{
					continue;
				}
				HashSet<string> value7 = item7.Value;
				bool flag4 = true;
				while (flag4)
				{
					flag4 = false;
					foreach (List<string> value9 in value6.Values)
					{
						bool flag5 = false;
						foreach (string item8 in value9)
						{
							if (value7.Contains(item8))
							{
								flag5 = true;
								break;
							}
						}
						if (!flag5)
						{
							continue;
						}
						foreach (string item9 in value9)
						{
							if (value7.Add(item9))
							{
								flag4 = true;
							}
						}
					}
				}
			}
			foreach (Occurrence item10 in list4)
			{
				if (item10.Scoped && dictionary2.TryGetValue(item10.Scope, out var value8) && value8.Contains(item10.Value))
				{
					report.SkippedSentence++;
					report.Notes.Add("left to display time (another piece of the same sentence stays as it is): " + item10.Scope + "  \"" + Escape(item10.Value) + "\"");
				}
				else
				{
					AddEdit(plan, item10.Token, item10.Index, item10.Translated);
					report.Replaced++;
					if (item10.Scoped)
					{
						report.ReplacedScoped++;
						report.UsedScoped.Add(item10.Scope + "\n" + item10.Value);
						report.UsedScoped.Add(item10.TypeKey + "::*\n" + item10.Value);
					}
					else
					{
						report.UsedGlobal.Add(item10.Value);
					}
				}
			}
			return plan;
		}
		finally
		{
			((IDisposable)val)?.Dispose();
		}
	}

	private static string Refusal(Occurrence occ, Plan plan, HashSet<string> usedAsId, Report report)
	{
		if (occ.Skipped)
		{
			report.SkippedType++;
			return "skipped (excluded type)";
		}
		if (occ.Use == Use.Id || occ.Use == Use.Keep)
		{
			report.SkippedVeto++;
			return (occ.Scoped ? "scoped entry ignored, " : "kept, ") + ((occ.Use == Use.Id) ? "used as id" : "log/network") + " (" + occ.Why + ")";
		}
		if (!occ.Scoped && occ.Use != Use.Display)
		{
			bool flag = Analysis.IsTokenLike(occ.Value);
			if (flag || usedAsId.Contains(occ.Value))
			{
				report.SkippedToken++;
				return "left to display time (" + (flag ? "single word" : "also used as id") + ", " + occ.Why + ")";
			}
		}
		Probe probe = BrokenProbe(plan.Probes, plan.Free, occ.Value, occ.Translated);
		if (probe != null)
		{
			report.SkippedProbe++;
			return "left to display time (the mod tests texts with " + probe?.ToString() + " in " + probe.Where + ")";
		}
		return null;
	}

	private static Probe BrokenProbe(List<Probe> probes, HashSet<string> free, string original, string translated)
	{
		if (free != null && free.Contains(original))
		{
			return null;
		}
		for (int i = 0; i < probes.Count; i++)
		{
			Probe probe = probes[i];
			if (probe.Hits(original) != probe.Hits(translated))
			{
				return probe;
			}
		}
		return null;
	}

	private static bool IsCallHook(Rules rules, MethodReference target)
	{
		if (target == null || !target.HasParameters)
		{
			return false;
		}
		int num = target.Parameters.Count - 1;
		if (((MemberReference)((ParameterReference)target.Parameters[num]).ParameterType).FullName != "System.String")
		{
			return false;
		}
		string dt = Analysis.TypeName(((MemberReference)target).DeclaringType);
		for (int i = 0; i < rules.Calls.Count; i++)
		{
			if (Analysis.Match(rules.Calls[i], target, dt, ((MemberReference)target).Name, num))
			{
				return true;
			}
		}
		return false;
	}

	private static bool IsSkipped(Rules rules, string typeKey, string scope)
	{
		for (int i = 0; i < rules.Skip.Count; i++)
		{
			string text = rules.Skip[i];
			if (text.IndexOf("::", StringComparison.Ordinal) >= 0)
			{
				if (Rules.Glob(text, scope))
				{
					return true;
				}
			}
			else if (Rules.Glob(text, typeKey) || typeKey.StartsWith(text + ".", StringComparison.Ordinal))
			{
				return true;
			}
		}
		return false;
	}

	private static void AddEdit(Plan plan, uint token, int index, string value)
	{
		if (!plan.Edits.TryGetValue(token, out var value2))
		{
			value2 = new List<Edit>();
			plan.Edits[token] = value2;
		}
		Edit edit = new Edit();
		edit.Index = index;
		edit.Value = value;
		value2.Add(edit);
	}

	private static byte[] Apply(byte[] original, BuildOptions o, Plan plan, Report report)
	{
		DirectoryResolver directoryResolver = new DirectoryResolver(o.SearchDirs);
		EnumResolver enumResolver = (EnumResolver)(object)(directoryResolver.Metadata = (IMetadataResolver)(object)new EnumResolver((IAssemblyResolver)(object)directoryResolver));
		try
		{
			return Apply(original, o, plan, report, directoryResolver, enumResolver);
		}
		finally
		{
			report.EnumsKnown = enumResolver.Count;
			report.EnumsAnswered = enumResolver.Answered;
			report.AssemblyRequests = directoryResolver.Requests;
			directoryResolver.Dispose();
		}
	}

	private static byte[] Apply(byte[] original, BuildOptions o, Plan plan, Report report, DirectoryResolver directories, EnumResolver enums)
	{
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0828: Unknown result type (might be due to invalid IL or missing references)
		//IL_082d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0818: Unknown result type (might be due to invalid IL or missing references)
		//IL_0822: Expected O, but got Unknown
		//IL_0534: Unknown result type (might be due to invalid IL or missing references)
		//IL_0539: Unknown result type (might be due to invalid IL or missing references)
		//IL_053d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Invalid comparison between Unknown and I4
		//IL_05b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0601: Unknown result type (might be due to invalid IL or missing references)
		//IL_061b: Unknown result type (might be due to invalid IL or missing references)
		//IL_062e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0643: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Invalid comparison between Unknown and I4
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0245: Invalid comparison between Unknown and I4
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_03db: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0408: Unknown result type (might be due to invalid IL or missing references)
		AssemblyDefinition val = Read(original, (IAssemblyResolver)(object)directories, (IMetadataResolver)(object)enums);
		try
		{
			ModuleDefinition mainModule = val.MainModule;
			OpCode opCode;
			foreach (KeyValuePair<uint, List<Edit>> edit in plan.Edits)
			{
				IMetadataTokenProvider obj = mainModule.LookupToken((int)edit.Key);
				MethodDefinition val2 = (MethodDefinition)(object)((obj is MethodDefinition) ? obj : null);
				if (val2 == null || !val2.HasBody)
				{
					throw new InvalidOperationException("method token " + edit.Key.ToString("x8") + " vanished");
				}
				MethodBody body = val2.Body;
				foreach (Edit item in edit.Value)
				{
					Instruction obj2 = body.Instructions[item.Index];
					opCode = obj2.OpCode;
					if ((int)((OpCode)(ref opCode)).Code != 113)
					{
						throw new InvalidOperationException("instruction mismatch in " + ((MemberReference)val2).FullName);
					}
					obj2.Operand = item.Value;
				}
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			Enumerator<AssemblyNameReference> enumerator3 = mainModule.AssemblyReferences.GetEnumerator();
			try
			{
				while (enumerator3.MoveNext())
				{
					AssemblyNameReference current3 = enumerator3.Current;
					hashSet.Add(current3.Name);
				}
			}
			finally
			{
				((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
			}
			MethodDefinition val3 = null;
			foreach (KeyValuePair<uint, List<int>> shim in plan.Shims)
			{
				IMetadataTokenProvider obj3 = mainModule.LookupToken((int)shim.Key);
				MethodDefinition val4 = (MethodDefinition)(object)((obj3 is MethodDefinition) ? obj3 : null);
				if (val4 == null || !val4.HasBody)
				{
					throw new InvalidOperationException("call hook target " + shim.Key.ToString("x8") + " vanished");
				}
				MethodBody body2 = val4.Body;
				ILProcessor iLProcessor = body2.GetILProcessor();
				int num = shim.Value.Count - 1;
				while (num >= 0)
				{
					Instruction val5 = body2.Instructions[shim.Value[num]];
					object operand = val5.Operand;
					MethodReference val6 = (MethodReference)((operand is MethodReference) ? operand : null);
					if (val6 != null)
					{
						opCode = val5.OpCode;
						if ((int)((OpCode)(ref opCode)).Code != 39)
						{
							opCode = val5.OpCode;
							if ((int)((OpCode)(ref opCode)).Code != 110)
							{
								goto IL_0247;
							}
						}
						if (val3 == null)
						{
							val3 = AddGuard(mainModule, o, ((ParameterReference)val6.Parameters[val6.Parameters.Count - 1]).ParameterType);
						}
						Instruction val7 = iLProcessor.Create(val5.OpCode, val6);
						val5.OpCode = OpCodes.Call;
						val5.Operand = val3;
						iLProcessor.InsertAfter(val5, val7);
						report.CallHooks++;
						num--;
						continue;
					}
					goto IL_0247;
					IL_0247:
					throw new InvalidOperationException("instruction mismatch in " + ((MemberReference)val4).FullName);
				}
			}
			if (plan.Hooks.Count > 0)
			{
				foreach (KeyValuePair<uint, List<int>> hook in plan.Hooks)
				{
					IMetadataTokenProvider obj4 = mainModule.LookupToken((int)hook.Key);
					MethodDefinition val8 = (MethodDefinition)(object)((obj4 is MethodDefinition) ? obj4 : null);
					if (val8 == null || !val8.HasBody)
					{
						throw new InvalidOperationException("hook target " + hook.Key.ToString("x8") + " vanished");
					}
					MethodBody body3 = val8.Body;
					if (body3.Instructions.Count == 0)
					{
						continue;
					}
					ILProcessor iLProcessor2 = body3.GetILProcessor();
					Instruction val9 = body3.Instructions[0];
					foreach (int item2 in hook.Value)
					{
						ParameterDefinition val10 = ((MethodReference)val8).Parameters[item2];
						if (val3 == null)
						{
							val3 = AddGuard(mainModule, o, ((ParameterReference)val10).ParameterType);
						}
						iLProcessor2.InsertBefore(val9, iLProcessor2.Create(OpCodes.Ldarg, val10));
						iLProcessor2.InsertBefore(val9, iLProcessor2.Create(OpCodes.Call, (MethodReference)(object)val3));
						iLProcessor2.InsertBefore(val9, iLProcessor2.Create(OpCodes.Starg, val10));
						report.HooksApplied++;
					}
				}
			}
			foreach (KeyValuePair<uint, int> item3 in new List<KeyValuePair<uint, int>>(plan.Fonts))
			{
				IMetadataTokenProvider obj5 = mainModule.LookupToken((int)item3.Key);
				MethodDefinition val11 = (MethodDefinition)(object)((obj5 is MethodDefinition) ? obj5 : null);
				if (val11 == null || !val11.HasBody)
				{
					throw new InvalidOperationException("font method " + item3.Key.ToString("x8") + " vanished");
				}
				MethodBody body4 = val11.Body;
				ILProcessor iLProcessor3 = body4.GetILProcessor();
				List<Instruction> list = new List<Instruction>();
				Instruction val12;
				try
				{
					int num2 = 0;
					if (plan.Hooks.TryGetValue(item3.Key, out var value))
					{
						num2 = value.Count * 3;
					}
					val12 = body4.Instructions[num2];
					TypeReference val13 = null;
					for (int i = 0; i < item3.Value; i++)
					{
						Instruction val14 = body4.Instructions[num2 + i];
						opCode = val14.OpCode;
						if ((int)((OpCode)(ref opCode)).Code != 0)
						{
							list.Add(Copy(iLProcessor3, val14));
							object operand2 = val14.Operand;
							MethodReference val15 = (MethodReference)((operand2 is MethodReference) ? operand2 : null);
							if (val15 != null && ((MemberReference)((MemberReference)val15).DeclaringType).FullName == "System.String")
							{
								val13 = ((MemberReference)val15).DeclaringType;
							}
						}
					}
					if (val13 == null)
					{
						val13 = mainModule.TypeSystem.String;
					}
					if (list.Count == 0)
					{
						list.Add(iLProcessor3.Create(OpCodes.Ldnull));
					}
					if (val3 == null)
					{
						val3 = AddGuard(mainModule, o, val13);
					}
					Instruction val16 = iLProcessor3.Create(OpCodes.Pop);
					list.Add(iLProcessor3.Create(OpCodes.Call, (MethodReference)(object)AddFontGuard(mainModule, o, val3, val13)));
					list.Add(iLProcessor3.Create(OpCodes.Isinst, ((MethodReference)val11).ReturnType));
					list.Add(iLProcessor3.Create(OpCodes.Dup));
					list.Add(iLProcessor3.Create(OpCodes.Brfalse, val16));
					list.Add(iLProcessor3.Create(OpCodes.Ret));
					list.Add(val16);
					if (list.Count != FontAdded(body4, num2, item3.Value))
					{
						throw new InvalidOperationException("plan and result differ");
					}
				}
				catch (Exception ex)
				{
					plan.Fonts.Remove(item3.Key);
					plan.FontAdded.Remove(item3.Key);
					report.FontRulesMissed++;
					report.Notes.Add("font method " + ((MemberReference)val11.DeclaringType).Name + "::" + ((MemberReference)val11).Name + " left as it is: " + ex.Message);
					continue;
				}
				foreach (Instruction item4 in list)
				{
					iLProcessor3.InsertBefore(val12, item4);
				}
				report.FontHooks++;
				if (item3.Value == 0)
				{
					report.Notes.Add("font method " + ((MemberReference)val11.DeclaringType).Name + "::" + ((MemberReference)val11).Name + ": does not begin by reading its setting the way 1.0.100 does - the add-on reads the setting from the mod's config file instead");
				}
			}
			if (o.RequirePlugin)
			{
				BumpVersion(mainModule, report);
			}
			if (o.Settings.TranslateData || o.Dump)
			{
				TranslateData(mainModule, o, report, plan.Probes);
			}
			if (o.Stamp != null)
			{
				mainModule.Resources.Add((Resource)new EmbeddedResource("RepoRPG_RU.stamp", (ManifestResourceAttributes)2, Encoding.UTF8.GetBytes(o.Stamp)));
			}
			enumerator3 = mainModule.AssemblyReferences.GetEnumerator();
			try
			{
				while (enumerator3.MoveNext())
				{
					AssemblyNameReference current9 = enumerator3.Current;
					if (!hashSet.Contains(current9.Name) && current9.Name != o.RuntimeAssemblyName)
					{
						throw new InvalidOperationException("unexpected new assembly reference: " + current9.Name);
					}
				}
			}
			finally
			{
				((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
			}
			enums.Learn(mainModule, AllTypes(mainModule));
			MemoryStream memoryStream = new MemoryStream(original.Length + 65536);
			val.Write((Stream)memoryStream);
			return memoryStream.ToArray();
		}
		finally
		{
			((IDisposable)val)?.Dispose();
		}
	}

	private static int FontSetting(MethodBody body)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: 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_0022: 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_0026: Invalid comparison between Unknown and I4
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Invalid comparison between Unknown and I4
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Invalid comparison between Unknown and I4
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Invalid comparison between Unknown and I4
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Invalid comparison between Unknown and I4
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Invalid comparison between Unknown and I4
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//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_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Invalid comparison between Unknown and I4
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Invalid comparison between Unknown and I4
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Invalid comparison between Unknown and I4
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Invalid comparison between Unknown and I4
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Invalid comparison between Unknown and I4
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Invalid comparison between Unknown and I4
		for (int i = 0; i < body.Instructions.Count && i < 10; i++)
		{
			Instruction val = body.Instructions[i];
			OpCode opCode = val.OpCode;
			Code code = ((OpCode)(ref opCode)).Code;
			if ((int)code <= 39)
			{
				if ((int)code == 0 || (int)code == 2)
				{
					continue;
				}
				if ((int)code == 39)
				{
					goto IL_0059;
				}
			}
			else
			{
				if ((int)code == 110)
				{
					goto IL_0059;
				}
				if ((int)code == 120 || (int)code == 123)
				{
					continue;
				}
			}
			return 0;
			IL_0059:
			object operand = val.Operand;
			MethodReference val2 = (MethodReference)((operand is MethodReference) ? operand : null);
			if (val2 == null)
			{
				return 0;
			}
			if (((MemberReference)val2).Name == "Trim" && !val2.HasParameters && ((MemberReference)((MemberReference)val2).DeclaringType).FullName == "System.String")
			{
				Instruction next = val.Next;
				if (next == null)
				{
					return 0;
				}
				opCode = next.OpCode;
				Code code2 = ((OpCode)(ref opCode)).Code;
				if ((int)code2 != 10 && (int)code2 != 11 && (int)code2 != 12 && (int)code2 != 13 && (int)code2 != 19 && (int)code2 != 204)
				{
					return 0;
				}
				return i + 1;
			}
			if (val2.HasParameters || ((MemberReference)val2.ReturnType).FullName == "System.Void")
			{
				return 0;
			}
		}
		return 0;
	}

	private static int FontAdded(MethodBody body, int at, int setting)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		for (int i = 0; i < setting; i++)
		{
			OpCode opCode = body.Instructions[at + i].OpCode;
			if ((int)((OpCode)(ref opCode)).Code != 0)
			{
				num++;
			}
		}
		return ((num == 0) ? 1 : num) + 6;
	}

	private static Instruction Copy(ILProcessor il, Instruction ins)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		if (ins.Operand == null)
		{
			return il.Create(ins.OpCode);
		}
		object operand = ins.Operand;
		FieldReference val = (FieldReference)((operand is FieldReference) ? operand : null);
		if (val != null)
		{
			return il.Create(ins.OpCode, val);
		}
		object operand2 = ins.Operand;
		MethodReference val2 = (MethodReference)((operand2 is MethodReference) ? operand2 : null);
		if (val2 != null)
		{
			return il.Create(ins.OpCode, val2);
		}
		OpCode opCode = ins.OpCode;
		throw new InvalidOperationException("font method: cannot repeat " + ((OpCode)(ref opCode)).Name);
	}

	private static MethodDefinition AddFontGuard(ModuleDefinition module, BuildOptions o, MethodDefinition guard, TypeReference stringType)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Expected O, but got Unknown
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Expected O, but got Unknown
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Expected O, but got Unknown
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Expected O, but got Unknown
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Expected O, but got Unknown
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Expected O, but got Unknown
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Expected O, but got Unknown
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Expected O, but got Unknown
		//IL_0233: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0268: Unknown result type (might be due to invalid IL or missing references)
		//IL_027b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0314: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0343: Expected O, but got Unknown
		TypeDefinition declaringType = guard.DeclaringType;
		Enumerator<MethodDefinition> enumerator = declaringType.Methods.GetEnumerator();
		try
		{
			while (enumerator.MoveNext())
			{
				MethodDefinition current = enumerator.Current;
				if (((MemberReference)current).Name == "F")
				{
					return current;
				}
			}
		}
		finally
		{
			((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
		}
		TypeReference val = module.TypeSystem.Object;
		TypeReference val2 = null;
		enumerator = declaringType.Methods.GetEnumerator();
		try
		{
			while (enumerator.MoveNext())
			{
				MethodDefinition current2 = enumerator.Current;
				if (((MemberReference)current2).Name != "Call")
				{
					continue;
				}
				Enumerator<Instruction> enumerator2 = current2.Body.Instructions.GetEnumerator();
				try
				{
					while (enumerator2.MoveNext())
					{
						object operand = enumerator2.Current.Operand;
						MethodReference val3 = (MethodReference)((operand is MethodReference) ? operand : null);
						if (val3 != null)
						{
							val2 = ((MemberReference)val3).DeclaringType;
						}
					}
				}
				finally
				{
					((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
				}
			}
		}
		finally
		{
			((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
		}
		if (val2 == null)
		{
			throw new InvalidOperationException("the guard class has no reference to the runtime");
		}
		MethodReference val4 = new MethodReference("MenuFont", val, val2);
		val4.HasThis = false;
		val4.Parameters.Add(new ParameterDefinition(stringType));
		FieldDefinition val5 = new FieldDefinition("offF", (FieldAttributes)17, module.TypeSystem.Boolean);
		declaringType.Fields.Add(val5);
		MethodDefinition val6 = new MethodDefinition("CallF", (MethodAttributes)145, val);
		val6.ImplAttributes = (MethodImplAttributes)8;
		((MethodReference)val6).Parameters.Add(new ParameterDefinition("s", (ParameterAttributes)0, stringType));
		declaringType.Methods.Add(val6);
		ILProcessor iLProcessor = val6.Body.GetILProcessor();
		iLProcessor.Append(iLProcessor.Create(OpCodes.Ldarg_0));
		iLProcessor.Append(iLProcessor.Create(OpCodes.Call, val4));
		iLProcessor.Append(iLProcessor.Create(OpCodes.Ret));
		MethodDefinition val7 = new MethodDefinition("F", (MethodAttributes)147, val);
		val7.ImplAttributes = (MethodImplAttributes)0;
		((MethodReference)val7).Parameters.Add(new ParameterDefinition("s", (ParameterAttributes)0, stringType));
		declaringType.Methods.Add(val7);
		MethodBody body = val7.Body;
		body.InitLocals = true;
		VariableDefinition val8 = new VariableDefinition(val);
		body.Variables.Add(val8);
		ILProcessor iLProcessor2 = body.GetILProcessor();
		Instruction val9 = iLProcessor2.Create(OpCodes.Ldnull);
		Instruction val10 = iLProcessor2.Create(OpCodes.Ldarg_0);
		Instruction val11 = iLProcessor2.Create(OpCodes.Pop);
		Instruction val12 = iLProcessor2.Create(OpCodes.Ldloc_0);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ldsfld, (FieldReference)(object)val5));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Brtrue, val9));
		iLProcessor2.Append(val10);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Call, (MethodReference)(object)val6));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Stloc_0));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Leave, val12));
		iLProcessor2.Append(val11);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ldc_I4_1));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Stsfld, (FieldReference)(object)val5));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Leave, val9));
		iLProcessor2.Append(val12);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ret));
		iLProcessor2.Append(val9);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ret));
		ExceptionHandler val13 = new ExceptionHandler((ExceptionHandlerType)0);
		val13.CatchType = val;
		val13.TryStart = val10;
		val13.TryEnd = val11;
		val13.HandlerStart = val11;
		val13.HandlerEnd = val12;
		body.ExceptionHandlers.Add(val13);
		return val7;
	}

	private static MethodDefinition AddGuard(ModuleDefinition module, BuildOptions o, TypeReference stringType)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Expected O, but got Unknown
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Expected O, but got Unknown
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Expected O, but got Unknown
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Expected O, but got Unknown
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Expected O, but got Unknown
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Expected O, but got Unknown
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Expected O, but got Unknown
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Expected O, but got Unknown
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Expected O, but got Unknown
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Expected O, but got Unknown
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0232: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Unknown result type (might be due to invalid IL or missing references)
		//IL_0271: Unknown result type (might be due to invalid IL or missing references)
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_029d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fa: Expected O, but got Unknown
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Expected O, but got Unknown
		TypeReference val = module.TypeSystem.Object;
		TypeReference boolean = module.TypeSystem.Boolean;
		AssemblyNameReference val2 = null;
		Enumerator<AssemblyNameReference> enumerator = module.AssemblyReferences.GetEnumerator();
		try
		{
			while (enumerator.MoveNext())
			{
				AssemblyNameReference current = enumerator.Current;
				if (current.Name == o.RuntimeAssemblyName)
				{
					val2 = current;
					break;
				}
			}
		}
		finally
		{
			((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
		}
		if (val2 == null)
		{
			val2 = new AssemblyNameReference(o.RuntimeAssemblyName, o.RuntimeVersion);
			module.AssemblyReferences.Add(val2);
		}
		TypeReference val3 = new TypeReference("RepoRPG_RU", "Loc", module, (IMetadataScope)(object)val2);
		MethodReference val4 = new MethodReference("T", stringType, val3);
		val4.HasThis = false;
		val4.Parameters.Add(new ParameterDefinition(stringType));
		TypeDefinition val5 = new TypeDefinition("", "<RepoRPG_RU>", (TypeAttributes)1048960, val);
		module.Types.Add(val5);
		FieldDefinition val6 = new FieldDefinition("off", (FieldAttributes)17, boolean);
		val5.Fields.Add(val6);
		MethodDefinition val7 = new MethodDefinition("Call", (MethodAttributes)145, stringType);
		val7.ImplAttributes = (MethodImplAttributes)8;
		((MethodReference)val7).Parameters.Add(new ParameterDefinition("s", (ParameterAttributes)0, stringType));
		val5.Methods.Add(val7);
		ILProcessor iLProcessor = val7.Body.GetILProcessor();
		iLProcessor.Append(iLProcessor.Create(OpCodes.Ldarg_0));
		iLProcessor.Append(iLProcessor.Create(OpCodes.Call, val4));
		iLProcessor.Append(iLProcessor.Create(OpCodes.Ret));
		MethodDefinition val8 = new MethodDefinition("T", (MethodAttributes)147, stringType);
		val8.ImplAttributes = (MethodImplAttributes)0;
		((MethodReference)val8).Parameters.Add(new ParameterDefinition("s", (ParameterAttributes)0, stringType));
		val5.Methods.Add(val8);
		MethodBody body = val8.Body;
		body.InitLocals = true;
		VariableDefinition val9 = new VariableDefinition(stringType);
		body.Variables.Add(val9);
		ILProcessor iLProcessor2 = body.GetILProcessor();
		Instruction val10 = iLProcessor2.Create(OpCodes.Ldarg_0);
		Instruction val11 = iLProcessor2.Create(OpCodes.Ldarg_0);
		Instruction val12 = iLProcessor2.Create(OpCodes.Pop);
		Instruction val13 = iLProcessor2.Create(OpCodes.Ldloc_0);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ldsfld, (FieldReference)(object)val6));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Brtrue, val10));
		iLProcessor2.Append(val11);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Call, (MethodReference)(object)val7));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Stloc_0));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Leave, val13));
		iLProcessor2.Append(val12);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ldc_I4_1));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Stsfld, (FieldReference)(object)val6));
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Leave, val10));
		iLProcessor2.Append(val13);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ret));
		iLProcessor2.Append(val10);
		iLProcessor2.Append(iLProcessor2.Create(OpCodes.Ret));
		ExceptionHandler val14 = new ExceptionHandler((ExceptionHandlerType)0);
		val14.CatchType = val;
		val14.TryStart = val11;
		val14.TryEnd = val12;
		val14.HandlerStart = val12;
		val14.HandlerEnd = val13;
		body.ExceptionHandlers.Add(val14);
		return val8;
	}

	private static void BumpVersion(ModuleDefinition module, Report report)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		foreach (TypeDefinition item in AllTypes(module))
		{
			if (!item.HasCustomAttributes)
			{
				continue;
			}
			Enumerator<CustomAttribute> enumerator2 = item.CustomAttributes.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					CustomAttribute current2 = enumerator2.Current;
					if (!(((MemberReference)current2.AttributeType).FullName != "BepInEx.BepInPlugin") && current2.ConstructorArguments.Count == 3)
					{
						CustomAttributeArgument val = current2.ConstructorArguments[0];
						if (string.Equals(((CustomAttributeArgument)(ref val)).Value as string, "rpgmod.semibotrpg", StringComparison.Ordinal))
						{
							val = current2.ConstructorArguments[2];
							string text = ((CustomAttributeArgument)(ref val)).Value as string;
							string text2 = Bump(text);
							Collection<CustomAttributeArgument> constructorArguments = current2.ConstructorArguments;
							val = current2.ConstructorArguments[2];
							constructorArguments[2] = new CustomAttributeArgument(((CustomAttributeArgument)(ref val)).Type, (object)text2);
							report.OriginalVersion = text;
							report.NewVersion = text2;
							return;
						}
					}
				}
			}
			finally
			{
				((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
			}
		}
		throw new InvalidOperationException("[BepInPlugin(\"rpgmod.semibotrpg\", ...)] not found - is this really RepoRPG?");
	}

	internal static string Bump(string version)
	{
		Version version2 = new Version(version);
		int num = ((version2.Build >= 0) ? version2.Build : 0);
		int num2 = ((version2.Revision < 0) ? 1 : (version2.Revision + 1));
		return version2.Major + "." + version2.Minor + "." + num + "." + num2;
	}

	public static string ReadPluginVersion(ModuleDefinition module)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		foreach (TypeDefinition item in AllTypes(module))
		{
			if (!item.HasCustomAttributes)
			{
				continue;
			}
			Enumerator<CustomAttribute> enumerator2 = item.CustomAttributes.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					CustomAttribute current2 = enumerator2.Current;
					if (!(((MemberReference)current2.AttributeType).FullName != "BepInEx.BepInPlugin") && current2.ConstructorArguments.Count == 3)
					{
						CustomAttributeArgument val = current2.ConstructorArguments[0];
						if (string.Equals(((CustomAttributeArgument)(ref val)).Value as string, "rpgmod.semibotrpg", StringComparison.Ordinal))
						{
							val = current2.ConstructorArguments[2];
							return ((CustomAttributeArgument)(ref val)).Value as string;
						}
					}
				}
			}
			finally
			{
				((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
			}
		}
		return null;
	}

	private static void TranslateData(ModuleDefinition module, BuildOptions o, Report report, List<Probe> probes)
	{
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Expected O, but got Unknown
		for (int i = 0; i < module.Resources.Count; i++)
		{
			Resource obj = module.Resources[i];
			EmbeddedResource val = (EmbeddedResource)(object)((obj is EmbeddedResource) ? obj : null);
			if (val == null || !((Resource)val).Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
			{
				continue;
			}
			byte[] resourceData = val.GetResourceData();
			if (o.Dump)
			{
				report.Resources[((Resource)val).Name] = resourceData;
			}
			bool translate = o.Settings.TranslateData;
			string text = ((Resource)val).Name.Substring(0, ((Resource)val).Name.Length - 5);
			int num = text.LastIndexOf('.');
			if (num >= 0)
			{
				text = text.Substring(num + 1);
			}
			bool flag = resourceData.Length >= 3 && resourceData[0] == 239 && resourceData[1] == 187 && resourceData[2] == 191;
			string json = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false).GetString(resourceData, flag ? 3 : 0, resourceData.Length - (flag ? 3 : 0));
			o.Lang.Data.TryGetValue(text, out var own);
			o.Lang.Data.TryGetValue("", out var any);
			string stemCopy = text;
			Rules rules = o.Rules;
			bool dump = o.Dump;
			int replaced;
			string s = JsonText.Translate(json, delegate(string path, string property, string value)
			{
				bool flag2 = rules.DataAllowed(stemCopy, property, path);
				if (dump)
				{
					report.DataDump.Add(stemCopy + "\t" + path + "\t" + (flag2 ? "+" : "-") + "\t" + Escape(value));
				}
				if (!flag2 || !translate)
				{
					return (string)null;
				}
				string value2;
				bool flag3 = own != null && own.TryGetValue(value, out value2);
				if (!flag3)
				{
					if (any == null || !any.TryGetValue(value, out value2))
					{
						return (string)null;
					}
				}
				else
				{
					value2 = own[value];
				}
				Probe probe = (rules.ProbeFreeData.Contains(stemCopy) ? null : BrokenProbe(probes, rules.ProbeFree, value, value2));
				if (probe != null)
				{
					report.SkippedProbe++;
					report.Notes.Add("data left as is (the mod tests texts with " + probe?.ToString() + " in " + probe.Where + "): " + stemCopy + " " + path + "  \"" + Escape(value) + "\"");
					return (string)null;
				}
				report.UsedData.Add((flag3 ? stemCopy : "") + "\n" + value);
				return value2;
			}, out replaced);
			if (replaced != 0)
			{
				byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(s);
				byte[] array = bytes;
				if (flag)
				{
					array = new byte[bytes.Length + 3];
					array[0] = 239;
					array[1] = 187;
					array[2] = 191;
					Buffer.BlockCopy(bytes, 0, array, 3, bytes.Length);
				}
				module.Resources[i] = (Resource)new EmbeddedResource(((Resource)val).Name, ((Resource)val).Attributes, array);
				report.DataReplaced += replaced;
				report.DataFiles++;
			}
		}
	}

	private static void Verify(byte[] result, Plan plan, Report report)
	{
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_055a: Unknown result type (might be due to invalid IL or missing references)
		//IL_055f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0284: Invalid comparison between Unknown and I4
		//IL_0341: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: Unknown result type (might be due to invalid IL or missing references)
		//IL_034a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0351: Invalid comparison between Unknown and I4
		//IL_041b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0420: Unknown result type (might be due to invalid IL or missing references)
		//IL_0424: Unknown result type (might be due to invalid IL or missing references)
		//IL_042b: Invalid comparison between Unknown and I4
		//IL_037f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0384: Unknown result type (might be due to invalid IL or missing references)
		//IL_0388: Unknown result type (might be due to invalid IL or missing references)
		//IL_038f: Invalid comparison between Unknown and I4
		//IL_0398: Unknown result type (might be due to invalid IL or missing references)
		//IL_039d: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a8: Invalid comparison between Unknown and I4
		Dictionary<string, Expect> dictionary = new Dictionary<string, Expect>(StringComparer.Ordinal);
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		foreach (KeyValuePair<uint, int> count in plan.Counts)
		{
			string text = plan.Names[count.Key];
			Expect expect = new Expect();
			expect.Count = count.Value;
			expect.Shift = (plan.Hooks.TryGetValue(count.Key, out var value) ? (value.Count * 3) : 0);
			if (plan.FontAdded.TryGetValue(count.Key, out expect.Font))
			{
				expect.Shift += expect.Font;
			}
			plan.Shims.TryGetValue(count.Key, out expect.Shims);
			plan.Edits.TryGetValue(count.Key, out expect.Edits);
			if (dictionary.ContainsKey(text))
			{
				hashSet.Add(text);
			}
			else
			{
				dictionary[text] = expect;
			}
		}
		AssemblyDefinition val = Read(result);
		try
		{
			ModuleDefinition mainModule = val.MainModule;
			int num = 0;
			foreach (TypeDefinition item in AllTypes(mainModule))
			{
				Enumerator<MethodDefinition> enumerator3 = item.Methods.GetEnumerator();
				try
				{
					while (enumerator3.MoveNext())
					{
						MethodDefinition current3 = enumerator3.Current;
						if (!current3.HasBody)
						{
							continue;
						}
						MethodBody body = current3.Body;
						num++;
						string fullName = ((MemberReference)current3).FullName;
						if (((MemberReference)item).Name == "<RepoRPG_RU>" && ((TypeReference)item).Namespace.Length == 0)
						{
							num--;
						}
						else
						{
							if (hashSet.Contains(fullName))
							{
								continue;
							}
							if (!dictionary.TryGetValue(fullName, out var value2))
							{
								throw new InvalidOperationException("verification: unexpected method " + fullName);
							}
							value2.Seen = true;
							if (body.Instructions.Count != value2.Count + value2.Shift + ((value2.Shims != null) ? value2.Shims.Count : 0))
							{
								throw new InvalidOperationException("verification: instruction count changed in " + fullName);
							}
							OpCode opCode;
							if (value2.Font > 0)
							{
								bool flag = false;
								for (int i = 0; i < value2.Shift && i < body.Instructions.Count; i++)
								{
									object operand = body.Instructions[i].Operand;
									MethodReference val2 = (MethodReference)((operand is MethodReference) ? operand : null);
									opCode = body.Instructions[i].OpCode;
									if ((int)((OpCode)(ref opCode)).Code == 39 && val2 != null && ((MemberReference)((MemberReference)val2).DeclaringType).Name == "<RepoRPG_RU>" && ((MemberReference)val2).Name == "F")
									{
										flag = true;
									}
								}
								if (!flag)
								{
									throw new InvalidOperationException("verification: font hook not written in " + fullName);
								}
							}
							if (value2.Shims != null)
							{
								foreach (int shim in value2.Shims)
								{
									Instruction val3 = body.Instructions[value2.Moved(shim)];
									object operand2 = val3.Operand;
									MethodReference val4 = (MethodReference)((operand2 is MethodReference) ? operand2 : null);
									opCode = val3.OpCode;
									if ((int)((OpCode)(ref opCode)).Code == 39 && val4 != null && !(((MemberReference)((MemberReference)val4).DeclaringType).Name != "<RepoRPG_RU>") && val3.Next != null)
									{
										opCode = val3.Next.OpCode;
										if ((int)((OpCode)(ref opCode)).Code == 39)
										{
											continue;
										}
										opCode = val3.Next.OpCode;
										if ((int)((OpCode)(ref opCode)).Code == 110)
										{
											continue;
										}
									}
									throw new InvalidOperationException("verification: call hook not written in " + fullName);
								}
							}
							if (value2.Edits == null)
							{
								continue;
							}
							foreach (Edit edit in value2.Edits)
							{
								Instruction val5 = body.Instructions[value2.Moved(edit.Index)];
								opCode = val5.OpCode;
								if ((int)((OpCode)(ref opCode)).Code != 113 || !string.Equals(val5.Operand as string, edit.Value, StringComparison.Ordinal))
								{
									throw new InvalidOperationException("verification: literal not written in " + fullName);
								}
							}
						}
					}
				}
				finally
				{
					((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
				}
			}
			if (num != plan.Counts.Count)
			{
				throw new InvalidOperationException("verification: method count changed (" + num + " vs " + plan.Counts.Count + ")");
			}
			foreach (KeyValuePair<string, Expect> item2 in dictionary)
			{
				if (!item2.Value.Seen)
				{
					throw new InvalidOperationException("verification: method lost: " + item2.Key);
				}
			}
			Enumerator<Resource> enumerator7 = mainModule.Resources.GetEnumerator();
			try
			{
				while (enumerator7.MoveNext())
				{
					Resource current7 = enumerator7.Current;
					EmbeddedResource val6 = (EmbeddedResource)(object)((current7 is EmbeddedResource) ? current7 : null);
					if (val6 != null)
					{
						val6.GetResourceData();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator7/*cast due to .constrained prefix*/).Dispose();
			}
		}
		finally
		{
			((IDisposable)val)?.Dispose();
		}
	}

	internal static string Escape(string s)
	{
		StringBuilder stringBuilder = new StringBuilder(s.Length + 8);
		foreach (char c in s)
		{
			switch (c)
			{
			case '\\':
				stringBuilder.Append("\\\\");
				break;
			case '\n':
				stringBuilder.Append("\\n");
				break;
			case '\r':
				stringBuilder.Append("\\r");
				break;
			case '\t':
				stringBuilder.Append("\\t");
				break;
			default:
				stringBuilder.Append(c);
				break;
			}
		}
		return stringBuilder.ToString();
	}
}
public static class Patcher
{
	private static readonly string[] None = new string[0];

	public static IEnumerable<string> TargetDLLs => None;

	public static void Patch(AssemblyDefinition assembly)
	{
	}

	private static void AddPath(List<string> list, string property)
	{
		try
		{
			PropertyInfo property2 = typeof(Paths).GetProperty(property, BindingFlags.Static | BindingFlags.Public);
			if (!(property2 == null))
			{
				object value = property2.GetValue(null, null);
				if (value is string item)
				{
					list.Add(item);
				}
				else if (value is string[] collection)
				{
					list.AddRange(collection);
				}
			}
		}
		catch
		{
		}
	}

	public static void Initialize()
	{
		ManualLogSource val = null;
		try
		{
			val = Logger.CreateLogSource("RepoRPG RU");
			Env env = new Env();
			env.PluginPath = Paths.PluginPath;
			env.ConfigPath = Paths.ConfigPath;
			AddPath(env.SearchDirs, "DllSearchPaths");
			AddPath(env.SearchDirs, "ManagedPath");
			AddPath(env.SearchDirs, "BepInExAssemblyDirectory");
			try
			{
				env.SearchDirs.Add(Path.GetDirectoryName(typeof(object).Assembly.Location));
			}
			catch
			{
			}
			env.SearchDirs.Add(Paths.PluginPath);
			env.SearchDirs.Add(Paths.PatcherPluginPath);
			ManualLogSource sink = val;
			env.Info = delegate(string s)
			{
				sink.LogInfo((object)s);
			};
			env.Warn = delegate(string s)
			{
				sink.LogWarning((object)s);
			};
			env.Error = delegate(string s)
			{
				sink.LogError((object)s);
			};
			Worker.Run(env);
		}
		catch (Exception ex)
		{
			try
			{
				if (val != null)
				{
					val.LogError((object)("Русификатор не запустился, мод RepoRPG останется английским: " + ex));
				}
			}
			catch
			{
			}
		}
	}
}
internal sealed class Env
{
	public string PluginPath;

	public string ConfigPath;

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

	public Action<string> Info;

	public Action<string> Warn;

	public Action<string> Error;
}
internal static class Worker
{
	internal sealed class Candidate
	{
		public string Path;

		public byte[] Bytes;

		public Version Version = new Version(0, 0);

		public string VersionText = "?";

		public bool Generated;

		public string Stamp;
	}

	public const string StampResource = "RepoRPG_RU.stamp";

	private const string OutputName = "RepoRPG.dll";

	public static void Run(Env env)
	{
		if (string.IsNullOrEmpty(env.PluginPath) || !Directory.Exists(env.PluginPath))
		{
			return;
		}
		Settings settings = Settings.Load(Path.Combine(env.ConfigPath ?? "", "RepoRPG_RU.cfg"), createIfMissing: true);
		string text = FindFile(env.PluginPath, "RepoRPG_RU.dll");
		string text2 = ((text != null) ? Path.GetDirectoryName(text) : null);
		string text3 = ((text2 != null) ? Path.Combine(text2, "RepoRPG.dll") : null);
		Candidate candidate = null;
		foreach (string item in FindAll(env.PluginPath, "RepoRPG.dll"))
		{
			Candidate candidate2 = Inspect(item);
			if (candidate2 == null)
			{
				continue;
			}
			if (candidate2.Generated)
			{
				if (text3 == null || !SamePath(item, text3))
				{
					TryDelete(item, env, "устаревшая копия");
				}
				continue;
			}
			if (text3 != null && SamePath(item, text3))
			{
				env.Warn("Оригинальный RepoRPG.dll лежит в папке русификатора (" + item + "). Перенесите его в отдельную папку, иначе перевод не применяется.");
				return;
			}
			if (candidate == null || candidate2.Version > candidate.Version)
			{
				candidate = candidate2;
			}
		}
		if (text2 == null)
		{
			env.Warn("Не найден RepoRPG_RU.dll в BepInEx/plugins - русификатор установлен не полностью, перевод не применяется.");
			return;
		}
		if (!settings.Enabled)
		{
			TryDelete(text3, env, "перевод выключен в RepoRPG_RU.cfg");
			env.Info("Перевод выключен (Enabled = false).");
			return;
		}
		if (candidate == null)
		{
			TryDelete(text3, env, "оригинальный мод не найден");
			env.Warn("Мод RepoRPG (RepoRPG.dll) не найден или выключен - переводить нечего.");
			return;
		}
		try
		{
			Translate(env, settings, candidate, text2, text3);
		}
		catch (Exception ex)
		{
			TryDelete(text3, env, "ошибка при создании");
			env.Error("Не удалось создать переведённую копию RepoRPG " + candidate.VersionText + " - мод загрузится на английском. Причина: " + ex);
		}
	}

	private static void Translate(Env env, Sett

plugins/RepoRPG_RU.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("RepoRPG RU - runtime")]
[assembly: AssemblyVersion("0.2.1.0")]
namespace RepoRPG_RU;

internal static class Fonts
{
	private sealed class Expect
	{
		public char Char;

		public int Size;

		public int Advance;
	}

	private sealed class Unity
	{
		private static Unity found;

		public string Problem;

		private Type fontType;

		private Type objectType;

		private ConstructorInfo create;

		private MethodInfo request;

		private MethodInfo info;

		private MethodInfo destroy;

		private MethodInfo exists;

		private MethodInfo system;

		private MethodInfo findAll;

		private PropertyInfo advance;

		private PropertyInfo hideFlags;

		private PropertyInfo objectName;

		private PropertyInfo fontSize;

		private PropertyInfo lineHeight;

		private PropertyInfo ascent;

		private PropertyInfo isDynamic;

		private object normal;

		public bool CanAskSystem => system != null;

		public static Unity Find()
		{
			if (found != null && found.Problem == null)
			{
				return found;
			}
			Unity unity = new Unity();
			try
			{
				unity.Bind();
			}
			catch (Exception ex)
			{
				unity.Problem = "Unity: " + ex.GetType().Name + ": " + ex.Message;
			}
			found = unity;
			return unity;
		}

		private static Type Lookup(string name, string module)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			Assembly[] array = assemblies;
			foreach (Assembly assembly in array)
			{
				if (!(assembly.GetName().Name != module))
				{
					Type type = assembly.GetType(name, throwOnError: false);
					if (type != null)
					{
						return type;
					}
				}
			}
			array = assemblies;
			foreach (Assembly assembly2 in array)
			{
				if (assembly2.GetName().Name.StartsWith("UnityEngine", StringComparison.Ordinal))
				{
					Type type2 = assembly2.GetType(name, throwOnError: false);
					if (type2 != null)
					{
						return type2;
					}
				}
			}
			try
			{
				return Type.GetType(name + ", " + module, throwOnError: false);
			}
			catch
			{
				return null;
			}
		}

		private void Bind()
		{
			fontType = Lookup("UnityEngine.Font", "UnityEngine.TextRenderingModule");
			Type type = Lookup("UnityEngine.FontStyle", "UnityEngine.TextRenderingModule");
			Type type2 = Lookup("UnityEngine.CharacterInfo", "UnityEngine.TextRenderingModule");
			objectType = Lookup("UnityEngine.Object", "UnityEngine.CoreModule");
			if (fontType == null || type == null || type2 == null)
			{
				Problem = "в игре не найден тип UnityEngine.Font";
				return;
			}
			create = fontType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
			request = fontType.GetMethod("RequestCharactersInTexture", BindingFlags.Instance | BindingFlags.Public, null, new Type[3]
			{
				typeof(string),
				typeof(int),
				type
			}, null);
			info = fontType.GetMethod("GetCharacterInfo", BindingFlags.Instance | BindingFlags.Public, null, new Type[4]
			{
				typeof(char),
				type2.MakeByRefType(),
				typeof(int),
				type
			}, null);
			advance = type2.GetProperty("advance", BindingFlags.Instance | BindingFlags.Public);
			if (create == null || request == null || info == null || advance == null || advance.PropertyType != typeof(int))
			{
				Problem = "у UnityEngine.Font в этой версии игры другие методы (" + ((create == null) ? "конструктор " : "") + ((request == null) ? "RequestCharactersInTexture " : "") + ((info == null) ? "GetCharacterInfo " : "") + ((advance == null) ? "CharacterInfo.advance" : "").TrimEnd(Array.Empty<char>()) + ")";
				return;
			}
			normal = Enum.ToObject(type, 0);
			try
			{
				system = fontType.GetMethod("CreateDynamicFontFromOSFont", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(string),
					typeof(int)
				}, null);
			}
			catch
			{
			}
			try
			{
				fontSize = fontType.GetProperty("fontSize", BindingFlags.Instance | BindingFlags.Public);
			}
			catch
			{
			}
			try
			{
				lineHeight = fontType.GetProperty("lineHeight", BindingFlags.Instance | BindingFlags.Public);
			}
			catch
			{
			}
			try
			{
				ascent = fontType.GetProperty("ascent", BindingFlags.Instance | BindingFlags.Public);
			}
			catch
			{
			}
			try
			{
				isDynamic = fontType.GetProperty("dynamic", BindingFlags.Instance | BindingFlags.Public);
			}
			catch
			{
			}
			try
			{
				Type type3 = Lookup("UnityEngine.Resources", "UnityEngine.CoreModule");
				if (type3 != null)
				{
					findAll = type3.GetMethod("FindObjectsOfTypeAll", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null);
				}
			}
			catch
			{
			}
			if (objectType != null)
			{
				try
				{
					objectName = objectType.GetProperty("name", BindingFlags.Instance | BindingFlags.Public);
				}
				catch
				{
				}
				try
				{
					hideFlags = objectType.GetProperty("hideFlags", BindingFlags.Instance | BindingFlags.Public);
				}
				catch
				{
				}
				try
				{
					destroy = objectType.GetMethod("Destroy", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { objectType }, null);
				}
				catch
				{
				}
				try
				{
					exists = objectType.GetMethod("op_Implicit", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { objectType }, null);
				}
				catch
				{
				}
				if (exists != null && exists.ReturnType != typeof(bool))
				{
					exists = null;
				}
			}
		}

		public object Create(string path)
		{
			return create.Invoke(new object[1] { path });
		}

		public List<object> AllFonts()
		{
			if (findAll == null)
			{
				return null;
			}
			if (!(findAll.Invoke(null, new object[1] { fontType }) is Array array))
			{
				return null;
			}
			List<object> list = new List<object>();
			foreach (object item in array)
			{
				if (item != null && Exists(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		public string Describe(object f)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(Read(objectName, f) ?? "?").Append(": ").Append(Read(fontSize, f) ?? "?")
				.Append(" / ")
				.Append(Read(lineHeight, f) ?? "?")
				.Append(" / ")
				.Append(Read(ascent, f) ?? "?");
			object obj = null;
			try
			{
				if (isDynamic != null)
				{
					obj = isDynamic.GetValue(f, null);
				}
			}
			catch
			{
			}
			if (obj is bool && !(bool)obj)
			{
				return stringBuilder.Append("; не динамический").ToString();
			}
			try
			{
				Request(f, "HW→★", 100);
				stringBuilder.Append(';');
				string text = "HW→★";
				foreach (char c in text)
				{
					stringBuilder.Append(' ').Append(c).Append(' ')
						.Append(Advance(f, c, 100, out var pixels) ? pixels.ToString(CultureInfo.InvariantCulture) : "-");
				}
			}
			catch
			{
				stringBuilder.Append("; не измерен");
			}
			return stringBuilder.ToString();
		}

		private static string Read(PropertyInfo p, object o)
		{
			try
			{
				if (p == null)
				{
					return null;
				}
				object value = p.GetValue(o, null);
				return (value == null) ? null : Convert.ToString(value, CultureInfo.InvariantCulture);
			}
			catch
			{
				return null;
			}
		}

		public object CreateSystem(string family)
		{
			return system.Invoke(null, new object[2] { family, 32 });
		}

		public void Request(object f, string characters, int size)
		{
			request.Invoke(f, new object[3] { characters, size, normal });
		}

		public bool Advance(object f, char c, int size, out int pixels)
		{
			object[] array = new object[4] { c, null, size, normal };
			pixels = 0;
			if (!(bool)info.Invoke(f, array) || array[1] == null)
			{
				return false;
			}
			pixels = (int)advance.GetValue(array[1], null);
			return true;
		}

		public void Keep(object f)
		{
			try
			{
				if (hideFlags != null && hideFlags.CanWrite)
				{
					hideFlags.SetValue(f, Enum.ToObject(hideFlags.PropertyType, 61), null);
				}
			}
			catch
			{
			}
		}

		public void Destroy(object f)
		{
			try
			{
				if (destroy != null)
				{
					destroy.Invoke(null, new object[1] { f });
				}
			}
			catch
			{
			}
		}

		public bool Exists(object f)
		{
			if (exists == null)
			{
				return true;
			}
			return (bool)exists.Invoke(null, new object[1] { f });
		}
	}

	public const string FileName = "RepoRPG_RU.ttf";

	private const string ModConfigFile = "rpgmod.semibotrpg.cfg";

	private const int Tolerance = 3;

	private static readonly object Gate = new object();

	private static object font;

	private static bool refused;

	private static string made;

	private static string madeSummary;

	private static readonly List<string> decisions = new List<string>();

	private static string written;

	private static string said;

	private static string home;

	private static string config;

	private static bool placed;

	private static object tried;

	private static object logSource;

	private static MethodInfo logInfo;

	public static object Pick(string setting)
	{
		lock (Gate)
		{
			StringBuilder stringBuilder = new StringBuilder();
			object obj = null;
			string summary;
			try
			{
				obj = Decide(setting, stringBuilder, out summary);
			}
			catch (Exception ex)
			{
				obj = null;
				refused = true;
				summary = (madeSummary = "шрифт не подключён: " + ex.GetType().Name + ": " + ex.Message);
			}
			Report(stringBuilder.ToString(), summary);
			return obj;
		}
	}

	private static object Decide(string setting, StringBuilder log, out string summary)
	{
		if (!placed)
		{
			try
			{
				home = Path.GetDirectoryName(typeof(Fonts).Assembly.Location);
			}
			catch
			{
			}
			if (!string.IsNullOrEmpty(home))
			{
				config = Loc.FindConfigPath(home);
			}
			placed = true;
		}
		if (string.IsNullOrEmpty(home))
		{
			summary = "шрифт не подключён: неизвестно, где лежит русификатор";
			return null;
		}
		Settings settings = ((config == null) ? new Settings() : Settings.Load(Path.Combine(config, "RepoRPG_RU.cfg"), createIfMissing: false));
		if (!settings.Enabled || !settings.DisplayHooks || !settings.MenuFont)
		{
			summary = "шрифт не подключён: выключено в RepoRPG_RU.cfg (MenuFont = false)";
			return null;
		}
		if (setting == null)
		{
			setting = ModSetting();
			log.Append("настройка мода Controls/UiFont (из файла ").Append("rpgmod.semibotrpg.cfg").Append("): ")
				.Append(setting ?? "не найдена, считаем auto")
				.Append('\n');
		}
		else
		{
			log.Append("настройка мода Controls/UiFont: ").Append((setting.Length == 0) ? "(пусто)" : setting).Append('\n');
		}
		if (setting != null)
		{
			setting = setting.Trim();
		}
		if (!string.IsNullOrEmpty(setting) && !string.Equals(setting, "auto", StringComparison.OrdinalIgnoreCase))
		{
			summary = "шрифт не подключён: в настройках мода выбран свой шрифт («" + setting + "») - он и остаётся. Чтобы вернуть шрифт игры с русскими буквами, поставьте там auto";
			return null;
		}
		if (font != null)
		{
			if (Alive(font))
			{
				summary = madeSummary;
				return font;
			}
			font = null;
			log.Append("шрифт был выгружен игрой - создаём заново\n");
		}
		if (refused)
		{
			summary = madeSummary;
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder();
		object obj2 = Make(stringBuilder, out summary);
		if (obj2 == null)
		{
			refused = true;
		}
		font = obj2;
		made = stringBuilder.ToString();
		madeSummary = summary;
		return obj2;
	}

	private static object Make(StringBuilder log, out string summary)
	{
		string text = Find(home);
		if (text == null)
		{
			summary = "шрифт не подключён: файл RepoRPG_RU.ttf не найден в папке " + home;
			return null;
		}
		string family;
		List<Expect> list = ReadCheck(text + ".check", out family);
		if (list.Count == 0)
		{
			summary = "шрифт не подключён: рядом с RepoRPG_RU.ttf нет файла с контрольными ширинами (RepoRPG_RU.ttf.check)";
			return null;
		}
		long value = 0L;
		try
		{
			value = new FileInfo(text).Length;
		}
		catch
		{
		}
		log.Append("файл: ").Append(text).Append(" (")
			.Append(value)
			.Append(" байт)\n");
		Unity unity = Unity.Find();
		if (unity.Problem != null)
		{
			summary = "шрифт не подключён: " + unity.Problem;
			return null;
		}
		List<string> list2 = new List<string>();
		list2.Add(text);
		int num = 0;
		for (int i = 0; i < list2.Count; i++)
		{
			string text2 = list2[i];
			log.Append("попытка ").Append(++num).Append(": файл ")
				.Append(text2)
				.Append('\n');
			if (Try(unity, text2, system: false, list, log))
			{
				Survey(unity, tried, log);
				summary = "шрифт подключён: шрифт игры (Teko) с русскими буквами" + ((i > 0) ? (", прочитан по пути " + text2) : "");
				return tried;
			}
			if (i == 0 && !Ascii(text))
			{
				string text3 = ShortPath(text);
				if (text3 != null)
				{
					list2.Add(text3);
				}
				string text4 = Copy(text, log);
				if (text4 != null)
				{
					list2.Add(text4);
				}
				if (list2.Count == 1)
				{
					log.Append("  в пути к файлу есть буквы не из латиницы, а другого пути к нему нет\n");
				}
			}
		}
		if (family != null && unity.CanAskSystem)
		{
			log.Append("попытка ").Append(++num).Append(": шрифт «")
				.Append(family)
				.Append("», установленный в системе\n");
			if (Try(unity, family, system: true, list, log))
			{
				Survey(unity, tried, log);
				summary = "шрифт подключён: шрифт игры (Teko) с русскими буквами, установленный в системе («" + family + "»)";
				return tried;
			}
		}
		Survey(unity, null, log);
		summary = "шрифт не подключён: игра не прочитала файл шрифта (подробности выше) - мод рисует своим шрифтом, как раньше. Что можно сделать: установить этот файл в Windows (правый щелчок по " + text + " - «Установить для всех пользователей») и перезапустить игру: русификатор найдёт шрифт по имени" + ((family != null) ? (" «" + family + "»") : "");
		return null;
	}

	private static void Survey(Unity unity, object ours, StringBuilder log)
	{
		try
		{
			List<object> list = unity.AllFonts();
			if (list == null || list.Count == 0)
			{
				return;
			}
			log.Append("шрифты в игре (размер / высота строки / подъём; ширина H, W и знаков → ★ при 100 пикс.):\n");
			int num = 0;
			foreach (object item in list)
			{
				if (num++ >= 16)
				{
					log.Append("  ... всего ").Append(list.Count).Append('\n');
					break;
				}
				log.Append("  ").Append((item == ours) ? "* " : "").Append(unity.Describe(item))
					.Append('\n');
			}
		}
		catch
		{
		}
	}

	private static bool Try(Unity unity, string what, bool system, List<Expect> expect, StringBuilder log)
	{
		object obj = null;
		tried = null;
		string text;
		try
		{
			obj = (system ? unity.CreateSystem(what) : unity.Create(what));
			text = ((obj == null) ? "игра не создала шрифт" : Measure(unity, obj, expect, log));
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex);
			text = ex2.GetType().Name + ": " + ex2.Message;
		}
		if (text == null)
		{
			unity.Keep(obj);
			tried = obj;
			return true;
		}
		log.Append("  не подошло: ").Append(text).Append('\n');
		if (obj != null)
		{
			unity.Destroy(obj);
		}
		return false;
	}

	private static string Find(string dir)
	{
		try
		{
			string text = Path.Combine(Path.Combine(dir, "font"), "RepoRPG_RU.ttf");
			if (File.Exists(text))
			{
				return text;
			}
			text = Path.Combine(dir, "RepoRPG_RU.ttf");
			if (File.Exists(text))
			{
				return text;
			}
			string[] files = Directory.GetFiles(dir, "RepoRPG_RU.ttf", SearchOption.AllDirectories);
			if (files.Length != 0)
			{
				Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
				return files[0];
			}
		}
		catch
		{
		}
		return null;
	}

	private static List<Expect> ReadCheck(string path, out string family)
	{
		List<Expect> list = new List<Expect>();
		family = null;
		try
		{
			if (!File.Exists(path))
			{
				return list;
			}
			string[] array = File.ReadAllLines(path, Encoding.UTF8);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Trim().Split(new char[1] { '\t' });
				int result;
				int result2;
				int result3;
				if (array2.Length == 2 && array2[0] == "family" && array2[1].Trim().Length > 0)
				{
					family = array2[1].Trim();
				}
				else if (array2.Length == 3 && array2[0].StartsWith("U+", StringComparison.Ordinal) && int.TryParse(array2[0].Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out result2) && int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out result3) && result > 0 && result <= 65535 && result2 >= 8 && result2 <= 400 && result3 > 0)
				{
					Expect expect = new Expect();
					expect.Char = (char)result;
					expect.Size = result2;
					expect.Advance = result3;
					list.Add(expect);
				}
			}
		}
		catch
		{
			list.Clear();
		}
		return list;
	}

	private static string Measure(Unity unity, object f, List<Expect> expect, StringBuilder log)
	{
		Dictionary<int, StringBuilder> dictionary = new Dictionary<int, StringBuilder>();
		foreach (Expect item in expect)
		{
			if (!dictionary.TryGetValue(item.Size, out var value))
			{
				value = new StringBuilder();
				dictionary[item.Size] = value;
			}
			value.Append(item.Char);
		}
		foreach (KeyValuePair<int, StringBuilder> item2 in dictionary)
		{
			unity.Request(f, item2.Value.ToString(), item2.Key);
		}
		string text = null;
		foreach (Expect item3 in expect)
		{
			int pixels;
			bool flag = unity.Advance(f, item3.Char, item3.Size, out pixels);
			log.Append("  ").Append(item3.Char).Append(" (")
				.Append(item3.Size)
				.Append(" пикс.): по файлу ")
				.Append(item3.Advance)
				.Append(", в игре ")
				.Append(flag ? pixels.ToString(CultureInfo.InvariantCulture) : "нет такого знака")
				.Append('\n');
			if (!flag)
			{
				if (text == null)
				{
					text = "в шрифте, который создал Unity, нет знака «" + item3.Char + "»";
				}
			}
			else if (Math.Abs(pixels - item3.Advance) > 3 && text == null)
			{
				text = "ширина «" + item3.Char + "» " + pixels + " вместо " + item3.Advance + " - игра подставила другой шрифт";
			}
		}
		return text;
	}

	private static bool Ascii(string s)
	{
		for (int i = 0; i < s.Length; i++)
		{
			if (s[i] > '~')
			{
				return false;
			}
		}
		return true;
	}

	[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetShortPathNameW", SetLastError = true)]
	private static extern uint GetShortPathName(string longPath, StringBuilder shortPath, uint size);

	private static string ShortPath(string file)
	{
		try
		{
			if (Path.DirectorySeparatorChar != '\\')
			{
				return null;
			}
			StringBuilder stringBuilder = new StringBuilder(1024);
			uint shortPathName = GetShortPathName(file, stringBuilder, (uint)stringBuilder.Capacity);
			if (shortPathName == 0 || shortPathName >= stringBuilder.Capacity)
			{
				return null;
			}
			string text = stringBuilder.ToString();
			if (text.Length == 0 || !Ascii(text) || string.Equals(text, file, StringComparison.OrdinalIgnoreCase) || !File.Exists(text))
			{
				return null;
			}
			return text;
		}
		catch
		{
			return null;
		}
	}

	private static string Copy(string file, StringBuilder log)
	{
		List<string> list = new List<string>();
		try
		{
			list.Add(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
		}
		catch
		{
		}
		list.Add(BepInExPath("GameRootPath"));
		try
		{
			list.Add(Path.GetTempPath());
		}
		catch
		{
		}
		byte[] array = null;
		foreach (string item in list)
		{
			if (string.IsNullOrEmpty(item) || !Ascii(item))
			{
				continue;
			}
			try
			{
				if (!Directory.Exists(item))
				{
					continue;
				}
				string text = Path.Combine(item, "RepoRPG_RU");
				string text2 = Path.Combine(text, "RepoRPG_RU.ttf");
				if (array == null)
				{
					array = File.ReadAllBytes(file);
				}
				if (!Same(text2, array))
				{
					Directory.CreateDirectory(text);
					File.WriteAllBytes(text2, array);
				}
				return text2;
			}
			catch (Exception ex)
			{
				log.Append("  копия в ").Append(item).Append(" не удалась: ")
					.Append(ex.Message)
					.Append('\n');
			}
		}
		return null;
	}

	private static string BepInExPath(string property)
	{
		try
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (assembly.GetName().Name != "BepInEx")
				{
					continue;
				}
				Type type = assembly.GetType("BepInEx.Paths", throwOnError: false);
				if (!(type == null))
				{
					PropertyInfo property2 = type.GetProperty(property, BindingFlags.Static | BindingFlags.Public);
					if (!(property2 == null))
					{
						return property2.GetValue(null, null) as string;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static bool Same(string path, byte[] bytes)
	{
		try
		{
			if (!File.Exists(path))
			{
				return false;
			}
			byte[] array = File.ReadAllBytes(path);
			if (array.Length != bytes.Length)
			{
				return false;
			}
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] != bytes[i])
				{
					return false;
				}
			}
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static string ModSetting()
	{
		try
		{
			if (config == null)
			{
				return null;
			}
			string path = Path.Combine(config, "rpgmod.semibotrpg.cfg");
			if (!File.Exists(path))
			{
				return null;
			}
			string text = "";
			string[] array = File.ReadAllLines(path, Encoding.UTF8);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0 || text2[0] == '#' || text2[0] == ';')
				{
					continue;
				}
				if (text2[0] == '[' && text2[text2.Length - 1] == ']')
				{
					text = text2.Substring(1, text2.Length - 2).Trim();
					continue;
				}
				int num = text2.IndexOf('=');
				if (num > 0 && !(text != "Controls") && text2.Substring(0, num).Trim() == "UiFont")
				{
					return text2.Substring(num + 1).Trim();
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static void Report(string log, string summary)
	{
		if (summary == null)
		{
			return;
		}
		string item = log + "итог: " + summary + "\n";
		if (!decisions.Contains(item) && decisions.Count < 16)
		{
			decisions.Add(item);
		}
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("RepoRPG RU ").Append("0.2.1").Append(" - шрифт меню\n");
		if (!string.IsNullOrEmpty(made))
		{
			stringBuilder.Append('\n').Append(made);
		}
		foreach (string decision in decisions)
		{
			stringBuilder.Append('\n').Append(decision);
		}
		string text = stringBuilder.ToString();
		if (text == written)
		{
			return;
		}
		written = text;
		if (summary != said)
		{
			said = summary;
			Say("Шрифт меню: " + summary + ".");
		}
		try
		{
			if (config != null)
			{
				string text2 = Path.Combine(config, "RepoRPG_RU");
				Directory.CreateDirectory(text2);
				File.WriteAllText(Path.Combine(text2, "font.txt"), text.Replace("\n", Environment.NewLine), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			}
		}
		catch
		{
		}
	}

	private static void Say(string message)
	{
		try
		{
			if (logInfo == null)
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.GetName().Name != "BepInEx")
					{
						continue;
					}
					Type type = assembly.GetType("BepInEx.Logging.Logger", throwOnError: false);
					if (type == null)
					{
						continue;
					}
					MethodInfo method = type.GetMethod("CreateLogSource", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
					if (method == null)
					{
						continue;
					}
					object obj = method.Invoke(null, new object[1] { "RepoRPG RU" });
					if (obj != null)
					{
						MethodInfo method2 = obj.GetType().GetMethod("LogInfo", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(object) }, null);
						if (!(method2 == null))
						{
							logSource = obj;
							logInfo = method2;
							break;
						}
					}
				}
			}
			if (logInfo != null)
			{
				logInfo.Invoke(logSource, new object[1] { message });
			}
		}
		catch
		{
		}
	}

	private static bool Alive(object o)
	{
		try
		{
			return Unity.Find().Exists(o);
		}
		catch
		{
			return true;
		}
	}
}
public static class Loc
{
	private sealed class Thing
	{
		public int Gender;

		public string Name;
	}

	private sealed class CaseEntry
	{
		public string Key;

		public string Value;
	}

	private sealed class Pattern
	{
		public string[] Lits;

		public int[] Slots;

		public string Template;

		public int Weight;

		public int[] Ghosts;

		public bool Tight;

		public bool[] Glued;

		public byte[] Kind;

		public bool[] Numeric;

		public bool Counter;

		public bool[] Dropped;

		public bool[] Roomy;

		public bool[] Framed;

		public bool[] Known;

		public int[] Form;

		public bool[] Rarity;

		private const byte Value = 0;

		private const byte Clause = 1;

		private const byte Line = 2;

		public static Pattern Parse(string original, string translation, bool explicitPattern, int[] numbers, int[] words, int[] forms)
		{
			List<string> list = new List<string>();
			List<int> list2 = new List<int>();
			List<int> list3 = null;
			List<bool> list4 = new List<bool>();
			List<bool> list5 = new List<bool>();
			string text = null;
			StringBuilder stringBuilder = new StringBuilder();
			int num = 0;
			int num2 = 0;
			List<int> list6 = new List<int>();
			for (int i = 0; i < original.Length; i++)
			{
				char c = original[i];
				switch (c)
				{
				case '{':
				{
					if (i + 1 < original.Length && original[i + 1] == '{')
					{
						stringBuilder.Append('{');
						i++;
						text = null;
						continue;
					}
					int num4 = original.IndexOf('}', i);
					if (num4 < 0)
					{
						return null;
					}
					string text2 = original.Substring(i, num4 - i + 1);
					int num5 = Fmt.FormatIndex(text2);
					if (num5 < 0)
					{
						return null;
					}
					if (text != null && stringBuilder.Length == 0)
					{
						if (translation.IndexOf(text + text2, StringComparison.Ordinal) < 0 || list2.Contains(num5))
						{
							return null;
						}
						if (list3 == null)
						{
							list3 = new List<int>();
						}
						list3.Add(num5);
						text = text2;
						i = num4;
					}
					else
					{
						text = text2;
						list5.Add(text2.IndexOf(':') > 0 || (numbers != null && Array.IndexOf(numbers, num5) >= 0));
						list4.Add(stringBuilder.Length > 0 && IsLatinLetter(stringBuilder[stringBuilder.Length - 1]));
						list.Add(stringBuilder.ToString());
						list6.Add(num2);
						num2 = 0;
						stringBuilder.Length = 0;
						list2.Add(num5);
						i = num4;
					}
					continue;
				}
				case '}':
					if (i + 1 < original.Length && original[i + 1] == '}')
					{
						stringBuilder.Append('}');
						i++;
						continue;
					}
					return null;
				case '<':
				{
					int num3 = original.IndexOf('>', i);
					if (num3 > i && num3 - i <= 40 && original.IndexOf('{', i, num3 - i) < 0)
					{
						stringBuilder.Append(original, i, num3 - i + 1);
						i = num3;
						text = null;
						continue;
					}
					break;
				}
				}
				if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
				{
					num++;
					num2++;
				}
				stringBuilder.Append(c);
				text = null;
			}
			list.Add(stringBuilder.ToString());
			list6.Add(num2);
			if (list2.Count == 0)
			{
				return null;
			}
			if (num < (explicitPattern ? 1 : 3))
			{
				return null;
			}
			Pattern pattern = new Pattern();
			pattern.Lits = list.ToArray();
			pattern.Slots = list2.ToArray();
			pattern.Template = translation;
			pattern.Ghosts = list3?.ToArray();
			pattern.Tight = num < 14;
			pattern.Glued = list4.ToArray();
			pattern.Numeric = list5.ToArray();
			string[] lits;
			if (pattern.Tight && pattern.Slots.Length == 1 && num > 0)
			{
				bool counter = true;
				lits = pattern.Lits;
				foreach (string text3 in lits)
				{
					for (int k = 0; k < text3.Length; k++)
					{
						switch (text3[k])
						{
						case ' ':
						case 'A':
						case 'B':
						case 'C':
						case 'D':
						case 'E':
						case 'F':
						case 'G':
						case 'H':
						case 'I':
						case 'J':
						case 'K':
						case 'L':
						case 'M':
						case 'N':
						case 'O':
						case 'P':
						case 'Q':
						case 'R':
						case 'S':
						case 'T':
						case 'U':
						case 'V':
						case 'W':
						case 'X':
						case 'Y':
						case 'Z':
							continue;
						}
						counter = false;
					}
				}
				pattern.Counter = counter;
			}
			pattern.Dropped = new bool[pattern.Slots.Length];
			List<string> list7 = Fmt.Holes(translation);
			for (int l = 0; l < pattern.Slots.Length; l++)
			{
				bool flag = false;
				foreach (string item in list7)
				{
					if (Fmt.FormatIndex(item) == pattern.Slots[l])
					{
						flag = true;
					}
				}
				pattern.Dropped[l] = !flag;
			}
			pattern.Kind = new byte[pattern.Slots.Length];
			pattern.Roomy = new bool[pattern.Slots.Length];
			pattern.Framed = new bool[pattern.Slots.Length];
			pattern.Known = new bool[pattern.Slots.Length];
			pattern.Form = new int[pattern.Slots.Length];
			pattern.Rarity = new bool[pattern.Slots.Length];
			for (int m = 0; m < pattern.Slots.Length; m++)
			{
				int num6 = ((words == null) ? (-1) : Array.IndexOf(words, pattern.Slots[m]));
				int num7 = ((num6 >= 0 && forms != null && num6 < forms.Length) ? forms[num6] : (-1));
				pattern.Known[m] = num6 >= 0;
				pattern.Form[m] = ((num7 < 0) ? (-1) : (num7 & 3));
				pattern.Rarity[m] = num7 >= 4;
			}
			for (int n = 0; n < pattern.Slots.Length; n++)
			{
				pattern.Framed[n] = num >= 30 && list6[n] >= 3 && list6[n + 1] >= 3;
				string text4 = pattern.Lits[n];
				string text5 = pattern.Lits[n + 1];
				int length = text4.Length;
				bool flag2 = n == 0 && length == 0;
				bool num8 = n == pattern.Slots.Length - 1 && text5.Length == 0;
				bool flag3 = flag2 || text4[length - 1] == '\n';
				bool flag4 = num8 || text5[0] == '\n';
				bool flag5 = flag3 || text4[length - 1] == '>' || (length > 1 && text4[length - 1] == ' ' && (text4[length - 2] == '.' || text4[length - 2] == '!' || text4[length - 2] == '?' || text4[length - 2] == ':' || text4[length - 2] == '-' || text4[length - 2] == '>'));
				bool flag6 = flag4 || text5[0] == '.' || text5[0] == '!' || text5[0] == '?' || text5[0] == ':' || text5[0] == '<' || (text5.Length > 1 && text5[0] == ' ' && ((text5[1] >= 'A' && text5[1] <= 'Z') || text5[1] == '<' || text5[1] == '-' || text5[1] == '(')) || (text5.Length > 2 && text5[0] == ' ' && text5[1] == ' ' && (text5[2] == '(' || text5[2] == '-' || text5[2] == '<'));
				pattern.Kind[n] = (byte)((flag3 && flag4) ? 2 : ((flag5 && flag6) ? 1 : 0));
				bool flag7 = length > 1 && text4[length - 1] == ' ' && (text4[length - 2] == '–' || text4[length - 2] == '—');
				pattern.Roomy[n] = (flag5 || flag7) && flag6;
			}
			lits = pattern.Lits;
			foreach (string text6 in lits)
			{
				pattern.Weight += text6.Length;
			}
			return pattern;
		}

		private static bool Several(string v)
		{
			for (int i = 0; i < v.Length; i++)
			{
				switch (v[i])
				{
				case '\n':
					return true;
				case '!':
				case '.':
				case ';':
				case '?':
					if (i + 2 < v.Length && v[i + 1] == ' ')
					{
						return true;
					}
					break;
				}
			}
			return false;
		}

		internal static bool Simple(string v)
		{
			if (v.Length <= 80 && NameLike(v, lenient: true))
			{
				return Whole(v);
			}
			return false;
		}

		private static bool Short(string v)
		{
			if (v.Length > 32 || !Whole(v))
			{
				return false;
			}
			int num = 0;
			bool flag = false;
			for (int i = 0; i < v.Length; i++)
			{
				if (v[i] == '<' || v[i] == '>')
				{
					return false;
				}
				bool num2 = !IsBlank(v[i]);
				if (num2 && !flag)
				{
					num++;
				}
				flag = num2;
			}
			return num <= 4;
		}

		private static bool Whole(string v)
		{
			if (v.Length > 0 && (IsBlank(v[0]) || IsBlank(v[v.Length - 1])))
			{
				return false;
			}
			int num = 0;
			for (int i = 0; i < v.Length; i++)
			{
				char c = v[i];
				switch (c)
				{
				case '\n':
					return false;
				case '<':
				{
					int num2 = v.IndexOf('>', i);
					if (num2 <= i || num2 - i > 40 || i + 1 >= v.Length)
					{
						continue;
					}
					if (v[i + 1] == '/')
					{
						if (--num < 0)
						{
							return false;
						}
					}
					else
					{
						if (!IsLatinLetter(v[i + 1]))
						{
							continue;
						}
						if (num == 0 && i > 0)
						{
							return false;
						}
						num++;
					}
					if (num == 0 && num2 + 1 < v.Length)
					{
						return false;
					}
					i = num2;
					continue;
				}
				default:
					if (i + 1 < v.Length)
					{
						char c2 = v[i + 1];
						if (c2 == ' ' && (c == ':' || c == ',' || c == '.' || c == '!' || c == '?' || c == ';') && i + 2 < v.Length)
						{
							return false;
						}
						if (c == ' ' && (c2 == '·' || c2 == '|'))
						{
							return false;
						}
						if (c != ' ' || c2 != ' ')
						{
							continue;
						}
						return false;
					}
					break;
				}
				break;
			}
			return num == 0;
		}

		public string Apply(string s, int depth)
		{
			int num = Lits.Length - 1;
			string text = Lits[0];
			string text2 = Lits[num];
			if (s.Length < Weight)
			{
				return null;
			}
			if (text.Length > 0 && string.CompareOrdinal(s, 0, text, 0, text.Length) != 0)
			{
				return null;
			}
			int num2 = s.Length - text2.Length;
			if (text2.Length > 0 && string.CompareOrdinal(s, num2, text2, 0, text2.Length) != 0)
			{
				return null;
			}
			int num3 = text.Length;
			if (num3 > num2)
			{
				return null;
			}
			string[] array = new string[Slots.Length];
			for (int i = 1; i < num; i++)
			{
				int num4 = s.IndexOf(Lits[i], num3, num2 - num3, StringComparison.Ordinal);
				if (num4 < 0)
				{
					return null;
				}
				array[i - 1] = s.Substring(num3, num4 - num3);
				num3 = num4 + Lits[i].Length;
			}
			array[num - 1] = s.Substring(num3, num2 - num3);
			int num5 = 0;
			for (int j = 0; j < array.Length; j++)
			{
				string text3 = array[j];
				if (Numeric[j])
				{
					if (text3.Length > 0 && (IsBlank(text3[0]) || IsBlank(text3[text3.Length - 1])))
					{
						return null;
					}
					bool flag = false;
					for (int k = 0; k < text3.Length; k++)
					{
						if (char.IsLetter(text3[k]))
						{
							return null;
						}
						if (text3[k] >= '0' && text3[k] <= '9')
						{
							flag = true;
						}
					}
					if (!flag)
					{
						return null;
					}
					continue;
				}
				if (Known[j])
				{
					if (Exact(text3) == null && !HasCyrillic(text3))
					{
						return null;
					}
					if (Rarity[j] && InForm(text3, 0, inside: false) == null)
					{
						return null;
					}
				}
				else if (Tight && !Simple(text3) && (things == null || Built(text3) == null))
				{
					if (!Roomy[j] || j >= 30 || Dropped[j])
					{
						return null;
					}
					if ((text3.Length > 80 || !Whole(text3)) && Exact(text3) == null && (shapes == null || Shape(text3) == null))
					{
						return null;
					}
					num5 |= 1 << j;
				}
				if (Kind[j] == 0)
				{
					if (Several(text3))
					{
						return null;
					}
					if (j == 0 && Lits[0].Length == 0 && text3.Length > 0 && text3[0] == ' ')
					{
						return null;
					}
					if (j == 0 && Lits[0].Length == 0 && text3.IndexOf(": ", StringComparison.Ordinal) >= 0)
					{
						return null;
					}
					if (j == array.Length - 1 && Lits[j + 1].Length == 0 && text3.Length > 0 && text3[text3.Length - 1] == ' ')
					{
						return null;
					}
				}
				if (Dropped[j])
				{
					if (text3.Length > 3)
					{
						return null;
					}
					for (int l = 0; l < text3.Length; l++)
					{
						if (!IsLatinLetter(text3[l]))
						{
							return null;
						}
					}
				}
				else if (Glued[j] && text3.Length > 0 && IsLatinLetter(text3[0]))
				{
					return null;
				}
			}
			StringBuilder stringBuilder = new StringBuilder(Template.Length + s.Length);
			int num6 = -1;
			int num7 = -1;
			for (int m = 0; m < Template.Length; m++)
			{
				char c = Template[m];
				switch (c)
				{
				case '{':
				{
					if (m + 1 < Template.Length && Template[m + 1] == '{')
					{
						stringBuilder.Append('{');
						m++;
						continue;
					}
					int num8 = Template.IndexOf('}', m);
					if (num8 < 0)
					{
						return null;
					}
					int num9 = Fmt.FormatIndex(Template.Substring(m, num8 - m + 1));
					int num10 = ((num9 < 0) ? (-1) : Array.IndexOf(Slots, num9));
					if (num10 < 0)
					{
						if (num9 >= 0 && Ghosts != null && Array.IndexOf(Ghosts, num9) >= 0)
						{
							m = num8;
							continue;
						}
						return null;
					}
					string text4 = array[num10];
					if (things != null && num10 + 1 < array.Length && Lits[num10 + 1] == " " && num8 + 2 < Template.Length && Template[num8 + 1] == ' ' && Template[num8 + 2] == '{')
					{
						int num11 = Template.IndexOf('}', num8 + 2);
						if (num11 > 0 && Fmt.FormatIndex(Template.Substring(num8 + 2, num11 - num8 - 1)) == Slots[num10 + 1])
						{
							string text5 = array[num10 + 1];
							string text6 = Built(text4 + " " + text5);
							if (text6 == null)
							{
								int num12 = text5.IndexOf(", ", StringComparison.Ordinal);
								string text7 = ((num12 > 0) ? Built(text4 + " " + text5.Substring(0, num12)) : null);
								if (text7 != null)
								{
									bool unknown = false;
									string text8 = Piece(text5.Substring(num12), depth, ref unknown);
									if (text8 == null && !unknown)
									{
										text8 = Piece(text5.Substring(num12 + 2), depth, ref unknown);
										if (text8 != null)
										{
											text8 = ", " + text8;
										}
									}
									if (unknown)
									{
										return null;
									}
									if (text8 != null)
									{
										text6 = text7 + text8;
									}
								}
							}
							if (text6 != null)
							{
								stringBuilder.Append(text6);
								m = num11;
								continue;
							}
						}
					}
					if (Form[num10] >= 0 && things != null)
					{
						string text9 = InForm(text4, Form[num10], Worded(stringBuilder));
						if (text9 != null)
						{
							stringBuilder.Append(text9);
							num6 = num10;
							num7 = num8 + 1;
							m = num8;
							continue;
						}
					}
					bool unknown2 = false;
					string text10 = null;
					if (num10 == num6 + 1 && num10 > 0 && m - num7 == 2 && Template[num7] == ' ' && Template[num7 + 1] == '(' && Lits[num10] == " (")
					{
						text10 = Agreed(array[num10 - 1], text4, depth, ref unknown2);
					}
					if (text10 == null)
					{
						text10 = Piece(text4, depth, ref unknown2);
					}
					if (unknown2)
					{
						return null;
					}
					if (text10 == null && (num5 & (1 << num10)) != 0)
					{
						return null;
					}
					bool flag2 = text10 == null && Framed[num10] && text4.Length <= 200 && text4.IndexOf('<') < 0 && !Several(text4);
					if (text10 == null && Kind[num10] == 1 && HasLatin(text4) && !Simple(text4) && !flag2)
					{
						return null;
					}
					if (text10 == null && Counter && HasLatin(text4))
					{
						return null;
					}
					if (text10 == null && Kind[num10] == 0 && HasLatin(text4) && !Simple(text4) && !Short(text4) && !flag2)
					{
						return null;
					}
					stringBuilder.Append(text10 ?? text4);
					num6 = num10;
					num7 = num8 + 1;
					m = num8;
					continue;
				}
				case '}':
					if (m + 1 < Template.Length && Template[m + 1] == '}')
					{
						stringBuilder.Append('}');
						m++;
						continue;
					}
					break;
				}
				stringBuilder.Append(c);
			}
			return stringBuilder.ToString();
		}
	}

	private static readonly object Gate = new object();

	private static volatile bool ready;

	private static Dictionary<string, string> map = new Dictionary<string, string>(StringComparer.Ordinal);

	private static int minLength = int.MaxValue;

	private static int maxLength = -1;

	private static bool fallbacks;

	private static Dictionary<string, CaseEntry> upper;

	private static Dictionary<string, Pattern[]> byHead;

	private static Dictionary<string, Pattern[]> byTail;

	private static Dictionary<string, string> shapes;

	private static Dictionary<string, string[]> kinds;

	private static Dictionary<string, Thing> things;

	private static Dictionary<string, string> owners;

	private static Pattern[] loose;

	private static KeyValuePair<string, string>[] prefixes = new KeyValuePair<string, string>[0];

	private static KeyValuePair<string, string>[] suffixes = new KeyValuePair<string, string>[0];

	private static Dictionary<string, string> memo;

	private const int MemoLimit = 6000;

	private static bool logging;

	private static HashSet<string> seen;

	private static List<string> pending;

	private static string logPath;

	private static int nextFlush;

	private const int MaxLogged = 4000;

	private const int MaxDepth = 6;

	private const int MaxSteps = 4000;

	[ThreadStatic]
	private static int cuts;

	[ThreadStatic]
	private static int steps;

	private const char NumberMark = '\u0001';

	[ThreadStatic]
	private static List<int> runStart;

	[ThreadStatic]
	private static List<int> runEnd;

	[ThreadStatic]
	private static List<string> runText;

	private const int MaxKinds = 4;

	private const int Lines = 0;

	private const int Cells = 1;

	private const int Phrase = 2;

	private const int Label = 3;

	public static int Count
	{
		get
		{
			Init();
			return map.Count;
		}
	}

	public static object MenuFont(string setting)
	{
		try
		{
			return Fonts.Pick(setting);
		}
		catch
		{
			return null;
		}
	}

	public static string T(string text)
	{
		if (text == null)
		{
			return null;
		}
		int length = text.Length;
		if (length == 0)
		{
			return text;
		}
		if (!ready)
		{
			Init();
		}
		if (length >= minLength && length <= maxLength && map.TryGetValue(text, out var value))
		{
			return value;
		}
		if (!fallbacks)
		{
			return text;
		}
		try
		{
			return Slow(text);
		}
		catch
		{
			fallbacks = false;
			return text;
		}
	}

	private static string Slow(string text)
	{
		if (!HasLatin(text))
		{
			return text;
		}
		string value;
		lock (Gate)
		{
			if (memo.TryGetValue(text, out value))
			{
				return value ?? text;
			}
		}
		steps = 0;
		value = Derive(text, 0);
		lock (Gate)
		{
			if (memo.Count >= 6000)
			{
				memo.Clear();
			}
			memo[text] = value;
			if (logging)
			{
				if (value == null)
				{
					Note(LooksEnglish(text) ? text : (Leftover(text) ? ("~ " + text) : null));
				}
				else if (Leftover(value))
				{
					Note("~ " + text + "  =>  " + value);
				}
			}
		}
		return value ?? text;
	}

	private static string Sub(string text, int depth)
	{
		if (text.Length < 2 || !HasLatin(text))
		{
			return null;
		}
		string value;
		lock (Gate)
		{
			if (memo.TryGetValue(text, out value))
			{
				return value;
			}
		}
		int num = cuts;
		value = Derive(text, depth);
		if (value == null && cuts != num)
		{
			return null;
		}
		lock (Gate)
		{
			if (memo.Count < 6000)
			{
				memo[text] = value;
			}
		}
		return value;
	}

	private static string Piece(string text, int depth, ref bool unknown)
	{
		int num = cuts;
		string text2 = Sub(text, depth + 1);
		if (text2 == null && cuts != num)
		{
			unknown = true;
		}
		return text2;
	}

	private static string Exact(string text)
	{
		if (map.TryGetValue(text, out var value))
		{
			return value;
		}
		return ByCase(text);
	}

	private static string Derive(string text, int depth)
	{
		string text2 = Exact(text);
		if (text2 != null)
		{
			return text2;
		}
		if (things != null && (text2 = Built(text)) != null)
		{
			return text2;
		}
		if (shapes != null && (text2 = Shape(text)) != null)
		{
			return text2;
		}
		if (depth >= 6 || ++steps > 4000)
		{
			cuts++;
			return null;
		}
		text2 = Compose(text, depth);
		if (text2 != null && HasLatin(text2))
		{
			text2 = Islands(text2, depth) ?? text2;
		}
		return text2;
	}

	private static bool IsDigit(char c)
	{
		if (c >= '0')
		{
			return c <= '9';
		}
		return false;
	}

	private static int NumberEnd(string s, int i)
	{
		int length = s.Length;
		int j;
		for (j = i; j < length && IsDigit(s[j]); j++)
		{
		}
		for (; j + 3 < length && (s[j] == '\u00a0' || s[j] == '\u202f') && IsDigit(s[j + 1]) && IsDigit(s[j + 2]) && IsDigit(s[j + 3]); j += 4)
		{
		}
		if (j + 1 < length && (s[j] == '.' || s[j] == ',') && IsDigit(s[j + 1]))
		{
			for (j += 2; j < length && IsDigit(s[j]); j++)
			{
			}
		}
		return j;
	}

	private static string Shape(string text)
	{
		int length = text.Length;
		int i;
		for (i = 0; i < length && !IsDigit(text[i]); i++)
		{
		}
		if (i == length)
		{
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder(length);
		List<string> list = new List<string>(4);
		int num = 0;
		while (i < length)
		{
			if (!IsDigit(text[i]))
			{
				i++;
				continue;
			}
			int num2 = NumberEnd(text, i);
			stringBuilder.Append(text, num, i - num).Append('\u0001');
			list.Add(text.Substring(i, num2 - i));
			num = (i = num2);
		}
		stringBuilder.Append(text, num, length - num);
		if (!shapes.TryGetValue(stringBuilder.ToString(), out var value))
		{
			return null;
		}
		StringBuilder stringBuilder2 = new StringBuilder(value.Length + 16);
		for (int j = 0; j < value.Length; j++)
		{
			char c = value[j];
			if (c == '{')
			{
				int num3 = value.IndexOf('}', j);
				int num4 = ((num3 < 0) ? (-1) : Fmt.FormatIndex(value.Substring(j, num3 - j + 1)));
				if (num4 < 0 || num4 >= list.Count)
				{
					return null;
				}
				stringBuilder2.Append(list[num4]);
				j = num3;
			}
			else
			{
				stringBuilder2.Append(c);
			}
		}
		return stringBuilder2.ToString();
	}

	private static string Compose(string text, int depth)
	{
		string result;
		if (text.Length >= 2)
		{
			if (byHead.TryGetValue(text.Substring(0, 2), out var value) && (result = Try(value, text, depth)) != null)
			{
				return result;
			}
			if (byTail.TryGetValue(text.Substring(text.Length - 2), out value) && (result = Try(value, text, depth)) != null)
			{
				return result;
			}
			if (loose.Length != 0 && (result = Try(loose, text, depth)) != null)
			{
				return result;
			}
		}
		int i = 0;
		int num;
		for (num = text.Length; i < num && IsBlank(text[i]); i++)
		{
		}
		while (num > i && IsBlank(text[num - 1]))
		{
			num--;
		}
		if (num - i >= 2 && (i > 0 || num < text.Length))
		{
			string text2 = Sub(text.Substring(i, num - i), depth + 1);
			if (text2 != null)
			{
				return text.Substring(0, i) + text2 + text.Substring(num);
			}
		}
		int num2 = 0;
		int num3 = text.Length;
		while (num2 < num3 && text[num2] == '<')
		{
			int num4 = text.IndexOf('>', num2);
			if (num4 < 0 || num4 - num2 > 40 || text[num2 + 1] == '/')
			{
				break;
			}
			num2 = num4 + 1;
		}
		while (num3 > num2 && text[num3 - 1] == '>')
		{
			int num5 = text.LastIndexOf('<', num3 - 1);
			if (num5 < num2 || num3 - num5 > 40 || num5 + 1 >= num3 || text[num5 + 1] != '/')
			{
				break;
			}
			num3 = num5;
		}
		if ((num2 > 0 || num3 < text.Length) && num3 > num2)
		{
			string text3 = Sub(text.Substring(num2, num3 - num2), depth + 1);
			if (text3 != null)
			{
				return text.Substring(0, num2) + text3 + text.Substring(num3);
			}
		}
		if ((result = Parts(text, "\n", 0, depth)) != null)
		{
			return result;
		}
		if ((result = Quoted(text, depth)) != null)
		{
			return result;
		}
		if ((result = Edge(text, depth)) != null)
		{
			return result;
		}
		if ((result = Runs(text, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, "  ·  ", 1, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, " · ", 1, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, " | ", 1, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, "   ", 1, depth)) != null)
		{
			return result;
		}
		if ((result = Sentences(text, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, " + ", 2, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, " – ", 2, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, " - ", 2, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, ": ", 3, depth)) != null)
		{
			return result;
		}
		if ((result = Parts(text, ", ", 2, depth)) != null)
		{
			return result;
		}
		if ((result = Bracket(text, depth)) != null)
		{
			return result;
		}
		if ((result = Peel(text, depth)) != null)
		{
			return result;
		}
		if ((result = Counted(text)) != null)
		{
			return result;
		}
		return Islands(text, depth);
	}

	private static string Agreed(string outer, string inner, int depth, ref bool unknown)
	{
		if (things == null)
		{
			return null;
		}
		int num = inner.IndexOf(", ", StringComparison.Ordinal);
		string text = ((num < 0) ? inner : inner.Substring(0, num));
		if (text.Length > 24 || !kinds.TryGetValue(text.ToUpperInvariant(), out var value))
		{
			return null;
		}
		if (string.Equals(text, text.ToUpperInvariant(), StringComparison.Ordinal))
		{
			return null;
		}
		int i = outer.Length;
		while (i > 0 && (IsLatinLetter(outer[i - 1]) || outer[i - 1] == ' ' || outer[i - 1] == '\'' || outer[i - 1] == '-'))
		{
			i--;
		}
		for (; i < outer.Length && outer[i] == ' '; i++)
		{
		}
		if (i >= outer.Length)
		{
			return null;
		}
		int num2 = Gender(outer.Substring(i));
		if (num2 < 0)
		{
			return null;
		}
		string text2 = LowerFirst(value[num2]);
		if (num < 0)
		{
			return text2;
		}
		string text3 = inner.Substring(num + 2);
		string text4 = Piece(text3, depth, ref unknown);
		if (text4 == null && (unknown || (HasLatin(text3) && !NameLike(text3, lenient: false))))
		{
			return null;
		}
		return text2 + ", " + (text4 ?? text3);
	}

	private static string Bracket(string text, int depth)
	{
		int length = text.Length;
		if (length < 6)
		{
			return null;
		}
		char c = text[length - 1];
		char c2 = c switch
		{
			']' => '[', 
			')' => '(', 
			_ => '\0', 
		};
		if (c2 == '\0')
		{
			return null;
		}
		int num = 0;
		int num2 = -1;
		for (int num3 = length - 1; num3 >= 0; num3--)
		{
			char c3 = text[num3];
			if (c3 == c)
			{
				num++;
			}
			else if (c3 == c2 && --num == 0)
			{
				num2 = num3;
				break;
			}
		}
		if (num2 < 2 || text[num2 - 1] != ' ' || num2 + 1 >= length - 1)
		{
			return null;
		}
		string text2 = text.Substring(0, num2 - 1);
		string text3 = text.Substring(num2 + 1, length - num2 - 2);
		bool unknown = false;
		string text4 = Piece(text2, depth, ref unknown);
		string text5 = ((c2 == '(') ? Agreed(text2, text3, depth, ref unknown) : null) ?? Piece(text3, depth, ref unknown);
		if (unknown || (text4 == null && text5 == null))
		{
			return null;
		}
		if (text4 == null && HasLatin(text2) && !NameLike(text2, lenient: false))
		{
			return null;
		}
		if (text5 == null && HasLatin(text3) && !NameLike(text3, lenient: false))
		{
			return null;
		}
		return (text4 ?? text2) + " " + c2 + (text5 ?? text3) + c;
	}

	private static string Quoted(string text, int depth)
	{
		int num = text.Length - 1;
		while (num > 0 && text[num] != '"')
		{
			char c = text[num];
			if (IsBlank(c))
			{
				num--;
				continue;
			}
			if (c != '>')
			{
				return null;
			}
			int num2 = text.LastIndexOf('<', num);
			if (num2 < 0 || num - num2 > 40)
			{
				return null;
			}
			num = num2 - 1;
		}
		if (num <= 0)
		{
			return null;
		}
		int num3 = text.IndexOf('"');
		if (num3 >= num - 2)
		{
			return null;
		}
		bool unknown = false;
		string text2 = Piece(text.Substring(num3 + 1, num - num3 - 1), depth, ref unknown);
		if (text2 == null)
		{
			return null;
		}
		int num4 = num3;
		while (num4 > 0)
		{
			char c2 = text[num4 - 1];
			if (IsBlank(c2))
			{
				num4--;
				continue;
			}
			if (c2 != '>')
			{
				break;
			}
			int num5 = text.LastIndexOf('<', num4 - 1);
			if (num5 < 0 || num4 - num5 > 41 || num5 + 1 >= num4 || text[num5 + 1] == '/')
			{
				break;
			}
			num4 = num5;
		}
		string text3 = text.Substring(0, num4);
		string text4 = null;
		if (text3.Length > 0 && HasLatin(text3))
		{
			text4 = Piece(text3, depth, ref unknown);
			if (unknown || (text4 == null && !NameLike(text3, lenient: false)))
			{
				return null;
			}
		}
		return (text4 ?? text3) + text.Substring(num4, num3 - num4) + "«" + text2 + "»" + text.Substring(num + 1);
	}

	private static string Counted(string text)
	{
		int num = text.LastIndexOf(' ');
		if (num < 2 || num == text.Length - 1 || text.Length - num > 12)
		{
			return null;
		}
		bool flag = false;
		for (int i = num + 1; i < text.Length; i++)
		{
			char c = text[i];
			if (c >= '0' && c <= '9')
			{
				flag = true;
			}
			else if ((i != num + 1 || (c != 'x' && c != '×')) && c != '.' && c != ',' && c != '%' && c != '+' && c != '-' && c != '/' && c != '\u00a0')
			{
				return null;
			}
		}
		if (!flag)
		{
			return null;
		}
		string text2 = Named(text.Substring(0, num));
		if (text2 != null)
		{
			return text2 + text.Substring(num);
		}
		return null;
	}

	private static string Islands(string text, int depth)
	{
		if (!HasCyrillic(text))
		{
			return null;
		}
		StringBuilder sb = null;
		int length = text.Length;
		int num = 0;
		int copied = 0;
		while (num < length)
		{
			int i = num;
			bool russian = false;
			for (; i < length; i++)
			{
				char c = text[i];
				if (c == '\n')
				{
					break;
				}
				if (c == '<')
				{
					int num2 = text.IndexOf('>', i);
					if (num2 > i && num2 - i <= 40)
					{
						break;
					}
				}
				if (c >= 'Ѐ' && c <= 'ӿ')
				{
					russian = true;
				}
			}
			Stretch(text, num, i, russian, depth, ref sb, ref copied);
			if (i >= length)
			{
				break;
			}
			num = ((text[i] == '\n') ? (i + 1) : (text.IndexOf('>', i) + 1));
		}
		if (sb == null)
		{
			return null;
		}
		sb.Append(text, copied, length - copied);
		return sb.ToString();
	}

	private static void Stretch(string text, int from, int to, bool russian, int depth, ref StringBuilder sb, ref int copied)
	{
		List<int> list = runStart ?? (runStart = new List<int>(8));
		List<int> list2 = runEnd ?? (runEnd = new List<int>(8));
		List<string> list3 = runText ?? (runText = new List<string>(8));
		list.Clear();
		list2.Clear();
		list3.Clear();
		int length = text.Length;
		int num = from;
		bool flag = false;
		while (num < to)
		{
			if (!IsLatinLetter(text[num]) || (num > 0 && IsWordChar(text[num - 1])))
			{
				num++;
				continue;
			}
			int num2 = num;
			int num3 = num;
			int i = num;
			while (i < to && IsLatinLetter(text[i]) && (i <= num2 || text[i] != 'x' || i + 1 >= to || !IsDigit(text[i + 1])))
			{
				for (; i < to && (IsWordChar(text[i]) || ((text[i] == '\'' || text[i] == '-') && i + 1 < to && IsWordChar(text[i + 1]))); i++)
				{
				}
				num3 = i;
				if (i + 1 < to && (text[i] == ' ' || text[i] == '/') && IsLatinLetter(text[i + 1]))
				{
					i++;
					continue;
				}
				if (i + 3 >= to || text[i] != ' ' || text[i + 1] != '&' || text[i + 2] != ' ' || !IsLatinLetter(text[i + 3]))
				{
					break;
				}
				i += 3;
			}
			if (num3 > num2)
			{
				string text2 = null;
				if (num3 - num2 >= 2 && (num2 != 0 || num3 != length))
				{
					string text3 = text.Substring(num2, num3 - num2);
					text2 = Named(text3) ?? Names(text3);
				}
				if ((list.Count > 0 && OnlyNumber(text, list2[list2.Count - 1], num2)) || (text2 == null && (!russian || !NameLike(text.Substring(num2, num3 - num2), lenient: true))))
				{
					return;
				}
				if (text2 != null)
				{
					int num4 = num2;
					if (num4 > from && text[num4 - 1] == ' ')
					{
						num4--;
					}
					int num5 = num4;
					while (num5 > from && (IsDigit(text[num5 - 1]) || ((text[num5 - 1] == '.' || text[num5 - 1] == ',' || text[num5 - 1] == '\u00a0') && num5 - 1 > from && IsDigit(text[num5 - 2]) && num5 < num4 && IsDigit(text[num5]))))
					{
						num5--;
					}
					if (num5 < num4 && num4 < num2 && (num5 == from || !IsWordChar(text[num5 - 1])) && depth < 6)
					{
						string text4 = text.Substring(num5, num3 - num5);
						string text5 = Sub(text4, depth + 1);
						if (text5 != null && !string.Equals(text5, text4, StringComparison.Ordinal))
						{
							num2 = num5;
							text2 = text5;
						}
					}
				}
				list.Add(num2);
				list2.Add(num3);
				list3.Add(text2);
				if (text2 != null)
				{
					flag = true;
				}
			}
			num = ((num3 > num2) ? num3 : (num2 + 1));
		}
		if (!flag)
		{
			return;
		}
		for (int j = 0; j < list.Count; j++)
		{
			if (list3[j] != null)
			{
				if (sb == null)
				{
					sb = new StringBuilder(length + 16);
				}
				sb.Append(text, copied, list[j] - copied).Append(list3[j]);
				copied = list2[j];
			}
		}
	}

	private static bool OnlyNumber(string text, int from, int to)
	{
		bool result = false;
		for (int i = from; i < to; i++)
		{
			char c = text[i];
			if (IsDigit(c))
			{
				result = true;
			}
			else if (c != ' ' && c != '\u00a0' && ((c != '.' && c != ',') || i <= from || !IsDigit(text[i - 1]) || i + 1 >= to || !IsDigit(text[i + 1])))
			{
				return false;
			}
		}
		return result;
	}

	private static string InForm(string word, int gender, bool inside)
	{
		if (things == null || word.Length < 2 || word.Length > 24 || !kinds.TryGetValue(word.ToUpperInvariant(), out var value))
		{
			return null;
		}
		if (string.Equals(word, word.ToUpperInvariant(), StringComparison.Ordinal))
		{
			return Upper(value[gender]);
		}
		if (!inside)
		{
			return value[gender];
		}
		return LowerFirst(value[gender]);
	}

	private static string Beside(int gender, string word)
	{
		if (gender >= 0)
		{
			return InForm(word, gender, inside: false);
		}
		return null;
	}

	private static bool Worded(StringBuilder sb)
	{
		bool flag = false;
		for (int i = 0; i < sb.Length; i++)
		{
			char c = sb[i];
			switch (c)
			{
			case '<':
				flag = true;
				continue;
			case '>':
				flag = false;
				continue;
			}
			if (!flag && char.IsLetter(c))
			{
				return true;
			}
		}
		return false;
	}

	private static string Named(string text)
	{
		string text2 = Exact(text);
		if (text2 == null)
		{
			if (things == null)
			{
				return null;
			}
			text2 = Built(text);
		}
		return text2;
	}

	private static string Built(string text)
	{
		string[][] array = new string[4][];
		int count;
		string owner;
		bool lower;
		Thing thing = Parse(text, array, out count, out owner, out lower);
		if (thing == null || (count == 0 && owner == null))
		{
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length + 24);
		for (int i = 0; i < count; i++)
		{
			string text2 = array[i][thing.Gender];
			stringBuilder.Append((i == 0) ? text2 : LowerFirst(text2)).Append(' ');
		}
		stringBuilder.Append((count == 0) ? thing.Name : LowerFirst(thing.Name));
		if (owner != null)
		{
			stringBuilder.Append(' ').Append(owner);
		}
		string s = stringBuilder.ToString();
		if (!lower)
		{
			return Upper(s);
		}
		if (text[0] < 'a' || text[0] > 'z')
		{
			return UpperFirst(s);
		}
		return LowerFirst(s);
	}

	private static int Gender(string text)
	{
		int count;
		string owner;
		bool lower;
		return Parse(text, new string[4][], out count, out owner, out lower)?.Gender ?? (-1);
	}

	private static Thing Parse(string text, string[][] found, out int count, out string owner, out bool lower)
	{
		count = 0;
		owner = null;
		lower = false;
		int length = text.Length;
		if (length < 2 || length > 120)
		{
			return null;
		}
		for (int i = 0; i < length; i++)
		{
			char c = text[i];
			switch (c)
			{
			case ' ':
				if (i == 0 || i == length - 1 || text[i - 1] == ' ')
				{
					return null;
				}
				break;
			case 'a':
			case 'b':
			case 'c':
			case 'd':
			case 'e':
			case 'f':
			case 'g':
			case 'h':
			case 'i':
			case 'j':
			case 'k':
			case 'l':
			case 'm':
			case 'n':
			case 'o':
			case 'p':
			case 'q':
			case 'r':
			case 's':
			case 't':
			case 'u':
			case 'v':
			case 'w':
			case 'x':
			case 'y':
			case 'z':
				lower = true;
				break;
			default:
				if ((c < 'A' || c > 'Z') && c != '\'' && c != '-')
				{
					return null;
				}
				break;
			}
		}
		string text2 = (lower ? text.ToUpperInvariant() : text);
		int num = text2.LastIndexOf(" OF THE ", StringComparison.Ordinal);
		if (num > 0 && owners.TryGetValue(text2.Substring(num + 8), out owner))
		{
			text2 = text2.Substring(0, num);
		}
		else
		{
			owner = null;
		}
		return Kinds(text2, 0, found, ref count);
	}

	private static Thing Kinds(string u, int from, string[][] found, ref int count)
	{
		if (things.TryGetValue((from == 0) ? u : u.Substring(from), out var value))
		{
			return value;
		}
		if (count == 4)
		{
			return null;
		}
		int num = from;
		for (int i = 0; i < 3; i++)
		{
			num = u.IndexOf(' ', num + 1);
			if (num < 0)
			{
				break;
			}
			if (kinds.TryGetValue(u.Substring(from, num - from), out var value2))
			{
				found[count++] = value2;
				value = Kinds(u, num + 1, found, ref count);
				if (value != null)
				{
					return value;
				}
				count--;
			}
		}
		return null;
	}

	private static string Names(string run)
	{
		if (run.Length > 120 || run.IndexOf(' ') < 0 || !IsUpperLetter(run[0]))
		{
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder(run.Length + 16);
		int budget = 200;
		if (!NamesFrom(run, 0, stringBuilder, ref budget))
		{
			return null;
		}
		return stringBuilder.ToString();
	}

	private static bool NamesFrom(string run, int from, StringBuilder sb, ref int budget)
	{
		int length = sb.Length;
		for (int num = run.Length; num > from; num--)
		{
			if ((num >= run.Length || (run[num] == ' ' && num + 1 < run.Length && IsUpperLetter(run[num + 1]))) && (from != 0 || num != run.Length))
			{
				if (--budget < 0)
				{
					return false;
				}
				string text = Exact(run.Substring(from, num - from));
				if (text != null)
				{
					if (from > 0)
					{
						sb.Append(' ');
					}
					sb.Append(text);
					if (num == run.Length || NamesFrom(run, num + 1, sb, ref budget))
					{
						return true;
					}
					sb.Length = length;
				}
			}
		}
		return false;
	}

	private static bool IsWordChar(char c)
	{
		if (!IsLatinLetter(c) && (c < '0' || c > '9'))
		{
			return c == '_';
		}
		return true;
	}

	private static bool IsBlank(char c)
	{
		if (c != ' ' && c != '\n' && c != '\r')
		{
			return c == '\t';
		}
		return true;
	}

	private static bool IsLatinLetter(char c)
	{
		if (c < 'a' || c > 'z')
		{
			if (c >= 'A')
			{
				return c <= 'Z';
			}
			return false;
		}
		return true;
	}

	private static string Edge(string text, int depth)
	{
		for (int i = 0; i < suffixes.Length; i++)
		{
			string key = suffixes[i].Key;
			if (text.Length > key.Length && string.CompareOrdinal(text, text.Length - key.Length, key, 0, key.Length) == 0)
			{
				string text2 = text.Substring(0, text.Length - key.Length);
				bool unknown = false;
				string text3 = Piece(text2, depth, ref unknown);
				if (text3 != null || (!unknown && Pattern.Simple(text2) && NameLike(text2, lenient: false)))
				{
					return (text3 ?? text2) + suffixes[i].Value;
				}
			}
		}
		if (!IsLatinLetter(text[text.Length - 1]))
		{
			for (int j = 0; j < suffixes.Length; j++)
			{
				string value = suffixes[j].Value;
				if (value.Length >= 3 && text.Length > value.Length && HasCyrillic(value) && string.CompareOrdinal(text, text.Length - value.Length, value, 0, value.Length) == 0)
				{
					string text4 = Sub(text.Substring(0, text.Length - value.Length), depth + 1);
					if (text4 != null)
					{
						return text4 + value;
					}
				}
			}
		}
		for (int k = 0; k < prefixes.Length; k++)
		{
			string key2 = prefixes[k].Key;
			if (text.Length > key2.Length && string.CompareOrdinal(text, 0, key2, 0, key2.Length) == 0)
			{
				string text5 = text.Substring(key2.Length);
				bool unknown2 = false;
				string text6 = Piece(text5, depth, ref unknown2);
				if (text6 != null || (!unknown2 && Pattern.Simple(text5) && NameLike(text5, lenient: false)))
				{
					return prefixes[k].Value + (text6 ?? text5);
				}
			}
		}
		return null;
	}

	internal static bool NameLike(string v, bool lenient)
	{
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		int num5 = 0;
		bool flag = false;
		bool flag2 = true;
		for (int i = 0; i < v.Length; i++)
		{
			char c = v[i];
			switch (c)
			{
			case '\n':
				return false;
			case '<':
			{
				int num6 = v.IndexOf('>', i);
				if (num6 > i && num6 - i <= 40)
				{
					i = num6;
					flag = false;
					continue;
				}
				break;
			}
			}
			num3++;
			switch (c)
			{
			case '(':
				num4++;
				break;
			case ')':
				if (--num4 < 0)
				{
					return false;
				}
				break;
			case '[':
				num5++;
				break;
			case ']':
				if (--num5 < 0)
				{
					return false;
				}
				break;
			}
			bool flag3 = IsLatinLetter(c);
			if (flag3 || (c >= '0' && c <= '9') || c == '\'' || c == '_')
			{
				if (flag)
				{
					continue;
				}
				flag = true;
				num2++;
				if (!flag3)
				{
					continue;
				}
				num++;
				if (c < 'A' || c > 'Z')
				{
					int j;
					for (j = 1; i + j < v.Length && IsLatinLetter(v[i + j]); j++)
					{
					}
					if (num == 1 || j >= 4)
					{
						flag2 = false;
					}
				}
			}
			else
			{
				flag = false;
			}
		}
		if (num4 != 0 || num5 != 0)
		{
			return false;
		}
		if (num == 0)
		{
			return true;
		}
		if (num3 > 60)
		{
			return false;
		}
		if (lenient && num2 == 1)
		{
			return true;
		}
		if (flag2)
		{
			return num <= 4;
		}
		return false;
	}

	private static string Parts(string text, string sep, int mode, int depth)
	{
		int num = text.IndexOf(sep, StringComparison.Ordinal);
		if (num < 0)
		{
			return null;
		}
		StringBuilder stringBuilder = null;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		int num5 = 0;
		string text2 = null;
		while (true)
		{
			int num6 = ((num < 0) ? text.Length : num);
			string text3 = text.Substring(num2, num6 - num2);
			bool unknown = false;
			string text4 = ((mode == 1 && text2 != null) ? Beside(Gender(text2), text3) : null) ?? Piece(text3, depth, ref unknown);
			text2 = text3;
			if (unknown)
			{
				return null;
			}
			if (text4 != null)
			{
				num4++;
			}
			else if (mode != 0 && HasLatin(text3))
			{
				if (mode == 3 && num3 == 0)
				{
					return null;
				}
				if (!NameLike(text3, lenient: false))
				{
					if (mode != 1)
					{
						return null;
					}
					num5++;
				}
			}
			if (stringBuilder == null)
			{
				stringBuilder = new StringBuilder(text.Length + 16);
			}
			stringBuilder.Append(text4 ?? text3);
			if (num < 0)
			{
				break;
			}
			stringBuilder.Append(sep);
			num2 = num + sep.Length;
			num3++;
			num = ((mode == 3) ? (-1) : text.IndexOf(sep, num2, StringComparison.Ordinal));
		}
		if (num4 <= 0 || num4 < num5)
		{
			return null;
		}
		return stringBuilder.ToString();
	}

	private static string Sentences(string text, int depth)
	{
		StringBuilder stringBuilder = null;
		int num = 0;
		int num2 = 0;
		for (int i = 0; i + 2 < text.Length; i++)
		{
			char c = text[i];
			if ((c != '.' && c != '!' && c != '?') || text[i + 1] != ' ')
			{
				continue;
			}
			char c2 = text[i + 2];
			if (c2 < 'A' || c2 > 'Z')
			{
				switch (c2)
				{
				case '(':
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
				case '<':
				case '[':
					break;
				default:
					continue;
				}
			}
			string text2 = text.Substring(num, i + 1 - num);
			string text3 = Sub(text2, depth + 1);
			if (text3 == null && HasLatin(text2))
			{
				return null;
			}
			if (stringBuilder == null)
			{
				stringBuilder = new StringBuilder(text.Length + 16);
			}
			stringBuilder.Append(text3 ?? text2).Append(' ');
			num = i + 2;
			num2++;
		}
		if (num2 == 0)
		{
			return null;
		}
		string text4 = text.Substring(num);
		string text5 = Sub(text4, depth + 1);
		if (text5 == null && HasLatin(text4))
		{
			return null;
		}
		return stringBuilder.Append(text5 ?? text4).ToString();
	}

	private static string Runs(string text, int depth)
	{
		int num = text.IndexOf('<');
		if (num < 0)
		{
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length + 16);
		int num2 = 0;
		int num3 = num;
		int num4 = 0;
		bool flag = false;
		bool unknown = false;
		int gender = -1;
		while (num3 >= 0 && num3 < text.Length)
		{
			int num5 = text.IndexOf('>', num3);
			if (num5 <= num3 || num5 - num3 > 40 || num3 + 1 >= text.Length || (text[num3 + 1] != '/' && (text[num3 + 1] < 'a' || text[num3 + 1] > 'z') && (text[num3 + 1] < 'A' || text[num3 + 1] > 'Z')) || text.IndexOf('<', num3 + 1, num5 - num3 - 1) >= 0)
			{
				num3 = text.IndexOf('<', num3 + 1);
				continue;
			}
			if (num3 > num2)
			{
				string text2 = text.Substring(num2, num3 - num2);
				string text3 = Beside(gender, text2) ?? Piece(text2, depth, ref unknown);
				if (unknown)
				{
					return null;
				}
				if (things != null && text2.Length <= 120 && IsLatinLetter(text2[0]))
				{
					int num6 = Gender(text2);
					if (num6 >= 0)
					{
						gender = num6;
					}
				}
				if (text3 != null)
				{
					flag = true;
				}
				stringBuilder.Append(text3 ?? text2);
			}
			stringBuilder.Append(text, num3, num5 - num3 + 1);
			num4++;
			num2 = num5 + 1;
			num3 = text.IndexOf('<', num2);
		}
		if (num4 == 0)
		{
			return null;
		}
		if (num2 < text.Length)
		{
			string text4 = text.Substring(num2);
			string text5 = Beside(gender, text4) ?? Piece(text4, depth, ref unknown);
			if (unknown)
			{
				return null;
			}
			if (text5 != null)
			{
				flag = true;
			}
			stringBuilder.Append(text5 ?? text4);
		}
		if (!flag)
		{
			return null;
		}
		return stringBuilder.ToString();
	}

	private static string Peel(string text, int depth)
	{
		int i = 0;
		int num = text.Length;
		if (num > 2 && text[0] == '>' && text[1] == ' ')
		{
			i = 2;
		}
		for (; i < num && Peelable(text[i]); i++)
		{
		}
		while (num > i && Peelable(text[num - 1]))
		{
			num--;
		}
		int num2 = 0;
		for (int j = i; j < num; j++)
		{
			if (text[j] == '(')
			{
				num2++;
			}
			else if (text[j] == ')' && num2 > 0)
			{
				num2--;
			}
		}
		while (num2 > 0 && num < text.Length && text[num] == ')')
		{
			num++;
			num2--;
		}
		if (text.Length > 5 && text[0] == 'x' && text[1] >= '0' && text[1] <= '9')
		{
			int k;
			for (k = 2; k < text.Length && k < 5 && text[k] >= '0' && text[k] <= '9'; k++)
			{
			}
			if (k + 2 < text.Length && text[k] == ':' && text[k + 1] == ' ')
			{
				string text2 = Sub(text.Substring(k + 2), depth + 1);
				if (text2 != null)
				{
					return text.Substring(0, k + 2) + text2;
				}
			}
		}
		if (text.Length > 5 && text[0] == '[')
		{
			int num3 = text.IndexOf(']');
			if (num3 > 1 && num3 <= 14 && num3 + 2 < text.Length && text[num3 + 1] == ' ')
			{
				string text3 = Sub(text.Substring(num3 + 2), depth + 1);
				if (text3 != null)
				{
					return text.Substring(0, num3 + 2) + text3;
				}
			}
		}
		if ((i == 0 && num == text.Length) || num - i < 2)
		{
			return null;
		}
		string text4 = Sub(text.Substring(i, num - i), depth + 1);
		if (text4 != null)
		{
			return text.Substring(0, i) + text4 + text.Substring(num);
		}
		int length = text.Length;
		if (i == 0 && length - num >= 2 && (text[length - 1] == '.' || text[length - 1] == '!' || text[length - 1] == '?' || text[length - 1] == ':' || text[length - 1] == ',') && (text[length - 2] == ')' || text[length - 2] == ']'))
		{
			text4 = Sub(text.Substring(0, length - 1), depth + 1);
			if (text4 != null)
			{
				return text4 + text.Substring(length - 1);
			}
		}
		return null;
	}

	private static bool Peelable(char c)
	{
		if (c <= ' ')
		{
			return true;
		}
		if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<' || c == '>' || c == '{' || c == '}' || c == '%')
		{
			return false;
		}
		if (c < '\u0080')
		{
			return true;
		}
		if ((c >= '←' && c <= '⇿') || (c >= '■' && c <= '◿') || (c >= '☀' && c <= '➿'))
		{
			return true;
		}
		if (c != '•' && c != '·' && c != '…' && c != '–' && c != '—' && c != '×' && c != '‘' && c != '’' && c != '“' && c != '”' && c != '‹' && c != '›')
		{
			return c == '\u00a0';
		}
		return true;
	}

	private static string ByCase(string text)
	{
		if (text.Length > 120)
		{
			return null;
		}
		string text2 = text.ToUpperInvariant();
		if (!upper.TryGetValue(text2, out var value))
		{
			return null;
		}
		if (string.Equals(text, text2, StringComparison.Ordinal))
		{
			return Upper(value.Value);
		}
		bool flag = string.Equals(value.Key, text2, StringComparison.Ordinal);
		if (string.Equals(text, text.ToLowerInvariant(), StringComparison.Ordinal))
		{
			if (!flag)
			{
				return LowerFirst(value.Value);
			}
			return Lower(value.Value);
		}
		if (flag)
		{
			return Sentence(value.Value);
		}
		if (char.IsUpper(text[0]) && char.IsLower(value.Key[0]))
		{
			return UpperFirst(value.Value);
		}
		return value.Value;
	}

	private static string LowerFirst(string s)
	{
		if (s.Length == 0)
		{
			return s;
		}
		if (s.Length > 1 && IsUpperLetter(s[1]))
		{
			return s;
		}
		return Lower(s.Substring(0, 1)) + s.Substring(1);
	}

	private static string UpperFirst(string s)
	{
		for (int i = 0; i < s.Length; i++)
		{
			char c = s[i];
			if (c == '<')
			{
				int num = s.IndexOf('>', i);
				if (num > i && num - i <= 40)
				{
					i = num;
					continue;
				}
			}
			if (char.IsLetter(c))
			{
				return s.Substring(0, i) + Upper(s.Substring(i, 1)) + s.Substring(i + 1);
			}
			if (char.IsDigit(c))
			{
				return s;
			}
		}
		return s;
	}

	private static string Sentence(string s)
	{
		if (s.Length == 0)
		{
			return s;
		}
		return Upper(s.Substring(0, 1)) + Lower(s.Substring(1));
	}

	private static bool IsUpperLetter(char c)
	{
		if ((c < 'A' || c > 'Z') && (c < 'А' || c > 'Я'))
		{
			return c == 'Ё';
		}
		return true;
	}

	private static string Lower(string s)
	{
		char[] array = s.ToLowerInvariant().ToCharArray();
		for (int i = 0; i < array.Length; i++)
		{
			char c = array[i];
			if (c >= 'А' && c <= 'Я')
			{
				array[i] = (char)(c + 32);
			}
			else if (c >= 'Ѐ' && c <= 'Џ')
			{
				array[i] = (char)(c + 80);
			}
		}
		return new string(array);
	}

	private static string Try(Pattern[] bucket, string text, int depth)
	{
		for (int i = 0; i < bucket.Length; i++)
		{
			string text2 = bucket[i].Apply(text, depth);
			if (text2 != null)
			{
				return text2;
			}
		}
		return null;
	}

	private static string Upper(string s)
	{
		char[] array = s.ToUpperInvariant().ToCharArray();
		for (int i = 0; i < array.Length; i++)
		{
			char c = array[i];
			if (c >= 'а' && c <= 'я')
			{
				array[i] = (char)(c - 32);
			}
			else if (c >= 'ѐ' && c <= 'џ')
			{
				array[i] = (char)(c - 80);
			}
		}
		return new string(array);
	}

	private static bool HasCyrillic(string s)
	{
		for (int i = 0; i < s.Length; i++)
		{
			if (s[i] >= 'Ѐ' && s[i] <= 'ӿ')
			{
				return true;
			}
		}
		return false;
	}

	private static bool HasLatin(string s)
	{
		foreach (char c in s)
		{
			if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
			{
				return true;
			}
		}
		return false;
	}

	private static void Init()
	{
		if (ready)
		{
			return;
		}
		lock (Gate)
		{
			if (!ready)
			{
				try
				{
					Load();
				}
				catch
				{
				}
				ready = true;
			}
		}
	}

	private static void Load()
	{
		string text = null;
		try
		{
			text = Path.GetDirectoryName(typeof(Loc).Assembly.Location);
		}
		catch
		{
		}
		if (string.IsNullOrEmpty(text))
		{
			return;
		}
		string text2 = FindConfigPath(text);
		Settings settings = ((text2 == null) ? new Settings() : Settings.Load(Path.Combine(text2, "RepoRPG_RU.cfg"), createIfMissing: false));
		if (!settings.Enabled || !settings.DisplayHooks)
		{
			return;
		}
		Lang lang = Lang.Load(text);
		Dictionary<string, string> dictionary = new Dictionary<string, string>(lang.Global.Count + lang.Terms.Count, StringComparer.Ordinal);
		foreach (KeyValuePair<string, string> item in lang.Global)
		{
			dictionary[item.Key] = item.Value;
		}
		foreach (KeyValuePair<string, string> term in lang.Terms)
		{
			dictionary[term.Key] = term.Value;
		}
		int num = int.MaxValue;
		int num2 = -1;
		foreach (string key2 in dictionary.Keys)
		{
			if (key2.Length < num)
			{
				num = key2.Length;
			}
			if (key2.Length > num2)
			{
				num2 = key2.Length;
			}
		}
		Dictionary<string, CaseEntry> dictionary2 = new Dictionary<string, CaseEntry>(dictionary.Count, StringComparer.Ordinal);
		foreach (KeyValuePair<string, string> item2 in dictionary)
		{
			if (item2.Key.Length > 120 || item2.Key.IndexOf('{') >= 0)
			{
				continue;
			}
			string text3 = item2.Key.ToUpperInvariant();
			if (dictionary2.TryGetValue(text3, out var value))
			{
				bool num3 = !string.Equals(value.Key, text3, StringComparison.Ordinal) && !string.Equals(value.Key, value.Key.ToLowerInvariant(), StringComparison.Ordinal);
				bool flag = !string.Equals(item2.Key, text3, StringComparison.Ordinal) && !string.Equals(item2.Key, item2.Key.ToLowerInvariant(), StringComparison.Ordinal);
				if (num3 || !flag)
				{
					continue;
				}
			}
			CaseEntry caseEntry = new CaseEntry();
			caseEntry.Key = item2.Key;
			caseEntry.Value = item2.Value;
			dictionary2[text3] = caseEntry;
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		List<KeyValuePair<string, string>> list2 = new List<KeyValuePair<string, string>>();
		foreach (KeyValuePair<string, string> item3 in dictionary)
		{
			string key = item3.Key;
			if (key.Length >= 3 && key.Length <= 60 && key.IndexOf('{') < 0 && HasLatin(key))
			{
				if (key[key.Length - 1] == ' ')
				{
					list.Add(item3);
				}
				else if (key[0] == ' ' || key[0] == ',')
				{
					list2.Add(item3);
				}
			}
		}
		Comparison<KeyValuePair<string, string>> comparison = delegate(KeyValuePair<string, string> a, KeyValuePair<string, string> b)
		{
			int num8 = b.Key.Length.CompareTo(a.Key.Length);
			return (num8 == 0) ? string.CompareOrdinal(a.Key, b.Key) : num8;
		};
		list.Sort(comparison);
		list2.Sort(comparison);
		List<Pattern> list3 = new List<Pattern>();
		foreach (KeyValuePair<string, string> pattern3 in lang.Patterns)
		{
			lang.Numbers.TryGetValue(pattern3.Key, out var value2);
			lang.Words.TryGetValue(pattern3.Key, out var value3);
			lang.WordForms.TryGetValue(pattern3.Key, out var value4);
			Pattern pattern = Pattern.Parse(pattern3.Key, pattern3.Value, explicitPattern: true, value2, value3, value4);
			if (pattern != null)
			{
				list3.Add(pattern);
			}
		}
		foreach (KeyValuePair<string, string> item4 in dictionary)
		{
			if (item4.Key.IndexOf('{') >= 0 && !lang.Patterns.ContainsKey(item4.Key))
			{
				lang.Numbers.TryGetValue(item4.Key, out var value5);
				lang.Words.TryGetValue(item4.Key, out var value6);
				lang.WordForms.TryGetValue(item4.Key, out var value7);
				Pattern pattern2 = Pattern.Parse(item4.Key, item4.Value, explicitPattern: false, value5, value6, value7);
				if (pattern2 != null)
				{
					list3.Add(pattern2);
				}
			}
		}
		list3.Sort(delegate(Pattern a, Pattern b)
		{
			int num8 = b.Weight.CompareTo(a.Weight);
			return (num8 == 0) ? string.CompareOrdinal(a.Template, b.Template) : num8;
		});
		Dictionary<string, List<Pattern>> table = new Dictionary<string, List<Pattern>>(StringComparer.Ordinal);
		Dictionary<string, List<Pattern>> table2 = new Dictionary<string, List<Pattern>>(StringComparer.Ordinal);
		List<Pattern> list4 = new List<Pattern>();
		foreach (Pattern item5 in list3)
		{
			string text4 = item5.Lits[0];
			string text5 = item5.Lits[item5.Lits.Length - 1];
			if (text4.Length >= 2)
			{
				Bucket(table, text4.Substring(0, 2), item5);
			}
			else if (text5.Length >= 2)
			{
				Bucket(table2, text5.Substring(text5.Length - 2), item5);
			}
			else
			{
				list4.Add(item5);
			}
		}
		Dictionary<string, string> dictionary3 = null;
		if (lang.Shapes.Count > 0)
		{
			dictionary3 = new Dictionary<string, string>(lang.Shapes.Count, StringComparer.Ordinal);
			foreach (KeyValuePair<string, string> shape in lang.Shapes)
			{
				StringBuilder stringBuilder = new StringBuilder(shape.Key.Length);
				bool flag2 = true;
				for (int num4 = 0; num4 < shape.Key.Length && flag2; num4++)
				{
					char c = shape.Key[num4];
					if (c != '{')
					{
						stringBuilder.Append(c);
						continue;
					}
					int num5 = shape.Key.IndexOf('}', num4);
					if (num5 < 0 || Fmt.FormatIndex(shape.Key.Substring(num4, num5 - num4 + 1)) < 0)
					{
						flag2 = false;
						break;
					}
					stringBuilder.Append('\u0001');
					num4 = num5;
				}
				if (flag2)
				{
					dictionary3[stringBuilder.ToString()] = shape.Value;
				}
			}
		}
		Dictionary<string, string[]> dictionary4 = null;
		Dictionary<string, Thing> dictionary5 = null;
		Dictionary<string, string> dictionary6 = null;
		if (lang.Nouns.Count > 0)
		{
			dictionary4 = new Dictionary<string, string[]>(lang.Adjectives.Count, StringComparer.Ordinal);
			foreach (KeyValuePair<string, string[]> adjective in lang.Adjectives)
			{
				dictionary4[adjective.Key.ToUpperInvariant()] = adjective.Value;
			}
			dictionary6 = new Dictionary<string, string>(lang.Owners.Count, StringComparer.Ordinal);
			foreach (KeyValuePair<string, string> owner in lang.Owners)
			{
				dictionary6[owner.Key.ToUpperInvariant()] = owner.Value;
			}
			dictionary5 = new Dictionary<string, Thing>(lang.Nouns.Count, StringComparer.Ordinal);
			foreach (KeyValuePair<string, string> noun in lang.Nouns)
			{
				Thing thing = new Thing();
				thing.Gender = "mfnp".IndexOf(noun.Value[0]);
				int num6 = noun.Value.IndexOf('|');
				if (num6 > 0)
				{
					thing.Name = noun.Value.Substring(num6 + 1);
				}
				else if (!dictionary.TryGetValue(noun.Key, out thing.Name))
				{
					continue;
				}
				if (thing.Gender >= 0 && !string.IsNullOrEmpty(thing.Name))
				{
					dictionary5[noun.Key.ToUpperInvariant()] = thing;
				}
			}
			if (dictionary5.Count == 0)
			{
				dictionary5 = null;
			}
		}
		minLength = num;
		maxLength = num2;
		kinds = dictionary4;
		owners = dictionary6;
		things = dictionary5;
		shapes = dictionary3;
		upper = dictionary2;
		prefixes = list.ToArray();
		suffixes = list2.ToArray();
		byHead = Freeze(table);
		byTail = Freeze(table2);
		loose = list4.ToArray();
		memo = new Dictionary<string, string>(StringComparer.Ordinal);
		map = dictionary;
		fallbacks = dictionary.Count > 0;
		if (!settings.LogUntranslated || text2 == null)
		{
			return;
		}
		string text6 = Path.Combine(text2, "RepoRPG_RU");
		Directory.CreateDirectory(text6);
		logPath = Path.Combine(text6, "untranslated.txt");
		seen = new HashSet<string>(StringComparer.Ordinal);
		pending = new List<string>();
		try
		{
			if (File.Exists(logPath))
			{
				string[] array = File.ReadAllLines(logPath, Encoding.UTF8);
				foreach (string text7 in array)
				{
					if (text7.Length > 0)
					{
						seen.Add(text7);
					}
				}
			}
		}
		catch
		{
		}
		nextFlush = Environment.TickCount;
		try
		{
			AppDomain.CurrentDomain.ProcessExit += delegate
			{
				Flush();
			};
		}
		catch
		{
		}
		logging = true;
	}

	private static void Bucket(Dictionary<string, List<Pattern>> table, string key, Pattern p)
	{
		if (!table.TryGetValue(key, out var value))
		{
			value = (table[key] = new List<Pattern>());
		}
		value.Add(p);
	}

	private static Dictionary<string, Pattern[]> Freeze(Dictionary<string, List<Pattern>> table)
	{
		Dictionary<string, Pattern[]> dictionary = new Dictionary<string, Pattern[]>(table.Count, StringComparer.Ordinal);
		foreach (KeyValuePair<string, List<Pattern>> item in table)
		{
			dictionary[item.Key] = item.Value.ToArray();
		}
		return dictionary;
	}

	internal static string FindConfigPath(string home)
	{
		try
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (assembly.GetName().Name != "BepInEx")
				{
					continue;
				}
				Type type = assembly.GetType("BepInEx.Paths", throwOnError: false);
				if (type == null)
				{
					continue;
				}
				PropertyInfo property = type.GetProperty("ConfigPath", BindingFlags.Static | BindingFlags.Public);
				if (!(property == null))
				{
					string text = property.GetValue(null, null) as string;
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
			}
		}
		catch
		{
		}
		try
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(home);
			int num = 0;
			while (num < 6 && directoryInfo != null)
			{
				string text2 = Path.Combine(directoryInfo.FullName, "config");
				if (string.Equals(directoryInfo.Name, "BepInEx", StringComparison.OrdinalIgnoreCase) && Directory.Exists(text2))
				{
					return text2;
				}
				num++;
				directoryInfo = directoryInfo.Parent;
			}
		}
		catch
		{
		}
		return null;
	}

	private static bool Leftover(string s)
	{
		bool flag = false;
		int num = 0;
		int num2 = 0;
		for (int i = 0; i < s.Length; i++)
		{
			char c = s[i];
			if (c >= 'Ѐ' && c <= 'ӿ')
			{
				flag = true;
				num = 0;
				continue;
			}
			if (c == '<')
			{
				int num3 = s.IndexOf('>', i);
				if (num3 > i && num3 - i < 24)
				{
					i = num3;
					num = 0;
					continue;
				}
			}
			if (c >= 'a' && c <= 'z')
			{
				if (num > 0 || i == 0 || !IsLatinLetter(s[i - 1]))
				{
					num++;
				}
				if (num > num2)
				{
					num2 = num;
				}
			}
			else
			{
				num = 0;
			}
		}
		if (flag)
		{
			return num2 >= 4;
		}
		return false;
	}

	private static void Note(string text)
	{
		try
		{
			if (text != null && seen.Count < 4000 && text.Length <= 400)
			{
				string item = Flatten(text);
				if (seen.Add(item))
				{
					pending.Add(item);
				}
			}
			if (pending.Count != 0)
			{
				int tickCount = Environment.TickCount;
				if (tickCount - nextFlush >= 0)
				{
					nextFlush = tickCount + 3000;
					Flush();
				}
			}
		}
		catch
		{
			logging = false;
		}
	}

	private static void Flush()
	{
		try
		{
			lock (Gate)
			{
				if (pending != null && pending.Count != 0)
				{
					File.AppendAllText(logPath, string.Join("\n", pending.ToArray()) + "\n", new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
					pending.Clear();
				}
			}
		}
		catch
		{
			logging = false;
		}
	}

	private static bool LooksEnglish(string s)
	{
		int num = 0;
		int num2 = 0;
		for (int i = 0; i < s.Length; i++)
		{
			char c = s[i];
			if (c >= 'Ѐ' && c <= 'ӿ')
			{
				return false;
			}
			if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
			{
				num++;
				if (num > num2)
				{
					num2 = num;
				}
			}
			else if (c == '<')
			{
				int num3 = s.IndexOf('>', i);
				if (num3 > i && num3 - i < 24)
				{
					i = num3;
				}
				num = 0;
			}
			else
			{
				num = 0;
			}
		}
		return num2 >= 3;
	}

	private static string Flatten(string s)
	{
		if (s.IndexOf('\n') < 0 && s.IndexOf('\r') < 0 && s.IndexOf('\\') < 0)
		{
			return s;
		}
		return s.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n");
	}
}
internal sealed class Lang
{
	public readonly Dictionary<string, string> Global = new Dictionary<string, string>(StringComparer.Ordinal);

	public readonly Dictionary<string, Dictionary<string, string>> Scoped = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal);

	public readonly Dictionary<string, Dictionary<string, List<string>>> Sentences = new Dictionary<string, Dictionary<string, List<string>>>(StringComparer.Ordinal);

	public readonly Dictionary<string, HashSet<string>> Unsafe = new Dictionary<string, HashSet<string>>(StringComparer.Ordinal);

	public readonly Dictionary<string, string> Terms = new Dictionary<string, string>(StringComparer.Ordinal);

	public readonly Dictionary<string, int[]> Numbers = new Dictionary<string, int[]>(StringComparer.Ordinal);

	public readonly Dictionary<string, int[]> Words = new Dictionary<string, int[]>(StringComparer.Ordinal);

	public readonly Dictionary<string, int[]> WordForms = new Dictionary<string, int[]>(StringComparer.Ordinal);

	public readonly Dictionary<string, string> Patterns = new Dictionary<string, string>(StringComparer.Ordinal);

	public readonly Dictionary<string, Dictionary<string, string>> Data = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal);

	public readonly Dictionary<string, string> Shapes = new Dictionary<string, string>(StringComparer.Ordinal);

	public readonly Dictionary<string, string[]> Adjectives = new Dictionary<string, string[]>(StringComparer.Ordinal);

	public readonly Dictionary<string, string> Nouns = new Dictionary<string, string>(StringComparer.Ordinal);

	public readonly Dictionary<string, string> Owners = new Dictionary<string, string>(StringComparer.Ordinal);

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

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

	public int Entries;

	public int Rejected;

	public ulong Fingerprint = 14695981039346656037uL;

	public static Lang Load(string dir)
	{
		Lang lang = new Lang();
		if (string.IsNullOrEmpty(dir) || !Directory.Exists(dir))
		{
			return lang;
		}
		string[] files = Directory.GetFiles(dir, "*.po", SearchOption.AllDirectories);
		Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
		string[] array = files;
		foreach (string text in array)
		{
			try
			{
				byte[] array2 = File.ReadAllBytes(text);
				lang.Fingerprint = Hash.Fnv(lang.Fingerprint, Path.GetFileName(text));
				lang.Fingerprint = Hash.Fnv(lang.Fingerprint, array2);
				lang.Files.Add(text);
				List<PoEntry> list = new List<PoEntry>();
				Po.Parse(Encoding.UTF8.GetString(array2), Path.GetFileName(text), list, lang.Problems);
				foreach (PoEntry item in list)
				{
					lang.Add(item);
				}
			}
			catch (Exception ex)
			{
				lang.Problems.Add(Path.GetFileName(text) + ": " + ex.Message);
			}
		}
		return lang;
	}

	private void Add(PoEntry e)
	{
		if (e.Ctx == "numbers" || e.Ctx == "words")
		{
			List<int> list = new List<int>();
			List<int> list2 = new List<int>();
			bool flag = false;
			string[] array = e.Str.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				int num = -1;
				if (e.Ctx == "words" && text.Length > 1)
				{
					num = "mfnpMFNP".IndexOf(text[text.Length - 1]);
					if (num >= 0)
					{
						text = text.Substring(0, text.Length - 1);
					}
				}
				if (int.TryParse(text, out var result) && result >= 0)
				{
					list.Add(result);
					list2.Add(num);
					if (num >= 0)
					{
						flag = true;
					}
				}
			}
			if (list.Count > 0)
			{
				((e.Ctx == "numbers") ? Numbers : Words)[e.Id] = list.ToArray();
				if (flag)
				{
					WordForms[e.Id] = list2.ToArray();
				}
			}
			return;
		}
		if ((e.Ctx != null && (e.Ctx == "data" || e.Ctx.StartsWith("data:", StringComparison.Ordinal))) ? (!Fmt.SameTokens(e.Id, e.Str)) : (!Fmt.SameHoles(e.Id, e.Str)))
		{
			Rejected++;
			Problems.Add(e.File + ":" + e.Line + ": {placeholders} differ from the original, entry ignored");
			return;
		}
		Entries++;
		if (e.Ctx == "shape")
		{
			Shapes[e.Id] = e.Str;
		}
		else if (e.Ctx == null)
		{
			Global[e.Id] = e.Str;
		}
		else if (e.Ctx == "term")
		{
			Terms[e.Id] = e.Str;
		}
		else if (e.Ctx == "adj" || e.Ctx == "noun" || e.Ctx == "of")
		{
			string[] array2 = e.Str.Split(new char[1] { '|' });
			bool flag2 = e.Id.Trim().Length > 0;
			string[] array = array2;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].Trim().Length == 0)
				{
					flag2 = false;
				}
			}
			if (!((e.Ctx == "adj") ? (flag2 && array2.Length == 4) : ((!(e.Ctx == "noun")) ? (flag2 && array2.Length == 1) : (flag2 && array2.Length <= 2 && array2[0].Length == 1 && "mfnp".IndexOf(array2[0][0]) >= 0))))
			{
				Entries--;
				Rejected++;
				Problems.Add(e.File + ":" + e.Line + ": " + ((e.Ctx == "adj") ? "an adjective needs four forms (m|f|n|p)" : ((e.Ctx == "noun") ? "a noun needs its gender (m, f, n or p)" : "one word form expected")) + ", entry ignored");
			}
			else if (e.Ctx == "adj")
			{
				Adjectives[e.Id] = array2;
			}
			else if (e.Ctx == "noun")
			{
				Nouns[e.Id] = e.Str;
			}
			else
			{
				Owners[e.Id] = e.Str;
			}
		}
		else if (e.Ctx == "pattern")
		{
			bool flag3 = false;
			foreach (string item in Fmt.Holes(e.Id))
			{
				if (Fmt.FormatIndex(item) >= 0)
				{
					flag3 = true;
				}
			}
			if (!flag3)
			{
				Entries--;
				Rejected++;
				Problems.Add(e.File + ":" + e.Line + ": a pattern needs at least one {0} placeholder, entry ignored");
			}
			else
			{
				Patterns[e.Id] = e.Str;
			}
		}
		else if (e.Ctx[0] == '@')
		{
			string text2 = e.Ctx.Substring(1).Trim();
			int num2 = text2.LastIndexOf('#');
			if (num2 > 0)
			{
				string key = text2.Substring(num2 + 1).Trim();
				text2 = text2.Substring(0, num2).Trim();
				if (!Sentences.TryGetValue(text2, out var value))
				{
					value = new Dictionary<string, List<string>>(StringComparer.Ordinal);
					Sentences[text2] = value;
				}
				if (!value.TryGetValue(key, out var value2))
				{
					value2 = (value[key] = new List<string>());
				}
				value2.Add(e.Id);
			}
			if (Scoped.TryGetValue(text2, out var value3) && value3.TryGetValue(e.Id, out var value4) && !string.Equals(value4, e.Str, StringComparison.Ordinal))
			{
				if (!Unsafe.TryGetValue(text2, out var value5))
				{
					value5 = new HashSet<string>(StringComparer.Ordinal);
					Unsafe[text2] = value5;
				}
				value5.Add(e.Id);
				Problems.Add(e.File + ":" + e.Line + ": two different translations of one text inside " + text2 + ", it stays untouched in the code");
			}
			else
			{
				Put(Scoped, text2, e);
			}
		}
		else if (e.Ctx == "data")
		{
			Put(Data, "", e);
		}
		else if (e.Ctx.StartsWith("data:", StringComparison.Ordinal))
		{
			Put(Data, e.Ctx.Substring(5).Trim(), e);
		}
		else
		{
			Entries--;
			Rejected++;
			Problems.Add(e.File + ":" + e.Line + ": unknown msgctxt \"" + e.Ctx + "\", entry ignored");
		}
	}

	private static void Put(Dictionary<string, Dictionary<string, string>> table, string key, PoEntry e)
	{
		if (!table.TryGetValue(key, out var value))
		{
			value = (table[key] = new Dictionary<string, string>(StringComparer.Ordinal));
		}
		value[e.Id] = e.Str;
	}
}
internal sealed class PoEntry
{
	public string Ctx;

	public string Id;

	public string Str;

	public string File;

	public int Line;
}
internal static class Po
{
	public static void Parse(string text, string file, List<PoEntry> output, List<string> problems)
	{
		string ctx = null;
		string id = null;
		string str = null;
		int num = 0;
		int line = 0;
		int num2 = 0;
		int num3 = 0;
		int length = text.Length;
		while (num3 <= length)
		{
			int num4 = text.IndexOf('\n', num3);
			if (num4 < 0)
			{
				num4 = length;
			}
			string text2 = text.Substring(num3, num4 - num3).Trim();
			num3 = num4 + 1;
			num2++;
			if (num2 == 1 && text2.Length > 0 && text2[0] == '\ufeff')
			{
				text2 = text2.Substring(1).Trim();
			}
			if (text2.Length == 0)
			{
				Flush(ref ctx, ref id, ref str, file, line, output);
				num = 0;
			}
			else
			{
				if (text2[0] == '#')
				{
					continue;
				}
				if (text2[0] == '"')
				{
					string text3 = Unquote(text2, file, num2, problems);
					switch (num)
					{
					case 1:
						ctx += text3;
						break;
					case 2:
						id += text3;
						break;
					case 3:
						str += text3;
						break;
					}
				}
				else if (text2.StartsWith("msgctxt", StringComparison.Ordinal))
				{
					if (num == 3)
					{
						Flush(ref ctx, ref id, ref str, file, line, output);
					}
					ctx = Unquote(text2, file, num2, problems);
					num = 1;
					line = num2;
				}
				else if (text2.StartsWith("msgid_plural", StringComparison.Ordinal))
				{
					num = 0;
				}
				else if (text2.StartsWith("msgid", StringComparison.Ordinal))
				{
					if (num == 3)
					{
						Flush(ref ctx, ref id, ref str, file, line, output);
					}
					id = Unquote(text2, file, num2, problems);
					if (num != 1)
					{
						line = num2;
					}
					num = 2;
				}
				else if (text2.StartsWith("msgstr[", StringComparison.Ordinal))
				{
					if (text2.StartsWith("msgstr[0]", StringComparison.Ordinal))
					{
						str = Unquote(text2, file, num2, problems);
						num = 3;
					}
					else
					{
						num = 0;
					}
				}
				else if (text2.StartsWith("msgstr", StringComparison.Ordinal))
				{
					str = Unquote(text2, file, num2, problems);
					num = 3;
				}
				else
				{
					problems?.Add(file + ":" + num2 + ": unrecognised line");
					num = 0;
				}
			}
		}
		Flush(ref ctx, ref id, ref str, file, line, output);
	}

	private static void Flush(ref string ctx, ref string id, ref string str, string file, int line, List<PoEntry> output)
	{
		if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(str))
		{
			PoEntry poEntry = new PoEntry();
			poEntry.Ctx = (string.IsNullOrEmpty(ctx) ? null : ctx);
			poEntry.Id = id;
			poEntry.Str = str;
			poEntry.File = file;
			poEntry.Line = line;
			output.Add(poEntry);
		}
		ctx = null;
		id = null;
		str = null;
	}

	private static string Unquote(string line, string file, int n, List<string> problems)
	{
		int num = line.IndexOf('"');
		int num2 = line.LastIndexOf('"');
		if (num < 0 || num2 <= num)
		{
			problems?.Add(file + ":" + n + ": missing quotes");
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder(num2 - num);
		for (int i = num + 1; i < num2; i++)
		{
			char c = line[i];
			if (c != '\\' || i + 1 >= num2)
			{
				stringBuilder.Append(c);
				continue;
			}
			char c2 = line[++i];
			switch (c2)
			{
			case 'n':
				stringBuilder.Append('\n');
				break;
			case 't':
				stringBuilder.Append('\t');
				break;
			case 'r':
				stringBuilder.Append('\r');
				break;
			case '0':
				stringBuilder.Append('\0');
				break;
			case 'u':
				if (i + 4 < num2 && IsHex4(line, i + 1))
				{
					stringBuilder.Append((char)Convert.ToInt32(line.Substring(i + 1, 4), 16));
					i += 4;
				}
				else
				{
					stringBuilder.Append('u');
				}
				break;
			default:
				stringBuilder.Append(c2);
				break;
			}
		}
		return stringBuilder.ToString();
	}

	private static bool IsHex4(string s, int at)
	{
		if (at + 4 > s.Length)
		{
			return false;
		}
		for (int i = at; i < at + 4; i++)
		{
			char c = s[i];
			if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
			{
				return false;
			}
		}
		return true;
	}
}
internal static class Fmt
{
	public static bool SameHoles(string a, string b)
	{
		if (a.IndexOf('{') < 0 && a.IndexOf('}') < 0 && b.IndexOf('{') < 0 && b.IndexOf('}') < 0)
		{
			return true;
		}
		List<string> list = Holes(a);
		List<string> list2 = Holes(b);
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		List<string> list3 = new List<string>();
		List<string> list4 = new List<string>();
		foreach (string item in list)
		{
			if (IsNamed(item) || FormatIndex(item) >= 0)
			{
				hashSet.Add(item);
			}
			else
			{
				list3.Add(item);
			}
		}
		foreach (string item2 in list2)
		{
			if (IsNamed(item2) || FormatIndex(item2) >= 0)
			{
				if (!hashSet.Contains(item2))
				{
					return false;
				}
			}
			else
			{
				list4.Add(item2);
			}
		}
		if (list3.Count != list4.Count)
		{
			return false;
		}
		list3.Sort(string.CompareOrdinal);
		list4.Sort(string.CompareOrdinal);
		for (int i = 0; i < list3.Count; i++)
		{
			if (!string.Equals(list3[i], list4[i], StringComparison.Ordinal))
			{
				return false;
			}
		}
		return true;
	}

	public static bool SameTokens(string a, string b)
	{
		if (a.IndexOf('{') < 0 && a.IndexOf('}') < 0 && b.IndexOf('{') < 0 && b.IndexOf('}') < 0)
		{
			return true;
		}
		List<string> list = Holes(a);
		List<string> list2 = Holes(b);
		if (list.Count != list2.Count)
		{
			return false;
		}
		for (int i = 0; i < list.Count; i++)
		{
			list[i] = TokenHead(list[i]);
		}
		for (int j = 0; j < list2.Count; j++)
		{
			list2[j] = TokenHead(list2[j]);
		}
		list.Sort(string.CompareOrdinal);
		list2.Sort(string.CompareOrdinal);
		for (int k = 0; k < list.Count; k++)
		{
			if (!string.Equals(list[k], list2[k], StringComparison.Ordinal))
			{
				return false;
			}
		}
		return true;
	}

	private static string TokenHead(string hole)
	{
		int num = hole.IndexOf('?');
		if (num <= 0 || hole.IndexOf(':') <= 0 || hole.IndexOf(':') >= num)
		{
			return hole;
		}
		return hole.Substring(0, num);
	}

	private static bool IsNamed(string hole)
	{
		if (hole.Length >= 3 && hole[0] == '{' && hole[hole.Length - 1] == '}')
		{
			if (hole[1] < 'a' || hole[1] > 'z')
			{
				if (hole[1] >= 'A')
				{
					return hole[1] <= 'Z';
				}
				return false;
			}
			return true;
		}
		return false;
	}

	public static int FormatIndex(string hole)
	{
		if (hole.Length < 3 || hole[0] != '{' || hole[hole.L