Decompiled source of Megabonk Level Editor v0.1.0

BepInEx/plugins/MegabonkLevels/MegabonkLevels.Mod.dll

Decompiled 9 hours ago
using System;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Actors.Enemies;
using Assets.Scripts.Actors;
using Assets.Scripts.Actors.Enemies;
using Assets.Scripts.Actors.Player;
using Assets.Scripts.Audio.Music;
using Assets.Scripts.Game.Combat;
using Assets.Scripts.Game.MapGeneration;
using Assets.Scripts.Game.Other;
using Assets.Scripts.Inventory__Items__Pickups;
using Assets.Scripts.Inventory__Items__Pickups.Chests;
using Assets.Scripts.Inventory__Items__Pickups.Items;
using Assets.Scripts.Inventory__Items__Pickups.Items.ItemImplementations;
using Assets.Scripts.Inventory__Items__Pickups.Stats;
using Assets.Scripts.Inventory__Items__Pickups.Weapons;
using Assets.Scripts.Managers;
using Assets.Scripts.MapGeneration.ProceduralTiles;
using Assets.Scripts.Menu.Shop;
using Assets.Scripts.Saves___Serialization.Progression.Achievements;
using Assets.Scripts.Saves___Serialization.SaveFiles.Configs;
using Assets.Scripts.Settings___Saves.SaveFiles;
using Assets.Scripts.Settings___Saves.SaveFiles.ConfigSaves;
using Assets.Scripts.Steam;
using Assets.Scripts.UI.Debug;
using Assets.Scripts.UI.InGame.Levelup;
using Assets.Scripts.UI.InGame.Rewards;
using Assets.Scripts.Utility;
using Assets.Scripts._Data.MapsAndStages;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using NLayer;
using Rewired;
using Steamworks;
using TMPro;
using Unity.AI.Navigation;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Utility;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MegabonkLevels.Mod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+0ebefc8288bdf46075af01840000a6780e450789")]
[assembly: AssemblyProduct("MegabonkLevels.Mod")]
[assembly: AssemblyTitle("MegabonkLevels.Mod")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace MegabonkLevels;

public enum ActorKind
{
	Enemy,
	Elite,
	Miniboss,
	StageBoss,
	FinalBoss
}
public static class ActorKinds
{
	private const int Elite = 1;

	private const int Boss = 2;

	private const int StageBoss = 4;

	private const int SummonerMiniboss = 16;

	private const int FinalBoss = 32;

	public static ActorKind Of(int enemyFlags)
	{
		if ((enemyFlags & 0x20) != 0)
		{
			return ActorKind.FinalBoss;
		}
		if ((enemyFlags & 4) != 0)
		{
			return ActorKind.StageBoss;
		}
		if ((enemyFlags & 0x12) != 0)
		{
			return ActorKind.Miniboss;
		}
		if ((enemyFlags & 1) != 0)
		{
			return ActorKind.Elite;
		}
		return ActorKind.Enemy;
	}

	public static string Label(ActorKind kind)
	{
		return kind switch
		{
			ActorKind.FinalBoss => "final boss:", 
			ActorKind.StageBoss => "boss:", 
			ActorKind.Miniboss => "miniboss:", 
			ActorKind.Elite => "elite:", 
			_ => "enemy:", 
		};
	}

	public static bool IsBossTier(ActorKind kind)
	{
		if ((uint)(kind - 2) <= 2u)
		{
			return true;
		}
		return false;
	}
}
public static class AssetDump
{
	private sealed class Walk
	{
		public HashSet<object> Path { get; } = new HashSet<object>();

		public int MaxItems { get; }

		public int MaxNodes { get; }

		public int Nodes { get; set; }

		public int Level { get; set; }

		public Walk(int maxItems, int maxNodes)
		{
			MaxItems = maxItems;
			MaxNodes = maxNodes;
		}
	}

	public const int MaxDepth = 6;

	public const int DefaultMaxItems = 64;

	public const int DefaultMaxNodes = 20000;

	private const int MaxLevel = 24;

	private const BindingFlags Members = BindingFlags.Instance | BindingFlags.Public;

	public static JsonNode Describe(object value, int depth, int maxItems = 64, int maxNodes = 20000)
	{
		return Describe(value, Math.Min(depth, 6), new Walk(Math.Max(1, maxItems), Math.Max(1, maxNodes)));
	}

	private static JsonNode Describe(object value, int depth, Walk walk)
	{
		if (value == null)
		{
			return null;
		}
		if (IsPrimitive(value, out var primitive))
		{
			return primitive;
		}
		if (walk.Nodes >= walk.MaxNodes || walk.Level >= 24)
		{
			return new JsonObject { ["$truncated"] = true };
		}
		walk.Nodes++;
		if (walk.Path.Contains(value))
		{
			return new JsonObject
			{
				["$type"] = value.GetType().Name,
				["name"] = ReadName(value),
				["$cycle"] = true
			};
		}
		if (value is IEnumerable sequence)
		{
			return DescribeSequence(sequence, depth, walk);
		}
		if (depth <= 0)
		{
			return JsonValue.Create(SafeText(value));
		}
		Type type = value.GetType();
		bool flag = Inherits(type, "UnityEngine.Object") && !Inherits(type, "UnityEngine.ScriptableObject");
		walk.Path.Add(value);
		walk.Level++;
		JsonObject jsonObject = new JsonObject { ["$type"] = type.Name };
		if (flag)
		{
			jsonObject["name"] = JsonValue.Create(ReadName(value));
		}
		foreach (KeyValuePair<string, Func<object, object>> item in MembersOf(type, flag))
		{
			jsonObject[item.Key] = DescribeMember(item, value, depth - 1, walk);
		}
		walk.Level--;
		walk.Path.Remove(value);
		if (flag)
		{
			jsonObject["$fieldsOnly"] = true;
		}
		return jsonObject;
	}

	private static bool Inherits(Type type, string fullName)
	{
		Type baseType = type.BaseType;
		while (baseType != null)
		{
			if (baseType.FullName == fullName)
			{
				return true;
			}
			baseType = baseType.BaseType;
		}
		return false;
	}

	private static JsonNode DescribeSequence(IEnumerable sequence, int depth, Walk walk)
	{
		walk.Path.Add(sequence);
		walk.Level++;
		JsonArray jsonArray = new JsonArray();
		int num = 0;
		foreach (object item in sequence)
		{
			num++;
			if (jsonArray.Count < walk.MaxItems)
			{
				jsonArray.Add(Describe(item, depth, walk));
			}
		}
		walk.Level--;
		walk.Path.Remove(sequence);
		if (num <= walk.MaxItems)
		{
			return jsonArray;
		}
		return new JsonObject
		{
			["count"] = JsonValue.Create((long)num, (JsonNodeOptions?)null),
			["truncated"] = true,
			["items"] = jsonArray
		};
	}

	private static JsonNode DescribeMember(KeyValuePair<string, Func<object, object>> member, object owner, int depth, Walk walk)
	{
		object value;
		try
		{
			value = member.Value(owner);
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex is TargetInvocationException { InnerException: not null } ex3) ? ex3.InnerException : ex);
			return JsonValue.Create("$error: " + ex2.GetType().Name + ": " + ex2.Message);
		}
		return Describe(value, depth, walk);
	}

	private static IEnumerable<KeyValuePair<string, Func<object, object>>> MembersOf(Type type, bool fieldsOnly)
	{
		FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
		foreach (FieldInfo field in fields)
		{
			yield return new KeyValuePair<string, Func<object, object>>(field.Name, (object instance) => field.GetValue(instance));
		}
		if (fieldsOnly)
		{
			yield break;
		}
		PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
		foreach (PropertyInfo property in properties)
		{
			if (property.GetIndexParameters().Length == 0 && !(property.GetMethod == null))
			{
				yield return new KeyValuePair<string, Func<object, object>>(property.Name, (object instance) => property.GetValue(instance));
			}
		}
	}

	private static bool IsPrimitive(object value, out JsonNode primitive)
	{
		JsonValue jsonValue = ((value is string value2) ? JsonValue.Create(value2) : ((value is bool value3) ? JsonValue.Create(value3) : ((value is Enum value4) ? JsonValue.Create(Convert.ToInt64(value4)) : ((!(value is sbyte) && !(value is byte) && !(value is short) && !(value is ushort) && !(value is int) && !(value is uint) && !(value is long)) ? ((value is ulong value5) ? JsonValue.Create(value5) : ((value is float value6) ? JsonValue.Create(value6) : ((!(value is double) && !(value is decimal)) ? ((!(value is char c)) ? null : JsonValue.Create(c.ToString())) : JsonValue.Create(Convert.ToDouble(value))))) : JsonValue.Create(Convert.ToInt64(value))))));
		primitive = jsonValue;
		bool flag = primitive != null;
		if (!flag)
		{
			bool flag2 = ((value is string || value is bool) ? true : false);
			flag = flag2;
		}
		return flag;
	}

	private static string ReadName(object value)
	{
		try
		{
			return (value.GetType().GetProperty("name", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value) as string) ?? (value.GetType().GetField("name", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value) as string);
		}
		catch (Exception ex)
		{
			return "$error: " + ex.GetType().Name + ": " + ex.Message;
		}
	}

	private static string SafeText(object value)
	{
		try
		{
			return value.ToString() ?? value.GetType().Name;
		}
		catch (Exception ex)
		{
			return "$error: " + ex.GetType().Name + ": " + ex.Message;
		}
	}
}
public static class BlankLevel
{
	public const int DefaultSize = 7;

	public const int MinimumSize = 3;

	private const float SpawnBodyY = 2f;

	private const float BossSpawnerRotationY = 270f;

	public static LevelFile Create(EMap map, int stageIndex, int tier, int size, float spacing, string gameBuildId)
	{
		if (size < 3)
		{
			throw new ArgumentException($"A from-scratch grid must be at least {3} by {3}, got {size}.", "size");
		}
		List<AuthoredCell> list = new List<AuthoredCell>(size * size);
		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size; j++)
			{
				list.Add(new AuthoredCell(i, j, 0));
			}
		}
		int num = size / 2;
		int cellX = Math.Min(num + 2, size - 1);
		(float X, float Z) tuple = PositionReadout.CellCentre(num, num, size, size, spacing);
		float item = tuple.X;
		float item2 = tuple.Z;
		(float X, float Z) tuple2 = PositionReadout.CellCentre(cellX, num, size, size, spacing);
		float item3 = tuple2.X;
		float item4 = tuple2.Z;
		Dictionary<string, string> packs = new Dictionary<string, string>();
		EditOp[] edits = Array.Empty<EditOp>();
		LevelGrid? grid = new LevelGrid(size, size, list);
		SpawnPoint? spawn = new SpawnPoint(new float[3] { item, 2f, item2 }, new float[3]);
		SpawnPoint? bossSpawner = new SpawnPoint(new float[3] { item3, 0f, item4 }, new float[3] { 0f, 270f, 0f });
		return new LevelFile(4, gameBuildId, map, stageIndex, tier, 0, packs, edits, NoGrass: false, null, null, null, null, null, null, null, null, null, GrindRequiresSlide: false, null, null, RandomizeShadyGuy: false, RandomizeChests: false, RandomizeMoai: false, 0, null, null, null, null, null, null, null, null, null, null, null, null, "none", grid, spawn, bossSpawner);
	}
}
public static class BossEventLog
{
	public static string Format(string eventName)
	{
		return "BossEvents: " + eventName;
	}

	public static string Format<T>(string eventName, T value)
	{
		return $"BossEvents: {eventName} {value}";
	}
}
public static class BossEventPatch
{
	public static void Install(ModLogger logger)
	{
		InteractableBossSpawner.A_BossSpawned += Action.op_Implicit((Action)delegate
		{
			logger.Msg(BossEventLog.Format("A_BossSpawned"));
		});
		InteractableBossSpawner.A_BossDefeated += Action<bool>.op_Implicit((Action<bool>)delegate(bool flag)
		{
			logger.Msg(BossEventLog.Format("A_BossDefeated", flag));
		});
		InteractableBossSpawner.A_NumBossesDefeated += Action<int>.op_Implicit((Action<int>)delegate(int count)
		{
			logger.Msg(BossEventLog.Format("A_NumBossesDefeated", count));
		});
		GraveyardBossRoom.A_BossDied += Action.op_Implicit((Action)delegate
		{
			logger.Msg(BossEventLog.Format("A_BossDied"));
		});
		EnemyManager.A_StageBossDied += Action.op_Implicit((Action)delegate
		{
			logger.Msg(BossEventLog.Format("A_StageBossDied"));
		});
	}
}
public enum BossPoolKind
{
	None,
	Boss,
	Miniboss
}
public static class BossPools
{
	private const int BossBit = 2;

	private const int StageBossBit = 4;

	private const int SummonerMinibossBit = 16;

	private const int FinalBossBit = 32;

	public const int MaxEntries = 64;

	public static BossPoolKind Classify(int flags)
	{
		if ((flags & 0x24) == 0)
		{
			if ((flags & 0x12) == 0)
			{
				return BossPoolKind.None;
			}
			return BossPoolKind.Miniboss;
		}
		return BossPoolKind.Boss;
	}

	public static string Pick(IReadOnlyList<string> pool, Random random, ISet<string> used = null)
	{
		List<string> list = pool?.Where((string name) => used == null || !used.Contains(name)).ToList();
		if (list == null || list.Count <= 0)
		{
			return null;
		}
		string text = list[random.Next(list.Count)];
		used?.Add(text);
		return text;
	}

	public static void Validate(IReadOnlyList<string> pool, string field)
	{
		if (pool == null || (pool.Count <= 64 && !pool.Any(string.IsNullOrWhiteSpace)))
		{
			return;
		}
		throw new ArgumentException($"{field} lists up to {64} enemy names, none blank.");
	}
}
public static class BossPoolPatch
{
	[HarmonyPatch(typeof(EnemyManager), "SpawnBoss")]
	private static class SpawnBossDrawsFromThePool
	{
		private static void Prefix(ref EEnemy eEnemy, EEnemyFlag enemyFlag)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected I4, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: 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: Expected I4, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (!CustomLevelState.IsActive)
			{
				return;
			}
			LevelFile currentSettings = LiveEditPatch.CurrentSettings;
			BossPoolKind bossPoolKind = BossPools.Classify((int)enemyFlag);
			IReadOnlyList<string> readOnlyList = bossPoolKind switch
			{
				BossPoolKind.Boss => currentSettings.BossPool, 
				BossPoolKind.Miniboss => currentSettings.MinibossPool, 
				_ => null, 
			};
			string text = LiveEditPatch.RunRandom.PickBoss(readOnlyList);
			EEnemy result;
			if (text == null)
			{
				if (readOnlyList != null && readOnlyList.Count > 0)
				{
					_logger?.Msg($"BossPool: {bossPoolKind} pool exhausted; keeping {eEnemy} (flags {enemyFlag})");
				}
			}
			else if (!Enum.TryParse<EEnemy>(text, ignoreCase: true, out result))
			{
				if (s_unknown.Add(text))
				{
					_logger?.Warning("BossPool: unknown enemy '" + text + "' ignored");
				}
			}
			else
			{
				_logger?.Msg($"BossPool: {bossPoolKind} spawn of {eEnemy} (flags {enemyFlag}) replaced by {result}");
				eEnemy = (EEnemy)(int)result;
			}
		}
	}

	private static ModLogger _logger;

	private static readonly HashSet<string> s_unknown = new HashSet<string>();

	public static void Install(ModLogger logger)
	{
		_logger = logger;
	}
}
public readonly record struct Vec3(float X, float Y, float Z);
public static class BossSpawnRedirect
{
	public const int ArmWindowFrames = 2;

	public const float MinDistanceFromSpawner = 35f;

	public const float MaxDistanceFromSpawner = 68f;

	public const float MinSpacingBetweenCopies = 20f;

	public const float KillFloorMargin = 5f;

	public const float BoxFloorBelowSpawner = 2f;

	public const float BoxRoofAboveSpawner = 10f;

	public static bool ShouldArm(bool customLevelActive, bool fromScratch, bool redirectRequested)
	{
		if (customLevelActive)
		{
			return !fromScratch || redirectRequested;
		}
		return false;
	}

	public static bool IsInsideBossBox(Vec3 pos, Vec3 spawner)
	{
		if (XzDistance(pos, spawner) < 35f && pos.Y >= spawner.Y - 2f)
		{
			return pos.Y <= spawner.Y + 10f;
		}
		return false;
	}

	public static int ExpectedMoves(int bossCurses)
	{
		return Math.Max(1, 1 + bossCurses);
	}

	public static bool ShouldConsume(int? armedFrame, int frame, int windowFrames = 2)
	{
		if (armedFrame.HasValue && frame >= armedFrame.Value)
		{
			return frame <= armedFrame.Value + windowFrames;
		}
		return false;
	}

	public static bool ShouldExpire(int? armedFrame, int expectedMoves, int moveCount, int frame, int windowFrames = 2)
	{
		if (armedFrame.HasValue)
		{
			if (moveCount < expectedMoves)
			{
				return frame > armedFrame.Value + windowFrames;
			}
			return true;
		}
		return false;
	}

	public static List<Vec3> CandidateRing(Vec3 spawner, int seed, int count)
	{
		Random random = new Random(seed);
		List<Vec3> list = new List<Vec3>(count);
		for (int i = 0; i < count; i++)
		{
			float x = (float)(random.NextDouble() * 2.0 * Math.PI);
			float num = 35f + (float)(random.NextDouble() * 33.0);
			list.Add(new Vec3(spawner.X + MathF.Cos(x) * num, spawner.Y, spawner.Z + MathF.Sin(x) * num));
		}
		return list;
	}

	public static bool SpotUsable(Vec3 floorPoint, Vec3 spawner, float killFloorY, IReadOnlyList<Vec3> taken)
	{
		if (XzDistance(floorPoint, spawner) < 35f)
		{
			return false;
		}
		if (floorPoint.Y < killFloorY + 5f)
		{
			return false;
		}
		foreach (Vec3 item in taken)
		{
			if (XzDistance(floorPoint, item) < 20f)
			{
				return false;
			}
		}
		return true;
	}

	public static bool PickSpot(IReadOnlyList<Vec3> usable, IReadOnlyList<Vec3> taken, out Vec3 spot)
	{
		return Maximin.Pick(usable, taken, XzDistance, out spot);
	}

	public static Vec3 FloorPlacement(Vec3 floorPoint, Vec3 requestedPosition, Vec3 actualPosition)
	{
		return new Vec3(floorPoint.X, floorPoint.Y + actualPosition.Y - requestedPosition.Y, floorPoint.Z);
	}

	public static float XzDistance(Vec3 a, Vec3 b)
	{
		float num = a.X - b.X;
		float num2 = a.Z - b.Z;
		return MathF.Sqrt(num * num + num2 * num2);
	}
}
public static class BossSpawnRedirectPatch
{
	[HarmonyPatch(typeof(InteractableBossSpawner), "Interact")]
	private static class InteractArmsTheRedirect
	{
		private static void Prefix(InteractableBossSpawner __instance)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			if (BossSpawnRedirect.ShouldArm(CustomLevelState.IsActive, FromScratchGenerationPatch.ActiveLevel.HasValue, FromScratchGenerationPatch.ActiveLevel?.BossRedirect ?? false) && !((Object)(object)__instance == (Object)null))
			{
				_expectedMoves = BossSpawnRedirect.ExpectedMoves(((Object)(object)GameManager.Instance != (Object)null) ? GameManager.Instance.bossCurses : 0);
				_moveCount = 0;
				_taken.Clear();
				_movedBosses.Clear();
				Vector3 position = ((Component)__instance).transform.position;
				_spawner = new Vec3(position.x, position.y, position.z);
				_seed = Environment.TickCount;
				_armedFrame = Time.frameCount;
				_logger?.Msg($"BossSpawnRedirect: armed at spawner ({position.x:0.###}, {position.y:0.###}, {position.z:0.###}), expecting {_expectedMoves} boss(es) at frame {Time.frameCount}.");
			}
		}
	}

	[HarmonyPatch(typeof(EnemyManager), "SpawnBoss")]
	private static class SpawnBossMovesTheBoss
	{
		private static void Postfix(Enemy __result, Vector3 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			MoveIfArmed(__result, pos, "SpawnBoss");
		}
	}

	[HarmonyPatch(typeof(EnemyManager), "SpawnEnemy", new Type[]
	{
		typeof(EnemyData),
		typeof(Vector3),
		typeof(int),
		typeof(bool),
		typeof(EEnemyFlag),
		typeof(bool),
		typeof(float)
	})]
	private static class SpawnEnemyMovesTheBoss
	{
		private static void Postfix(Enemy __result, Vector3 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			MoveIfArmed(__result, pos, "SpawnEnemy");
		}
	}

	private const int CandidatesPerBoss = 48;

	private const int SeedPerCopy = 7919;

	private static ModLogger _logger;

	private static int? _armedFrame;

	private static int _expectedMoves;

	private static int _moveCount;

	private static Vec3 _spawner;

	private static int _seed;

	private static readonly List<Vec3> _taken = new List<Vec3>();

	private static readonly HashSet<IntPtr> _movedBosses = new HashSet<IntPtr>();

	public static void Install(ModLogger logger)
	{
		_logger = logger;
	}

	public static void Disarm()
	{
		_armedFrame = null;
		_expectedMoves = 0;
		_moveCount = 0;
		_taken.Clear();
		_movedBosses.Clear();
	}

	private static void MoveIfArmed(Enemy boss, Vector3 requested, string via)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: 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_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_0266: Unknown result type (might be due to invalid IL or missing references)
		if (!_armedFrame.HasValue)
		{
			MoveMinibossOutOfTheBox(boss, requested, via);
			return;
		}
		int frameCount = Time.frameCount;
		if (BossSpawnRedirect.ShouldExpire(_armedFrame, _expectedMoves, _moveCount, frameCount))
		{
			if (_moveCount < _expectedMoves)
			{
				_logger?.Msg($"BossSpawnRedirect: window expired at frame {frameCount} after {_moveCount}/{_expectedMoves} moves.");
			}
			_armedFrame = null;
		}
		else
		{
			if (!BossSpawnRedirect.ShouldConsume(_armedFrame, frameCount) || (Object)(object)boss == (Object)null || !boss.IsBoss() || !_movedBosses.Add(((Il2CppObjectBase)boss).Pointer))
			{
				return;
			}
			if (!TryFindSpot(boss, _spawner, _seed + _moveCount * 7919, _taken, out var floorPoint))
			{
				_logger?.Msg("BossSpawnRedirect: no usable interior spot for the boss spawned via " + via + ", left alone.");
				return;
			}
			Vector3 position = ((Component)boss).transform.position;
			Vec3 vec = BossSpawnRedirect.FloorPlacement(floorPoint, new Vec3(requested.x, requested.y, requested.z), new Vec3(position.x, position.y, position.z));
			((Component)boss).transform.position = new Vector3(vec.X, vec.Y, vec.Z);
			if ((Object)(object)boss.rb != (Object)null)
			{
				boss.rb.velocity = Vector3.zero;
			}
			_taken.Add(floorPoint);
			_moveCount++;
			_logger?.Msg($"BossSpawnRedirect: boss {_moveCount}/{_expectedMoves} moved from ({position.x:0.###}, {position.y:0.###}, {position.z:0.###}) to ({vec.X:0.###}, {vec.Y:0.###}, {vec.Z:0.###}) via {via}.");
			if (BossSpawnRedirect.ShouldExpire(_armedFrame, _expectedMoves, _moveCount, frameCount))
			{
				_armedFrame = null;
			}
		}
	}

	private static void MoveMinibossOutOfTheBox(Enemy boss, Vector3 requested, string via)
	{
		//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_006d: 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_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: 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)
		if ((Object)(object)boss == (Object)null || !boss.IsBoss() || !BossSpawnRedirect.ShouldArm(CustomLevelState.IsActive, FromScratchGenerationPatch.ActiveLevel.HasValue, FromScratchGenerationPatch.ActiveLevel?.BossRedirect ?? false))
		{
			return;
		}
		InteractableBossSpawner val = Object.FindObjectOfType<InteractableBossSpawner>();
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		Vector3 position = ((Component)val).transform.position;
		Vec3 spawner = new Vec3(position.x, position.y, position.z);
		Vector3 position2 = ((Component)boss).transform.position;
		if (!BossSpawnRedirect.IsInsideBossBox(new Vec3(position2.x, position2.y, position2.z), spawner))
		{
			return;
		}
		if (!TryFindSpot(boss, spawner, Environment.TickCount, Array.Empty<Vec3>(), out var floorPoint))
		{
			_logger?.Msg("BossSpawnRedirect: no usable interior spot for the miniboss spawned via " + via + ", left alone.");
			return;
		}
		Vec3 vec = BossSpawnRedirect.FloorPlacement(floorPoint, new Vec3(requested.x, requested.y, requested.z), new Vec3(position2.x, position2.y, position2.z));
		((Component)boss).transform.position = new Vector3(vec.X, vec.Y, vec.Z);
		if ((Object)(object)boss.rb != (Object)null)
		{
			boss.rb.velocity = Vector3.zero;
		}
		ModLogger logger = _logger;
		if (logger != null)
		{
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(62, 8);
			defaultInterpolatedStringHandler.AppendLiteral("BossSpawnRedirect: miniboss ");
			EnemyData enemyData = boss.enemyData;
			defaultInterpolatedStringHandler.AppendFormatted((enemyData != null) ? new EEnemy?(enemyData.enemyName) : ((EEnemy?)null));
			defaultInterpolatedStringHandler.AppendLiteral(" moved from (");
			defaultInterpolatedStringHandler.AppendFormatted(position2.x, "0.###");
			defaultInterpolatedStringHandler.AppendLiteral(", ");
			defaultInterpolatedStringHandler.AppendFormatted(position2.y, "0.###");
			defaultInterpolatedStringHandler.AppendLiteral(", ");
			defaultInterpolatedStringHandler.AppendFormatted(position2.z, "0.###");
			defaultInterpolatedStringHandler.AppendLiteral(") to ");
			defaultInterpolatedStringHandler.AppendLiteral("(");
			defaultInterpolatedStringHandler.AppendFormatted(vec.X, "0.###");
			defaultInterpolatedStringHandler.AppendLiteral(", ");
			defaultInterpolatedStringHandler.AppendFormatted(vec.Y, "0.###");
			defaultInterpolatedStringHandler.AppendLiteral(", ");
			defaultInterpolatedStringHandler.AppendFormatted(vec.Z, "0.###");
			defaultInterpolatedStringHandler.AppendLiteral(") via ");
			defaultInterpolatedStringHandler.AppendFormatted(via);
			defaultInterpolatedStringHandler.AppendLiteral(".");
			logger.Msg(defaultInterpolatedStringHandler.ToStringAndClear());
		}
	}

	private static bool TryFindSpot(Enemy boss, Vec3 spawner, int seed, IReadOnlyList<Vec3> taken, out Vec3 floorPoint)
	{
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		floorPoint = default(Vec3);
		float num = LiveEditPatch.KillFloorY ?? float.MinValue;
		float top = spawner.Y + 20f;
		List<Vec3> list = new List<Vec3>();
		foreach (Vec3 item in BossSpawnRedirect.CandidateRing(spawner, seed, 48))
		{
			if (BossSpawnRedirect.SpotUsable(item, spawner, num, taken) && PlacementProbe.HighestFloor(item.X, item.Z, top, (num == float.MinValue) ? (-100f) : (num - 5f), ((Component)boss).transform, out var floor))
			{
				Vec3 vec = new Vec3(item.X, floor.y, item.Z);
				if (BossSpawnRedirect.SpotUsable(vec, spawner, num, taken) && PlacementProbe.ClearPoint(new Vector3(vec.X, vec.Y, vec.Z)))
				{
					list.Add(vec);
				}
			}
		}
		return BossSpawnRedirect.PickSpot(list, taken, out floorPoint);
	}
}
public static class CameraOverride
{
	private static CameraPose? _pose;

	private static bool _hasSaved;

	private static Vector3 _savedLocalPosition;

	private static Quaternion _savedLocalRotation;

	public static void Set(CameraPose pose)
	{
		_pose = pose;
	}

	public static void Clear()
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		_pose = null;
		if (_hasSaved)
		{
			_hasSaved = false;
			PlayerCamera instance = PlayerCamera.Instance;
			Camera val = ((instance != null) ? instance.camera : null);
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).transform.localPosition = _savedLocalPosition;
				((Component)val).transform.localRotation = _savedLocalRotation;
			}
		}
	}

	public static void Apply()
	{
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		CameraPose? pose = _pose;
		if (!pose.HasValue)
		{
			return;
		}
		CameraPose valueOrDefault = pose.GetValueOrDefault();
		PlayerCamera instance = PlayerCamera.Instance;
		Camera val = ((instance != null) ? instance.camera : null);
		if (!((Object)(object)val == (Object)null))
		{
			Transform transform = ((Component)val).transform;
			if (!_hasSaved)
			{
				_savedLocalPosition = transform.localPosition;
				_savedLocalRotation = transform.localRotation;
				_hasSaved = true;
			}
			transform.position = new Vector3(valueOrDefault.X, valueOrDefault.Y, valueOrDefault.Z);
			transform.rotation = Quaternion.Euler(valueOrDefault.Rx, valueOrDefault.Ry, valueOrDefault.Rz);
		}
	}
}
public enum CatalogNamespace
{
	GameAsset,
	Bundle
}
public readonly record struct CatalogId(CatalogNamespace ns, IReadOnlyList<string> segments)
{
	private static readonly Regex SegmentPattern = new Regex("^[A-Za-z0-9_-]+$", RegexOptions.Compiled);

	private const string BundlePrefix = "bundle:";

	public static CatalogId Parse(string raw)
	{
		if (!TryParse(raw, out var id, out var error))
		{
			throw new ArgumentException(error, "raw");
		}
		return id;
	}

	public static bool TryParse(string raw, out CatalogId id, out string error)
	{
		id = default(CatalogId);
		if (string.IsNullOrWhiteSpace(raw))
		{
			error = "catalogId must not be empty or whitespace.";
			return false;
		}
		CatalogNamespace ns;
		string text;
		if (raw.StartsWith("bundle:", StringComparison.Ordinal))
		{
			ns = CatalogNamespace.Bundle;
			text = raw.Substring("bundle:".Length);
		}
		else
		{
			if (raw.Contains(':'))
			{
				error = "catalogId '" + raw + "' has an unknown namespace prefix; only 'bundle:' is recognized.";
				return false;
			}
			ns = CatalogNamespace.GameAsset;
			text = raw;
		}
		string[] array = text.Split('/');
		string[] array2 = array;
		foreach (string text2 in array2)
		{
			if (text2.Length == 0)
			{
				error = "catalogId '" + raw + "' contains an empty segment (check for leading/trailing or doubled '/').";
				return false;
			}
			if (!SegmentPattern.IsMatch(text2))
			{
				error = $"catalogId '{raw}' has invalid character(s) in segment '{text2}'; only letters, digits, '_', and '-' are allowed.";
				return false;
			}
		}
		if (array.Length < 2)
		{
			error = $"catalogId '{raw}' has too few segments; must have at least 2, got {array.Length}.";
			return false;
		}
		id = new CatalogId(ns, array);
		error = null;
		return true;
	}

	public string Serialize()
	{
		return Namespace switch
		{
			CatalogNamespace.Bundle => "bundle:" + string.Join("/", Segments), 
			CatalogNamespace.GameAsset => string.Join("/", Segments), 
			_ => throw new ArgumentException($"Unknown {"CatalogNamespace"}: {Namespace}"), 
		};
	}

	public bool Equals(CatalogId other)
	{
		if (Namespace == other.Namespace)
		{
			if (Segments != null && other.Segments != null)
			{
				return Segments.SequenceEqual(other.Segments);
			}
			return Segments == other.Segments;
		}
		return false;
	}

	public override int GetHashCode()
	{
		HashCode hashCode = default(HashCode);
		hashCode.Add(Namespace);
		if (Segments != null)
		{
			foreach (string segment in Segments)
			{
				hashCode.Add(segment);
			}
		}
		return hashCode.ToHashCode();
	}
}
public static class CatalogPrefabs
{
	private static MapData _lastMap;

	public static MapData TryFindMap(EMap map)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Invalid comparison between Unknown and I4
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Invalid comparison between Unknown and I4
		if ((Object)(object)_lastMap != (Object)null && (int)_lastMap.eMap == (int)map)
		{
			return _lastMap;
		}
		foreach (MapData item in Resources.FindObjectsOfTypeAll<MapData>())
		{
			if ((Object)(object)item != (Object)null && (int)item.eMap == (int)map)
			{
				_lastMap = item;
				return item;
			}
		}
		return null;
	}

	public static MapData FindMap(EMap map)
	{
		return TryFindMap(map) ?? throw new ArgumentException($"No MapData for map {map}.");
	}

	public static IReadOnlyList<PaletteMapCatalog> DescribeAll(MapData current, SpawnInteractables interactables, RandomObjectPlacer placer)
	{
		List<PaletteMapCatalog> list = new List<PaletteMapCatalog>();
		if ((Object)(object)current != (Object)null)
		{
			list.Add(Describe(current, interactables, placer));
		}
		foreach (MapData item in OtherLoadedMaps(current))
		{
			list.Add(Describe(item, null, null));
		}
		return list;
	}

	public static PaletteMapCatalog Describe(MapData mapData, SpawnInteractables interactables, RandomObjectPlacer placer)
	{
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bd: Expected I4, but got Unknown
		PaletteStageCatalog[] array = new PaletteStageCatalog[((Il2CppArrayBase<StageData>)(object)mapData.stages)?.Length ?? 0];
		for (int i = 0; i < array.Length; i++)
		{
			StageData val = ((Il2CppArrayBase<StageData>)(object)mapData.stages)[i];
			Il2CppReferenceArray<RandomMapObject> randomMapObjects = val.randomMapObjects;
			int[] array2 = new int[((Il2CppArrayBase<RandomMapObject>)(object)randomMapObjects)?.Length ?? 0];
			for (int j = 0; j < array2.Length; j++)
			{
				array2[j] = ((Il2CppArrayBase<GameObject>)(object)((Il2CppArrayBase<RandomMapObject>)(object)randomMapObjects)[j].prefabs)?.Length ?? 0;
			}
			int num = i;
			StageTilePrefabs stageTilePrefabs = val.stageTilePrefabs;
			int valueOrDefault = ((stageTilePrefabs != null) ? ((Il2CppArrayBase<GameObject>)(object)stageTilePrefabs.flatTilePrefabs)?.Length : ((int?)null)).GetValueOrDefault();
			StageTilePrefabs stageTilePrefabs2 = val.stageTilePrefabs;
			array[num] = new PaletteStageCatalog(array2, valueOrDefault, ((stageTilePrefabs2 != null) ? ((Il2CppArrayBase<GameObject>)(object)stageTilePrefabs2.mapSpecificTilesPrefabs)?.Length : ((int?)null)).GetValueOrDefault());
		}
		Il2CppReferenceArray<RandomMapObject> randomObjectsOverride = mapData.randomObjectsOverride;
		int[] array3 = new int[((Il2CppArrayBase<RandomMapObject>)(object)randomObjectsOverride)?.Length ?? 0];
		for (int k = 0; k < array3.Length; k++)
		{
			int num2 = k;
			RandomMapObject obj = ((Il2CppArrayBase<RandomMapObject>)(object)randomObjectsOverride)[k];
			array3[num2] = ((obj != null) ? ((Il2CppArrayBase<GameObject>)(object)obj.prefabs)?.Length : ((int?)null)).GetValueOrDefault();
		}
		EMap eMap = mapData.eMap;
		int shrineCount = ((Il2CppArrayBase<GameObject>)(object)mapData.shrines)?.Length ?? 0;
		bool hasChest = (Object)(object)((interactables != null) ? interactables.chest : null) != (Object)null;
		bool hasChestFree = (Object)(object)((interactables != null) ? interactables.chestFree : null) != (Object)null;
		int valueOrDefault2 = ((interactables == null) ? ((int?)null) : ((Il2CppArrayBase<GameObject>)(object)interactables.rails)?.Length).GetValueOrDefault();
		int hasBoombox;
		if ((Object)(object)interactables != (Object)null)
		{
			EffectManager instance = EffectManager.Instance;
			hasBoombox = (((Object)(object)((instance != null) ? instance.boomboxQuest : null) != (Object)null) ? 1 : 0);
		}
		else
		{
			hasBoombox = 0;
		}
		int? obj2;
		if (placer == null)
		{
			obj2 = null;
		}
		else
		{
			RandomMapObject chargeShrineSpawns = placer.chargeShrineSpawns;
			obj2 = ((chargeShrineSpawns == null) ? ((int?)null) : ((Il2CppArrayBase<GameObject>)(object)chargeShrineSpawns.prefabs)?.Length);
		}
		int? num3 = obj2;
		int valueOrDefault3 = num3.GetValueOrDefault();
		int? obj3;
		if (placer == null)
		{
			obj3 = null;
		}
		else
		{
			RandomMapObject greedShrineSpawns = placer.greedShrineSpawns;
			obj3 = ((greedShrineSpawns == null) ? ((int?)null) : ((Il2CppArrayBase<GameObject>)(object)greedShrineSpawns.prefabs)?.Length);
		}
		num3 = obj3;
		return new PaletteMapCatalog((EMap)eMap, array, shrineCount, hasChest, hasChestFree, valueOrDefault2, (byte)hasBoombox != 0, valueOrDefault3, num3.GetValueOrDefault(), array3);
	}

	public static GameObject Resolve(CatalogRoute route, SpawnInteractables interactables, RandomObjectPlacer placer)
	{
		switch (route.Kind)
		{
		case CatalogRouteKind.Chest:
			return interactables.chest;
		case CatalogRouteKind.ChestFree:
			return interactables.chestFree;
		case CatalogRouteKind.Boombox:
			return EffectManager.Instance.boomboxQuest;
		case CatalogRouteKind.Rail:
			return ((Il2CppArrayBase<GameObject>)(object)interactables.rails)[route.Index];
		case CatalogRouteKind.ChargeShrine:
		{
			object obj2;
			if (placer == null)
			{
				obj2 = null;
			}
			else
			{
				RandomMapObject chargeShrineSpawns = placer.chargeShrineSpawns;
				obj2 = ((chargeShrineSpawns != null) ? chargeShrineSpawns.prefabs : null);
			}
			return PrefabAt(Il2CppArrayBase<GameObject>.op_Implicit((Il2CppArrayBase<GameObject>)obj2), route.Index);
		}
		case CatalogRouteKind.GreedShrine:
		{
			object obj3;
			if (placer == null)
			{
				obj3 = null;
			}
			else
			{
				RandomMapObject greedShrineSpawns = placer.greedShrineSpawns;
				obj3 = ((greedShrineSpawns != null) ? greedShrineSpawns.prefabs : null);
			}
			return PrefabAt(Il2CppArrayBase<GameObject>.op_Implicit((Il2CppArrayBase<GameObject>)obj3), route.Index);
		}
		default:
		{
			MapData val = FindMap(route.Map);
			if (route.Kind == CatalogRouteKind.Shrine)
			{
				return ((Il2CppArrayBase<GameObject>)(object)val.shrines)[route.Index];
			}
			if (route.Kind == CatalogRouteKind.RandomObjectOverride)
			{
				Il2CppReferenceArray<RandomMapObject> randomObjectsOverride = val.randomObjectsOverride;
				if (randomObjectsOverride == null || route.Index >= ((Il2CppArrayBase<RandomMapObject>)(object)randomObjectsOverride).Length)
				{
					return null;
				}
				RandomMapObject obj = ((Il2CppArrayBase<RandomMapObject>)(object)randomObjectsOverride)[route.Index];
				return PrefabAt(Il2CppArrayBase<GameObject>.op_Implicit((Il2CppArrayBase<GameObject>)(object)((obj != null) ? obj.prefabs : null)), route.SubIndex);
			}
			StageData val2 = ((Il2CppArrayBase<StageData>)(object)val.stages)[route.Stage];
			return (GameObject)(route.Kind switch
			{
				CatalogRouteKind.RandomMapObject => ((Il2CppArrayBase<GameObject>)(object)((Il2CppArrayBase<RandomMapObject>)(object)val2.randomMapObjects)[route.Index].prefabs)[route.SubIndex], 
				CatalogRouteKind.FlatTilePrefab => ((Il2CppArrayBase<GameObject>)(object)val2.stageTilePrefabs.flatTilePrefabs)[route.Index], 
				CatalogRouteKind.SpecificTilePrefab => ((Il2CppArrayBase<GameObject>)(object)val2.stageTilePrefabs.mapSpecificTilesPrefabs)[route.Index], 
				_ => throw new ArgumentException($"Unhandled catalog route kind {route.Kind}."), 
			});
		}
		}
	}

	private static IEnumerable<MapData> OtherLoadedMaps(MapData current)
	{
		HashSet<int> seen = new HashSet<int>();
		return from mapData in (IEnumerable<MapData>)Resources.FindObjectsOfTypeAll<MapData>()
			where (Object)(object)mapData != (Object)null && mapData != current && seen.Add((int)mapData.eMap)
			orderby (int)mapData.eMap
			select mapData;
	}

	private static GameObject PrefabAt(GameObject[] prefabs, int index)
	{
		if (prefabs == null || index < 0 || index >= prefabs.Length)
		{
			return null;
		}
		return prefabs[index];
	}
}
public enum CatalogRouteKind
{
	RandomMapObject,
	FlatTilePrefab,
	SpecificTilePrefab,
	Shrine,
	RandomObjectOverride,
	Chest,
	ChestFree,
	Boombox,
	Rail,
	ChargeShrine,
	GreedShrine
}
public readonly record struct CatalogRoute(CatalogRouteKind Kind, EMap Map, int Stage, int Index, int SubIndex)
{
	public static CatalogRoute Parse(CatalogId id)
	{
		if (id.Namespace != CatalogNamespace.GameAsset)
		{
			throw new ArgumentException("'" + id.Serialize() + "' is not a game-asset catalogId.", "id");
		}
		IReadOnlyList<string> segments = id.Segments;
		if (segments.Count == 2 && segments[0] == "interactable")
		{
			return segments[1] switch
			{
				"chest" => new CatalogRoute(CatalogRouteKind.Chest, EMap.None, 0, 0, 0), 
				"chestFree" => new CatalogRoute(CatalogRouteKind.ChestFree, EMap.None, 0, 0, 0), 
				"boombox" => new CatalogRoute(CatalogRouteKind.Boombox, EMap.None, 0, 0, 0), 
				_ => throw Unresolvable(id), 
			};
		}
		if (segments.Count == 3 && segments[0] == "interactable" && segments[1] == "rail")
		{
			return new CatalogRoute(CatalogRouteKind.Rail, EMap.None, 0, Number(segments[2], id), 0);
		}
		if (segments.Count == 3 && segments[0] == "interactable" && segments[1] == "chargeShrine")
		{
			return new CatalogRoute(CatalogRouteKind.ChargeShrine, EMap.None, 0, Number(segments[2], id), 0);
		}
		if (segments.Count == 3 && segments[0] == "interactable" && segments[1] == "greedShrine")
		{
			return new CatalogRoute(CatalogRouteKind.GreedShrine, EMap.None, 0, Number(segments[2], id), 0);
		}
		EMap map = ParseMap(segments[0], id);
		if (segments.Count == 3 && segments[1] == "shrines")
		{
			return new CatalogRoute(CatalogRouteKind.Shrine, map, 0, Number(segments[2], id), 0);
		}
		if (segments.Count == 4 && segments[1] == "randomObjectsOverride")
		{
			return new CatalogRoute(CatalogRouteKind.RandomObjectOverride, map, 0, Number(segments[2], id), Number(segments[3], id));
		}
		if (segments.Count >= 4 && segments[1].StartsWith("stage", StringComparison.Ordinal))
		{
			int stage = Number(segments[1].Substring("stage".Length), id);
			if (segments.Count == 5 && segments[2] == "randomMapObjects")
			{
				return new CatalogRoute(CatalogRouteKind.RandomMapObject, map, stage, Number(segments[3], id), Number(segments[4], id));
			}
			if (segments.Count == 5 && segments[2] == "stageTilePrefabs" && segments[3] == "flat")
			{
				return new CatalogRoute(CatalogRouteKind.FlatTilePrefab, map, stage, Number(segments[4], id), 0);
			}
			if (segments.Count == 5 && segments[2] == "stageTilePrefabs" && segments[3] == "specific")
			{
				return new CatalogRoute(CatalogRouteKind.SpecificTilePrefab, map, stage, Number(segments[4], id), 0);
			}
		}
		throw Unresolvable(id);
	}

	private static EMap ParseMap(string segment, CatalogId id)
	{
		if (!Enum.TryParse<EMap>(segment, ignoreCase: true, out var result) || result == EMap.None || !Enum.IsDefined(typeof(EMap), result))
		{
			throw Unresolvable(id);
		}
		return result;
	}

	private static int Number(string segment, CatalogId id)
	{
		if (!int.TryParse(segment, out var result) || result < 0)
		{
			throw Unresolvable(id);
		}
		return result;
	}

	private static ArgumentException Unresolvable(CatalogId id)
	{
		return new ArgumentException("catalogId '" + id.Serialize() + "' does not match a known game-asset catalog shape.", "id");
	}
}
public sealed class CellChangeTracker
{
	public const uint PlayerId = uint.MaxValue;

	private readonly Dictionary<uint, (GridCell Cell, int Level)> _last = new Dictionary<uint, (GridCell, int)>();

	public bool Changed(uint id, GridCell cell, int level)
	{
		if (_last.TryGetValue(id, out (GridCell, int) value) && value.Item1.Equals(cell) && value.Item2 == level)
		{
			return false;
		}
		_last[id] = (cell, level);
		return true;
	}

	public void Reset()
	{
		_last.Clear();
	}
}
public static class CharacterOverride
{
	public const int TonyMcZoomId = 13;

	public const int CalciumId = 1;

	public static string DisplayName(int id)
	{
		return id switch
		{
			1 => "Calcium", 
			13 => "Tony McZoom", 
			_ => $"character {id}", 
		};
	}

	public static bool IsAllowed(int id)
	{
		if (id != 1)
		{
			return id == 13;
		}
		return true;
	}

	public static int? TryParseName(string name)
	{
		switch (name?.Trim().ToLowerInvariant())
		{
		case "calcium":
			return 1;
		case "tony":
		case "tonymczoom":
			return 13;
		default:
			return null;
		}
	}

	public static string TryApply(Action<int> setSelected, int id = 13)
	{
		try
		{
			setSelected(id);
			return null;
		}
		catch (Exception ex)
		{
			return $"LevelLoader: could not select character {id}, run starts with the default character: {ex.Message}";
		}
	}
}
public static class DevCharacter
{
	public static int? Resolve(bool devEnabled, string name)
	{
		if (!devEnabled)
		{
			return null;
		}
		if (string.IsNullOrWhiteSpace(name))
		{
			return 13;
		}
		return CharacterOverride.TryParseName(name) ?? throw new ArgumentException("'" + name + "' is not an allowed character (calcium, tonymczoom)");
	}
}
public static class CharacterGridOrder
{
	public static IReadOnlyList<int> Pin(IReadOnlyList<int> stockIds)
	{
		return new int[2] { 1, 13 }.Where(((IEnumerable<int>)stockIds).Contains<int>).Concat(stockIds.Where((int id) => !CharacterOverride.IsAllowed(id))).ToList();
	}
}
public static class CharacterPolicy
{
	public static IReadOnlyList<int> AllowedIds(IReadOnlyList<string> names)
	{
		List<int> list = (names ?? new List<string>()).Select(CharacterOverride.TryParseName).OfType<int>().Distinct()
			.ToList();
		if (list.Count != 0)
		{
			return list;
		}
		return null;
	}

	public static IReadOnlyList<string> UnknownNames(IReadOnlyList<string> names)
	{
		return (names ?? new List<string>()).Where((string name) => !CharacterOverride.TryParseName(name).HasValue).ToList();
	}

	public static bool Permits(IReadOnlyList<int> allowedIds, int id)
	{
		return allowedIds?.Contains(id) ?? true;
	}

	public static string Refusal(IReadOnlyList<int> allowedIds, string levelTitle)
	{
		string text = string.Join(" or ", allowedIds.Select(CharacterOverride.DisplayName));
		return "Pick " + text + " for " + (levelTitle ?? "this level");
	}
}
public static class CharacterScreenPatch
{
	private readonly record struct ButtonSnapshot(int SiblingIndex, bool CanUse, Color IconColor, bool OverlayActive, string Reason);

	[HarmonyPatch(typeof(CharacterMenu), "OnEnable")]
	private static class OnEnablePostfix
	{
		private static void Postfix(CharacterMenu __instance)
		{
			if (Restricted)
			{
				Apply(__instance);
			}
		}
	}

	[HarmonyPatch(typeof(CharacterMenu), "OnDisable")]
	private static class OnDisablePostfix
	{
		private static void Postfix(CharacterMenu __instance)
		{
			MainMenu mainMenu = __instance.mainMenu;
			GameObject val = ((mainMenu != null) ? mainMenu.tabMaps : null);
			LevelLoaderPatch.OnMenuDisabled((Object)(object)val != (Object)null && val.activeInHierarchy);
		}
	}

	private const int PlaceholderId = -1;

	private static ModLogger _logger;

	private static readonly Dictionary<int, ButtonSnapshot> _stock = new Dictionary<int, ButtonSnapshot>();

	private static readonly int[] DefaultAllowedIds = new int[2] { 1, 13 };

	private static IReadOnlyList<int> _allowedIds = DefaultAllowedIds;

	private static ECharacter? _savedCharacter;

	public static bool Restricted { get; private set; }

	public static void Install(ModLogger logger)
	{
		_logger = logger;
	}

	public static void SetRestricted(bool restricted, IReadOnlyList<int> allowedIds = null)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		_allowedIds = allowedIds ?? DefaultAllowedIds;
		if (restricted && !Restricted)
		{
			Preferences obj = SavedPreferences();
			_savedCharacter = ((obj != null) ? new ECharacter?(obj.selectedCharacter) : ((ECharacter?)null));
		}
		else if (!restricted && Restricted)
		{
			RestoreSavedCharacter();
		}
		Restricted = restricted;
		foreach (CharacterMenu item in Resources.FindObjectsOfTypeAll<CharacterMenu>())
		{
			Apply(item);
		}
	}

	private static bool IsAllowed(int id)
	{
		return CharacterPolicy.Permits(_allowedIds, id);
	}

	private static Preferences SavedPreferences()
	{
		SaveManager instance = SaveManager.Instance;
		if (instance == null)
		{
			return null;
		}
		ConfigSaveFile config = instance.config;
		if (config == null)
		{
			return null;
		}
		return config.preferences;
	}

	private static void RestoreSavedCharacter()
	{
		//IL_0017: 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)
		//IL_0021: 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_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		Preferences val = SavedPreferences();
		ECharacter? savedCharacter = _savedCharacter;
		if (savedCharacter.HasValue)
		{
			ECharacter valueOrDefault = savedCharacter.GetValueOrDefault();
			if (val != null && val.selectedCharacter != valueOrDefault)
			{
				val.selectedCharacter = valueOrDefault;
				SaveManager.Instance.SaveConfig();
				_logger?.Msg($"CharacterScreen: saved character restored to {valueOrDefault}");
			}
		}
		_savedCharacter = null;
	}

	private static void Apply(CharacterMenu menu)
	{
		if ((Object)(object)menu == (Object)null || (Object)(object)menu.characterGridParent == (Object)null)
		{
			return;
		}
		Il2CppArrayBase<MyButtonCharacter> componentsInChildren = ((Component)menu.characterGridParent).GetComponentsInChildren<MyButtonCharacter>(true);
		if (componentsInChildren.Length < 2)
		{
			return;
		}
		foreach (MyButtonCharacter item in componentsInChildren)
		{
			if (!_stock.ContainsKey(((Object)item).GetInstanceID()))
			{
				_stock[((Object)item).GetInstanceID()] = Snapshot(item);
			}
		}
		if (Restricted)
		{
			Restrict(menu, Il2CppArrayBase<MyButtonCharacter>.op_Implicit(componentsInChildren));
		}
		else
		{
			RestoreStock(Il2CppArrayBase<MyButtonCharacter>.op_Implicit(componentsInChildren));
		}
		RebuildNavigation(menu);
		if (Restricted && ((Component)menu).gameObject.activeInHierarchy)
		{
			FocusFirstAllowed(Il2CppArrayBase<MyButtonCharacter>.op_Implicit(componentsInChildren));
		}
	}

	private static void FocusFirstAllowed(MyButtonCharacter[] buttons)
	{
		MyButtonCharacter val = null;
		foreach (MyButtonCharacter val2 in buttons)
		{
			if (IsAllowed(IdOf(val2)) && ((Object)(object)val == (Object)null || ((Component)val2).transform.GetSiblingIndex() < ((Component)val).transform.GetSiblingIndex()))
			{
				val = val2;
			}
		}
		if ((Object)(object)val != (Object)null && (Object)(object)EventSystem.current != (Object)null)
		{
			EventSystem.current.SetSelectedGameObject(((Component)val).gameObject);
		}
	}

	private static void RebuildNavigation(CharacterMenu menu)
	{
		try
		{
			List<MyButtonCharacter> value = Traverse.Create((object)menu).Property("characterButtons", (object[])null).GetValue<List<MyButtonCharacter>>();
			if (value != null)
			{
				List<MyButtonCharacter> list = new List<MyButtonCharacter>();
				Enumerator<MyButtonCharacter> enumerator = value.GetEnumerator();
				while (enumerator.MoveNext())
				{
					MyButtonCharacter current = enumerator.Current;
					list.Add(current);
				}
				list.Sort((MyButtonCharacter a, MyButtonCharacter b) => ((Component)a).transform.GetSiblingIndex().CompareTo(((Component)b).transform.GetSiblingIndex()));
				value.Clear();
				foreach (MyButtonCharacter item in list)
				{
					value.Add(item);
				}
			}
			AccessTools.Method(typeof(CharacterMenu), "SetupButtonNavigation", (Type[])null, (Type[])null).Invoke(menu, null);
		}
		catch (Exception ex)
		{
			_logger?.Warning("CharacterScreen: could not rebuild navigation: " + ex.Message);
		}
	}

	private static ButtonSnapshot Snapshot(MyButtonCharacter button)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		return new ButtonSnapshot(((Component)button).transform.GetSiblingIndex(), button.canUseCharacter, ((Object)(object)button.i_icon != (Object)null) ? ((Graphic)button.i_icon).color : Color.white, (Object)(object)button.unavailableOverlay != (Object)null && button.unavailableOverlay.activeSelf, button.cantUseCharacterReason);
	}

	private static int IdOf(MyButtonCharacter button)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected I4, but got Unknown
		if (!((Object)(object)button.characterData != (Object)null))
		{
			return -1;
		}
		return (int)button.characterData.eCharacter;
	}

	private static void Restrict(CharacterMenu menu, MyButtonCharacter[] buttons)
	{
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		List<MyButtonCharacter> list = new List<MyButtonCharacter>(buttons);
		list.Sort((MyButtonCharacter a, MyButtonCharacter b) => _stock[((Object)a).GetInstanceID()].SiblingIndex.CompareTo(_stock[((Object)b).GetInstanceID()].SiblingIndex));
		List<int> list2 = list.ConvertAll(IdOf);
		Dictionary<int, Queue<MyButtonCharacter>> dictionary = new Dictionary<int, Queue<MyButtonCharacter>>();
		for (int num = 0; num < list.Count; num++)
		{
			if (!dictionary.TryGetValue(list2[num], out var value))
			{
				value = (dictionary[list2[num]] = new Queue<MyButtonCharacter>());
			}
			value.Enqueue(list[num]);
		}
		int num2 = 0;
		foreach (int item in CharacterGridOrder.Pin(list2))
		{
			((Component)dictionary[item].Dequeue()).transform.SetSiblingIndex(num2++);
		}
		foreach (MyButtonCharacter val in buttons)
		{
			if (!((Object)(object)val.characterData == (Object)null) && !IsAllowed(IdOf(val)))
			{
				val.canUseCharacter = false;
				val.cantUseCharacterReason = CharacterPolicy.Refusal(_allowedIds, null);
				if ((Object)(object)val.i_icon != (Object)null)
				{
					((Graphic)val.i_icon).color = Color.black;
				}
				if ((Object)(object)val.unavailableOverlay != (Object)null)
				{
					val.unavailableOverlay.SetActive(true);
				}
			}
		}
		_logger?.Msg($"CharacterScreen: restricted to {string.Join(", ", _allowedIds)}, {buttons.Length} buttons");
	}

	private static void RestoreStock(MyButtonCharacter[] buttons)
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		foreach (MyButtonCharacter val in buttons)
		{
			ButtonSnapshot buttonSnapshot = _stock[((Object)val).GetInstanceID()];
			((Component)val).transform.SetSiblingIndex(buttonSnapshot.SiblingIndex);
			val.canUseCharacter = buttonSnapshot.CanUse;
			val.cantUseCharacterReason = buttonSnapshot.Reason;
			if ((Object)(object)val.i_icon != (Object)null)
			{
				((Graphic)val.i_icon).color = buttonSnapshot.IconColor;
			}
			if ((Object)(object)val.unavailableOverlay != (Object)null)
			{
				val.unavailableOverlay.SetActive(buttonSnapshot.OverlayActive);
			}
		}
	}
}
public static class ChestLuck
{
	public static float Roll(IReadOnlyList<float> range, Random random)
	{
		if (range != null)
		{
			return range[0] + (float)random.NextDouble() * (range[1] - range[0]);
		}
		return 0f;
	}

	public static float Apply(float luck, float shift)
	{
		return luck + shift;
	}
}
public static class ChestLuckPatch
{
	[HarmonyPatch(typeof(ItemUtility), "GetRandomChestItem")]
	private static class GetRandomChestItemPrefix
	{
		private static void Prefix(ref float luck)
		{
			if (_shift != 0f && CustomLevelState.IsActive)
			{
				float num = ChestLuck.Apply(luck, _shift);
				_logger?.Msg($"ChestLuck: chest loot rolled with luck {luck:F2} shifted to {num:F2}");
				luck = num;
			}
		}
	}

	private static float _shift;

	private static ModLogger _logger;

	public static void Install(ModLogger logger)
	{
		_logger = logger;
	}

	public static void Roll(IReadOnlyList<float> range, ModLogger logger)
	{
		_shift = ChestLuck.Roll(range, new Random(Guid.NewGuid().GetHashCode()));
		if (range != null)
		{
			logger.Msg($"ChestLuck: this run's chest luck shift is {_shift:F2} (range {range[0]:F2} to {range[1]:F2})");
		}
	}
}
public static class ChildHider
{
	public static void Hide(GameObject go, IReadOnlyList<string> names, ModLogger logger)
	{
		if (names == null || names.Count == 0)
		{
			return;
		}
		foreach (Transform componentsInChild in go.GetComponentsInChildren<Transform>(true))
		{
			if (!names.Contains(((Object)componentsInChild).name))
			{
				continue;
			}
			foreach (Renderer component in ((Component)componentsInChild).GetComponents<Renderer>())
			{
				component.enabled = false;
			}
			foreach (Collider component2 in ((Component)componentsInChild).GetComponents<Collider>())
			{
				component2.enabled = false;
			}
			logger?.Msg($"LiveEdit: hid child '{((Object)componentsInChild).name}' of '{((Object)go).name}'");
		}
	}
}
public static class CollisionRebuild
{
	public static void Replace(ProceduralTileGeneration tileGen, ModLogger logger)
	{
		GameObject collider = tileGen.collider;
		GameObject val = Build(tileGen, logger);
		if ((Object)(object)val == (Object)null)
		{
			logger.Warning("CollisionRebuild: combiner returned nothing; keeping the original collision");
			return;
		}
		tileGen.collider = val;
		if ((Object)(object)collider != (Object)null)
		{
			Object.Destroy((Object)(object)collider);
		}
	}

	private static GameObject Build(ProceduralTileGeneration tileGen, ModLogger logger)
	{
		Dictionary<string, Mesh> dictionary = PrefabColliderMeshes(tileGen);
		List<GameObject> val = new List<GameObject>();
		List<MeshCollider> list = new List<MeshCollider>();
		List<GameObject>[] array = new List<GameObject>[3] { tileGen.tiles, tileGen.flatTiles, tileGen.fillTiles };
		foreach (List<GameObject> val2 in array)
		{
			for (int j = 0; j < val2.Count; j++)
			{
				GameObject val3 = val2[j];
				if (!((Object)(object)val3 == (Object)null) && val3.activeInHierarchy && dictionary.TryGetValue(StripClone(((Object)val3).name), out var value))
				{
					MeshCollider component = val3.GetComponent<MeshCollider>();
					if ((Object)(object)component == (Object)null)
					{
						component = val3.AddComponent<MeshCollider>();
						component.sharedMesh = value;
						list.Add(component);
					}
					val.Add(val3);
				}
			}
		}
		GameObject result = MeshColliderCombiner.CombineMeshes(val);
		foreach (MeshCollider item in list)
		{
			Object.Destroy((Object)(object)item);
		}
		logger.Msg($"CollisionRebuild: combined {val.Count} pieces ({list.Count} temporary colliders)");
		return result;
	}

	private static Dictionary<string, Mesh> PrefabColliderMeshes(ProceduralTileGeneration tileGen)
	{
		Dictionary<string, Mesh> dictionary = new Dictionary<string, Mesh>();
		GameObject[] array = (GameObject[])(object)new GameObject[6] { tileGen.flatTile, tileGen.slopeTile, tileGen.wallFlat, tileGen.wallLeftUp, tileGen.wallLeftDown, tileGen.wallLeftCross };
		foreach (GameObject val in array)
		{
			MeshCollider val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<MeshCollider>());
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMesh != (Object)null)
			{
				dictionary[((Object)val).name] = val2.sharedMesh;
			}
		}
		return dictionary;
	}

	private static string StripClone(string name)
	{
		if (!name.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			return name;
		}
		return name.Substring(0, name.Length - "(Clone)".Length);
	}
}
public readonly record struct ConsoleDevState(bool DevEnabled);
public readonly record struct ConsoleToggleState(bool Invulnerable, bool Editor, bool Hud, bool Coordinates);
public readonly record struct ConsoleBindResult(HarnessCommand? Command, string Reply, string Error, bool ListHistory = false)
{
	public bool Ok => Error == null;
}
public sealed class ConsoleVerb
{
	private readonly Func<IReadOnlyList<string>, ConsoleToggleState, IReadOnlyList<string>, ConsoleBindResult> _bind;

	private Func<int, IReadOnlyList<string>, IEnumerable<string>> _candidates;

	public string Name { get; }

	public string Help { get; }

	public bool Gated { get; }

	public string Usage { get; }

	public string[] Aliases { get; private set; } = Array.Empty<string>();

	public bool RawError { get; private set; }

	public ConsoleVerb(string name, string help, bool gated, Func<IReadOnlyList<string>, ConsoleToggleState, IReadOnlyList<string>, ConsoleBindResult> bind, string usage = null)
	{
		Name = name;
		Help = help;
		Gated = gated;
		_bind = bind;
		Usage = usage ?? ("usage: " + name);
	}

	public ConsoleVerb WithRawError()
	{
		RawError = true;
		return this;
	}

	public ConsoleVerb WithAliases(params string[] aliases)
	{
		Aliases = aliases;
		return this;
	}

	public ConsoleVerb WithCandidates(Func<int, IReadOnlyList<string>, IEnumerable<string>> candidates)
	{
		_candidates = candidates;
		return this;
	}

	internal IEnumerable<string> Candidates(int argumentIndex, IReadOnlyList<string> levels)
	{
		return _candidates?.Invoke(argumentIndex, levels) ?? Enumerable.Empty<string>();
	}

	internal ConsoleBindResult Bind(IReadOnlyList<string> args, ConsoleToggleState toggles, IReadOnlyList<string> levels)
	{
		return _bind(args, toggles, levels);
	}
}
public readonly record struct ConsoleCompletion(IReadOnlyList<string> Matches, int Index, string Prefix, IReadOnlyList<string> Lines = null, string Original = "")
{
	public string Text
	{
		get
		{
			IReadOnlyList<string> matches = Matches;
			if (matches == null || matches.Count <= 0 || Index < 0 || Index >= matches.Count)
			{
				return "";
			}
			return matches[Index];
		}
	}

	public string Completion
	{
		get
		{
			if (Text.Length < Prefix.Length)
			{
				return "";
			}
			return Text.Substring(Prefix.Length);
		}
	}

	public string Line
	{
		get
		{
			IReadOnlyList<string> lines = Lines;
			if (lines == null || lines.Count <= 0 || Index < 0 || Index >= lines.Count)
			{
				return Original;
			}
			return lines[Index];
		}
	}

	public ConsoleCompletion Next()
	{
		IReadOnlyList<string> matches = Matches;
		if (matches == null || matches.Count <= 0)
		{
			return this;
		}
		return this with
		{
			Index = (Index + 1) % matches.Count
		};
	}

	public ConsoleCompletion Prev()
	{
		IReadOnlyList<string> matches = Matches;
		if (matches == null || matches.Count <= 0)
		{
			return this;
		}
		return this with
		{
			Index = (Index - 1 + matches.Count) % matches.Count
		};
	}
}
public sealed class ConsoleCommandRegistry
{
	private readonly record struct OptionSet(int? Map, int? Stage, int? Tier, int? Seed, int? Size, bool Unseeded, bool Bad)
	{
		public static OptionSet Rejected { get; } = new OptionSet(null, null, null, null, null, Unseeded: false, Bad: true);
	}

	public const string GatedReply = "requires MEGABONK_DEV";

	private const int MinDamageAmount = 1;

	private const int MaxDamageAmount = 99;

	private static readonly string[] PerfActions = new string[13]
	{
		"report", "status", "start", "reset", "spawn", "timescale", "toggle", "vsync", "render", "physics",
		"animation", "health", "census"
	};

	private readonly Dictionary<string, ConsoleVerb> _byName = new Dictionary<string, ConsoleVerb>(StringComparer.OrdinalIgnoreCase);

	private readonly List<ConsoleVerb> _verbs = new List<ConsoleVerb>();

	public static ConsoleCommandRegistry Default { get; } = Build();

	public IReadOnlyList<ConsoleVerb> Verbs => _verbs;

	public ConsoleVerb Find(string name)
	{
		if (name == null || !_byName.TryGetValue(name, out var value))
		{
			return null;
		}
		return value;
	}

	public ConsoleBindResult Bind(string line, ConsoleDevState dev, ConsoleToggleState toggles, IReadOnlyList<string> levels = null)
	{
		ConsoleTokens consoleTokens = ConsoleCommandTokenizer.Tokenize(line);
		if (consoleTokens.Tokens == null)
		{
			return new ConsoleBindResult(null, null, consoleTokens.Error);
		}
		if (consoleTokens.IsBlank)
		{
			return new ConsoleBindResult(null, null, null);
		}
		ConsoleVerb consoleVerb = Find(consoleTokens.Verb);
		if (consoleVerb == null)
		{
			return new ConsoleBindResult(null, null, UnknownVerb(consoleTokens.Verb));
		}
		if (consoleVerb.Gated && !dev.DevEnabled)
		{
			return new ConsoleBindResult(null, null, "requires MEGABONK_DEV");
		}
		if (consoleVerb.Name == "help")
		{
			if (consoleTokens.Arguments.Count > 1)
			{
				return new ConsoleBindResult(null, null, consoleVerb.Usage);
			}
			return new ConsoleBindResult(null, Help((consoleTokens.Arguments.Count == 1) ? consoleTokens.Arguments[0] : null, dev.DevEnabled), null);
		}
		ConsoleBindResult result = consoleVerb.Bind(consoleTokens.Arguments, toggles, levels);
		if (result.Error == "no match")
		{
			return new ConsoleBindResult(null, null, consoleVerb.Usage);
		}
		if (result.Error != null && !consoleVerb.RawError && !result.Error.StartsWith("usage:", StringComparison.Ordinal))
		{
			return new ConsoleBindResult(null, null, result.Error + "\n" + consoleVerb.Usage);
		}
		return result;
	}

	public ConsoleCompletion Complete(string line, IReadOnlyList<string> levels = null)
	{
		if (line == null)
		{
			line = "";
		}
		ConsoleLastWord word = ConsoleCommandTokenizer.LastWord(line);
		string head = line.Substring(0, word.Start);
		List<string> list = (from name in Candidates(head, word.WordsBefore, levels)
			where name.StartsWith(word.Text, StringComparison.OrdinalIgnoreCase)
			select name).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList();
		return new ConsoleCompletion(list, (list.Count == 0) ? (-1) : 0, word.Text, list.Select((string m) => head + QuoteWord(m)).ToList(), line);
	}

	private IEnumerable<string> Candidates(string head, int wordsBefore, IReadOnlyList<string> levels)
	{
		object obj;
		if (wordsBefore != 0)
		{
			obj = Find(ConsoleCommandTokenizer.Tokenize(head).Verb)?.Candidates(wordsBefore - 1, levels);
			if (obj == null)
			{
				return Enumerable.Empty<string>();
			}
		}
		else
		{
			IEnumerable<string> enumerable = _verbs.SelectMany(VerbNames).OrderBy<string, string>((string name) => name, StringComparer.Ordinal);
			obj = enumerable;
		}
		return (IEnumerable<string>)obj;
	}

	private static string QuoteWord(string word)
	{
		if (!word.Any(char.IsWhiteSpace))
		{
			return word;
		}
		return "\"" + word + "\"";
	}

	private string Help(string filter, bool dev)
	{
		List<(string Names, string Help)> rows = (from verb in _verbs
			where (dev || !verb.Gated) && (filter == null || verb.Name.StartsWith(filter, StringComparison.OrdinalIgnoreCase) || verb.Aliases.Any((string a) => a.StartsWith(filter, StringComparison.OrdinalIgnoreCase)))
			select (Names: verb.Name + ((verb.Aliases.Length != 0) ? (", " + string.Join(", ", verb.Aliases)) : ""), Help: verb.Help)).ToList();
		if (rows.Count != 0)
		{
			return string.Join("\n", rows.Select(((string Names, string Help) row) => row.Names.PadRight(rows.Max(((string Names, string Help) r) => r.Names.Length) + 2) + row.Help));
		}
		return "no verb matches " + filter;
	}

	private string UnknownVerb(string typed)
	{
		List<string> list = Suggest(typed);
		string text = "unknown verb '" + typed + "'";
		if (list.Count != 0)
		{
			return text + "; did you mean " + string.Join(", ", list) + "?";
		}
		return text;
	}

	private static IEnumerable<string> VerbNames(ConsoleVerb verb)
	{
		yield return verb.Name;
		string[] aliases = verb.Aliases;
		for (int i = 0; i < aliases.Length; i++)
		{
			yield return aliases[i];
		}
	}

	private List<string> Suggest(string typed)
	{
		string lower = typed.ToLowerInvariant();
		int threshold = Math.Max(2, typed.Length / 2);
		return (from row in (from name in _verbs.SelectMany(VerbNames)
				select (name: name, distance: Distance(lower, name.ToLowerInvariant())) into row
				where row.distance <= threshold || row.name.StartsWith(typed, StringComparison.OrdinalIgnoreCase)
				orderby row.distance
				select row).ThenBy<(string, int), string>(((string name, int distance) row) => row.name, StringComparer.Ordinal)
			select row.name).Distinct<string>(StringComparer.OrdinalIgnoreCase).Take(3).ToList();
	}

	private static int Distance(string a, string b)
	{
		int[] array = new int[b.Length + 1];
		int[] array2 = new int[b.Length + 1];
		for (int i = 0; i <= b.Length; i++)
		{
			array[i] = i;
		}
		for (int j = 1; j <= a.Length; j++)
		{
			array2[0] = j;
			for (int k = 1; k <= b.Length; k++)
			{
				int num = ((a[j - 1] != b[k - 1]) ? 1 : 0);
				array2[k] = Math.Min(Math.Min(array2[k - 1] + 1, array[k] + 1), array[k - 1] + num);
			}
			int[] array3 = array2;
			array2 = array;
			array = array3;
		}
		return array[b.Length];
	}

	private ConsoleVerb Add(ConsoleVerb verb)
	{
		_verbs.Add(verb);
		_byName[verb.Name] = verb;
		string[] aliases = verb.Aliases;
		foreach (string key in aliases)
		{
			_byName[key] = verb;
		}
		return verb;
	}

	private static ConsoleCommandRegistry Build()
	{
		ConsoleCommandRegistry consoleCommandRegistry = new ConsoleCommandRegistry();
		consoleCommandRegistry.Add(new ConsoleVerb("help", "list verbs, aliases and one line of help", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => (args.Count > 1) ? NoMatch() : new ConsoleBindResult(null, null, null)).WithAliases("?"));
		consoleCommandRegistry.Add(new ConsoleVerb("clear", "clear the console scrollback", gated: false, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => NoCommand()).WithAliases("cls"));
		consoleCommandRegistry.Add(new ConsoleVerb("history", "list the lines typed in earlier sessions and this one", gated: false, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => new ConsoleBindResult(null, "", null, ListHistory: true)));
		consoleCommandRegistry.Add(new ConsoleVerb("state", "read the game's current state", gated: false, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.State)));
		float[] values;
		consoleCommandRegistry.Add(new ConsoleVerb("player.teleport", "move the player to a world position", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			if (args.Count != 3 || !Floats(args, out values))
			{
				return NoMatch();
			}
			TeleportArgs teleport = new TeleportArgs
			{
				Position = values
			};
			return Command(new HarnessCommand(HarnessCommandKind.Teleport, null, default(CameraPose), Enabled: false, null, null, teleport));
		}, "usage: player.teleport x y z").WithAliases("tp"));
		consoleCommandRegistry.Add(new ConsoleVerb("player.teleport_cell", "move the player to a grid cell", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			if (args.Count != 2 || !Ints(args, out values))
			{
				return NoMatch();
			}
			TeleportArgs teleport = new TeleportArgs
			{
				Cell = values
			};
			return Command(new HarnessCommand(HarnessCommandKind.Teleport, null, default(CameraPose), Enabled: false, null, null, teleport));
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("player.god", "make the player survive damage", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState toggles, IReadOnlyList<string> _)
		{
			bool? flag = Flag(args, toggles.Invulnerable);
			if (!flag.HasValue)
			{
				return NoMatch();
			}
			bool valueOrDefault = flag == true;
			return Enabled(valueOrDefault ? HarnessCommandKind.Invulnerable : HarnessCommandKind.Vulnerable, valueOrDefault);
		}).WithAliases("tgm"));
		consoleCommandRegistry.Add(new ConsoleVerb("player.kill", "end the run at once", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.Kill)));
		consoleCommandRegistry.Add(new ConsoleVerb("player.damage", "apply 1-99 damage, fatal with 'lethal'", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			int count = args.Count;
			bool flag = (uint)(count - 1) <= 1u;
			if (flag && Int(args[0], 1, 99, out var parsed))
			{
				bool? flag2 = Nonlethal(args);
				if (flag2.HasValue)
				{
					bool valueOrDefault = flag2 == true;
					DamageArgs damage = new DamageArgs
					{
						Amount = parsed,
						Nonlethal = valueOrDefault
					};
					return Command(new HarnessCommand(HarnessCommandKind.Damage, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, damage));
				}
			}
			return NoMatch();
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("player.add_item", "read or set an item amount", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			int parsed = 0;
			int count = args.Count;
			bool flag = (uint)(count - 1) <= 1u;
			if (!flag || args[0].Length <= 0 || (args.Count != 1 && !Int(args[1], 0, 999, out parsed)))
			{
				return NoMatch();
			}
			ItemArgs item = new ItemArgs
			{
				Name = args[0],
				Amount = ((args.Count == 2) ? new int?(parsed) : ((int?)null))
			};
			return Command(new HarnessCommand(HarnessCommandKind.Item, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), item));
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("player.fall_damage", "read the live fall-damage inputs", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.FallDamage)));
		consoleCommandRegistry.Add(new ConsoleVerb("enemies.kill", "kill nearest, all or bosses", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			string text = ((args.Count == 0) ? "all" : args[0].ToLowerInvariant());
			if (Array.IndexOf(EnemyKillTargets.Names, text) < 0)
			{
				return NoMatch();
			}
			string killTarget = text;
			return Command(new HarnessCommand(HarnessCommandKind.KillEnemies, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, null, null, Skip: false, null, null, killTarget));
		}).WithAliases("killall"));
		consoleCommandRegistry.Add(new ConsoleVerb("enemies.spawns", "allow or stop new enemy spawns", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			bool? flag = Flag(args, current: true);
			if (!flag.HasValue)
			{
				return NoMatch();
			}
			bool valueOrDefault = flag == true;
			return Enabled(HarnessCommandKind.Spawns, valueOrDefault);
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("run.freeze", "stop gameplay", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.Freeze)));
		consoleCommandRegistry.Add(new ConsoleVerb("run.resume", "start gameplay again", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.Resume)));
		consoleCommandRegistry.Add(new ConsoleVerb("run.restart", "run the death screen's Retry", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.RestartRun)));
		consoleCommandRegistry.Add(new ConsoleVerb("run.dismiss_levelup", "pick an upgrade in the level-up dialog", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			int parsed = 0;
			if (args.Count > 1 || (args.Count != 0 && !Int(args[0], 0, int.MaxValue, out parsed)))
			{
				return NoMatch();
			}
			int choice = ((args.Count == 1) ? parsed : 0);
			return Command(new HarnessCommand(HarnessCommandKind.DismissLevelUp, null, default(CameraPose), Enabled: false, null, null, null, choice));
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("run.dismiss_offers", "close, pick or skip the open reward window", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			switch (args.Count)
			{
			case 0:
				return Command(new HarnessCommand(HarnessCommandKind.DismissOffers, null));
			case 1:
			{
				if (args[0] == "skip")
				{
					return Command(new HarnessCommand(HarnessCommandKind.DismissOffers, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, null, null, Skip: true));
				}
				if (Int(args[0], 0, int.MaxValue, out var parsed))
				{
					int? offer = parsed;
					return Command(new HarnessCommand(HarnessCommandKind.DismissOffers, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, null, offer));
				}
				break;
			}
			}
			return NoMatch();
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("run.interact", "activate the nearest interactable, or one type", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			if (args.Count > 1 || (args.Count != 0 && args[0].Length <= 0))
			{
				return NoMatch();
			}
			InteractArgs interact = new InteractArgs
			{
				Type = ((args.Count == 1) ? args[0] : null)
			};
			return Command(new HarnessCommand(HarnessCommandKind.Interact, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, null, null, Skip: false, interact));
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("run.press_death_confirm", "press the death screen's confirm", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.PressDeathConfirm)));
		consoleCommandRegistry.Add(new ConsoleVerb("run.press_summary_restart", "press the run summary's restart", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.PressSummaryRestart)));
		consoleCommandRegistry.Add(new ConsoleVerb("level.list", "list the saved custom-level files", gated: false, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.ListLevels)));
		consoleCommandRegistry.Add(new ConsoleVerb("level.load", "load a level by path or title, with map/stage/tier/seed/noseed", gated: true, (IReadOnlyList<string> args, ConsoleToggleState toggles, IReadOnlyList<string> levels) => LoadLevel(args, toggles, levels)).WithAliases("coc").WithRawError().WithCandidates(LevelTitles));
		consoleCommandRegistry.Add(new ConsoleVerb("level.save", "save the editor's level, optionally under a name", gated: true, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => (args.Count > 1 || (args.Count != 0 && args[0].Trim().Length <= 0)) ? NoMatch() : Command(new HarnessCommand(HarnessCommandKind.SaveLevel, (args.Count == 1) ? args[0] : null))));
		consoleCommandRegistry.Add(new ConsoleVerb("level.new", "write a blank level and edit it, with map/stage/tier/size", gated: true, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => NewLevel(args)));
		consoleCommandRegistry.Add(new ConsoleVerb("editor", "enter or leave editor mode", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState toggles, IReadOnlyList<string> _)
		{
			bool? flag = Flag(args, toggles.Editor);
			if (!flag.HasValue)
			{
				return NoMatch();
			}
			bool valueOrDefault = flag == true;
			return Enabled(HarnessCommandKind.Editor, valueOrDefault);
		}).WithAliases("tfc"));
		consoleCommandRegistry.Add(new ConsoleVerb("camera.set", "hold the camera at a pose", gated: true, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => (args.Count != 6 || !Floats(args, out values)) ? NoMatch() : Command(new HarnessCommand(HarnessCommandKind.Camera, null, new CameraPose(values[0], values[1], values[2], values[3], values[4], values[5])))));
		consoleCommandRegistry.Add(new ConsoleVerb("camera.clear", "return the camera to the game", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.CameraClear)));
		consoleCommandRegistry.Add(new ConsoleVerb("ui.hud", "show or hide the stock HUD", gated: false, delegate(IReadOnlyList<string> args, ConsoleToggleState toggles, IReadOnlyList<string> _)
		{
			bool? flag = Flag(args, toggles.Hud);
			if (!flag.HasValue)
			{
				return NoMatch();
			}
			bool valueOrDefault = flag == true;
			return Enabled(HarnessCommandKind.Hud, valueOrDefault);
		}).WithAliases("tm"));
		consoleCommandRegistry.Add(new ConsoleVerb("ui.coordinates", "show or hide coordinates", gated: false, delegate(IReadOnlyList<string> args, ConsoleToggleState toggles, IReadOnlyList<string> _)
		{
			bool? flag = Flag(args, toggles.Coordinates);
			if (!flag.HasValue)
			{
				return NoMatch();
			}
			bool valueOrDefault = flag == true;
			return Enabled(HarnessCommandKind.Coordinates, valueOrDefault);
		}));
		string[] perfActions = PerfActions;
		foreach (string action in perfActions)
		{
			consoleCommandRegistry.Add(new ConsoleVerb("perf." + action, PerfHelp(action), gated: true, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => Perf(action, args), PerfUsage(action)));
		}
		consoleCommandRegistry.Add(new ConsoleVerb("time_scale", "hold MyTime.timeScale, or release it with no value", gated: true, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => Perf("timescale", args), "usage: time_scale [value]"));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.screenshot", "save the rendered frame as a PNG", gated: true, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => (args.Count != 1 || args[0].Trim().Length <= 0) ? NoMatch() : Command(new HarnessCommand(HarnessCommandKind.Screenshot, args[0]))));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.query_objects", "list loaded objects of a type with chosen fields", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			if (args.Count < 1 || args[0].Length <= 0 || !args.Skip(1).All((string f) => f.Length > 0))
			{
				return NoMatch();
			}
			QueryArgs query = new QueryArgs
			{
				TypeName = args[0],
				Fields = args.Skip(1).ToArray()
			};
			return Command(new HarnessCommand(HarnessCommandKind.QueryObjects, null, default(CameraPose), Enabled: false, null, null, null, 0, query));
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.material_dump", "dump the materials under the named objects", gated: true, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => (args.Count > 1 || (args.Count != 0 && args[0].Trim().Length <= 0)) ? NoMatch() : Command(new HarnessCommand(HarnessCommandKind.MaterialDump, (args.Count == 1) ? args[0] : null))));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.shader_report", "list the shaders the game ships and uses", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.ShaderReport)));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.heartbeat", "start or stop the kill-floor heartbeat", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			bool? flag = Flag(args, current: true);
			if (!flag.HasValue)
			{
				return NoMatch();
			}
			bool valueOrDefault = flag == true;
			return Enabled(HarnessCommandKind.Heartbeat, valueOrDefault);
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.cells", "start or stop the cell-change log", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			bool? flag = Flag(args, current: true);
			if (!flag.HasValue)
			{
				return NoMatch();
			}
			bool valueOrDefault = flag == true;
			return Enabled(HarnessCommandKind.Cells, valueOrDefault);
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.ui_tree", "list the editor widgets, or the one at a pixel", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			switch (args.Count)
			{
			case 0:
			{
				InputArgs input = new InputArgs
				{
					Action = "ui-tree"
				};
				return Command(new HarnessCommand(HarnessCommandKind.UiTree, null, default(CameraPose), Enabled: false, null, input));
			}
			case 2:
			{
				if (Float(args[0], out var parsed) && Float(args[1], out var parsed2))
				{
					InputArgs input = new InputArgs
					{
						Action = "ui-tree",
						X = parsed,
						Y = parsed2
					};
					return Command(new HarnessCommand(HarnessCommandKind.UiTree, null, default(CameraPose), Enabled: false, null, input));
				}
				break;
			}
			}
			return NoMatch();
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("debug.click_widget", "click the named editor widget", gated: true, delegate(IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _)
		{
			if (args.Count != 1 || args[0].Length <= 0)
			{
				return NoMatch();
			}
			InputArgs input = new InputArgs
			{
				Action = "click-widget",
				Text = args[0]
			};
			return Command(new HarnessCommand(HarnessCommandKind.ClickWidget, null, default(CameraPose), Enabled: false, null, input));
		}));
		consoleCommandRegistry.Add(new ConsoleVerb("app.quit", "quit the game", gated: true, (IReadOnlyList<string> _, ConsoleToggleState _, IReadOnlyList<string> _) => Command(HarnessCommandKind.Quit)).WithAliases("qqq"));
		consoleCommandRegistry.Add(new ConsoleVerb("music.play", "resume paused music, or play track n", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => (args.Count != 0) ? MusicTrack(args) : MusicTransport(args, "play"), "usage: music.play [n]"));
		consoleCommandRegistry.Add(new ConsoleVerb("music.pause", "pause the current music", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => MusicTransport(args, "pause")));
		consoleCommandRegistry.Add(new ConsoleVerb("music.next", "go to the next track", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => MusicTransport(args, "next")));
		consoleCommandRegistry.Add(new ConsoleVerb("music.prev", "go to the previous track", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => MusicTransport(args, "prev")));
		consoleCommandRegistry.Add(new ConsoleVerb("music.track", "jump to track n", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => MusicTrack(args), "usage: music.track n"));
		consoleCommandRegistry.Add(new ConsoleVerb("music.list", "list the tracks, marking the current one", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => MusicTransport(args, "list")));
		consoleCommandRegistry.Add(new ConsoleVerb("music.now", "show the current track", gated: false, (IReadOnlyList<string> args, ConsoleToggleState _, IReadOnlyList<string> _) => MusicTransport(args, "now")));
		return consoleCommandRegistry;
	}

	private static ConsoleBindResult MusicTrack(IReadOnlyList<string> args)
	{
		if (args.Count != 1 || !Int(args[0], 1, int.MaxValue, out var parsed))
		{
			return NoMatch();
		}
		MusicArgs music = new MusicArgs
		{
			Action = "track",
			Track = parsed
		};
		return Command(new HarnessCommand(HarnessCommandKind.Music, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, null, null, Skip: false, null, null, null, music));
	}

	private static ConsoleBindResult MusicTransport(IReadOnlyList<string> args, string action)
	{
		if (args.Count != 0)
		{
			return NoMatch();
		}
		MusicArgs music = new MusicArgs
		{
			Action = action
		};
		return Command(new HarnessCommand(HarnessCommandKind.Music, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, null, null, Skip: false, null, null, null, music));
	}

	private static ConsoleBindResult NoCommand()
	{
		return new ConsoleBindResult(null, "", null);
	}

	private static ConsoleBindResult NoMatch()
	{
		return new ConsoleBindResult(null, null, "no match");
	}

	private static ConsoleBindResult Command(HarnessCommandKind kind)
	{
		return new ConsoleBindResult(new HarnessCommand(kind, null), null, null);
	}

	private static ConsoleBindResult Command(HarnessCommand command)
	{
		return new ConsoleBindResult(command, null, null);
	}

	private static ConsoleBindResult Enabled(HarnessCommandKind kind, bool enabled)
	{
		bool enabled2 = enabled;
		return new ConsoleBindResult(new HarnessCommand(kind, null, default(CameraPose), enabled2), null, null);
	}

	private static string PerfHelp(string action)
	{
		return action switch
		{
			"report" => "frame percentiles for the last window", 
			"status" => "the live profiler toggles", 
			"start" => "clear the window and start measuring", 
			"reset" => "restore every profiler setting", 
			"spawn" => "add enemies around the player", 
			"timescale" => "hold or release MyTime.timeScale", 
			"toggle" => "switch one tick or patch probe", 
			"vsync" => "lift or restore the vsync cap", 
			"render" => "hide or show enemy renderers", 
			"physics" => "freeze or unfreeze enemy rigidbodies", 
			"animation" => "stop or resume enemy animation", 
			"health" => "park the player's hit points", 
			"census" => "count components by type", 
			_ => "frame profiler", 
		};
	}

	private static string PerfUsage(string action)
	{
		switch (action)
		{
		case "toggle":
			return "usage: perf.toggle <target> <on|off>";
		case "render":
		case "vsync":
		case "animation":
		case "physics":
			return "usage: perf." + action + " <on|off>";
		case "spawn":
			return $"usage: perf.spawn <1-{300}>";
		case "timescale":
			return "usage: perf.timescale [value]";
		case "health":
			return "usage: perf.health [hp]";
		default:
			return "usage: perf." + action;
		}
	}

	private static ConsoleBindResult Perf(string action, IReadOnlyList<string> args)
	{
		switch (action)
		{
		case "spawn":
		{
			if (args.Count != 1 || !Int(args[0], 1, 300, out var parsed3))
			{
				return NoMatch();
			}
			PerfArgs perf = new PerfArgs
			{
				Action = action,
				Count = parsed3
			};
			return Command(new HarnessCommand(HarnessCommandKind.Perf, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, perf));
		}
		case "timescale":
		{
			float parsed = 0f;
			if (args.Count > 1 || (args.Count != 0 && (!Float(args[0], out parsed) || !PerfLimits.ValidTimeScale(parsed))))
			{
				return NoMatch();
			}
			PerfArgs perf = new PerfArgs
			{
				Action = action,
				Value = ((args.Count == 1) ? new float?(parsed) : ((float?)null))
			};
			return Command(new HarnessCommand(HarnessCommandKind.Perf, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, perf));
		}
		case "toggle":
			if (args.Count == 2 && args[0].Length > 0)
			{
				bool? flag = OnOff(args[1]);
				if (flag.HasValue)
				{
					bool valueOrDefault = flag == true;
					PerfArgs perf = new PerfArgs
					{
						Action = action,
						Target = args[0],
						Enabled = valueOrDefault
					};
					return Command(new HarnessCommand(HarnessCommandKind.Perf, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, perf));
				}
			}
			return NoMatch();
		case "vsync":
		case "animation":
		case "render":
		case "physics":
			if (args.Count == 1)
			{
				bool? flag = OnOff(args[0]);
				if (flag.HasValue)
				{
					bool valueOrDefault2 = flag == true;
					PerfArgs perf = new PerfArgs
					{
						Action = action,
						Enabled = valueOrDefault2
					};
					return Command(new HarnessCommand(HarnessCommandKind.Perf, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, perf));
				}
			}
			return NoMatch();
		case "health":
		{
			int parsed2 = 0;
			if (args.Count > 1 || (args.Count != 0 && !Int(args[0], 1, 100000000, out parsed2)))
			{
				return NoMatch();
			}
			PerfArgs perf = new PerfArgs
			{
				Action = action,
				Hp = ((args.Count == 1) ? new int?(parsed2) : ((int?)null))
			};
			return Command(new HarnessCommand(HarnessCommandKind.Perf, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, perf));
		}
		default:
		{
			if (args.Count != 0)
			{
				return NoMatch();
			}
			PerfArgs perf = new PerfArgs
			{
				Action = action
			};
			return Command(new HarnessCommand(HarnessCommandKind.Perf, null, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, perf));
		}
		}
	}

	private static ConsoleBindResult LoadLevel(IReadOnlyList<string> args, ConsoleToggleState toggles, IReadOnlyList<string> levels)
	{
		if (args.Count == 0 || string.IsNullOrWhiteSpace(args[0]))
		{
			return NoMatch();
		}
		string error;
		string text = ResolveLevelTarget(args[0], levels, out error);
		if (text == null)
		{
			return new ConsoleBindResult(null, null, error);
		}
		OptionSet optionSet = ParseOverrides(args.Skip(1).ToArray(), allowSize: false);
		if (optionSet.Bad)
		{
			return NoMatch();
		}
		bool flag = !text.Contains('/') && !text.Contains('\\');
		bool flag2 = optionSet.Map.HasValue || optionSet.Stage.HasValue || optionSet.Tier.HasValue || optionSet.Seed.HasValue || optionSet.Unseeded;
		if (toggles.Editor && flag && !flag2)
		{
			return Command(new HarnessCommand(HarnessCommandKind.EditorLoad, text));
		}
		LoadOverrides overrides = new LoadOverrides(optionSet.Map, optionSet.Stage, optionSet.Tier, optionSet.Seed, null, optionSet.Unseeded);
		return Command(new HarnessCommand(HarnessCommandKind.LoadLevel, text, default(CameraPose), Enabled: false, null, null, null, 0, null, overrides));
	}

	private static ConsoleBindResult NewLevel(IReadOnlyList<string> args)
	{
		string text = ((args.Count > 0 && args[0].Trim().Length > 0) ? args[0] : null);
		OptionSet optionSet = ParseOverrides(args.Skip((text != null) ? 1 : 0).ToArray(), allowSize: true);
		if (!optionSet.Bad)
		{
			NewLevelArgs? newLevel = new NewLevelArgs(optionSet.Map ?? 1, optionSet.Stage.GetValueOrDefault(), optionSet.Tier.GetValueOrDefault(), optionSet.Size ?? 7);
			return Command(new HarnessCommand(HarnessCommandKind.NewLevel, text, default(CameraPose), Enabled: false, null, null, null, 0, null, default(LoadOverrides), null, null, null, null, null, Skip: false, null, newLevel));
		}
		return NoMatch();
	}

	private static OptionSet ParseOverrides(IReadOnlyList<string> args, bool allowSize)
	{
		int? map = null;
		int? stage = null;
		int? tier = null;
		int? seed = null;
		int? size = null;
		bool unseeded = false;
		for (int i = 0; i < args.Count; i++)
		{
			bool flag = i == args.Count - 1;
			if (args[i] == "noseed" && flag)
			{
				unseeded = true;
				continue;
			}
			if (flag)
			{
				return OptionSet.Rejected;
			}
			bool flag2 = true;
			switch (args[i])
			{
			case "map":
			{
				flag2 = Int(args[i + 1], 0, int.MaxValue, out var parsed4) && ValidMap(parsed4) && Set(parsed4, delegate(int v)
				{
					map = v;
				});
				break;
			}
			case "stage":
			{
				flag2 = Int(args[i + 1], 0, int.MaxValue, out var parsed3) && Set(parsed3, delegate(int v)
				{
					stage = v;
				});
				break;
			}
			case "tier":
			{
				flag2 = Int(args[i + 1], 0, int.MaxValue, out var parsed5) && Set(parsed5, delegate(int v)
				{
					tier = v;
				});
				break;
			}
			case "seed":
			{
				flag2 = Int(args[i + 1], int.MinValue, int.MaxValue, out var parsed2) && Set(parsed2, delegate(int v)
				{
					seed = v;
				});
				break;
			}
			case "size":
				if (allowSize)
				{
					flag2 = Int(args[i + 1], 3, int.MaxValue, out var parsed) && Set(parsed, delegate(int v)
					{
						size = v;
					});
					break;
				}
				goto default;
			default:
				flag2 = false;
				break;
			}
			if (!flag2)
			{
				return OptionSet.Rejected;
			}
			i++;
		}
		return new OptionSet(map, stage, tier, seed, size, unseeded, Bad: false);
	}

	private static bool Set<T>(T value, Action<T> assign)
	{
		assign(value);
		return true;
	}

	private static bool ValidMap(int value)
	{
		return Enum.GetValues<EMap>().Any((EMap m) => m != EMap.None && m == (EMap)value);
	}

	private static string ResolveLevelTarget(string target, IReadOnlyList<string> levels, out string error)
	{
		error = null;
		bool flag = target.EndsWith(".json", StringComparison.OrdinalIgnoreCase);
		if (target.Contains('/') || target.Contains('\\'))
		{
			return target;
		}
		string fileName = (flag ? target : (target + ".mblevel.json"));
		if (levels == null || levels.Count == 0)
		{
			return fileName;
		}
		string wanted = Normalize(target);
		List<string> list = levels.Where((string l) => Normalize(LevelStem(l)) == wanted).ToList();
		if (list.Count == 1)
		{
			return list[0];
		}
		if (list.Count > 1)
		{
			error = "'" + target + "' is ambiguous: " + string.Join(", ", list);
			return null;
		}
		string text = levels.FirstOrDefault((string l) => string.Equals(l, fileName, StringComparison.OrdinalIgnoreCase));
		if (text != null)
		{
			return text;
		}
		error = "no level named '" + target + "'; run level.list";
		return null;
	}

	private static IEnumerable<string> LevelTitles(int argumentIndex, IReadOnlyList<string> levels)
	{
		if (argumentIndex != 0 || levels == null)
		{
			return Enumerable.Empty<string>();
		}
		return levels.Select(LevelStem);
	}

	private static string Normalize(string value)
	{
		return new string((value ?? "").Where(char.IsLetterOrDigit).Select(char.ToLowerInvariant).ToArray());
	}

	private static string LevelStem(string fileName)
	{
		string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
		if (!fileNameWithoutExtension.EndsWith(".mblevel", StringComparison.OrdinalIgnoreCase))
		{
			return fileNameWithoutExtension;
		}
		return fileNameWithoutExtension.Substring(0, fileNameWithoutExtension.Length - ".mblevel".Length);
	}

	private static bool? Flag(IReadOnlyList<string> args, bool current)
	{
		if (args.Count != 1)
		{
			if (args.Count != 0)
			{
				return null;
			}
			return !current;
		}
		return OnOff(args[0]);
	}

	private static bool? OnOff(string value)
	{
		if (!string.Equals(value, "on", StringComparison.OrdinalIgnoreCase))
		{
			if (!string.Equals(value, "off", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			return false;
		}
		return true;
	}

	private static bool? Nonlethal(IReadOnlyList<string> args)
	{
		switch (args.Count)
		{
		case 1:
			return true;
		case 2:
			if (string.Equals(args[1], "lethal", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (string.Equals(args[1], "nonlethal", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return OnOff(args[1]);
		default:
			return null;
		}
	}

	private static bool Int(string value, int min, int max, out int parsed)
	{
		if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsed) && parsed >= min)
		{
			return parsed <= max;
		}
		return false;
	}

	private static bool Ints(IReadOnlyList<string> args, out int[] values)
	{
		values = null;
		if (args.Count != 2)
		{
			return false;
		}
		values = new int[2];
		if (Int(args[0], int.MinValue, int.MaxValue, out values[0]))
		{
			return Int(args[1], int.MinValue, int.MaxValue, out values[1]);
		}
		return false;
	}

	private static bool Float(string va

BepInEx/plugins/MegabonkLevels/NLayer.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using NLayer.Decoder;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Mark Heath, Andrew Ward")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fully Managed MPEG 1 & 2 Decoder for Layers 1, 2, & 3")]
[assembly: AssemblyFileVersion("1.16.0.0")]
[assembly: AssemblyInformationalVersion("1.16.0+c88b0d8abfa15c1e506106931ea8410170dc6326")]
[assembly: AssemblyProduct("NLayer")]
[assembly: AssemblyTitle("NLayer")]
[assembly: AssemblyVersion("1.16.0.0")]
namespace NLayer
{
	public enum MpegVersion
	{
		Unknown = 0,
		Version1 = 10,
		Version2 = 20,
		Version25 = 25
	}
	public enum MpegLayer
	{
		Unknown,
		LayerI,
		LayerII,
		LayerIII
	}
	public enum MpegChannelMode
	{
		Stereo,
		JointStereo,
		DualChannel,
		Mono
	}
	public enum StereoMode
	{
		Both,
		LeftOnly,
		RightOnly,
		DownmixToMono
	}
	public interface IMpegFrame
	{
		int SampleRate { get; }

		int SampleRateIndex { get; }

		int FrameLength { get; }

		int BitRate { get; }

		MpegVersion Version { get; }

		MpegLayer Layer { get; }

		MpegChannelMode ChannelMode { get; }

		int ChannelModeExtension { get; }

		int SampleCount { get; }

		int BitRateIndex { get; }

		bool IsCopyrighted { get; }

		bool HasCrc { get; }

		bool IsCorrupted { get; }

		void Reset();

		int ReadBits(int bitCount);
	}
	public class MpegFile : IDisposable
	{
		private Stream _stream;

		private bool _closeStream;

		private bool _eofFound;

		private MpegStreamReader _reader;

		private MpegFrameDecoder _decoder;

		private object _seekLock = new object();

		private long _position;

		private float[] _readBuf = new float[2304];

		private int _readBufLen;

		private int _readBufOfs;

		public int SampleRate => _reader.SampleRate;

		public int Channels => _reader.Channels;

		public bool CanSeek => _reader.CanSeek;

		public long Length => _reader.SampleCount * _reader.Channels * 4;

		public TimeSpan Duration
		{
			get
			{
				long sampleCount = _reader.SampleCount;
				if (sampleCount == -1)
				{
					return TimeSpan.Zero;
				}
				return TimeSpan.FromSeconds((double)sampleCount / (double)_reader.SampleRate);
			}
		}

		public long Position
		{
			get
			{
				return _position;
			}
			set
			{
				if (!_reader.CanSeek)
				{
					throw new InvalidOperationException("Cannot Seek!");
				}
				if (value < 0)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				long num = value / 4 / _reader.Channels;
				int num2 = 0;
				if (num >= _reader.FirstFrameSampleCount)
				{
					num2 = _reader.FirstFrameSampleCount;
					num -= num2;
				}
				lock (_seekLock)
				{
					long num3 = _reader.SeekTo(num);
					if (num3 == -1)
					{
						throw new ArgumentOutOfRangeException("value");
					}
					_decoder.Reset();
					if (num2 != 0)
					{
						_decoder.DecodeFrame(_reader.NextFrame(), _readBuf, 0);
						num3 += num2;
					}
					_position = num3 * 4 * _reader.Channels;
					_eofFound = false;
					_readBufOfs = (_readBufLen = 0);
				}
			}
		}

		public TimeSpan Time
		{
			get
			{
				return TimeSpan.FromSeconds((double)_position / 4.0 / (double)_reader.Channels / (double)_reader.SampleRate);
			}
			set
			{
				Position = (long)(value.TotalSeconds * (double)_reader.SampleRate * (double)_reader.Channels * 4.0);
			}
		}

		public StereoMode StereoMode
		{
			get
			{
				return _decoder.StereoMode;
			}
			set
			{
				_decoder.StereoMode = value;
			}
		}

		public MpegFile(string fileName)
		{
			Init(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), closeStream: true);
		}

		public MpegFile(Stream stream)
		{
			Init(stream, closeStream: false);
		}

		private void Init(Stream stream, bool closeStream)
		{
			_stream = stream;
			_closeStream = closeStream;
			_reader = new MpegStreamReader(_stream);
			_decoder = new MpegFrameDecoder();
		}

		public void Dispose()
		{
			if (_closeStream)
			{
				_stream.Dispose();
				_closeStream = false;
			}
		}

		public void SetEQ(float[] eq)
		{
			_decoder.SetEQ(eq);
		}

		public int ReadSamples(byte[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			count -= count % 4;
			return ReadSamplesImpl(buffer, index, count, 32);
		}

		public int ReadSamples(float[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return ReadSamplesImpl(buffer, index * 4, count * 4, 32) / 4;
		}

		public int ReadSamplesInt16(byte[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length * 2)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return ReadSamplesImpl(buffer, index, count, 16) * 2 / 4;
		}

		public int ReadSamplesInt8(byte[] buffer, int index, int count)
		{
			if (index < 0 || index + count > buffer.Length * 4)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return ReadSamplesImpl(buffer, index, count, 8) / 4;
		}

		private int ReadSamplesImpl(Array buffer, int index, int count, int bitDepth)
		{
			int num = 0;
			lock (_seekLock)
			{
				while (count > 0)
				{
					if (_readBufLen > _readBufOfs)
					{
						int num2 = _readBufLen - _readBufOfs;
						if (num2 > count)
						{
							num2 = count;
						}
						if (bitDepth == 32)
						{
							Buffer.BlockCopy(_readBuf, _readBufOfs, buffer, index, num2);
						}
						else
						{
							for (int i = 0; i < num2 / 4; i++)
							{
								switch (bitDepth)
								{
								case 8:
									buffer.SetValue((byte)Math.Round(127.5f * _readBuf[_readBufOfs / 4 + i] + 127.5f), index / 4 + i);
									break;
								case 16:
								{
									int num3 = (int)Math.Round(32767.5f * _readBuf[_readBufOfs / 4 + i] - 0.5f);
									if (num3 < 0)
									{
										num3 += 65536;
									}
									buffer.SetValue((byte)(num3 % 256), 2 * (index / 4 + i));
									buffer.SetValue((byte)(num3 / 256), 2 * (index / 4 + i) + 1);
									break;
								}
								}
							}
						}
						num += num2;
						count -= num2;
						index += num2;
						_position += num2;
						_readBufOfs += num2;
						if (_readBufOfs == _readBufLen)
						{
							_readBufLen = 0;
						}
					}
					if (_readBufLen != 0)
					{
						continue;
					}
					if (_eofFound)
					{
						break;
					}
					MpegFrame mpegFrame = _reader.NextFrame();
					if (mpegFrame == null)
					{
						_eofFound = true;
						break;
					}
					try
					{
						_readBufLen = _decoder.DecodeFrame(mpegFrame, _readBuf, 0) * 4;
						_readBufOfs = 0;
					}
					catch (InvalidDataException)
					{
						_decoder.Reset();
						_readBufOfs = (_readBufLen = 0);
					}
					catch (EndOfStreamException)
					{
						_eofFound = true;
						break;
					}
					finally
					{
						mpegFrame.ClearBuffer();
					}
				}
			}
			return num;
		}
	}
	public class MpegFrameDecoder
	{
		private LayerIDecoder _layerIDecoder;

		private LayerIIDecoder _layerIIDecoder;

		private LayerIIIDecoder _layerIIIDecoder;

		private float[] _eqFactors;

		private float[] _ch0;

		private float[] _ch1;

		public StereoMode StereoMode { get; set; }

		public MpegFrameDecoder()
		{
			_ch0 = new float[1152];
			_ch1 = new float[1152];
		}

		public void SetEQ(float[] eq)
		{
			if (eq != null)
			{
				float[] array = new float[32];
				for (int i = 0; i < eq.Length; i++)
				{
					array[i] = (float)Math.Pow(2.0, eq[i] / 6f);
				}
				_eqFactors = array;
			}
			else
			{
				_eqFactors = null;
			}
		}

		public int DecodeFrame(IMpegFrame frame, byte[] dest, int destOffset)
		{
			if (frame == null)
			{
				throw new ArgumentNullException("frame");
			}
			if (dest == null)
			{
				throw new ArgumentNullException("dest");
			}
			if (destOffset % 4 != 0)
			{
				throw new ArgumentException("Must be an even multiple of 4", "destOffset");
			}
			if ((dest.Length - destOffset) / 4 < ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) * frame.SampleCount)
			{
				throw new ArgumentException("Buffer not large enough!  Must be big enough to hold the frame's entire output.  This is up to 9,216 bytes.", "dest");
			}
			return DecodeFrameImpl(frame, dest, destOffset / 4) * 4;
		}

		public int DecodeFrame(IMpegFrame frame, float[] dest, int destOffset)
		{
			if (frame == null)
			{
				throw new ArgumentNullException("frame");
			}
			if (dest == null)
			{
				throw new ArgumentNullException("dest");
			}
			if (dest.Length - destOffset < ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) * frame.SampleCount)
			{
				throw new ArgumentException("Buffer not large enough!  Must be big enough to hold the frame's entire output.  This is up to 2,304 elements.", "dest");
			}
			return DecodeFrameImpl(frame, dest, destOffset);
		}

		private int DecodeFrameImpl(IMpegFrame frame, Array dest, int destOffset)
		{
			frame.Reset();
			LayerDecoderBase layerDecoderBase = null;
			switch (frame.Layer)
			{
			case MpegLayer.LayerI:
				if (_layerIDecoder == null)
				{
					_layerIDecoder = new LayerIDecoder();
				}
				layerDecoderBase = _layerIDecoder;
				break;
			case MpegLayer.LayerII:
				if (_layerIIDecoder == null)
				{
					_layerIIDecoder = new LayerIIDecoder();
				}
				layerDecoderBase = _layerIIDecoder;
				break;
			case MpegLayer.LayerIII:
				if (_layerIIIDecoder == null)
				{
					_layerIIIDecoder = new LayerIIIDecoder();
				}
				layerDecoderBase = _layerIIIDecoder;
				break;
			}
			if (layerDecoderBase != null)
			{
				layerDecoderBase.SetEQ(_eqFactors);
				layerDecoderBase.StereoMode = StereoMode;
				int num = layerDecoderBase.DecodeFrame(frame, _ch0, _ch1);
				if (frame.ChannelMode == MpegChannelMode.Mono)
				{
					Buffer.BlockCopy(_ch0, 0, dest, destOffset * 4, num * 4);
				}
				else
				{
					for (int i = 0; i < num; i++)
					{
						Buffer.BlockCopy(_ch0, i * 4, dest, destOffset * 4, 4);
						destOffset++;
						Buffer.BlockCopy(_ch1, i * 4, dest, destOffset * 4, 4);
						destOffset++;
					}
					num *= 2;
				}
				return num;
			}
			return 0;
		}

		public void Reset()
		{
			if (_layerIDecoder != null)
			{
				_layerIDecoder.ResetForSeek();
			}
			if (_layerIIDecoder != null)
			{
				_layerIIDecoder.ResetForSeek();
			}
			if (_layerIIIDecoder != null)
			{
				_layerIIIDecoder.ResetForSeek();
			}
		}
	}
}
namespace NLayer.Decoder
{
	internal class BitReservoir
	{
		private byte[] _buf = new byte[8192];

		private int _start;

		private int _end = -1;

		private int _bitsLeft;

		private long _bitsRead;

		public int BitsAvailable
		{
			get
			{
				if (_bitsLeft > 0)
				{
					return (_end + _buf.Length - _start) % _buf.Length * 8 + _bitsLeft;
				}
				return 0;
			}
		}

		public long BitsRead => _bitsRead;

		private static int GetSlots(IMpegFrame frame)
		{
			int num = frame.FrameLength - 4;
			if (frame.HasCrc)
			{
				num -= 2;
			}
			if (frame.Version == MpegVersion.Version1 && frame.ChannelMode != MpegChannelMode.Mono)
			{
				return num - 32;
			}
			if (frame.Version > MpegVersion.Version1 && frame.ChannelMode == MpegChannelMode.Mono)
			{
				return num - 9;
			}
			return num - 17;
		}

		public bool AddBits(IMpegFrame frame, int overlap)
		{
			int end = _end;
			int num = GetSlots(frame);
			while (--num >= 0)
			{
				int num2 = frame.ReadBits(8);
				if (num2 == -1)
				{
					throw new InvalidDataException("Frame did not have enough bytes!");
				}
				_buf[++_end] = (byte)num2;
				if (_end == _buf.Length - 1)
				{
					_end = -1;
				}
			}
			_bitsLeft = 8;
			if (end == -1)
			{
				return overlap == 0;
			}
			if ((end + 1 - _start + _buf.Length) % _buf.Length >= overlap)
			{
				_start = (end + 1 - overlap + _buf.Length) % _buf.Length;
				return true;
			}
			_start = end + overlap;
			return false;
		}

		public int GetBits(int count)
		{
			int readCount;
			int result = TryPeekBits(count, out readCount);
			if (readCount < count)
			{
				throw new InvalidDataException("Reservoir did not have enough bytes!");
			}
			SkipBits(count);
			return result;
		}

		public int Get1Bit()
		{
			if (_bitsLeft == 0)
			{
				throw new InvalidDataException("Reservoir did not have enough bytes!");
			}
			_bitsLeft--;
			_bitsRead++;
			int result = (_buf[_start] >> _bitsLeft) & 1;
			if (_bitsLeft == 0 && (_start = (_start + 1) % _buf.Length) != _end + 1)
			{
				_bitsLeft = 8;
			}
			return result;
		}

		public int TryPeekBits(int count, out int readCount)
		{
			if (count < 0 || count > 32)
			{
				throw new ArgumentOutOfRangeException("count", "Must return between 0 and 32 bits!");
			}
			if (_bitsLeft == 0 || count == 0)
			{
				readCount = 0;
				return 0;
			}
			int num = _buf[_start];
			if (count < _bitsLeft)
			{
				num >>= _bitsLeft - count;
				num &= (1 << count) - 1;
				readCount = count;
				return num;
			}
			num &= (1 << _bitsLeft) - 1;
			count -= _bitsLeft;
			readCount = _bitsLeft;
			int num2 = _start;
			while (count > 0 && (num2 = (num2 + 1) % _buf.Length) != _end + 1)
			{
				int num3 = Math.Min(count, 8);
				num <<= num3;
				num |= _buf[num2] >> (8 - num3) % 8;
				count -= num3;
				readCount += num3;
			}
			return num;
		}

		public void SkipBits(int count)
		{
			if (count > 0)
			{
				if (count > BitsAvailable)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				int num = 8 - _bitsLeft + count;
				_start = (num / 8 + _start) % _buf.Length;
				_bitsLeft = 8 - num % 8;
				_bitsRead += count;
			}
		}

		public void RewindBits(int count)
		{
			_bitsLeft += count;
			_bitsRead -= count;
			while (_bitsLeft > 8)
			{
				_start--;
				_bitsLeft -= 8;
			}
			while (_start < 0)
			{
				_start += _buf.Length;
			}
		}

		public void FlushBits()
		{
			if (_bitsLeft < 8)
			{
				SkipBits(_bitsLeft);
			}
		}

		public void Reset()
		{
			_start = 0;
			_end = -1;
			_bitsLeft = 0;
		}
	}
	internal abstract class FrameBase
	{
		private static int _totalAllocation;

		private MpegStreamReader _reader;

		private byte[] _savedBuffer;

		internal static int TotalAllocation => Interlocked.CompareExchange(ref _totalAllocation, 0, 0);

		internal long Offset { get; private set; }

		internal int Length { get; set; }

		internal bool Validate(long offset, MpegStreamReader reader)
		{
			Offset = offset;
			_reader = reader;
			int num = Validate();
			if (num > 0)
			{
				Length = num;
				return true;
			}
			return false;
		}

		protected int Read(int offset, byte[] buffer)
		{
			return Read(offset, buffer, 0, buffer.Length);
		}

		protected int Read(int offset, byte[] buffer, int index, int count)
		{
			if (_savedBuffer != null)
			{
				if (index < 0 || index + count > buffer.Length)
				{
					return 0;
				}
				if (offset < 0 || offset >= _savedBuffer.Length)
				{
					return 0;
				}
				if (offset + count > _savedBuffer.Length)
				{
					count = _savedBuffer.Length - index;
				}
				Array.Copy(_savedBuffer, offset, buffer, index, count);
				return count;
			}
			return _reader.Read(Offset + offset, buffer, index, count);
		}

		protected int ReadByte(int offset)
		{
			if (_savedBuffer != null)
			{
				if (offset < 0)
				{
					throw new ArgumentOutOfRangeException();
				}
				if (offset >= _savedBuffer.Length)
				{
					return -1;
				}
				return _savedBuffer[offset];
			}
			return _reader.ReadByte(Offset + offset);
		}

		protected abstract int Validate();

		internal void SaveBuffer()
		{
			_savedBuffer = new byte[Length];
			_reader.Read(Offset, _savedBuffer, 0, Length);
			Interlocked.Add(ref _totalAllocation, Length);
		}

		internal void ClearBuffer()
		{
			Interlocked.Add(ref _totalAllocation, -Length);
			_savedBuffer = null;
		}

		internal virtual void Parse()
		{
		}
	}
	internal class Huffman
	{
		private class HuffmanListNode
		{
			internal byte Value;

			internal int Length;

			internal int Bits;

			internal int Mask;

			internal HuffmanListNode Next;
		}

		private static readonly byte[][,] _codeTables;

		private static readonly float[] _floatLookup;

		private static HuffmanListNode[] _llCache;

		private static int[] _llCacheMaxBits;

		private static readonly int[] LIN_BITS;

		static Huffman()
		{
			_codeTables = new byte[17][,]
			{
				new byte[7, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 }
				},
				new byte[17, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 }
				},
				new byte[17, 2]
				{
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 2, 1 },
					{ 0, 16 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 }
				},
				new byte[31, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 49 },
					{ 2, 1 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 0, 51 }
				},
				new byte[31, 2]
				{
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 16 },
					{ 0, 17 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 51 }
				},
				new byte[71, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 0, 33 },
					{ 18, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 0, 4 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 65 },
					{ 2, 1 },
					{ 0, 20 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 67 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 52 },
					{ 0, 5 },
					{ 0, 81 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 53 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 83 },
					{ 0, 84 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 85 }
				},
				new byte[71, 2]
				{
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 34 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 2, 1 },
					{ 0, 65 },
					{ 2, 1 },
					{ 0, 20 },
					{ 0, 66 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 36 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 0, 81 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 82 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 37 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 83 },
					{ 2, 1 },
					{ 0, 69 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 85 }
				},
				new byte[71, 2]
				{
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 34 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 0, 49 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 20 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 51 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 80 },
					{ 0, 67 },
					{ 2, 1 },
					{ 0, 52 },
					{ 0, 81 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 21 },
					{ 0, 82 },
					{ 2, 1 },
					{ 0, 37 },
					{ 0, 68 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 84 },
					{ 0, 83 },
					{ 2, 1 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 85 }
				},
				new byte[127, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 10, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 28, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 50 },
					{ 2, 1 },
					{ 0, 35 },
					{ 0, 64 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 20 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 51 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 28, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 80 },
					{ 0, 5 },
					{ 0, 96 },
					{ 2, 1 },
					{ 0, 97 },
					{ 0, 22 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 0, 81 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 54 },
					{ 0, 113 },
					{ 20, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 0, 6 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 53 },
					{ 0, 69 },
					{ 0, 98 },
					{ 2, 1 },
					{ 0, 112 },
					{ 2, 1 },
					{ 0, 7 },
					{ 0, 100 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 114 },
					{ 0, 39 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 99 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 85 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 115 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 55 },
					{ 0, 101 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 116 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 71 },
					{ 2, 1 },
					{ 0, 102 },
					{ 0, 117 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 87 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 119 }
				},
				new byte[127, 2]
				{
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 0, 18 },
					{ 24, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 20 },
					{ 30, 1 },
					{ 16, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 67 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 52 },
					{ 0, 81 },
					{ 0, 97 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 22 },
					{ 2, 1 },
					{ 0, 6 },
					{ 0, 38 },
					{ 2, 1 },
					{ 0, 98 },
					{ 2, 1 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 82 },
					{ 16, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 37 },
					{ 0, 68 },
					{ 0, 96 },
					{ 2, 1 },
					{ 0, 99 },
					{ 0, 54 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 23 },
					{ 0, 113 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 7 },
					{ 0, 100 },
					{ 0, 114 },
					{ 2, 1 },
					{ 0, 39 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 83 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 69 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 115 },
					{ 2, 1 },
					{ 0, 55 },
					{ 2, 1 },
					{ 0, 101 },
					{ 0, 86 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 85 },
					{ 0, 87 },
					{ 0, 116 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 119 }
				},
				new byte[127, 2]
				{
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 16, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 49 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 64 },
					{ 26, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 2, 1 },
					{ 0, 65 },
					{ 0, 51 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 0, 66 },
					{ 2, 1 },
					{ 0, 36 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 80 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 2, 1 },
					{ 0, 81 },
					{ 0, 21 },
					{ 28, 1 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 2, 1 },
					{ 0, 83 },
					{ 0, 53 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 22 },
					{ 0, 97 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 98 },
					{ 0, 38 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 6 },
					{ 0, 68 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 69 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 99 },
					{ 0, 54 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 7 },
					{ 0, 113 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 0, 100 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 114 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 39 },
					{ 2, 1 },
					{ 0, 85 },
					{ 0, 115 },
					{ 2, 1 },
					{ 0, 55 },
					{ 0, 86 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 101 },
					{ 0, 116 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 119 }
				},
				new byte[511, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 28, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 0, 48 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 49 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 0, 65 },
					{ 70, 1 },
					{ 28, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 66 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 36 },
					{ 0, 80 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 81 },
					{ 0, 21 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 82 },
					{ 2, 1 },
					{ 0, 37 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 2, 1 },
					{ 0, 97 },
					{ 0, 22 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 128 },
					{ 0, 8 },
					{ 0, 129 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 53 },
					{ 0, 98 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 84 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 99 },
					{ 2, 1 },
					{ 0, 54 },
					{ 0, 112 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 7 },
					{ 0, 85 },
					{ 0, 113 },
					{ 2, 1 },
					{ 0, 23 },
					{ 2, 1 },
					{ 0, 39 },
					{ 0, 55 },
					{ 72, 1 },
					{ 24, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 24 },
					{ 0, 130 },
					{ 2, 1 },
					{ 0, 40 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 100 },
					{ 0, 70 },
					{ 0, 114 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 132 },
					{ 0, 72 },
					{ 2, 1 },
					{ 0, 144 },
					{ 0, 9 },
					{ 2, 1 },
					{ 0, 145 },
					{ 0, 25 },
					{ 24, 1 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 115 },
					{ 0, 101 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 116 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 0, 131 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 56 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 41 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 133 },
					{ 2, 1 },
					{ 0, 88 },
					{ 0, 57 },
					{ 2, 1 },
					{ 0, 147 },
					{ 2, 1 },
					{ 0, 73 },
					{ 0, 134 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 160 },
					{ 2, 1 },
					{ 0, 104 },
					{ 0, 10 },
					{ 2, 1 },
					{ 0, 161 },
					{ 0, 26 },
					{ 68, 1 },
					{ 24, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 0, 42 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 149 },
					{ 0, 89 },
					{ 2, 1 },
					{ 0, 163 },
					{ 0, 58 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 74 },
					{ 0, 150 },
					{ 2, 1 },
					{ 0, 176 },
					{ 0, 11 },
					{ 2, 1 },
					{ 0, 177 },
					{ 0, 27 },
					{ 20, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 178 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 118 },
					{ 0, 119 },
					{ 0, 148 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 135 },
					{ 0, 120 },
					{ 0, 164 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 105 },
					{ 0, 165 },
					{ 0, 43 },
					{ 12, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 90 },
					{ 0, 136 },
					{ 0, 179 },
					{ 2, 1 },
					{ 0, 59 },
					{ 2, 1 },
					{ 0, 121 },
					{ 0, 166 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 106 },
					{ 0, 180 },
					{ 0, 192 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 152 },
					{ 0, 193 },
					{ 60, 1 },
					{ 22, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 28 },
					{ 2, 1 },
					{ 0, 137 },
					{ 0, 181 },
					{ 2, 1 },
					{ 0, 91 },
					{ 0, 194 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 44 },
					{ 0, 60 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 182 },
					{ 0, 107 },
					{ 2, 1 },
					{ 0, 196 },
					{ 0, 76 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 168 },
					{ 0, 138 },
					{ 2, 1 },
					{ 0, 208 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 209 },
					{ 2, 1 },
					{ 0, 75 },
					{ 2, 1 },
					{ 0, 151 },
					{ 0, 167 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 195 },
					{ 2, 1 },
					{ 0, 122 },
					{ 0, 153 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 197 },
					{ 0, 92 },
					{ 0, 183 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 29 },
					{ 0, 210 },
					{ 2, 1 },
					{ 0, 45 },
					{ 2, 1 },
					{ 0, 123 },
					{ 0, 211 },
					{ 52, 1 },
					{ 28, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 169 },
					{ 2, 1 },
					{ 0, 154 },
					{ 0, 212 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 184 },
					{ 0, 139 },
					{ 2, 1 },
					{ 0, 77 },
					{ 0, 199 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 124 },
					{ 0, 213 },
					{ 2, 1 },
					{ 0, 93 },
					{ 0, 224 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 225 },
					{ 0, 30 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 14 },
					{ 0, 46 },
					{ 0, 226 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 227 },
					{ 0, 109 },
					{ 2, 1 },
					{ 0, 140 },
					{ 0, 228 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 229 },
					{ 0, 186 },
					{ 0, 240 },
					{ 38, 1 },
					{ 16, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 241 },
					{ 0, 31 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 155 },
					{ 0, 185 },
					{ 2, 1 },
					{ 0, 62 },
					{ 2, 1 },
					{ 0, 214 },
					{ 0, 200 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 78 },
					{ 2, 1 },
					{ 0, 215 },
					{ 0, 125 },
					{ 2, 1 },
					{ 0, 171 },
					{ 2, 1 },
					{ 0, 94 },
					{ 0, 201 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 15 },
					{ 2, 1 },
					{ 0, 156 },
					{ 0, 110 },
					{ 2, 1 },
					{ 0, 242 },
					{ 0, 47 },
					{ 32, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 216 },
					{ 0, 141 },
					{ 0, 63 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 243 },
					{ 2, 1 },
					{ 0, 230 },
					{ 0, 202 },
					{ 2, 1 },
					{ 0, 244 },
					{ 0, 79 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 187 },
					{ 0, 172 },
					{ 2, 1 },
					{ 0, 231 },
					{ 0, 245 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 217 },
					{ 0, 157 },
					{ 2, 1 },
					{ 0, 95 },
					{ 0, 232 },
					{ 30, 1 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 203 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 188 },
					{ 0, 173 },
					{ 0, 218 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 247 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 126 },
					{ 0, 127 },
					{ 0, 142 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 158 },
					{ 0, 174 },
					{ 0, 204 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 143 },
					{ 18, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 189 },
					{ 2, 1 },
					{ 0, 234 },
					{ 0, 249 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 235 },
					{ 2, 1 },
					{ 0, 190 },
					{ 2, 1 },
					{ 0, 205 },
					{ 0, 250 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 221 },
					{ 0, 236 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 233 },
					{ 0, 175 },
					{ 0, 220 },
					{ 2, 1 },
					{ 0, 206 },
					{ 0, 251 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 191 },
					{ 0, 222 },
					{ 2, 1 },
					{ 0, 207 },
					{ 0, 238 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 223 },
					{ 0, 239 },
					{ 2, 1 },
					{ 0, 255 },
					{ 2, 1 },
					{ 0, 237 },
					{ 2, 1 },
					{ 0, 253 },
					{ 2, 1 },
					{ 0, 252 },
					{ 0, 254 }
				},
				new byte[511, 2]
				{
					{ 16, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 2, 1 },
					{ 0, 16 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 17 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 50, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 49 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 19 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 64 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 20 },
					{ 0, 65 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 66 },
					{ 2, 1 },
					{ 0, 36 },
					{ 0, 67 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 52 },
					{ 2, 1 },
					{ 0, 80 },
					{ 0, 5 },
					{ 2, 1 },
					{ 0, 81 },
					{ 0, 21 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 0, 97 },
					{ 90, 1 },
					{ 36, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 2, 1 },
					{ 0, 22 },
					{ 0, 98 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 84 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 99 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 54 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 7 },
					{ 2, 1 },
					{ 0, 113 },
					{ 0, 85 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 0, 100 },
					{ 2, 1 },
					{ 0, 114 },
					{ 0, 39 },
					{ 24, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 115 },
					{ 2, 1 },
					{ 0, 55 },
					{ 0, 101 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 128 },
					{ 2, 1 },
					{ 0, 8 },
					{ 0, 116 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 129 },
					{ 0, 24 },
					{ 2, 1 },
					{ 0, 130 },
					{ 0, 40 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 71 },
					{ 0, 102 },
					{ 2, 1 },
					{ 0, 131 },
					{ 0, 56 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 132 },
					{ 0, 72 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 144 },
					{ 0, 25 },
					{ 0, 145 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 41 },
					{ 92, 1 },
					{ 36, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 133 },
					{ 0, 88 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 9 },
					{ 0, 119 },
					{ 0, 147 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 57 },
					{ 0, 148 },
					{ 2, 1 },
					{ 0, 73 },
					{ 0, 134 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 104 },
					{ 2, 1 },
					{ 0, 160 },
					{ 0, 10 },
					{ 2, 1 },
					{ 0, 161 },
					{ 0, 26 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 0, 42 },
					{ 2, 1 },
					{ 0, 149 },
					{ 0, 89 },
					{ 26, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 163 },
					{ 2, 1 },
					{ 0, 58 },
					{ 0, 135 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 120 },
					{ 0, 164 },
					{ 2, 1 },
					{ 0, 74 },
					{ 0, 150 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 105 },
					{ 0, 176 },
					{ 0, 177 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 27 },
					{ 0, 165 },
					{ 0, 178 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 90 },
					{ 0, 43 },
					{ 2, 1 },
					{ 0, 136 },
					{ 0, 151 },
					{ 2, 1 },
					{ 0, 179 },
					{ 2, 1 },
					{ 0, 121 },
					{ 0, 59 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 106 },
					{ 0, 180 },
					{ 2, 1 },
					{ 0, 75 },
					{ 0, 193 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 152 },
					{ 0, 137 },
					{ 2, 1 },
					{ 0, 28 },
					{ 0, 181 },
					{ 80, 1 },
					{ 34, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 91 },
					{ 0, 44 },
					{ 0, 194 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 11 },
					{ 0, 192 },
					{ 0, 166 },
					{ 2, 1 },
					{ 0, 167 },
					{ 0, 122 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 195 },
					{ 0, 60 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 153 },
					{ 0, 182 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 107 },
					{ 0, 196 },
					{ 2, 1 },
					{ 0, 76 },
					{ 0, 168 },
					{ 20, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 138 },
					{ 0, 197 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 208 },
					{ 0, 92 },
					{ 0, 209 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 183 },
					{ 0, 123 },
					{ 2, 1 },
					{ 0, 29 },
					{ 2, 1 },
					{ 0, 13 },
					{ 0, 45 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 210 },
					{ 0, 211 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 169 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 154 },
					{ 0, 184 },
					{ 0, 212 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 139 },
					{ 0, 77 },
					{ 2, 1 },
					{ 0, 199 },
					{ 0, 124 },
					{ 68, 1 },
					{ 34, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 213 },
					{ 0, 93 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 224 },
					{ 0, 14 },
					{ 0, 225 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 30 },
					{ 0, 226 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 46 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 185 },
					{ 0, 155 },
					{ 2, 1 },
					{ 0, 227 },
					{ 0, 214 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 109 },
					{ 0, 62 },
					{ 2, 1 },
					{ 0, 200 },
					{ 0, 140 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 228 },
					{ 0, 78 },
					{ 2, 1 },
					{ 0, 215 },
					{ 0, 125 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 229 },
					{ 0, 186 },
					{ 2, 1 },
					{ 0, 171 },
					{ 0, 94 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 201 },
					{ 0, 156 },
					{ 2, 1 },
					{ 0, 241 },
					{ 0, 31 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 240 },
					{ 0, 110 },
					{ 0, 242 },
					{ 2, 1 },
					{ 0, 47 },
					{ 0, 230 },
					{ 38, 1 },
					{ 18, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 216 },
					{ 0, 243 },
					{ 2, 1 },
					{ 0, 63 },
					{ 0, 244 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 79 },
					{ 2, 1 },
					{ 0, 141 },
					{ 0, 217 },
					{ 2, 1 },
					{ 0, 187 },
					{ 0, 202 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 172 },
					{ 0, 231 },
					{ 2, 1 },
					{ 0, 126 },
					{ 0, 245 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 157 },
					{ 0, 95 },
					{ 2, 1 },
					{ 0, 232 },
					{ 0, 142 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 203 },
					{ 34, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 15 },
					{ 0, 174 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 188 },
					{ 0, 218 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 173 },
					{ 0, 247 },
					{ 2, 1 },
					{ 0, 127 },
					{ 0, 233 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 158 },
					{ 0, 204 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 143 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 189 },
					{ 2, 1 },
					{ 0, 234 },
					{ 0, 249 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 220 },
					{ 2, 1 },
					{ 0, 205 },
					{ 0, 235 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 190 },
					{ 0, 250 },
					{ 2, 1 },
					{ 0, 175 },
					{ 0, 221 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 236 },
					{ 0, 206 },
					{ 0, 251 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 191 },
					{ 0, 237 },
					{ 2, 1 },
					{ 0, 222 },
					{ 0, 252 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 207 },
					{ 0, 253 },
					{ 0, 238 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 223 },
					{ 0, 254 },
					{ 2, 1 },
					{ 0, 239 },
					{ 0, 255 }
				},
				new byte[511, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 42, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 2, 1 },
					{ 0, 33 },
					{ 0, 18 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 0, 65 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 2, 1 },
					{ 0, 51 },
					{ 0, 66 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 36 },
					{ 0, 80 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 138, 1 },
					{ 40, 1 },
					{ 16, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 21 },
					{ 0, 81 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 53 },
					{ 0, 83 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 0, 97 },
					{ 2, 1 },
					{ 0, 22 },
					{ 0, 98 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 38 },
					{ 0, 84 },
					{ 2, 1 },
					{ 0, 69 },
					{ 0, 99 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 54 },
					{ 0, 112 },
					{ 0, 113 },
					{ 40, 1 },
					{ 18, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 23 },
					{ 2, 1 },
					{ 0, 7 },
					{ 2, 1 },
					{ 0, 85 },
					{ 0, 100 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 114 },
					{ 0, 39 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 70 },
					{ 0, 101 },
					{ 0, 115 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 55 },
					{ 2, 1 },
					{ 0, 86 },
					{ 0, 8 },
					{ 2, 1 },
					{ 0, 128 },
					{ 0, 129 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 24 },
					{ 2, 1 },
					{ 0, 116 },
					{ 0, 71 },
					{ 2, 1 },
					{ 0, 130 },
					{ 2, 1 },
					{ 0, 40 },
					{ 0, 102 },
					{ 24, 1 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 131 },
					{ 0, 56 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 132 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 72 },
					{ 0, 144 },
					{ 0, 145 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 25 },
					{ 2, 1 },
					{ 0, 9 },
					{ 0, 118 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 41 },
					{ 14, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 133 },
					{ 0, 88 },
					{ 2, 1 },
					{ 0, 147 },
					{ 0, 57 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 160 },
					{ 0, 10 },
					{ 0, 26 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 2, 1 },
					{ 0, 103 },
					{ 2, 1 },
					{ 0, 87 },
					{ 0, 73 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 148 },
					{ 2, 1 },
					{ 0, 119 },
					{ 0, 134 },
					{ 2, 1 },
					{ 0, 161 },
					{ 2, 1 },
					{ 0, 104 },
					{ 0, 149 },
					{ 220, 1 },
					{ 126, 1 },
					{ 50, 1 },
					{ 26, 1 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 42 },
					{ 2, 1 },
					{ 0, 89 },
					{ 0, 58 },
					{ 2, 1 },
					{ 0, 163 },
					{ 2, 1 },
					{ 0, 135 },
					{ 0, 120 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 164 },
					{ 0, 74 },
					{ 2, 1 },
					{ 0, 150 },
					{ 0, 105 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 176 },
					{ 0, 11 },
					{ 0, 177 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 27 },
					{ 0, 178 },
					{ 2, 1 },
					{ 0, 43 },
					{ 2, 1 },
					{ 0, 165 },
					{ 0, 90 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 179 },
					{ 2, 1 },
					{ 0, 166 },
					{ 0, 106 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 180 },
					{ 0, 75 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 193 },
					{ 30, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 181 },
					{ 0, 194 },
					{ 0, 44 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 167 },
					{ 0, 195 },
					{ 2, 1 },
					{ 0, 107 },
					{ 0, 196 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 29 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 136 },
					{ 0, 151 },
					{ 0, 59 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 209 },
					{ 0, 210 },
					{ 2, 1 },
					{ 0, 45 },
					{ 0, 211 },
					{ 18, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 30 },
					{ 0, 46 },
					{ 0, 226 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 121 },
					{ 0, 152 },
					{ 0, 192 },
					{ 2, 1 },
					{ 0, 28 },
					{ 2, 1 },
					{ 0, 137 },
					{ 0, 91 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 60 },
					{ 2, 1 },
					{ 0, 122 },
					{ 0, 182 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 76 },
					{ 0, 153 },
					{ 2, 1 },
					{ 0, 168 },
					{ 0, 138 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 197 },
					{ 0, 92 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 154 },
					{ 88, 1 },
					{ 86, 1 },
					{ 36, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 139 },
					{ 0, 77 },
					{ 2, 1 },
					{ 0, 199 },
					{ 0, 124 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 213 },
					{ 0, 93 },
					{ 2, 1 },
					{ 0, 224 },
					{ 0, 14 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 227 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 208 },
					{ 0, 183 },
					{ 0, 123 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 169 },
					{ 0, 184 },
					{ 0, 212 },
					{ 2, 1 },
					{ 0, 225 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 185 },
					{ 24, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 155 },
					{ 0, 214 },
					{ 0, 109 },
					{ 2, 1 },
					{ 0, 62 },
					{ 0, 200 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 140 },
					{ 0, 228 },
					{ 0, 78 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 215 },
					{ 0, 229 },
					{ 2, 1 },
					{ 0, 186 },
					{ 0, 171 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 156 },
					{ 0, 230 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 110 },
					{ 0, 216 },
					{ 2, 1 },
					{ 0, 141 },
					{ 0, 187 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 231 },
					{ 0, 157 },
					{ 2, 1 },
					{ 0, 232 },
					{ 0, 142 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 203 },
					{ 0, 188 },
					{ 0, 158 },
					{ 0, 241 },
					{ 2, 1 },
					{ 0, 31 },
					{ 2, 1 },
					{ 0, 15 },
					{ 0, 47 },
					{ 66, 1 },
					{ 56, 1 },
					{ 2, 1 },
					{ 0, 242 },
					{ 52, 1 },
					{ 50, 1 },
					{ 20, 1 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 189 },
					{ 2, 1 },
					{ 0, 94 },
					{ 2, 1 },
					{ 0, 125 },
					{ 0, 201 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 202 },
					{ 2, 1 },
					{ 0, 172 },
					{ 0, 126 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 218 },
					{ 0, 173 },
					{ 0, 204 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 174 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 220 },
					{ 2, 1 },
					{ 0, 205 },
					{ 0, 190 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 235 },
					{ 0, 237 },
					{ 0, 238 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 217 },
					{ 0, 234 },
					{ 0, 233 },
					{ 2, 1 },
					{ 0, 222 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 221 },
					{ 0, 236 },
					{ 0, 206 },
					{ 0, 63 },
					{ 0, 240 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 243 },
					{ 0, 244 },
					{ 2, 1 },
					{ 0, 79 },
					{ 2, 1 },
					{ 0, 245 },
					{ 0, 95 },
					{ 10, 1 },
					{ 2, 1 },
					{ 0, 255 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 247 },
					{ 0, 127 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 143 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 249 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 250 },
					{ 0, 175 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 251 },
					{ 0, 191 },
					{ 2, 1 },
					{ 0, 252 },
					{ 0, 207 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 253 },
					{ 0, 223 },
					{ 2, 1 },
					{ 0, 254 },
					{ 0, 239 }
				},
				new byte[512, 2]
				{
					{ 60, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 16 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 17 },
					{ 14, 1 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 32 },
					{ 0, 2 },
					{ 0, 33 },
					{ 2, 1 },
					{ 0, 18 },
					{ 2, 1 },
					{ 0, 34 },
					{ 2, 1 },
					{ 0, 48 },
					{ 0, 3 },
					{ 14, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 49 },
					{ 0, 19 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 50 },
					{ 0, 35 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 64 },
					{ 0, 4 },
					{ 0, 65 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 20 },
					{ 0, 51 },
					{ 2, 1 },
					{ 0, 66 },
					{ 0, 36 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 67 },
					{ 0, 52 },
					{ 0, 81 },
					{ 6, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 80 },
					{ 0, 5 },
					{ 0, 21 },
					{ 2, 1 },
					{ 0, 82 },
					{ 0, 37 },
					{ 250, 1 },
					{ 98, 1 },
					{ 34, 1 },
					{ 18, 1 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 68 },
					{ 0, 83 },
					{ 2, 1 },
					{ 0, 53 },
					{ 2, 1 },
					{ 0, 96 },
					{ 0, 6 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 97 },
					{ 0, 22 },
					{ 2, 1 },
					{ 0, 98 },
					{ 0, 38 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 84 },
					{ 0, 69 },
					{ 2, 1 },
					{ 0, 99 },
					{ 0, 54 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 113 },
					{ 0, 85 },
					{ 2, 1 },
					{ 0, 100 },
					{ 0, 70 },
					{ 32, 1 },
					{ 14, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 114 },
					{ 2, 1 },
					{ 0, 39 },
					{ 0, 55 },
					{ 2, 1 },
					{ 0, 115 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 112 },
					{ 0, 7 },
					{ 0, 23 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 101 },
					{ 0, 86 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 128 },
					{ 0, 8 },
					{ 0, 129 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 116 },
					{ 0, 71 },
					{ 2, 1 },
					{ 0, 24 },
					{ 0, 130 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 40 },
					{ 0, 102 },
					{ 2, 1 },
					{ 0, 131 },
					{ 0, 56 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 117 },
					{ 0, 87 },
					{ 2, 1 },
					{ 0, 132 },
					{ 0, 72 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 145 },
					{ 0, 25 },
					{ 2, 1 },
					{ 0, 146 },
					{ 0, 118 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 103 },
					{ 0, 41 },
					{ 2, 1 },
					{ 0, 133 },
					{ 0, 88 },
					{ 92, 1 },
					{ 34, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 147 },
					{ 0, 57 },
					{ 2, 1 },
					{ 0, 148 },
					{ 0, 73 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 119 },
					{ 0, 134 },
					{ 2, 1 },
					{ 0, 104 },
					{ 0, 161 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 162 },
					{ 0, 42 },
					{ 2, 1 },
					{ 0, 149 },
					{ 0, 89 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 163 },
					{ 0, 58 },
					{ 2, 1 },
					{ 0, 135 },
					{ 2, 1 },
					{ 0, 120 },
					{ 0, 74 },
					{ 22, 1 },
					{ 12, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 164 },
					{ 0, 150 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 105 },
					{ 0, 177 },
					{ 2, 1 },
					{ 0, 27 },
					{ 0, 165 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 178 },
					{ 2, 1 },
					{ 0, 90 },
					{ 0, 43 },
					{ 2, 1 },
					{ 0, 136 },
					{ 0, 179 },
					{ 16, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 144 },
					{ 2, 1 },
					{ 0, 9 },
					{ 0, 160 },
					{ 2, 1 },
					{ 0, 151 },
					{ 0, 121 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 166 },
					{ 0, 106 },
					{ 0, 180 },
					{ 12, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 26 },
					{ 2, 1 },
					{ 0, 10 },
					{ 0, 176 },
					{ 2, 1 },
					{ 0, 59 },
					{ 2, 1 },
					{ 0, 11 },
					{ 0, 192 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 75 },
					{ 0, 193 },
					{ 2, 1 },
					{ 0, 152 },
					{ 0, 137 },
					{ 67, 1 },
					{ 34, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 28 },
					{ 0, 181 },
					{ 2, 1 },
					{ 0, 91 },
					{ 0, 194 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 44 },
					{ 0, 167 },
					{ 2, 1 },
					{ 0, 122 },
					{ 0, 195 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 60 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 208 },
					{ 2, 1 },
					{ 0, 182 },
					{ 0, 107 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 196 },
					{ 0, 76 },
					{ 2, 1 },
					{ 0, 153 },
					{ 0, 168 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 138 },
					{ 0, 197 },
					{ 2, 1 },
					{ 0, 92 },
					{ 0, 209 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 183 },
					{ 0, 123 },
					{ 2, 1 },
					{ 0, 29 },
					{ 0, 210 },
					{ 9, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 45 },
					{ 0, 211 },
					{ 2, 1 },
					{ 0, 61 },
					{ 0, 198 },
					{ 85, 250 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 108 },
					{ 0, 169 },
					{ 2, 1 },
					{ 0, 154 },
					{ 0, 212 },
					{ 32, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 184 },
					{ 0, 139 },
					{ 2, 1 },
					{ 0, 77 },
					{ 0, 199 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 124 },
					{ 0, 213 },
					{ 2, 1 },
					{ 0, 93 },
					{ 0, 225 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 30 },
					{ 0, 226 },
					{ 2, 1 },
					{ 0, 170 },
					{ 0, 185 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 155 },
					{ 0, 227 },
					{ 2, 1 },
					{ 0, 214 },
					{ 0, 109 },
					{ 20, 1 },
					{ 10, 1 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 62 },
					{ 2, 1 },
					{ 0, 46 },
					{ 0, 78 },
					{ 2, 1 },
					{ 0, 200 },
					{ 0, 140 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 228 },
					{ 0, 215 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 125 },
					{ 0, 171 },
					{ 0, 229 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 186 },
					{ 0, 94 },
					{ 2, 1 },
					{ 0, 201 },
					{ 2, 1 },
					{ 0, 156 },
					{ 0, 110 },
					{ 8, 1 },
					{ 2, 1 },
					{ 0, 230 },
					{ 2, 1 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 224 },
					{ 0, 14 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 216 },
					{ 0, 141 },
					{ 2, 1 },
					{ 0, 187 },
					{ 0, 202 },
					{ 74, 1 },
					{ 2, 1 },
					{ 0, 255 },
					{ 64, 1 },
					{ 58, 1 },
					{ 32, 1 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 172 },
					{ 0, 231 },
					{ 2, 1 },
					{ 0, 126 },
					{ 0, 217 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 157 },
					{ 0, 232 },
					{ 2, 1 },
					{ 0, 142 },
					{ 0, 203 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 188 },
					{ 0, 218 },
					{ 2, 1 },
					{ 0, 173 },
					{ 0, 233 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 158 },
					{ 0, 204 },
					{ 2, 1 },
					{ 0, 219 },
					{ 0, 189 },
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 234 },
					{ 0, 174 },
					{ 2, 1 },
					{ 0, 220 },
					{ 0, 205 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 235 },
					{ 0, 190 },
					{ 2, 1 },
					{ 0, 221 },
					{ 0, 236 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 206 },
					{ 0, 237 },
					{ 2, 1 },
					{ 0, 222 },
					{ 0, 238 },
					{ 0, 15 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 240 },
					{ 0, 31 },
					{ 0, 241 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 242 },
					{ 0, 47 },
					{ 2, 1 },
					{ 0, 243 },
					{ 0, 63 },
					{ 18, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 244 },
					{ 0, 79 },
					{ 2, 1 },
					{ 0, 245 },
					{ 0, 95 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 246 },
					{ 0, 111 },
					{ 2, 1 },
					{ 0, 247 },
					{ 2, 1 },
					{ 0, 127 },
					{ 0, 143 },
					{ 10, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 248 },
					{ 0, 249 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 159 },
					{ 0, 175 },
					{ 0, 250 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 251 },
					{ 0, 191 },
					{ 2, 1 },
					{ 0, 252 },
					{ 0, 207 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 253 },
					{ 0, 223 },
					{ 2, 1 },
					{ 0, 254 },
					{ 0, 239 }
				},
				new byte[31, 2]
				{
					{ 2, 1 },
					{ 0, 0 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 8 },
					{ 0, 4 },
					{ 2, 1 },
					{ 0, 1 },
					{ 0, 2 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 10 },
					{ 2, 1 },
					{ 0, 3 },
					{ 0, 6 },
					{ 6, 1 },
					{ 2, 1 },
					{ 0, 9 },
					{ 2, 1 },
					{ 0, 5 },
					{ 0, 7 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 14 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 15 },
					{ 0, 11 }
				},
				new byte[31, 2]
				{
					{ 16, 1 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 0 },
					{ 0, 1 },
					{ 2, 1 },
					{ 0, 2 },
					{ 0, 3 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 4 },
					{ 0, 5 },
					{ 2, 1 },
					{ 0, 6 },
					{ 0, 7 },
					{ 8, 1 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 8 },
					{ 0, 9 },
					{ 2, 1 },
					{ 0, 10 },
					{ 0, 11 },
					{ 4, 1 },
					{ 2, 1 },
					{ 0, 12 },
					{ 0, 13 },
					{ 2, 1 },
					{ 0, 14 },
					{ 0, 15 }
				}
			};
			_llCache = new HuffmanListNode[_codeTables.Length];
			_llCacheMaxBits = new int[_codeTables.Length];
			LIN_BITS = new int[32]
			{
				0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
				0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
				6, 8, 10, 13, 4, 5, 6, 7, 8, 9,
				11, 13
			};
			_floatLookup = new float[8207];
			for (int i = 0; i < 8207; i++)
			{
				_floatLookup[i] = (float)Math.Pow(i, 1.3333333333333333);
			}
		}

		internal static void Decode(BitReservoir br, int table, out float x, out float y)
		{
			if (table == 0 || table == 4 || table == 14)
			{
				x = (y = 0f);
				return;
			}
			byte num = DecodeSymbol(br, table);
			int num2 = num >> 4;
			int num3 = num & 0xF;
			int num4 = LIN_BITS[table];
			if (num4 > 0 && num2 == 15)
			{
				num2 += br.GetBits(num4);
			}
			if (num2 != 0 && br.Get1Bit() != 0)
			{
				x = 0f - _floatLookup[num2];
			}
			else
			{
				x = _floatLookup[num2];
			}
			if (num4 > 0 && num3 == 15)
			{
				num3 += br.GetBits(num4);
			}
			if (num3 != 0 && br.Get1Bit() != 0)
			{
				y = 0f - _floatLookup[num3];
			}
			else
			{
				y = _floatLookup[num3];
			}
		}

		internal static void Decode(BitReservoir br, int table, out float x, out float y, out float v, out float w)
		{
			byte num = DecodeSymbol(br, table);
			v = (w = (x = (y = 0f)));
			if ((num & 8u) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					v = 0f - _floatLookup[1];
				}
				else
				{
					v = _floatLookup[1];
				}
			}
			if ((num & 4u) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					w = 0f - _floatLookup[1];
				}
				else
				{
					w = _floatLookup[1];
				}
			}
			if ((num & 2u) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					x = 0f - _floatLookup[1];
				}
				else
				{
					x = _floatLookup[1];
				}
			}
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				if (br.Get1Bit() == 1)
				{
					y = 0f - _floatLookup[1];
				}
				else
				{
					y = _floatLookup[1];
				}
			}
		}

		private static byte DecodeSymbol(BitReservoir br, int table)
		{
			int maxBits;
			HuffmanListNode huffmanListNode = GetNode(table, out maxBits);
			int readCount;
			int num = br.TryPeekBits(maxBits, out readCount);
			if (readCount < maxBits)
			{
				num <<= maxBits - readCount;
			}
			while (huffmanListNode != null && huffmanListNode.Length <= readCount)
			{
				if ((num & huffmanListNode.Mask) == huffmanListNode.Bits)
				{
					br.SkipBits(huffmanListNode.Length);
					break;
				}
				huffmanListNode = huffmanListNode.Next;
			}
			if (huffmanListNode != null && huffmanListNode.Length <= readCount)
			{
				return huffmanListNode.Value;
			}
			return 0;
		}

		private static HuffmanListNode GetNode(int table, out int maxBits)
		{
			int num = table;
			if (num > 16)
			{
				num = ((num > 31) ? (num - 17) : ((num < 24) ? 13 : 14));
			}
			else
			{
				if (num > 13)
				{
					num--;
				}
				if (num > 3)
				{
					num--;
				}
				num--;
			}
			if (_llCache[num] == null)
			{
				_llCache[num] = InitTable(_codeTables[num], out maxBits);
				_llCacheMaxBits[num] = maxBits;
			}
			else
			{
				maxBits = _llCacheMaxBits[num];
			}
			return _llCache[num];
		}

		private static HuffmanListNode InitTable(byte[,] tree, out int maxBits)
		{
			List<byte> list = new List<byte>();
			List<int> list2 = new List<int>();
			List<int> list3 = new List<int>();
			int length = tree.GetLength(0);
			for (int i = 0; i < length; i++)
			{
				if (tree[i, 0] == 0)
				{
					int num = 0;
					int item = 0;
					int num2 = i;
					do
					{
						num2 = FindPreviousNode(tree, num2, out var bit);
						num |= bit << item++;
					}
					while (num2 > 0);
					list.Add(tree[i, 1]);
					list2.Add(item);
					list3.Add(num);
				}
			}
			return BuildLinkedList(list, list2, list3, out maxBits);
		}

		private static int FindPreviousNode(byte[,] tree, int idx, out int bit)
		{
			for (int num = idx - 1; num >= 0; num--)
			{
				if (tree[num, 0] != 0)
				{
					for (int i = 0; i < 2; i++)
					{
						if (num + tree[num, i] != idx)
						{
							continue;
						}
						if (tree[num, i] >= 250)
						{
							int result = FindPreviousNode(tree, num, out bit);
							if (bit != i)
							{
								throw new InvalidOperationException();
							}
							return result;
						}
						bit = i;
						return num;
					}
				}
			}
			throw new InvalidOperationException();
		}

		private static HuffmanListNode BuildLinkedList(List<byte> values, List<int> lengthList, List<int> codeList, out int maxBits)
		{
			HuffmanListNode[] array = new HuffmanListNode[lengthList.Count];
			maxBits = lengthList.Max();
			for (int j = 0; j < array.Length; j++)
			{
				int num = maxBits - lengthList[j];
				array[j] = new HuffmanListNode
				{
					Value = values[j],
					Length = lengthList[j],
					Bits = codeList[j] << num,
					Mask = (1 << lengthList[j]) - 1 << num
				};
			}
			Array.Sort(array, (HuffmanListNode i1, HuffmanListNode i2) => i1.Length - i2.Length);
			for (int k = 1; k < array.Length && array[k].Length < 99999; k++)
			{
				array[k - 1].Next = array[k];
			}
			return array[0];
		}
	}
	internal class ID3Frame : FrameBase
	{
		private int _version;

		internal int Version
		{
			get
			{
				if (_version == 0)
				{
					return 1;
				}
				return _version;
			}
		}

		internal static ID3Frame TrySync(uint syncMark)
		{
			if ((syncMark & 0xFFFFFF00u) == 1229206272)
			{
				return new ID3Frame
				{
					_version = 2
				};
			}
			if ((syncMark & 0xFFFFFF00u) == 1413564160)
			{
				if ((syncMark & 0xFF) == 43)
				{
					return new ID3Frame
					{
						_version = 1
					};
				}
				return new ID3Frame
				{
					_version = 0
				};
			}
			return null;
		}

		private ID3Frame()
		{
		}

		protected override int Validate()
		{
			switch (_version)
			{
			case 2:
			{
				byte[] array = new byte[7];
				if (Read(3, array) == 7)
				{
					byte b;
					switch (array[0])
					{
					case 2:
						b = 63;
						break;
					case 3:
						b = 31;
						break;
					case 4:
						b = 15;
						break;
					default:
						return -1;
					}
					int num = (array[3] << 21) | (array[4] << 14) | (array[5] << 7) | array[6];
					if (((array[2] & b) | (array[3] & 0x80) | (array[4] & 0x80) | (array[5] & 0x80) | (array[6] & 0x80)) == 0 && array[1] != byte.MaxValue)
					{
						return num + 10;
					}
				}
				break;
			}
			case 1:
				return 355;
			case 0:
				return 128;
			}
			return -1;
		}

		internal override void Parse()
		{
			switch (_version)
			{
			case 2:
				ParseV2();
				break;
			case 1:
				ParseV1Enh();
				break;
			case 0:
				ParseV1(3);
				break;
			}
		}

		private void ParseV1(int offset)
		{
		}

		private void ParseV1Enh()
		{
			ParseV1(230);
		}

		private void ParseV2()
		{
		}

		internal void Merge(ID3Frame newFrame)
		{
		}
	}
	internal abstract class LayerDecoderBase
	{
		protected const int SBLIMIT = 32;

		private const float INV_SQRT_2 = 0.70710677f;

		private static float[] DEWINDOW_TABLE = new float[512]
		{
			0f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -1.5259E-05f, -3.0518E-05f, -3.0518E-05f, -3.0518E-05f,
			-3.0518E-05f, -4.5776E-05f, -4.5776E-05f, -6.1035E-05f, -6.1035E-05f, -7.6294E-05f, -7.6294E-05f, -9.1553E-05f, -0.000106812f, -0.000106812f,
			-0.00012207f, -0.000137329f, -0.000152588f, -0.000167847f, -0.000198364f, -0.000213623f, -0.000244141f, -0.000259399f, -0.000289917f, -0.000320435f,
			-0.000366211f, -0.000396729f, -0.000442505f, -0.000473022f, -0.000534058f, -0.000579834f, -0.00062561f, -0.000686646f, -0.000747681f, -0.000808716f,
			-0.00088501f, -0.000961304f, -0.001037598f, -0.001113892f, -0.001205444f, -0.001296997f, -0.00138855f, -0.001480103f, -0.001586914f, -0.001693726f,
			-0.001785278f, -0.001907349f, -0.00201416f, -0.002120972f, -0.002243042f, -0.002349854f, -0.002456665f, -0.002578735f, -0.002685547f, -0.002792358f,
			-0.00289917f, -0.002990723f, -0.003082275f, -0.003173828f, 0.003250122f, 0.003326416f, 0.003387451f, 0.003433228f, 0.003463745f, 0.003479004f,
			0.003479004f, 0.003463745f, 0.003417969f, 0.003372192f, 0.00328064f, 0.003173828f, 0.003051758f, 0.002883911f, 0.002700806f, 0.002487183f,
			0.002227783f, 0.001937866f, 0.001617432f, 0.001266479f, 0.000869751f, 0.000442505f, -3.0518E-05f, -0.000549316f, -0.001098633f, -0.001693726f,
			-0.002334595f, -0.003005981f, -0.003723145f, -0.004486084f, -0.0052948f, -0.006118774f, -0.007003784f, -0.007919312f, -0.008865356f, -0.009841919f,
			-0.010848999f, -0.011886597f, -0.012939453f, -0.014022827f, -0.01512146f, -0.016235352f, -0.017349243f, -0.018463135f, -0.019577026f, -0.020690918f,
			-0.02178955f, -0.022857666f, -0.023910522f, -0.024932861f, -0.025909424f, -0.02684021f, -0.02772522f, -0.028533936f, -0.029281616f, -0.029937744f,
			-0.030532837f, -0.03100586f, -0.03138733f, -0.031661987f, -0.031814575f, -0.031845093f, -0.03173828f, -0.03147888f, 0.031082153f, 0.030517578f,
			0.029785156f, 0.028884888f, 0.027801514f, 0.026535034f, 0.02508545f, 0.023422241f, 0.021575928f, 0.01953125f, 0.01725769f, 0.014801025f,
			0.012115479f, 0.009231567f, 0.006134033f, 0.002822876f, -0.000686646f, -0.004394531f, -0.00831604f, -0.012420654f, -0.016708374f, -0.0211792f,
			-0.025817871f, -0.03060913f, -0.03555298f, -0.040634155f, -0.045837402f, -0.051132202f, -0.056533813f, -0.06199646f, -0.06752014f, -0.07305908f,
			-0.07862854f, -0.08418274f, -0.08970642f, -0.09516907f, -0.10054016f, -0.1058197f, -0.110946655f, -0.11592102f, -0.12069702f, -0.1252594f,
			-0.12956238f, -0.1335907f, -0.13729858f, -0.14067078f, -0.14367676f, -0.1462555f, -0.14842224f, -0.15011597f, -0.15130615f, -0.15196228f,
			-0.15206909f, -0.15159607f, -0.15049744f, -0.1487732f, -0.1463623f, -0.14326477f, -0.13945007f, -0.1348877f, -0.12957764f, -0.12347412f,
			-0.11657715f, -0.1088562f, 0.10031128f, 0.090927124f, 0.08068848f, 0.06959534f, 0.057617188f, 0.044784546f, 0.031082153f, 0.01651001f,
			0.001068115f, -0.015228271f, -0.03237915f, -0.050354004f, -0.06916809f, -0.088775635f, -0.10916138f, -0.13031006f, -0.15220642f, -0.17478943f,
			-0.19805908f, -0.22198486f, -0.24650574f, -0.2715912f, -0.2972107f, -0.32331848f, -0.34986877f, -0.37680054f, -0.40408325f, -0.43165588f,
			-0.45947266f, -0.48747253f, -0.51560974f, -0.54382324f, -0.57203674f, -0.6002197f, -0.6282959f, -0.6562195f, -0.6839142f, -0.71131897f,
			-0.7383728f, -0.7650299f, -0.791214f, -0.816864f, -0.84194946f, -0.8663635f, -0.89009094f, -0.9130554f, -0.9351959f, -0.95648193f,
			-0.9768524f, -0.99624634f, -1.0146179f, -1.0319366f, -1.0481567f, -1.0632172f, -1.0771179f, -1.0897827f, -1.1012115f, -1.1113739f,
			-1.120224f, -1.1277466f, -1.1339264f, -1.1387634f, -1.1422119f, -1.1442871f, 1.144989f, 1.1442871f, 1.1422119f, 1.1387634f,
			1.1339264f, 1.1277466f, 1.120224f, 1.1113739f, 1.1012115f, 1.0897827f, 1.0771179f, 1.0632172f, 1.0481567f, 1.0319366f,
			1.0146179f, 0.99624634f, 0.9768524f, 0.95648193f, 0.9351959f, 0.9130554f, 0.89009094f, 0.8663635f, 0.84194946f, 0.816864f,
			0.791214f, 0.7650299f, 0.7383728f, 0.71131897f, 0.6839142f, 0.6562195f, 0.6282959f, 0.6002197f, 0.57203674f, 0.54382324f,
			0.51560974f, 0.48747253f, 0.45947266f, 0.43165588f, 0.40408325f, 0.37680054f, 0.34986877f, 0.32331848f, 0.2972107f, 0.2715912f,
			0.24650574f, 0.22198486f, 0.19805908f, 0.17478943f, 0.15220642f, 0.13031006f, 0.10916138f, 0.088775635f, 0.06916809f, 0.050354004f,
			0.03237915f, 0.015228271f, -0.001068115f, -0.01651001f, -0.031082153f, -0.044784546f, -0.057617188f, -0.06959534f, -0.08068848f, -0.090927124f,
			0.10031128f, 0.1088562f, 0.11657715f, 0.12347412f, 0.12957764f, 0.1348877f, 0.13945007f, 0.14326477f, 0.1463623f, 0.1487732f,
			0.15049744f, 0.15159607f, 0.15206909f, 0.15196228f, 0.15130615f, 0.15011597f, 0.14842224f, 0.1462555f, 0.14367676f, 0.14067078f,
			0.13729858f, 0.1335907f, 0.12956238f, 0.1252594f, 0.12069702f, 0.11592102f, 0.110946655f, 0.1058197f, 0.10054016f, 0.09516907f,
			0.08970642f, 0.08418274f, 0.07862854f, 0.07305908f, 0.06752014f, 0.06199646f, 0.056533813f, 0.051132202f, 0.045837402f, 0.040634155f,
			0.03555298f, 0.03060913f, 0.025817871f, 0.0211792f, 0.016708374f, 0.012420654f, 0.00831604f, 0.004394531f, 0.000686646f, -0.002822876f,
			-0.006134033f, -0.009231567f, -0.012115479f, -0.014801025f, -0.01725769f, -0.01953125f, -0.021575928f, -0.023422241f, -0.02508545f, -0.026535034f,
			-0.027801514f, -0.028884888f, -0.029785156f, -0.030517578f, 0.031082153f, 0.03147888f, 0.03173828f, 0.031845093f, 0.031814575f, 0.031661987f,
			0.03138733f, 0.03100586f, 0.030532837f, 0.029937744f, 0.029281616f, 0.028533936f, 0.02772522f, 0.02684021f, 0.025909424f, 0.024932861f,
			0.023910522f, 0.022857666f, 0.02178955f, 0.020690918f, 0.019577026f, 0.018463135f, 0.017349243f, 0.016235352f, 0.01512146f, 0.014022827f,
			0.012939453f, 0.011886597f, 0.010848999f, 0.009841919f, 0.008865356f, 0.007919312f, 0.007003784f, 0.006118774f, 0.0052948f, 0.004486084f,
			0.003723145f, 0.003005981f, 0.002334595f, 0.001693726f, 0.001098633f, 0.000549316f, 3.0518E-05f, -0.000442505f, -0.000869751f, -0.001266479f,
			-0.001617432f, -0.001937866f, -0.002227783f, -0.002487183f, -0.002700806f, -0.002883911f, -0.003051758f, -0.003173828f, -0.00328064f, -0.003372192f,
			-0.003417969f, -0.003463745f, -0.003479004f, -0.003479004f, -0.003463745f, -0.003433228f, -0.003387451f, -0.003326416f, 0.003250122f, 0.003173828f,
			0.003082275f, 0.002990723f, 0.00289917f, 0.002792358f, 0.002685547f, 0.002578735f, 0.002456665f, 0.002349854f, 0.002243042f, 0.002120972f,
			0.00201416f, 0.001907349f, 0.001785278f, 0.001693726f, 0.001586914f, 0.001480103f, 0.00138855f, 0.001296997f, 0.001205444f, 0.001113892f,
			0.001037598f, 0.000961304f, 0.00088501f, 0.000808716f, 0.000747681f, 0.000686646f, 0.00062561f, 0.000579834f, 0.000534058f, 0.000473022f,
			0.000442505f, 0.000396729f, 0.000366211f, 0.000320435f, 0.000289917f, 0.000259399f, 0.000244141f, 0.000213623f, 0.000198364f, 0.000167847f,
			0.000152588f, 0.000137329f, 0.00012207f, 0.000106812f, 0.000106812f, 9.1553E-05f, 7.6294E-05f, 7.6294E-05f, 6.1035E-05f, 6.1035E-05f,
			4.5776E-05f, 4.5776E-05f, 3.0518E-05f, 3.0518E-05f, 3.0518E-05f, 3.0518E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f, 1.5259E-05f,
			1.5259E-05f, 1.5259E-05f
		};

		private static float[] SYNTH_COS64_TABLE = new float[31]
		{
			0.500603f, 0.5024193f, 0.50547093f, 0.5097956f, 0.5154473f, 0.5224986f, 0.5310426f, 0.5411961f, 0.5531039f, 0.56694406f,
			0.582935f, 0.6013449f, 0.6225041f, 0.6468218f, 0.6748083f, 0.70710677f, 0.7445363f, 0.7881546f, 0.8393496f, 0.8999762f,
			0.9725682f, 1.0606776f, 1.1694399f, 1.306563f, 1.4841646f, 1.7224472f, 2.057781f, 2.5629156f, 3.4076085f, 5.1011486f,
			10.190008f
		};

		private List<float[]> _synBuf = new List<float[]>(2);

		private List<int> _bufOffset = new List<int>(2);

		private float[] _eq;

		private float[] ippuv = new float[512];

		private float[] ei32 = new float[16];

		private float[] eo32 = new float[16];

		private float[] oi32 = new float[16];

		private float[] oo32 = new float[16];

		private float[] ei16 = new float[8];

		private float[] eo16 = new float[8];

		private float[] oi16 = new float[8];

		private float[] oo16 = new float[8];

		private float[] ei8 = new float[4];

		private float[] tmp8 = new float[6];

		private float[] oi8 = new float[4];

		private float[] oo8 = new float[4];

		internal StereoMode StereoMode { get; set; }

		internal LayerDecoderBase()
		{
			StereoMode = StereoMode.Both;
		}

		internal abstract int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1);

		internal void SetEQ(float[] eq)
		{
			if (eq == null || eq.Length == 32)
			{
				_eq = eq;
			}
		}

		internal virtual void ResetForSeek()
		{
			_synBuf.Clear();
			_bufOffset.Clear();
		}

		protected void InversePolyPhase(int channel, float[] data)
		{
			GetBufAndOffset(channel, out var synBuf, out var k);
			if (_eq != null)
			{
				for (int i = 0; i < 32; i++)
				{
					data[i] *= _eq[i];
				}
			}
			DCT32(data, synBuf, k);
			BuildUVec(ippuv, synBuf, k);
			DewindowOutput(ippuv, data);
		}

		private void GetBufAndOffset(int channel, out float[] synBuf, out int k)
		{
			while (_synBuf.Count <= channel)
			{
				_synBuf.Add(new float[1024]);
			}
			while (_bufOffset.Count <= channel)
			{
				_bufOffset.Add(0);
			}
			synBuf = _synBuf[channel];
			k = _bufOffset[channel];
			k = (k - 32) & 0x1FF;
			_bufOffset[channel] = k;
		}

		private void DCT32(float[] _in, float[] _out, int k)
		{
			for (int i = 0; i < 16; i++)
			{
				ei32[i] = _in[i] + _in[31 - i];
				oi32[i] = (_in[i] - _in[31 - i]) * SYNTH_COS64_TABLE[2 * i];
			}
			DCT16(ei32, eo32);
			DCT16(oi32, oo32);
			for (int i = 0; i < 15; i++)
			{
				_out[2 * i + k] = eo32[i];
				_out[2 * i + 1 + k] = oo32[i] + oo32[i + 1];
			}
			_out[30 + k] = eo32[15];
			_out[31 + k] = oo32[15];
		}

		private void DCT16(float[] _in, float[] _out)
		{
			float num = _in[0];
			float num2 = _in[15];
			ei16[0] = num + num2;
			oi16[0] = (num - num2) * SYNTH_COS64_TABLE[1];
			num = _in[1];
			num2 = _in[14];
			ei16[1] = num + num2;
			oi16[1] = (num - num2) * SYNTH_COS64_TABLE[5];
			num = _in[2];
			num2 = _in[13];
			ei16[2] = num + num2;
			oi16[2] = (num - num2) * SYNTH_COS64_TABLE[9];
			num = _in[3];
			num2 = _in[12];
			ei16[3] = num + num2;
			oi16[3] = (num - num2) * SYNTH_COS64_TABLE[13];
			num = _in[4];
			num2 = _in[11];
			ei16[4] = num + num2;
			oi16[4] = (num - num2) * SYNTH_COS64_TABLE[17];
			num = _in[5];
			num2 = _in[10];
			ei16[5] = num + num2;
			oi16[5] = (num - num2) * SYNTH_COS64_TABLE[21];
			num = _in[6];
			num2 = _in[9];
			ei16[6] = num + num2;
			oi16[6] = (num - num2) * SYNTH_COS64_TABLE[25];
			num = _in[7];
			num2 = _in[8];
			ei16[7] = num + num2;
			oi16[7] = (num - num2) * SYNTH_COS64_TABLE[29];
			DCT8(ei16, eo16);
			DCT8(oi16, oo16);
			_out[0] = eo16[0];
			_out[1] = oo16[0] + oo16[1];
			_out[2] = eo16[1];
			_out[3] = oo16[1] + oo16[2];
			_out[4] = eo16[2];
			_out[5] = oo16[2] + oo16[3];
			_out[6] = eo16[3];
			_out[7] = oo16[3] + oo16[4];
			_out[8] = eo16[4];
			_out[9] = oo16[4] + oo16[5];
			_out[10] = eo16[5];
			_out[11] = oo16[5] + oo16[6];
			_out[12] = eo16[6];
			_out[13] = oo16[6] + oo16[7];
			_out[14] = eo16[7];
			_out[15] = oo16[7];
		}

		private void DCT8(float[] _in, float[] _out)
		{
			ei8[0] = _in[0] + _in[7];
			ei8[1] = _in[3] + _in[4];
			ei8[2] = _in[1] + _in[6];
			ei8[3] = _in[2] + _in[5];
			tmp8[0] = ei8[0] + ei8[1];
			tmp8[1] = ei8[2] + ei8[3];
			tmp8[2] = (ei8[0] - ei8[1]) * SYNTH_COS64_TABLE[7];
			tmp8[3] = (ei8[2] - ei8[3]) * SYNTH_COS64_TABLE[23];
			tmp8[4] = (tmp8[2] - tmp8[3]) * 0.70710677f;
			_out[0] = tmp8[0] + tmp8[1];
			_out[2] = tmp8[2] + tmp8[3] + tmp8[4];
			_out[4] = (tmp8[0] - tmp8[1]) * 0.70710677f;
			_out[6] = tmp8[4];
			oi8[0] = (_in[0] - _in[7]) * SYNTH_COS64_TABLE[3];
			oi8[1] = (_in[1] - _in[6]) * SYNTH_COS64_TABLE[11];
			oi8[2] = (_in[2] - _in[5]) * SYNTH_COS64_TABLE[19];
			oi8[3] = (_in[3] - _in[4]) * SYNTH_COS64_TABLE[27];
			tmp8[0] = oi8[0] + oi8[3];
			tmp8[1] = oi8[1] + oi8[2];
			tmp8[2] = (oi8[0] - oi8[3]) * SYNTH_COS64_TABLE[7];
			tmp8[3] = (oi8[1] - oi8[2]) * SYNTH_COS64_TABLE[23];
			tmp8[4] = tmp8[2] + tmp8[3];
			tmp8[5] = (tmp8[2] - tmp8[3]) * 0.70710677f;
			oo8[0] = tmp8[0] + tmp8[1];
			oo8[1] = tmp8[4] + tmp8[5];
			oo8[2] = (tmp8[0] - tmp8[1]) * 0.70710677f;
			oo8[3] = tmp8[5];
			_out[1] = oo8[0] + oo8[1];
			_out[3] = oo8[1] + oo8[2];
			_out[5] = oo8[2] + oo8[3];
			_out[7] = oo8[3];
		}

		private void BuildUVec(float[] u_vec, float[] cur_synbuf, int k)
		{
			int num = 0;
			for (int i = 0; i < 8; i++)
			{
				for (int j = 0; j < 16; j++)
				{
					u_vec[num + j] = cur_synbuf[k + j + 16];
					u_vec[num + j + 17] = 0f - cur_synbuf[k + 31 - j];
				}
				k = (k + 32) & 0x1FF;
				for (int j = 0; j < 16; j++)
				{
					u_vec[num + j + 32] = 0f - cur_synbuf[k + 16 - j];
					u_vec[num + j + 48] = 0f - cur_synbuf[k + j];
				}
				u_vec[num + 16] = 0f;
				k = (k + 32) & 0x1FF;
				num += 64;
			}
		}

		private void DewindowOutput(float[] u_vec, float[] samples)
		{
			for (int i = 0; i < 512; i++)
			{
				u_vec[i] *= DEWINDOW_TABLE[i];
			}
			for (int j = 0; j < 32; j++)
			{
				float num = u_vec[j];
				num += u_vec[j + 32];
				num += u_vec[j + 64];
				num += u_vec[j + 96];
				num += u_vec[j + 128];
				num += u_vec[j + 160];
				num += u_vec[j + 192];
				num += u_vec[j + 224];
				num += u_vec[j + 256];
				num += u_vec[j + 288];
				num += u_vec[j + 320];
				num += u_vec[j + 352];
				num += u_vec[j + 384];
				num += u_vec[j + 416];
				num += u_vec[j + 448];
				num += u_vec[j + 480];
				u_vec[j] = num;
			}
			for (int k = 0; k < 32; k++)
			{
				samples[k] = u_vec[k];
			}
		}
	}
	internal class LayerIDecoder : LayerIIDecoderBase
	{
		private static readonly int[] _rateTable = new int[32];

		private static readonly int[][] _allocLookupTable = new int[1][] { new int[17]
		{
			4, 0, 2, 3, 4, 5, 6, 7, 8, 9,
			10, 11, 12, 13, 14, 15, 16
		} };

		internal static bool GetCRC(MpegFrame frame, ref uint crc)
		{
			return LayerIIDecoderBase.GetCRC(frame, _rateTable, _allocLookupTable, readScfsiBits: false, ref crc);
		}

		internal LayerIDecoder()
			: base(_allocLookupTable, 1)
		{
		}

		protected override int[] GetRateTable(IMpegFrame frame)
		{
			return _rateTable;
		}

		protected override void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels)
		{
		}
	}
	internal class LayerIIDecoder : LayerIIDecoderBase
	{
		private static readonly int[][] _rateLookupTable = new int[5][]
		{
			new int[27]
			{
				3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
				2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 0, 0, 0, 0
			},
			new int[30]
			{
				3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
				2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 0, 0, 0, 0, 0, 0, 0
			},
			new int[8] { 4, 4, 5, 5, 5, 5, 5, 5 },
			new int[12]
			{
				4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
				5, 5
			},
			new int[30]
			{
				6, 6, 6, 6, 5, 5, 5, 5, 5, 5,
				5, 7, 7, 7, 7, 7, 7, 7, 7, 7,
				7, 7, 7, 7, 7, 7, 7, 7, 7, 7
			}
		};

		private static readonly int[][] _allocLookupTable = new int[8][]
		{
			new int[5] { 2, 0, -5, -7, 16 },
			new int[9] { 3, 0, -5, -7, 3, -10, 4, 5, 16 },
			new int[17]
			{
				4, 0, -5, -7, 3, -10, 4, 5, 6, 7,
				8, 9, 10, 11, 12, 13, 16
			},
			new int[17]
			{
				4, 0, -5, 3, 4, 5, 6, 7, 8, 9,
				10, 11, 12, 13, 14, 15, 16
			},
			new int[17]
			{
				4, 0, -5, -7, -10, 4, 5, 6, 7, 8,
				9, 10, 11, 12, 13, 14, 15
			},
			new int[9] { 3, 0, -5, -7, -10, 4, 5, 6, 9 },
			new int[17]
			{
				4, 0, -5, -7, 3, -10, 4, 5, 6, 7,
				8, 9, 10, 11, 12, 13, 14
			},
			new int[5] { 2, 0, -5, -7, 3 }
		};

		internal static bool GetCRC(MpegFrame frame, ref uint crc)
		{
			return LayerIIDecoderBase.GetCRC(frame, SelectTable(frame), _allocLookupTable, readScfsiBits: true, ref crc);
		}

		private static int[] SelectTable(IMpegFrame frame)
		{
			int num = frame.BitRate / ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2) / 1000;
			if (frame.Version == MpegVersion.Version1)
			{
				if ((num >= 56 && num <= 80) || (frame.SampleRate == 48000 && num >= 56))
				{
					return _rateLookupTable[0];
				}
				if (frame.SampleRate != 48000 && num >= 96)
				{
					return _rateLookupTable[1];
				}
				if (frame.SampleRate != 32000 && num <= 48)
				{
					return _rateLookupTable[2];
				}
				return _rateLookupTable[3];
			}
			return _rateLookupTable[4];
		}

		internal LayerIIDecoder()
			: base(_allocLookupTable, 3)
		{
		}

		protected override int[] GetRateTable(IMpegFrame frame)
		{
			return SelectTable(frame);
		}

		protected override void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels)
		{
			for (int i = 0; i < 30; i++)
			{
				for (int j = 0; j < channels; j++)
				{
					if (scfsi[j][i] == 2)
					{
						scfsi[j][i] = frame.ReadBits(2);
					}
				}
			}
		}
	}
	internal abstract class LayerIIDecoderBase : LayerDecoderBase
	{
		protected const int SSLIMIT = 12;

		private static readonly float[] _groupedC = new float[5] { 0f, 0f, 1.3333334f, 1.6f, 1.7777778f };

		private static readonly float[] _groupedD = new float[5] { 0f, 0f, -0.5f, -0.5f, -0.5f };

		private static readonly float[] _C = new float[17]
		{
			0f, 0f, 1.3333334f, 1.1428572f, 1.0666667f, 1.032258f, 1.0158731f, 1.007874f, 1.0039216f, 1.0019569f,
			1.0009775f, 1.0004885f, 1.0002443f, 1.0001221f, 1.000061f, 1.0000305f, 1.0000153f
		};

		private static readonly float[] _D = new float[17]
		{
			0f,
			0f,
			-0.5f,
			-0.75f,
			-0.875f,
			-0.9375f,
			-31f / 32f,
			-63f / 64f,
			-127f / 128f,
			-0.99609375f,
			-0.9980469f,
			-0.99902344f,
			-0.9995117f,
			-0.99975586f,
			-0.9998779f,
			-0.99993896f,
			-0.9999695f
		};

		private static readonly float[] _denormalMultiplier = new float[64]
		{
			2f,
			1.587401f,
			1.2599211f,
			1f,
			0.7937005f,
			0.62996054f,
			0.5f,
			0.39685026f,
			0.31498027f,
			0.25f,
			0.19842513f,
			0.15749013f,
			0.125f,
			0.099212565f,
			0.07874507f,
			0.0625f,
			0.049606282f,
			0.039372534f,
			1f / 32f,
			0.024803141f,
			0.019686267f,
			1f / 64f,
			0.012401571f,
			0.009843133f,
			1f / 128f,
			0.0062007853f,
			0.0049215667f,
			0.00390625f,
			0.0031003926f,
			0.0024607833f,
			0.001953125f,
			0.0015501963f,
			0.0012303917f,
			0.0009765625f,
			0.00077509816f,
			0.00061519584f,
			0.00048828125f,
			0.00038754908f,
			0.00030759792f,
			0.00024414062f,
			0.00019377454f,
			0.00015379896f,
			0.00012207031f,
			9.688727E-05f,
			7.689948E-05f,
			6.1035156E-05f,
			4.8443635E-05f,
			3.844974E-05f,
			3.0517578E-05f,
			2.4221818E-05f,
			1.922487E-05f,
			1.5258789E-05f,
			1.2110909E-05f,
			9.612435E-06f,
			7.6293945E-06f,
			6.0554544E-06f,
			4.8062175E-06f,
			3.8146973E-06f,
			3.0277272E-06f,
			2.4031087E-06f,
			1.9073486E-06f,
			1.5138636E-06f,
			1.2015544E-06f,
			9.536743E-07f
		};

		private int _channels;

		private int _jsbound;

		private int _granuleCount;

		private int[][] _allocLookupTable;

		private int[][] _scfsi;

		private int[][] _samples;

		private int[][][] _scalefac;

		private float[] _polyPhaseBuf;

		private int[][] _allocation;

		protected static bool GetCRC(MpegFrame frame, int[] rateTable, int[][] allocLookupTable, bool readScfsiBits, ref uint crc)
		{
			int num = 0;
			int num2 = rateTable.Length;
			int num3 = num2;
			if (frame.ChannelMode == MpegChannelMode.JointStereo)
			{
				num3 = frame.ChannelModeExtension * 4 + 4;
			}
			int num4 = ((frame.ChannelMode == MpegChannelMode.Mono) ? 1 : 2);
			int i;
			for (i = 0; i < num3; i++)
			{
				int num5 = allocLookupTable[rateTable[i]][0];
				for (int j = 0; j < num4; j++)
				{
					int num6 = frame.ReadBits(num5);
					if (num6 > 0)
					{
						num += 2;
					}
					MpegFrame.UpdateCRC(num6, num5, ref crc);
				}
			}
			for (; i < num2; i++)
			{
				int num7 = allocLookupTable[rateTable[i]][0];
				int num8 = frame.ReadBits(num7);
				if (num8 > 0)
				{
					num += num4 * 2;
				}
				MpegFrame.UpdateCRC(num8, num7, ref crc);
			}
			if (readScfsiBits)
			{
				while (num >= 2)
				{
					MpegFrame.UpdateCRC(frame.ReadBits(2), 2, ref crc);
					num -= 2;
				}
			}
			return true;
		}

		protected LayerIIDecoderBase(int[][] allocLookupTable, int granuleCount)
		{
			_allocLookupTable = allocLookupTable;
			_granuleCount = granuleCount;
			_allocation = new int[2][]
			{
				new int[32],
				new int[32]
			};
			_scfsi = new int[2][]
			{
				new int[32],
				new int[32]
			};
			_samples = new int[2][]
			{
				new int[384 * _granuleCount],
				new int[384 * _granuleCount]
			};
			_scalefac = new int[2][][]
			{
				new int[3][],
				new int[3][]
			};
			for (int i = 0; i < 3; i++)
			{
				_scalefac[0][i] = new int[32];
				_scalefac[1][i] = new int[32];
			}
			_polyPhaseBuf = new float[32];
		}

		internal override int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1)
		{
			InitFrame(frame);
			int[] rateTable = GetRateTable(frame);
			ReadAllocation(frame, rateTable);
			for (int i = 0; i < _scfsi[0].Length; i++)
			{
				_scfsi[0][i] = ((_allocation[0][i] != 0) ? 2 : (-1));
				_scfsi[1][i] = ((_allocation[1][i] != 0) ? 2 : (-1));
			}
			ReadScaleFactorSelection(frame, _scfsi, _channels);
			ReadScaleFactors(frame);
			ReadSamples(frame);
			return DecodeSamples(ch0, ch1);
		}

		private void InitFrame(IMpegFrame frame)
		{
			switch (frame.ChannelMode)
			{
			case MpegChannelMode.Mono:
				_channels = 1;
				_jsbound = 32;
				break;
			case MpegChannelMode.JointStereo:
				_channels = 2;
				_jsbound = frame.ChannelModeExtension * 4 + 4;
				break;
			default:
				_channels = 2;
				_jsbound = 32;
				break;
			}
		}

		protected abstract int[] GetRateTable(IMpegFrame frame);

		private void ReadAllocation(IMpegFrame frame, int[] rateTable)
		{
			int num = rateTable.Length;
			if (_jsbound > num)
			{
				_jsbound = num;
			}
			Array.Clear(_allocation[0], 0, 32);
			Array.Clear(_allocation[1], 0, 32);
			int i;
			for (i = 0; i < _jsbound; i++)
			{
				int[] array = _allocLookupTable[rateTable[i]];
				int bitCount = array[0];
				for (int j = 0; j < _channels; j++)
				{
					_allocation[j][i] = array[frame.ReadBits(bitCount) + 1];
				}
			}
			for (; i < num; i++)
			{
				int[] array2 = _allocLookupTable[rateTable[i]];
				_allocation[0][i] = (_allocation[1][i] = array2[frame.ReadBits(array2[0]) + 1]);
			}
		}

		protected abstract void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels);

		private void ReadScaleFactors(IMpegFrame frame)
		{
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < _channels; j++)
				{
					switch (_scfsi[j][i])
					{
					case 0:
						_scalefac[j][0][i] = frame.ReadBits(6);
						_scalefac[j][1][i] = frame.ReadBits(6);
						_scalefac[j][2][i] = frame.ReadBits(6);
						break;
					case 1:
						_scalefac[j][0][i] = (_scalefac[j][1][i] = frame.ReadBits(6));
						_scalefac[j][2][i] = frame.ReadBits(6);
						break;
					case 2:
						_scalefac[j][0][i] = (_scalefac[j][1][i] = (_scalefac[j][2][i] = frame.ReadBits(6)));
						break;
					case 3:
						_scalefac[j][0][i] = frame.ReadBits(6);
						_scalefac[j][1][i] = (_scalefac[j][2][i] = frame.ReadBits(6));
						break;
					default:
						_scalefac[j][0][i] = 63;
						_scalefac[j][1][i] = 63;
						_scalefac[j][2][i] = 63;
						break;
					}
				}
			}
		}

		private void ReadSamples(IMpegFrame frame)
		{
			int num = 0;
			int num2 = 0;
			while (num < 12)
			{
				int num3 = 0;
				while (num3 < 32)
				{
					for (int i = 0; i < _channels; i++)
					{
						if (i == 0 || num3 < _jsbound)
						{
							int num4 = _allocation[i][num3];
							if (num4 != 0)
							{
								if (num4 < 0)
								{
									int num5 = frame.ReadBits(-num4);
									int num6 = (1 << -num4 / 2 + -num4 % 2 - 1) + 1;
									_samples[i][num2] = num5 % num6;
									num5 /= num6;
									_samples[i][num2 + 32] = num5 % num6;
									_samples[i][num2 + 64] = num5 / num6;
								}
								else
								{
									for (int j = 0; j < _granuleCount; j++)
									{
										_samples[i][num2 + 32 * j] = frame.ReadBits(num4);
									}
								}
							}
							else
							{
								for (int k = 0; k < _granuleCount; k++)
								{
									_samples[i][num2 + 32 * k] = 0;
								}
							}
						}
						else
						{
							for (int l = 0; l < _granuleCount; l++)
							{
								_samples[1][num2 + 32 * l] = _samples[0][num2 + 32 * l];
							}
						}
					}
					num3++;
					num2++;
				}
				num++;
				num2 += 32 * (_granuleCount - 1);
			}
		}

		private int DecodeSamples(float[] ch0, float[] ch1)
		{
			float[][] array = new float[2][];
			int num = 0;
			int num2 = _channels - 1;
			if (_channels == 1 || base.StereoMode == StereoMode.LeftOnly)
			{
				array[0] = ch0;
				num2 = 0;
			}
			else if (base.StereoMode == StereoMode.RightOnly)
			{
				array[1] = ch0;
				num = 1;
			}
			else
			{
				array[0] = ch0;
				array[1] = ch1;
			}
			int num3 = 0;
			for (int i = num; i <= num2; i++)
			{
				num3 = 0;
				for (int j = 0; j < _granuleCount; j++)
				{
					for (int k = 0; k < 12; k++)
					{
						int num4 = 0;
						while (num4 < 32)
						{
							int num5 = _allocation[i][num4];
							if (num5 != 0)
							{
								float[] array2;
								float[] array3;
								if (num5 < 0)
								{
									num5 = -num5 / 2 + -num5 % 2 - 1;
									array2 = _groupedC;
									array3 = _groupedD;
								}
								else
								{
									array2 = _C;
									array3 = _D;
								}
								_polyPhaseBuf[num4] = array2[num5] * ((float)(_samples[i][num3] << 16 - num5) / 32768f + array3[num5]) * _denormalMultiplier[_scalefac[i][j][num4]];
							}
							else
							{
								_polyPhaseBuf[num4] = 0f;
							}
							num4++;
							num3++;
						}
						InversePolyPhase(i, _polyPhaseBuf);
						Array.Copy(_polyPhaseBuf, 0, array[i], num3 - 32, 32);
					}
				}
			}
			if (_channels == 2 && base.StereoMode == StereoMode.DownmixToMono)
			{
				for (int l = 0; l < num3; l++)
				{
					ch0[l] = (ch0[l] + ch1[l]) / 2f;
				}
			}
			return num3;
		}
	}
	internal sealed class LayerIIIDecoder : LayerDecoderBase
	{
		private class HybridMDCT
		{
			private const float PI = MathF.PI;

			private static float[][] _swin;

			private static float[] icos72_table;

			private List<float[]> _prevBlock;

			private List<float[]> _nextBlock;

			private float[] _imdctTemp = new float[18];

			private float[] _imdctResult = new float[36];

			private const float sqrt32 = 0.8660254f;

			static HybridMDCT()
			{
				icos72_table = new float[35]
				{
					0.50047636f, 0.5019099f, 0.5043145f, 0.5077133f, 0.51213974f, 0.5176381f, 0.5242646f, 0.5320889f, 0.5411961f, 0.55168897f,
					0.56369096f, 0.57735026f, 0.59284455f, 0.61038727f, 0.6302362f, 0.65270364f, 0.67817086f, 0.70710677f, 0.7400936f, 0.7778619f,
					0.8213398f, 0.8717234f, 0.9305795f, 1f, 1.0828403f, 1.1831008f, 1.306563f, 1.4619021f, 1.6627548f, 1.9318516f,
					2.3101132f, 2.8793852f, 3.830649f, 5.7368565f, 11.462792f
				};
				_swin = new float[4][]
				{
					new float[36],
					new float[36],
					new float[36],
					new float[36]
				};
				for (int i = 0; i < 36; i++)
				{
					_swin[0][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5));
				}
				for (int i = 0; i < 18; i++)
				{
					_swin[1][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5));
				}
				for (int i = 18; i < 24; i++)
				{
					_swin[1][i] = 1f;
				}
				for (int i = 24; i < 30; i++)
				{
					_swin[1][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5 - 18.0));
				}
				for (int i = 30; i < 36; i++)
				{
					_swin[1][i] = 0f;
				}
				for (int i = 0; i < 6; i++)
				{
					_swin[3][i] = 0f;
				}
				for (int i = 6; i < 12; i++)
				{
					_swin[3][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5 - 6.0));
				}
				for (int i = 12; i < 18; i++)
				{
					_swin[3][i] = 1f;
				}
				for (int i = 18; i < 36; i++)
				{
					_swin[3][i] = (float)Math.Sin(0.0872664675116539 * ((double)i + 0.5));
				}
				for (int i = 0; i < 12; i++)
				{
					_swin[2][i] = (float)Math.Sin(0.2617993950843811 * ((double)i + 0.5));
				}
				for (int i = 12; i < 36; i++)
				{
					_swin[2][i] = 0f;
				}
			}

			internal HybridMDCT()
			{
				_prevBlock = new List<float[]>();
				_nextBlock = new List<float[]>();
			}

			internal void Reset()
			{
				_prevBlock.Clear();
				_nextBlock.Clear();
			}

			private void GetPrevBlock(int channel, out float[] prevBlock, out float[] nextBlock)
			{
				while (_prevBlock.Count <= channel)
				{
					_prevBlock.Add(new float[576]);
				}
				while (_nextBlock.Count <= channel)
				{
					_nextBlock.Add(new float[576]);
				}
				prevBlock = _prevBlock[channel];
				nextBlock = _nextBlock[channel];
				_nextBlock[channel] = prevBlock;
				_prevBlock[channel] = nextBlock;
			}

			internal void Apply(float[] fsIn, int channel, int blockType, bool doMixed)
			{
				GetPrevBlock(channel, out var prevBlock, out var nextBlock);
				int sbStart = 0;
				if (doMixed)
				{
					LongImpl(fsIn, 0, 2, nextBlock, 0);
					sbStart = 2;
				}
				if (blockType == 2)
				{
					ShortImpl(fsIn, sbStart, nextBlock);
				}
				else
				{
					LongImpl(fsIn, sbStart, 32, nextBlock, blockType);
				}
				for (int i = 0; i < 576; i++)
				{
					fsIn[i] += prevBlock[i];
				}
			}

			private void LongImpl(float[] fsIn, int sbStart, int sbLimit, float[] nextblck, int blockType)
			{
				int i = sbStart;
				int num = sbStart * 18;
				for (; i < sbLimit; i++)
				{
					Array.Copy(fsIn, num, _imdctTemp, 0, 18);
					LongIMDCT(_imdctTemp, _imdctResult);
					float[] array = _swin[blockType];
					int j;
					for (j = 0; j < 18; j++)
					{
						fsIn[num++] = _imdctResult[j] * array[j];
					}
					num -= 18;
					for (; j < 36; j++)
					{
						nextblck[num++] = _imdctResult[j] * array[j];
					}
				}
			}

			private static void LongIMDCT(float[] invec, float[] outvec)
			{
				float[] array = new float[17];
				float[] array2 = new float[18];
				float[] array3 = new float[9];
				float[] array4 = new float[9];
				float[] array5 = new float[9];
				float[] array6 = new float[9];
				int i;
				for (i = 0; i < 17; i++)
				{
					array[i] = invec[i] + invec[i + 1];
				}
				array3[0] = invec[0];
				array4[0] = array[0];
				int num = 0;
				i = 1;
				while (i < 9)
				{
					array3[i] = array[num + 1];
					array4[i] = array[num] + array[num + 2];
					i++;
					num += 2;
				}
				imdct_9pt(array3, array5);
				imdct_9pt(array4, array6);
				for (i = 0; i < 9; i++)
				{
					array6[i] *= ICOS36_A(i);
					array2[i] = (array5[i] + array6[i]) * ICOS72_A(i);
				}
				for (; i < 18; i++)
				{
					array2[i] = (array5[17 - i] - array6[17 - i]) * ICOS72_A(i);
				}
				outvec[0] = array2[9];
				outvec[1] = array2[10];
				outvec[2] = array2[11];
				outvec[3] = array2[12];
				outvec[4] = array2[13];
				outvec[5] = array2[14];
				outvec[6] = array2[15];
				outvec[7] = array2[16];
				outvec[8] = array2[17];
				outvec[9] = 0f - array2[17];
				outvec[10] = 0f - array2[16];
				outvec[11] = 0f - array2[15];
				outvec[12] = 0f - array2[14];
				outvec[13] = 0f - array2[13];
				outvec[14] = 0f - array2[12];
				outvec[15] = 0f - array2[11];
				outvec[16] = 0f - array2[10];
				outvec[17] = 0f - array2[9];
				outvec[35] = (outvec[18] = 0f - array2[8]);
				outvec[34] = (outvec[19] = 0f - array2[7]);
				outvec[33] = (outvec[20] = 0f - array2[6]);
				outvec[32] = (outvec[21] = 0f - array2[5]);
				outvec[31] = (outvec[22] = 0f - array2[4]);
				outvec[30] = (outvec[23] = 0f - array2[3]);
				outvec[29] = (outvec[24] = 0f - array2[2]);
				outvec[28] = (outvec[25] = 0f - array2[1]);
				outvec[27] = (outvec[26] = 0f - array2[0]);
			}

			private static float ICOS72_A(int i)
			{
				return icos72_table[2 * i];
			}

			private static float ICOS36_A(int i)
			{
				return icos72_table[4 * i + 1];
			}

			private static void imdct_9pt(float[] invec, float[] outvec)
			{
				float[] array = new float[5];
				float[] array2 = new float[4];
				float num = invec[6] / 2f + invec[0];
				float num2 = invec[0] - invec[6];
				float num3 = invec[2] - invec[4] - invec[8];
				array[0] = num + invec[2] * 0.9396926f + invec[4] * 0.76604444f + invec[8] * 0.17364818f;
				array[1] = num3 / 2f + num2;
				array[2] = num - invec[2] * 0.17364818f - invec[4] * 0.9396926f + invec[8] * 0.76604444f;
				array[3] = num - invec[2] * 0.76604444f + invec[4] * 0.17364818f - invec[8] * 0.9396926f;
				array[4] = num2 - num3;
				float num4 = invec[1] + invec[3];
				float num5 = invec[3] + invec[5];
				num = (invec[5] + invec[7]) * 0.5f + invec[1];
				array2[0] = num + num4 * 0.9396926f + num5 * 0.76604444f;
				array2[1] = (invec[1] - invec[5]) * 1.5f - invec[7];
				array2[2] = num - num4 * 0.17364818f - num5 * 0.9396926f;
				array2[3] = num - num4 * 0.76604444f + num5 * 0.17364818f;
				array2[0] += invec[7] * 0.17364818f;
				array2[1] -= invec[7] * 0.5f;
				array2[2] += invec[7] * 0.76604444f;
				array2[3] -= invec[7] * 0.9396926f;
				array2[0] *= 0.5077133f;
				array2[1] *= 0.57735026f;
				array2[2] *= 0.7778619f;
				array2[3] *= 1.4619021f;
				for (int i = 0; i < 4; i++)
				{
					outvec[i] = array[i] + array2[i];
				}
				outvec[4] = array[4];
				for (int i = 5; i < 9; i++)
				{
					outvec[i] = array[8 - i] - array2[8 - i];
				}
			}

			private void ShortImpl(float[] fsIn, int sbStart, float[] nextblck)
			{
				_ = _swin[2];
				int num = sbStart;
				int num2 = sbStart * 18;
				while (num < 32)
				{
					int i = 0;
					int num3 = 0;
					for (; i < 3; i++)
					{
						int num4 = num2 + i;
						for (int j = 0; j < 6; j++)
						{
							_imdctTemp[num3 + j] = fsIn[num4];
							num4 += 3;
						}
						num3 += 6;
					}
					Array.Clear(fsIn, num2, 6);
					ShortIMDCT(_imdctTemp, 0, _imdctResult);
					Array.Copy(_imdctResult, 0, fsIn, num2 + 6, 12);
					ShortIMDCT(_imdct