Decompiled source of Sailwind Radio v1.0.1

BepInEx/plugins/SailwindRadio/SailwindRadio.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using System.Security;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NLayer;
using SailwindRadio.Acoustics;
using SailwindRadio.Library;
using SailwindRadio.Models;
using SailwindRadio.Persistence;
using SailwindRadio.Physical;
using SailwindRadio.Playback;
using SailwindRadio.Shops;
using SailwindRadio.UI;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[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("SailwindRadio")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("SailwindRadio")]
[assembly: AssemblyTitle("SailwindRadio")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SailwindRadio
{
	public sealed class RadioBassFilter : MonoBehaviour
	{
		private sealed class BassFilter
		{
			internal readonly int SampleRate;

			private readonly double[] b0 = new double[2];

			private readonly double[] b1 = new double[2];

			private readonly double[] b2 = new double[2];

			private readonly double[] a1 = new double[2];

			private readonly double[] a2 = new double[2];

			private readonly double[] z1 = new double[16];

			private readonly double[] z2 = new double[16];

			internal BassFilter(int sampleRate)
			{
				SampleRate = sampleRate;
				double num = Math.PI * 280.0 / (double)sampleRate;
				double num2 = Math.Cos(num);
				double num3 = Math.Sin(num);
				for (int i = 0; i < 2; i++)
				{
					double num4 = ((i == 0) ? 0.541196100146197 : 1.30656296487638);
					double num5 = num3 / (2.0 * num4);
					double num6 = 1.0 + num5;
					b0[i] = (1.0 - num2) / (2.0 * num6);
					b1[i] = (1.0 - num2) / num6;
					b2[i] = b0[i];
					a1[i] = -2.0 * num2 / num6;
					a2[i] = (1.0 - num5) / num6;
				}
			}

			internal float Apply(float sample, int channel)
			{
				if (channel >= 8)
				{
					return 0f;
				}
				double num = (RadioSpeakerOutput.Finite(sample) ? sample : 0f);
				for (int i = 0; i < 2; i++)
				{
					int num2 = i * 8 + channel;
					double num3 = b0[i] * num + z1[num2];
					z1[num2] = b1[i] * num - a1[i] * num3 + z2[num2];
					z2[num2] = b2[i] * num - a2[i] * num3;
					num = num3;
				}
				return (float)(num * 2.0);
			}
		}

		private volatile BassFilter bass;

		internal void SetProfile(int sampleRate, bool woofer)
		{
			BassFilter bassFilter = bass;
			if (!woofer)
			{
				bass = null;
				return;
			}
			if (sampleRate < 8000 || sampleRate > 192000)
			{
				sampleRate = 48000;
			}
			if (bassFilter == null || bassFilter.SampleRate != sampleRate)
			{
				bass = new BassFilter(sampleRate);
			}
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			Process(data, channels);
		}

		internal void Process(float[] data, int channels)
		{
			BassFilter bassFilter = bass;
			if (channels <= 0 || bassFilter == null)
			{
				return;
			}
			for (int i = 0; i < data.Length; i += channels)
			{
				for (int j = 0; j < channels && i + j < data.Length; j++)
				{
					float num = bassFilter.Apply(data[i + j], j);
					data[i + j] = (RadioSpeakerOutput.Finite(num) ? Math.Max(-1f, Math.Min(1f, num)) : 0f);
				}
			}
		}
	}
	public sealed class RadioPlayback : IDisposable
	{
		internal sealed class DecodedMp3
		{
			internal readonly List<float[]> Blocks = new List<float[]>();

			internal int Channels;

			internal int SampleRate;

			internal int SampleCount;
		}

		internal sealed class Mp3LoadResult
		{
			internal DecodedMp3 Decoded;

			internal StreamedMp3 Stream;
		}

		internal sealed class CancellableFileStream : Stream
		{
			private readonly FileStream input;

			private readonly CancellationToken token;

			public override bool CanRead => true;

			public override bool CanSeek => true;

			public override bool CanWrite => false;

			public override long Length => input.Length;

			public override long Position
			{
				get
				{
					return input.Position;
				}
				set
				{
					CancellationToken cancellationToken = token;
					cancellationToken.ThrowIfCancellationRequested();
					input.Position = value;
				}
			}

			internal CancellableFileStream(string path, CancellationToken token)
			{
				this.token = token;
				input = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
			}

			public override int Read(byte[] buffer, int offset, int count)
			{
				CancellationToken cancellationToken = token;
				cancellationToken.ThrowIfCancellationRequested();
				return input.Read(buffer, offset, count);
			}

			public override long Seek(long offset, SeekOrigin origin)
			{
				CancellationToken cancellationToken = token;
				cancellationToken.ThrowIfCancellationRequested();
				return input.Seek(offset, origin);
			}

			public override void Flush()
			{
			}

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

			public override void Write(byte[] buffer, int offset, int count)
			{
				throw new NotSupportedException();
			}

			protected override void Dispose(bool disposing)
			{
				if (disposing)
				{
					input.Dispose();
				}
				base.Dispose(disposing);
			}
		}

		private const double ScheduleLeadSeconds = 0.05;

		private const double LoadTimeoutSeconds = 60.0;

		private readonly RadioState state;

		private readonly Action<string> warning;

		private readonly MonoBehaviour host;

		private RadioAudioLifetime lifetime;

		private GameObject emitter;

		private AudioSource source;

		private RadioSpeakerOutput builtIn;

		private readonly Dictionary<int, RadioSpeakerOutput> endpoints = new Dictionary<int, RadioSpeakerOutput>();

		private readonly List<int> lostEndpoints = new List<int>();

		private Vector3 listenerPosition;

		private bool listenerKnown;

		private AudioClip clip;

		private UnityWebRequest request;

		private Task<Mp3LoadResult> mp3Task;

		private CancellationTokenSource mp3Cancellation;

		private StreamedMp3 streamedMp3;

		private string requestedPath;

		private string failure;

		private bool disposed;

		private bool running;

		private bool voicesPaused;

		private bool recoveryWarned;

		private double nextHealthCheck;

		private bool wasPowered;

		private volatile bool resetRequested;

		private double scheduledDsp;

		private double lastDsp;

		private int scheduledSample;

		private double loadStartedAt;

		private double streamWaitingSince = -1.0;

		internal const int MaximumMp3Samples = 67108864;

		internal const long MaximumMp3FileBytes = 134217728L;

		internal const long MaximumStreamedMp3FileBytes = 1073741824L;

		private static readonly SemaphoreSlim Mp3DecodeSlot = new SemaphoreSlim(1, 1);

		private string preloadPath;

		private bool preloadStarted;

		private bool preloadFailed;

		private AudioClip preloadClip;

		private UnityWebRequest preloadRequest;

		private Task<Mp3LoadResult> preloadTask;

		private CancellationTokenSource preloadCancellation;

		private double preloadStartedAt;

		public string Status { get; private set; }

		public string TrackLabel { get; private set; }

		public bool RepeatTrack { get; set; } = true;

		public bool TrackEnded { get; private set; }

		public bool LoadFailed => failure != null;

		public string FailedPath { get; private set; }

		public RadioPlayback(MonoBehaviour coroutineHost, RadioState state, Action<string> warning)
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			if ((Object)(object)coroutineHost == (Object)null)
			{
				throw new ArgumentNullException("coroutineHost");
			}
			if (state == null)
			{
				throw new ArgumentNullException("state");
			}
			this.state = state;
			host = coroutineHost;
			this.warning = warning ?? ((Action<string>)delegate
			{
			});
			builtIn = new RadioSpeakerOutput("Sailwind Radio audio", RadioSpeakerProfile.BuiltIn, this.warning);
			emitter = builtIn.Emitter;
			source = builtIn.Source;
			lifetime = emitter.AddComponent<RadioAudioLifetime>();
			lifetime.Host = coroutineHost;
			lifetime.Playback = this;
			AudioSettings.OnAudioConfigurationChanged += new AudioConfigurationChangeHandler(OnAudioConfigurationChanged);
			Status = "Off";
			TrackLabel = "No track";
			lastDsp = AudioSettings.dspTime;
		}

		public void SetTrack(string path)
		{
			if (!disposed)
			{
				path = path ?? "";
				if (!string.Equals(state.TrackPath, path, StringComparison.Ordinal))
				{
					state.PositionSeconds = 0.0;
				}
				state.TrackPath = path;
				ReleaseTrack();
				failure = null;
				FailedPath = null;
				TrackEnded = false;
				requestedPath = null;
				if (!AdoptPreload(path))
				{
					ReleasePreload();
				}
			}
		}

		public void SetCarried(bool carried)
		{
			if (!disposed)
			{
				builtIn.Carried = carried;
			}
		}

		public void BeginEndpoints()
		{
			if (disposed)
			{
				return;
			}
			foreach (RadioSpeakerOutput value in endpoints.Values)
			{
				value.Seen = false;
			}
		}

		public void SetEndpoint(int id, Vector3 position, bool carried, int kind, float localVolume, float bass, float obstruction)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (disposed)
			{
				return;
			}
			RadioSpeakerProfile radioSpeakerProfile = RadioSpeakerProfile.ForKind(kind);
			if (radioSpeakerProfile != null)
			{
				if (!endpoints.TryGetValue(id, out var value) || (Object)(object)value.Emitter == (Object)null || (Object)(object)value.Source == (Object)null || value.Profile != radioSpeakerProfile)
				{
					value?.Dispose();
					value = new RadioSpeakerOutput("Sailwind Radio speaker " + id, radioSpeakerProfile, warning);
					endpoints[id] = value;
				}
				value.Profile = radioSpeakerProfile;
				value.Position = position;
				value.Carried = carried;
				value.LocalVolume = localVolume;
				value.Bass = bass;
				value.Obstruction = obstruction;
				value.Seen = true;
			}
		}

		public void EndEndpoints()
		{
			if (disposed)
			{
				return;
			}
			lostEndpoints.Clear();
			foreach (KeyValuePair<int, RadioSpeakerOutput> endpoint in endpoints)
			{
				if (!endpoint.Value.Seen)
				{
					lostEndpoints.Add(endpoint.Key);
				}
			}
			foreach (int lostEndpoint in lostEndpoints)
			{
				endpoints[lostEndpoint].Dispose();
				endpoints.Remove(lostEndpoint);
			}
		}

		public void SetAcoustics(Vector3 listenerPosition, bool listenerKnown, float obstruction)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!disposed)
			{
				this.listenerPosition = listenerPosition;
				this.listenerKnown = listenerKnown && IsFinite(listenerPosition.x) && IsFinite(listenerPosition.y) && IsFinite(listenerPosition.z);
				builtIn.Obstruction = obstruction;
			}
		}

		public void Tick(Vector3 worldPosition, bool suspended)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Invalid comparison between Unknown and I4
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Invalid comparison between Unknown and I4
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Invalid comparison between Unknown and I4
			//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b8: Invalid comparison between Unknown and I4
			if (disposed)
			{
				return;
			}
			if ((Object)(object)host == (Object)null)
			{
				Dispose();
				return;
			}
			EnsureOwnedOutput();
			builtIn.Position = worldPosition;
			builtIn.LocalVolume = state.LocalVolume;
			state.Volume = (float.IsNaN(state.Volume) ? 0.5f : Mathf.Clamp01(state.Volume));
			builtIn.Update(state.Volume, listenerPosition, listenerKnown);
			source.loop = RepeatTrack;
			foreach (RadioSpeakerOutput value in endpoints.Values)
			{
				value.Update(state.Volume, listenerPosition, listenerKnown);
				if ((Object)(object)value.Source != (Object)null)
				{
					value.Source.loop = RepeatTrack;
				}
			}
			double dspTime = AudioSettings.dspTime;
			if (resetRequested || dspTime < lastDsp)
			{
				StopOutputs();
				resetRequested = false;
			}
			lastDsp = dspTime;
			PollPreload();
			if (!string.Equals(requestedPath, state.TrackPath ?? "", StringComparison.Ordinal))
			{
				ReleaseTrack();
				requestedPath = state.TrackPath ?? "";
				failure = null;
				FailedPath = null;
				TrackEnded = false;
				TrackLabel = SafeLabel(requestedPath);
				if (!AdoptPreload(requestedPath))
				{
					ReleasePreload();
					if (state.Powered)
					{
						BeginLoad();
					}
				}
			}
			else if (state.Powered && !wasPowered && (Object)(object)clip == (Object)null && request == null && mp3Task == null)
			{
				failure = null;
				FailedPath = null;
				BeginLoad();
			}
			wasPowered = state.Powered;
			CompleteLoad();
			CompleteMp3Load();
			if (streamedMp3 != null)
			{
				if (streamedMp3.Fault != null)
				{
					Fail("Unable to decode music", streamedMp3.Fault.Message);
				}
				else
				{
					int num = SafeSavedFrame();
					streamedMp3.Request(running ? SampleAt(dspTime) : num);
				}
			}
			if (request != null || mp3Task != null || ((Object)(object)clip != (Object)null && (int)clip.loadState != 2))
			{
				if ((Object)(object)clip != (Object)null && (int)clip.loadState == 3)
				{
					Fail("Unable to decode music", "The decoder failed to load audio data");
				}
				else if ((double)Time.realtimeSinceStartup - loadStartedAt >= 60.0)
				{
					Fail("Unable to load music", "Audio loading timed out after 60 seconds");
				}
			}
			FinishIfEnded();
			bool flag = state.Powered && !state.Paused && !suspended && !AudioListener.pause && !TrackEnded;
			int num2 = SafeSavedFrame();
			bool flag2 = streamedMp3 == null || streamedMp3.Ready(running ? SampleAt(dspTime) : num2);
			if (streamedMp3 != null && flag && !flag2)
			{
				if (streamWaitingSince < 0.0)
				{
					streamWaitingSince = Time.realtimeSinceStartup;
				}
				else if ((double)Time.realtimeSinceStartup - streamWaitingSince >= 60.0)
				{
					Fail("Unable to decode music", "Streamed MP3 buffer did not recover");
					flag = false;
				}
			}
			else
			{
				streamWaitingSince = -1.0;
			}
			if (!flag && running)
			{
				CapturePosition();
				PauseOutputs();
			}
			if (flag && (Object)(object)clip != (Object)null && (int)clip.loadState == 2 && !running && flag2)
			{
				StartAtSavedPosition();
			}
			if (running)
			{
				CapturePosition();
			}
			if (running)
			{
				JoinEndpoints();
			}
			if (running)
			{
				CheckOutputHealth();
			}
			Status = ((!state.Powered) ? "Off" : ((failure != null) ? failure : ((request != null || mp3Task != null || ((Object)(object)clip != (Object)null && (int)clip.loadState != 2) || (streamedMp3 != null && !running && !flag2)) ? "Loading" : (((Object)(object)clip == (Object)null) ? "No track" : (TrackEnded ? "Ended" : (state.Paused ? "Paused" : ((suspended || AudioListener.pause) ? "Suspended" : "Playing")))))));
		}

		public void CapturePosition()
		{
			if (!disposed && running && !((Object)(object)clip == (Object)null) && !resetRequested && !(AudioSettings.dspTime < lastDsp) && !FinishIfEnded())
			{
				state.PositionSeconds = (double)SampleAt(AudioSettings.dspTime) / (double)clip.frequency;
			}
		}

		private int SafeSavedFrame()
		{
			if ((Object)(object)clip == (Object)null || clip.samples <= 0 || clip.frequency <= 0)
			{
				return 0;
			}
			double positionSeconds = state.PositionSeconds;
			if (double.IsNaN(positionSeconds) || double.IsInfinity(positionSeconds) || positionSeconds < 0.0)
			{
				return 0;
			}
			return (int)Math.Min(clip.samples - 1, Math.Floor(positionSeconds * (double)clip.frequency));
		}

		private int SampleAt(double dsp)
		{
			long num = scheduledSample + (long)Math.Round(Math.Max(0.0, dsp - scheduledDsp) * (double)clip.frequency);
			if (!RepeatTrack)
			{
				return (int)Math.Min(clip.samples, num);
			}
			return (int)(num % clip.samples);
		}

		internal static float DistanceGain(float distance)
		{
			return RadioSpeakerOutput.DistanceGain(distance, RadioSpeakerProfile.BuiltIn.Radius);
		}

		private static bool IsFinite(float value)
		{
			return RadioSpeakerOutput.Finite(value);
		}

		private void BeginLoad()
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Invalid comparison between Unknown and I4
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Invalid comparison between Unknown and I4
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(requestedPath))
			{
				return;
			}
			try
			{
				if (!Path.IsPathRooted(requestedPath))
				{
					throw new IOException("Choose an absolute local music file path");
				}
				string fullPath = Path.GetFullPath(requestedPath);
				Uri uri = new Uri(fullPath);
				if (!uri.IsFile || uri.IsUnc)
				{
					throw new IOException("Choose a local music file");
				}
				AudioType val = (AudioType)(Path.GetExtension(fullPath).ToLowerInvariant() switch
				{
					".mp3" => 13, 
					".ogg" => 14, 
					".wav" => 20, 
					_ => throw new IOException("Choose an MP3, OGG or WAV file"), 
				});
				if (!File.Exists(fullPath))
				{
					throw new IOException("Music file is missing or inaccessible");
				}
				if (new FileInfo(fullPath).Length > (((int)val == 13) ? 1073741824 : 134217728))
				{
					throw new IOException("Audio file exceeds the size limit");
				}
				loadStartedAt = Time.realtimeSinceStartup;
				if ((int)val == 13)
				{
					mp3Cancellation = new CancellationTokenSource();
					mp3Cancellation.CancelAfter(60000);
					CancellationToken token = mp3Cancellation.Token;
					double saved = state.PositionSeconds;
					mp3Task = Task.Run(() => PrepareMp3(fullPath, saved, token), token);
				}
				else
				{
					request = UnityWebRequestMultimedia.GetAudioClip(uri.AbsoluteUri, val);
					((DownloadHandlerAudioClip)request.downloadHandler).streamAudio = false;
					request.SendWebRequest();
				}
			}
			catch (Exception ex)
			{
				Fail("Unable to load music", ex.Message);
			}
		}

		private void CompleteLoad()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			if (request == null || !request.isDone)
			{
				return;
			}
			try
			{
				if (request.isNetworkError || request.isHttpError)
				{
					throw new IOException(request.error ?? "Audio request failed");
				}
				clip = DownloadHandlerAudioClip.GetContent(request);
				if ((Object)(object)clip == (Object)null || (int)clip.loadState == 3 || clip.samples <= 0 || clip.frequency <= 0 || (long)clip.samples * (long)clip.channels > 67108864)
				{
					throw new IOException("The file could not be decoded as audio");
				}
				source.clip = clip;
				request.Dispose();
				request = null;
			}
			catch (Exception ex)
			{
				Fail("Unable to decode music", ex.Message);
			}
		}

		private void CompleteMp3Load()
		{
			if (mp3Task == null || !mp3Task.IsCompleted)
			{
				return;
			}
			try
			{
				if (mp3Task.IsCanceled)
				{
					throw new IOException("MP3 decoding timed out");
				}
				if (mp3Task.IsFaulted)
				{
					throw new IOException("MP3 decoding failed: " + mp3Task.Exception.GetBaseException().Message);
				}
				Mp3LoadResult result = mp3Task.Result;
				mp3Task = null;
				mp3Cancellation.Dispose();
				mp3Cancellation = null;
				if (result.Stream != null)
				{
					streamedMp3 = result.Stream;
					StreamedMp3.Reader reader = streamedMp3.CreateReader();
					clip = streamedMp3.CreateClip(reader);
					if ((Object)(object)clip == (Object)null)
					{
						throw new IOException("Unable to create streamed audio clip");
					}
					builtIn.StreamClip = clip;
					source.clip = clip;
					ReleasePreload();
					return;
				}
				DecodedMp3 decoded = result.Decoded;
				clip = AudioClip.Create("Sailwind Radio MP3", decoded.SampleCount / decoded.Channels, decoded.Channels, decoded.SampleRate, false);
				if ((Object)(object)clip == (Object)null)
				{
					throw new IOException("Unable to allocate the decoded audio clip");
				}
				int num = 0;
				foreach (float[] block in decoded.Blocks)
				{
					if (!clip.SetData(block, num))
					{
						throw new IOException("Unable to upload decoded audio");
					}
					num += block.Length / decoded.Channels;
				}
				source.clip = clip;
			}
			catch (Exception ex)
			{
				Fail("Unable to decode music", ex.Message);
			}
		}

		internal static Mp3LoadResult PrepareMp3(string path, double initialSeconds, CancellationToken token, int maximumSamples = 67108864)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			token.ThrowIfCancellationRequested();
			using (CancellableFileStream cancellableFileStream = new CancellableFileStream(path, token))
			{
				if (cancellableFileStream.Length > 1073741824)
				{
					throw new IOException("MP3 exceeds the streamed file size limit");
				}
				MpegFile val = new MpegFile((Stream)cancellableFileStream);
				try
				{
					int channels = val.Channels;
					if (channels < 1 || channels > 2 || val.SampleRate < 8000 || val.SampleRate > 96000)
					{
						throw new IOException("Unsupported MP3 channel count or sample rate");
					}
					if (((val.Length < 0) ? (-1) : (val.Length / 4)) > maximumSamples || cancellableFileStream.Length > 134217728)
					{
						if (val.Length % (channels * 4) != 0L)
						{
							throw new IOException("Invalid MP3 sample length");
						}
						if (double.IsNaN(initialSeconds) || double.IsInfinity(initialSeconds) || initialSeconds < 0.0)
						{
							initialSeconds = 0.0;
						}
						int initialFrame = (int)Math.Min(2147483646.0, initialSeconds * (double)val.SampleRate);
						return new Mp3LoadResult
						{
							Stream = StreamedMp3.Open(path, initialFrame, token)
						};
					}
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			return new Mp3LoadResult
			{
				Decoded = DecodeMp3(path, token, maximumSamples, 134217728L)
			};
		}

		internal static bool IsLongMp3(string path, CancellationToken token)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			token.ThrowIfCancellationRequested();
			using CancellableFileStream cancellableFileStream = new CancellableFileStream(path, token);
			if (cancellableFileStream.Length > 134217728)
			{
				return true;
			}
			MpegFile val = new MpegFile((Stream)cancellableFileStream);
			try
			{
				return val.Length > 268435456;
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		internal static DecodedMp3 DecodeMp3(string path, CancellationToken token, int maximumSamples = 67108864, long maximumFileBytes = 134217728L)
		{
			Mp3DecodeSlot.Wait(token);
			try
			{
				return DecodeMp3Core(path, token, maximumSamples, maximumFileBytes);
			}
			finally
			{
				Mp3DecodeSlot.Release();
			}
		}

		private static DecodedMp3 DecodeMp3Core(string path, CancellationToken token, int maximumSamples, long maximumFileBytes)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			token.ThrowIfCancellationRequested();
			using CancellableFileStream cancellableFileStream = new CancellableFileStream(path, token);
			if (cancellableFileStream.Length > maximumFileBytes)
			{
				throw new IOException("MP3 exceeds the 128 MiB file size limit");
			}
			MpegFile val = new MpegFile((Stream)cancellableFileStream);
			try
			{
				DecodedMp3 decodedMp = new DecodedMp3
				{
					Channels = val.Channels,
					SampleRate = val.SampleRate
				};
				if (decodedMp.Channels < 1 || decodedMp.Channels > 2 || decodedMp.SampleRate < 8000 || decodedMp.SampleRate > 96000)
				{
					throw new IOException("Unsupported MP3 channel count or sample rate");
				}
				while (true)
				{
					token.ThrowIfCancellationRequested();
					float[] array = new float[16384];
					int num = val.ReadSamples(array, 0, array.Length);
					if (num == 0)
					{
						break;
					}
					if (num < 0 || num % decodedMp.Channels != 0)
					{
						throw new IOException("MP3 decoder returned incomplete sample frames");
					}
					if (num > maximumSamples - decodedMp.SampleCount)
					{
						throw new IOException("MP3 exceeds the 256 MiB decoded audio limit");
					}
					if (num != array.Length)
					{
						Array.Resize(ref array, num);
					}
					for (int i = 0; i < array.Length; i++)
					{
						array[i] = (float.IsNaN(array[i]) ? 0f : Math.Max(-1f, Math.Min(1f, array[i])));
					}
					decodedMp.Blocks.Add(array);
					decodedMp.SampleCount += num;
				}
				token.ThrowIfCancellationRequested();
				if (decodedMp.SampleCount == 0)
				{
					throw new IOException("The MP3 contains no decodable audio");
				}
				return decodedMp;
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		private void StartAtSavedPosition()
		{
			double num = state.PositionSeconds;
			if (double.IsNaN(num) || double.IsInfinity(num) || num < 0.0)
			{
				num = 0.0;
			}
			double num2 = (double)clip.samples / (double)clip.frequency;
			if (!RepeatTrack && num >= num2)
			{
				state.PositionSeconds = num2;
				TrackEnded = true;
				return;
			}
			scheduledSample = (int)Math.Min(clip.samples - 1, Math.Floor(num % num2 * (double)clip.frequency));
			double dspTime = AudioSettings.dspTime;
			scheduledDsp = dspTime + (voicesPaused ? 0.0 : 0.05);
			if (voicesPaused)
			{
				ResumeOutput(builtIn, dspTime);
				foreach (RadioSpeakerOutput value in endpoints.Values)
				{
					ResumeOutput(value, dspTime);
				}
			}
			else
			{
				ScheduleEndpoint(builtIn, scheduledDsp, scheduledSample);
				foreach (RadioSpeakerOutput value2 in endpoints.Values)
				{
					ScheduleEndpoint(value2, scheduledDsp, scheduledSample);
				}
			}
			running = true;
			voicesPaused = false;
			nextHealthCheck = dspTime + 0.5;
		}

		private void ResumeOutput(RadioSpeakerOutput output, double now)
		{
			if (output.Paused && (Object)(object)output.Source != (Object)null && (Object)(object)output.Source.clip == (Object)(object)(((Object)(object)output.StreamClip != (Object)null) ? output.StreamClip : clip))
			{
				output.Resume(scheduledSample, now);
			}
			else
			{
				ScheduleEndpoint(output, now + 0.05, SampleAt(now + 0.05));
			}
		}

		private double EndDspTime()
		{
			if (!((Object)(object)clip == (Object)null))
			{
				return scheduledDsp + (double)(clip.samples - scheduledSample) / (double)clip.frequency;
			}
			return double.PositiveInfinity;
		}

		private bool FinishIfEnded()
		{
			if (!running || RepeatTrack || (Object)(object)clip == (Object)null || AudioSettings.dspTime < EndDspTime())
			{
				return false;
			}
			state.PositionSeconds = (double)clip.samples / (double)clip.frequency;
			TrackEnded = true;
			StopOutputs();
			return true;
		}

		private void JoinEndpoints()
		{
			double dspTime = AudioSettings.dspTime;
			bool waitingForStart = dspTime < scheduledDsp;
			JoinOutput(builtIn, dspTime, waitingForStart);
			foreach (RadioSpeakerOutput value in endpoints.Values)
			{
				JoinOutput(value, dspTime, waitingForStart);
			}
		}

		private void JoinOutput(RadioSpeakerOutput output, double now, bool waitingForStart)
		{
			if (!output.Running && !((Object)(object)output.Source == (Object)null))
			{
				double num = (waitingForStart ? scheduledDsp : (now + 0.05));
				if (RepeatTrack || !(num >= EndDspTime()))
				{
					ScheduleEndpoint(output, num, SampleAt(num));
				}
			}
		}

		private void ScheduleEndpoint(RadioSpeakerOutput endpoint, double start, int sample)
		{
			if (!((Object)(object)endpoint.Source == (Object)null) && !((Object)(object)clip == (Object)null) && sample >= 0 && sample < clip.samples && (RepeatTrack || !(start >= EndDspTime())))
			{
				if (streamedMp3 != null && (Object)(object)endpoint.StreamClip == (Object)null)
				{
					endpoint.StreamClip = streamedMp3.CreateClip(streamedMp3.CreateReader());
				}
				endpoint.Source.clip = (((Object)(object)endpoint.StreamClip != (Object)null) ? endpoint.StreamClip : clip);
				endpoint.Source.loop = RepeatTrack;
				endpoint.Source.timeSamples = sample;
				endpoint.Source.PlayScheduled(start);
				endpoint.Running = true;
				endpoint.Paused = false;
				endpoint.SettlesAt = start + 0.3;
				endpoint.StartsAt = start;
			}
		}

		private void PauseOutputs()
		{
			if (AudioSettings.dspTime < scheduledDsp)
			{
				StopOutputs();
				return;
			}
			running = false;
			voicesPaused = true;
			PauseOutput(builtIn);
			foreach (RadioSpeakerOutput value in endpoints.Values)
			{
				PauseOutput(value);
			}
		}

		private static void PauseOutput(RadioSpeakerOutput output)
		{
			if (AudioSettings.dspTime < output.StartsAt)
			{
				output.Stop();
			}
			else
			{
				output.Pause();
			}
		}

		private void StopOutputs(bool clearClip = false)
		{
			running = false;
			voicesPaused = false;
			if (builtIn != null)
			{
				builtIn.Stop(clearClip);
			}
			foreach (RadioSpeakerOutput value in endpoints.Values)
			{
				value.Stop(clearClip);
			}
		}

		private void EnsureOwnedOutput()
		{
			if ((Object)(object)emitter == (Object)null || (Object)(object)source == (Object)null)
			{
				RadioSpeakerOutput radioSpeakerOutput = builtIn;
				if ((Object)(object)lifetime != (Object)null)
				{
					lifetime.Playback = null;
				}
				builtIn = new RadioSpeakerOutput("Sailwind Radio audio", RadioSpeakerProfile.BuiltIn, warning);
				builtIn.Carried = radioSpeakerOutput.Carried;
				builtIn.Obstruction = radioSpeakerOutput.Obstruction;
				if ((Object)(object)radioSpeakerOutput.StreamClip == (Object)(object)clip)
				{
					radioSpeakerOutput.StreamClip = null;
				}
				radioSpeakerOutput.Dispose();
				emitter = builtIn.Emitter;
				source = builtIn.Source;
				lifetime = emitter.AddComponent<RadioAudioLifetime>();
				lifetime.Host = host;
				lifetime.Playback = this;
				WarnRecovery();
			}
			EnableOwnedOutput(builtIn);
			foreach (RadioSpeakerOutput value in endpoints.Values)
			{
				EnableOwnedOutput(value);
			}
		}

		private void EnableOwnedOutput(RadioSpeakerOutput output)
		{
			if (!((Object)(object)output.Emitter == (Object)null) && !((Object)(object)output.Source == (Object)null))
			{
				if (!output.Emitter.activeSelf)
				{
					output.Emitter.SetActive(true);
					WarnRecovery();
				}
				if (!((Behaviour)output.Source).enabled)
				{
					((Behaviour)output.Source).enabled = true;
					WarnRecovery();
				}
			}
		}

		private void WarnRecovery()
		{
			if (!recoveryWarned)
			{
				recoveryWarned = true;
				warning("Recovered an unavailable radio audio output");
			}
		}

		private void CheckOutputHealth()
		{
			double dspTime = AudioSettings.dspTime;
			if (dspTime < nextHealthCheck)
			{
				return;
			}
			nextHealthCheck = dspTime + 0.25;
			RepairOutput(builtIn, dspTime);
			foreach (RadioSpeakerOutput value in endpoints.Values)
			{
				RepairOutput(value, dspTime);
			}
		}

		private void RepairOutput(RadioSpeakerOutput output, double now)
		{
			if (!output.Running || (Object)(object)output.Source == (Object)null || now < output.SettlesAt)
			{
				return;
			}
			if (output.Source.isVirtual || output.Source.volume <= 0f)
			{
				output.DriftObservations = 0;
				return;
			}
			int num = SampleAt(now);
			int num2 = Math.Abs(output.Source.timeSamples - num);
			if (RepeatTrack)
			{
				num2 = Math.Min(num2, clip.samples - num2);
			}
			int num3 = default(int);
			int num4 = default(int);
			AudioSettings.GetDSPBufferSize(ref num3, ref num4);
			double num5 = Math.Max(0.05, 2.0 * (double)num3 / (double)Math.Max(8000, AudioSettings.outputSampleRate) + 0.01);
			if (output.Source.isPlaying)
			{
				if ((double)num2 <= (double)clip.frequency * num5)
				{
					output.DriftObservations = 0;
					return;
				}
				if (++output.DriftObservations < 2)
				{
					return;
				}
			}
			output.DriftObservations = 0;
			if (output.Source.isPlaying)
			{
				output.Pause();
				output.Resume(num, now);
			}
			else
			{
				ScheduleEndpoint(output, now + 0.05, SampleAt(now + 0.05));
			}
		}

		private void Fail(string message, string detail)
		{
			ReleaseTrack();
			failure = message;
			FailedPath = requestedPath;
			warning(message + ": " + detail);
		}

		private static string SafeLabel(string path)
		{
			if (string.IsNullOrWhiteSpace(path))
			{
				return "No track";
			}
			try
			{
				return Path.GetFileNameWithoutExtension(path);
			}
			catch
			{
				return "Music file";
			}
		}

		private void ReleaseTrack()
		{
			try
			{
				StopOutputs(clearClip: true);
			}
			finally
			{
				ReleaseTrackResources();
			}
		}

		private void ReleaseTrackResources()
		{
			if (mp3Cancellation != null)
			{
				Task<Mp3LoadResult> task = mp3Task;
				CancellationTokenSource cancellation = mp3Cancellation;
				mp3Task = null;
				mp3Cancellation = null;
				cancellation.Cancel();
				if (task == null)
				{
					cancellation.Dispose();
				}
				else
				{
					task.ContinueWith(delegate(Task<Mp3LoadResult> completed)
					{
						if (completed.IsFaulted)
						{
							_ = completed.Exception;
						}
						if (completed.Status == TaskStatus.RanToCompletion && completed.Result.Stream != null)
						{
							completed.Result.Stream.Dispose();
						}
						cancellation.Dispose();
					}, TaskScheduler.Default);
				}
			}
			try
			{
				DiscardRequest(ref request, clip);
			}
			finally
			{
				foreach (RadioSpeakerOutput value in endpoints.Values)
				{
					value.ReleaseStreamClip();
				}
				if (builtIn != null)
				{
					if ((Object)(object)builtIn.StreamClip == (Object)(object)clip)
					{
						builtIn.StreamClip = null;
					}
					else
					{
						builtIn.ReleaseStreamClip();
					}
				}
				if ((Object)(object)clip != (Object)null)
				{
					Object.Destroy((Object)(object)clip);
				}
				clip = null;
				if (streamedMp3 != null)
				{
					streamedMp3.Dispose();
					streamedMp3 = null;
				}
				streamWaitingSince = -1.0;
			}
		}

		private void OnAudioConfigurationChanged(bool deviceWasChanged)
		{
			resetRequested = true;
		}

		public void Dispose()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (disposed)
			{
				return;
			}
			try
			{
				CapturePosition();
			}
			finally
			{
				disposed = true;
				AudioSettings.OnAudioConfigurationChanged -= new AudioConfigurationChangeHandler(OnAudioConfigurationChanged);
				try
				{
					try
					{
						ReleaseTrack();
					}
					finally
					{
						ReleasePreload();
					}
				}
				finally
				{
					foreach (RadioSpeakerOutput value in endpoints.Values)
					{
						value.Dispose();
					}
					endpoints.Clear();
					if (builtIn != null)
					{
						builtIn.Dispose();
					}
					builtIn = null;
					emitter = null;
					source = null;
				}
			}
		}

		public void PreloadTrack(string path)
		{
			if (!disposed)
			{
				path = path ?? "";
				if (string.Equals(path, state.TrackPath, StringComparison.OrdinalIgnoreCase))
				{
					path = "";
				}
				if (!string.Equals(path, preloadPath ?? "", StringComparison.OrdinalIgnoreCase))
				{
					ReleasePreload();
					preloadPath = path;
				}
			}
		}

		private void PollPreload()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Invalid comparison between Unknown and I4
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Invalid comparison between Unknown and I4
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(preloadPath) || preloadFailed)
			{
				return;
			}
			try
			{
				if (!preloadStarted)
				{
					if (!state.Powered || (Object)(object)clip == (Object)null || (int)clip.loadState != 2 || streamedMp3 != null)
					{
						return;
					}
					if (!Path.IsPathRooted(preloadPath))
					{
						throw new IOException("Expected an absolute local path");
					}
					string fullPath = Path.GetFullPath(preloadPath);
					Uri uri = new Uri(fullPath);
					if (!uri.IsFile || uri.IsUnc || !File.Exists(fullPath))
					{
						throw new IOException("Upcoming track unavailable");
					}
					if (new FileInfo(fullPath).Length > 134217728)
					{
						throw new IOException("Upcoming file exceeds the size limit");
					}
					string text = Path.GetExtension(fullPath).ToLowerInvariant();
					preloadStartedAt = Time.realtimeSinceStartup;
					preloadStarted = true;
					int num;
					AudioType val;
					switch (text)
					{
					case ".mp3":
					{
						preloadCancellation = new CancellationTokenSource();
						preloadCancellation.CancelAfter(60000);
						CancellationToken token = preloadCancellation.Token;
						preloadTask = Task.Run(delegate
						{
							if (IsLongMp3(fullPath, token))
							{
								throw new IOException("Long MP3 starts streaming only when selected");
							}
							return new Mp3LoadResult
							{
								Decoded = DecodeMp3(fullPath, token, 67108864, 134217728L)
							};
						}, token);
						break;
					}
					default:
						num = 0;
						goto IL_017d;
					case ".wav":
						num = 20;
						goto IL_017d;
					case ".ogg":
						{
							num = 14;
							goto IL_017d;
						}
						IL_017d:
						val = (AudioType)num;
						if ((int)val == 0)
						{
							throw new IOException("Unsupported upcoming format");
						}
						preloadRequest = UnityWebRequestMultimedia.GetAudioClip(uri.AbsoluteUri, val);
						((DownloadHandlerAudioClip)preloadRequest.downloadHandler).streamAudio = false;
						preloadRequest.SendWebRequest();
						break;
					}
				}
				if (preloadRequest != null && preloadRequest.isDone)
				{
					if (preloadRequest.isNetworkError || preloadRequest.isHttpError)
					{
						throw new IOException("Upcoming decode failed");
					}
					preloadClip = DownloadHandlerAudioClip.GetContent(preloadRequest);
					preloadRequest.Dispose();
					preloadRequest = null;
					ValidatePreloadClip();
				}
				if (preloadTask != null && preloadTask.IsCompleted)
				{
					if (preloadTask.IsCanceled || preloadTask.IsFaulted)
					{
						throw new IOException("Upcoming MP3 decode failed");
					}
					DecodedMp3 decoded = preloadTask.Result.Decoded;
					preloadTask = null;
					preloadCancellation.Dispose();
					preloadCancellation = null;
					preloadClip = AudioClip.Create("Sailwind Radio next MP3", decoded.SampleCount / decoded.Channels, decoded.Channels, decoded.SampleRate, false);
					if ((Object)(object)preloadClip == (Object)null)
					{
						throw new IOException("Upcoming clip allocation failed");
					}
					int num2 = 0;
					foreach (float[] block in decoded.Blocks)
					{
						if (!preloadClip.SetData(block, num2))
						{
							throw new IOException("Upcoming clip upload failed");
						}
						num2 += block.Length / decoded.Channels;
					}
					ValidatePreloadClip();
				}
				if ((Object)(object)preloadClip != (Object)null && (int)preloadClip.loadState == 3)
				{
					throw new IOException("Upcoming audio data failed");
				}
				if (((Object)(object)preloadClip == (Object)null || (int)preloadClip.loadState != 2) && (double)Time.realtimeSinceStartup - preloadStartedAt >= 60.0)
				{
					throw new IOException("Upcoming load timed out");
				}
			}
			catch
			{
				string text2 = preloadPath;
				ReleasePreload();
				preloadPath = text2;
				preloadFailed = true;
			}
		}

		private void ValidatePreloadClip()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			if ((Object)(object)preloadClip == (Object)null || preloadClip.samples <= 0 || preloadClip.frequency <= 0 || (int)preloadClip.loadState == 3 || (long)preloadClip.samples * (long)preloadClip.channels > 67108864)
			{
				throw new IOException("Upcoming audio exceeds the decoded limit or is invalid");
			}
		}

		private bool AdoptPreload(string path)
		{
			if (!preloadStarted || preloadFailed || !string.Equals(path, preloadPath, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			requestedPath = path;
			TrackLabel = SafeLabel(path);
			clip = preloadClip;
			request = preloadRequest;
			mp3Task = preloadTask;
			mp3Cancellation = preloadCancellation;
			loadStartedAt = preloadStartedAt;
			if ((Object)(object)source != (Object)null)
			{
				source.clip = clip;
			}
			preloadClip = null;
			preloadRequest = null;
			preloadTask = null;
			preloadCancellation = null;
			preloadPath = null;
			preloadStarted = (preloadFailed = false);
			return true;
		}

		private void ReleasePreload()
		{
			if (preloadCancellation != null)
			{
				Task<Mp3LoadResult> task = preloadTask;
				CancellationTokenSource cancellation = preloadCancellation;
				cancellation.Cancel();
				if (task == null)
				{
					cancellation.Dispose();
				}
				else
				{
					task.ContinueWith(delegate(Task<Mp3LoadResult> completed)
					{
						if (completed.IsFaulted)
						{
							_ = completed.Exception;
						}
						cancellation.Dispose();
					}, TaskScheduler.Default);
				}
			}
			try
			{
				DiscardRequest(ref preloadRequest, preloadClip);
			}
			finally
			{
				if ((Object)(object)preloadClip != (Object)null)
				{
					Object.Destroy((Object)(object)preloadClip);
				}
				preloadPath = null;
				preloadClip = null;
				preloadTask = null;
				preloadCancellation = null;
				preloadStarted = (preloadFailed = false);
			}
		}

		private static void DiscardRequest(ref UnityWebRequest owned, AudioClip retained)
		{
			UnityWebRequest val = owned;
			owned = null;
			if (val == null)
			{
				return;
			}
			try
			{
				if (!val.isDone)
				{
					val.Abort();
				}
				else if (!val.isNetworkError && !val.isHttpError)
				{
					AudioClip content = DownloadHandlerAudioClip.GetContent(val);
					if ((Object)(object)content != (Object)null && (Object)(object)content != (Object)(object)retained)
					{
						Object.Destroy((Object)(object)content);
					}
				}
			}
			catch
			{
			}
			finally
			{
				val.Dispose();
			}
		}
	}
	public sealed class RadioAudioLifetime : MonoBehaviour
	{
		internal MonoBehaviour Host;

		internal RadioPlayback Playback;

		private void Update()
		{
			if ((Object)(object)Host == (Object)null && Playback != null)
			{
				Playback.Dispose();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Host == (Object)null && Playback != null)
			{
				Playback.Dispose();
			}
		}
	}
	internal sealed class RadioSpeakerProfile
	{
		internal readonly float Gain;

		internal readonly float Radius;

		internal readonly float HighPass;

		internal readonly float LowPass;

		internal readonly bool IsWoofer;

		internal static readonly RadioSpeakerProfile BuiltIn = new RadioSpeakerProfile(0.25f, 12f, 900f, 5000f);

		internal static readonly RadioSpeakerProfile Small = new RadioSpeakerProfile(0.35f, 15f, 600f, 9000f);

		internal static readonly RadioSpeakerProfile Normal = new RadioSpeakerProfile(0.65f, 20f, 160f, 18000f);

		internal static readonly RadioSpeakerProfile TurboWoofer = new RadioSpeakerProfile(1f, 20f, 20f, 140f, woofer: true);

		private RadioSpeakerProfile(float gain, float radius, float highPass, float lowPass, bool woofer = false)
		{
			Gain = gain;
			Radius = radius;
			HighPass = highPass;
			LowPass = lowPass;
			IsWoofer = woofer;
		}

		internal static RadioSpeakerProfile ForKind(int kind)
		{
			return kind switch
			{
				3 => TurboWoofer, 
				2 => Normal, 
				1 => Small, 
				_ => null, 
			};
		}
	}
	internal sealed class RadioSpeakerOutput : IDisposable
	{
		internal readonly GameObject Emitter;

		internal readonly AudioSource Source;

		internal AudioClip StreamClip;

		internal RadioSpeakerProfile Profile;

		internal Vector3 Position;

		internal bool Carried;

		internal bool Seen;

		internal bool Running;

		internal bool Paused;

		internal double SettlesAt;

		internal double StartsAt;

		internal int DriftObservations;

		internal float LocalVolume = 1f;

		internal float Bass = 1f;

		internal float Obstruction;

		private AudioHighPassFilter highPass;

		private AudioLowPassFilter lowPass;

		private RadioBassFilter bassFilter;

		private float smoothedObstruction;

		private bool initialized;

		internal RadioSpeakerOutput(string name, RadioSpeakerProfile profile, Action<string> warning)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			Profile = profile;
			Emitter = new GameObject(name);
			Object.DontDestroyOnLoad((Object)(object)Emitter);
			Source = Emitter.AddComponent<AudioSource>();
			Source.playOnAwake = false;
			Source.loop = true;
			Source.spatialBlend = 1f;
			AnimationCurve val = AnimationCurve.Constant(0f, 1f, 1f);
			val.preWrapMode = (WrapMode)8;
			val.postWrapMode = (WrapMode)8;
			Source.SetCustomCurve((AudioSourceCurveType)0, val);
			Source.rolloffMode = (AudioRolloffMode)2;
			Source.minDistance = 1f;
			Source.maxDistance = profile.Radius;
			Source.volume = 0f;
			Source.pitch = 1f;
			Source.dopplerLevel = 0f;
			Source.ignoreListenerPause = false;
			Source.bypassReverbZones = true;
			try
			{
				highPass = Emitter.AddComponent<AudioHighPassFilter>();
				if ((Object)(object)highPass == (Object)null)
				{
					throw new InvalidOperationException("High-pass component unavailable");
				}
				highPass.cutoffFrequency = profile.HighPass;
				highPass.highpassResonanceQ = 1f;
			}
			catch (Exception ex)
			{
				if ((Object)(object)highPass != (Object)null)
				{
					Object.Destroy((Object)(object)highPass);
				}
				highPass = null;
				warning("Radio high-pass filter unavailable: " + ex.Message);
			}
			try
			{
				lowPass = Emitter.AddComponent<AudioLowPassFilter>();
				if ((Object)(object)lowPass == (Object)null)
				{
					throw new InvalidOperationException("Low-pass component unavailable");
				}
				lowPass.cutoffFrequency = profile.LowPass;
				lowPass.lowpassResonanceQ = 1f;
			}
			catch (Exception ex2)
			{
				if ((Object)(object)lowPass != (Object)null)
				{
					Object.Destroy((Object)(object)lowPass);
				}
				lowPass = null;
				warning("Radio low-pass filter unavailable: " + ex2.Message);
			}
			if (!profile.IsWoofer)
			{
				return;
			}
			try
			{
				bassFilter = Emitter.AddComponent<RadioBassFilter>();
				if ((Object)(object)bassFilter == (Object)null)
				{
					throw new InvalidOperationException("Bass component unavailable");
				}
			}
			catch (Exception ex3)
			{
				if ((Object)(object)bassFilter != (Object)null)
				{
					Object.Destroy((Object)(object)bassFilter);
				}
				bassFilter = null;
				warning("Radio bass filter unavailable: " + ex3.Message);
			}
		}

		internal void Update(float masterVolume, Vector3 listener, bool listenerKnown)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Emitter == (Object)null) && !((Object)(object)Source == (Object)null))
			{
				Emitter.transform.position = Position;
				Source.spatialBlend = (Carried ? 0f : 1f);
				Source.maxDistance = Profile.Radius;
				float num = (Carried ? 0f : Clamp(Obstruction));
				if (!initialized)
				{
					smoothedObstruction = num;
					initialized = true;
				}
				float num2 = Time.unscaledDeltaTime;
				if (!Finite(num2) || num2 < 0f)
				{
					num2 = 0f;
				}
				smoothedObstruction += (num - smoothedObstruction) * (float)(1.0 - Math.Exp((double)(0f - num2) / 0.25));
				float num3 = (Carried ? 0f : smoothedObstruction);
				if ((Object)(object)highPass != (Object)null)
				{
					highPass.cutoffFrequency = Profile.HighPass;
				}
				float num4 = Math.Min(1500f, Profile.LowPass);
				if ((Object)(object)lowPass != (Object)null)
				{
					lowPass.cutoffFrequency = Profile.LowPass + (num4 - Profile.LowPass) * num3;
				}
				float num5 = ((!listenerKnown) ? 0f : (Carried ? 1f : DistanceGain(Vector3.Distance(Position, listener), Profile.Radius)));
				float num6 = (Profile.IsWoofer ? 1f : Clamp(LocalVolume));
				float num7 = (Profile.IsWoofer ? ((float)Math.Sqrt(Clamp(Bass))) : 1f);
				Source.volume = Profile.Gain * masterVolume * masterVolume * num6 * num6 * num7 * num5 * (1f - (Profile.IsWoofer ? 0.4f : 0.65f) * num3);
				if ((Object)(object)bassFilter != (Object)null)
				{
					bassFilter.SetProfile(AudioSettings.outputSampleRate, Profile.IsWoofer);
				}
			}
		}

		internal void Stop(bool clearClip = false)
		{
			Running = (Paused = false);
			if (!((Object)(object)Source == (Object)null))
			{
				Source.Stop();
				if (clearClip)
				{
					Source.clip = null;
				}
			}
		}

		internal void Pause()
		{
			if (Running && !((Object)(object)Source == (Object)null))
			{
				Source.Pause();
				Running = false;
				Paused = true;
			}
		}

		internal void Resume(int sample, double now)
		{
			if (!((Object)(object)Source == (Object)null))
			{
				Source.timeSamples = sample;
				Source.UnPause();
				Running = true;
				Paused = false;
				SettlesAt = now + 0.3;
				StartsAt = now;
			}
		}

		internal static float DistanceGain(float distance, float radius)
		{
			if (!Finite(distance))
			{
				return 0f;
			}
			float num = 1f - Mathf.Clamp01((distance - 1f) / (radius - 1f));
			return num * num;
		}

		internal static float Clamp(float value)
		{
			if (!float.IsNaN(value))
			{
				return Mathf.Clamp01(value);
			}
			return 0f;
		}

		internal static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		public void Dispose()
		{
			try
			{
				Stop(clearClip: true);
			}
			finally
			{
				ReleaseStreamClip();
				if ((Object)(object)Emitter != (Object)null)
				{
					Object.Destroy((Object)(object)Emitter);
				}
				highPass = null;
				lowPass = null;
				bassFilter = null;
			}
		}

		internal void ReleaseStreamClip()
		{
			if ((Object)(object)StreamClip != (Object)null)
			{
				Object.Destroy((Object)(object)StreamClip);
			}
			StreamClip = null;
		}
	}
	internal sealed class StreamedMp3 : IDisposable
	{
		private sealed class Chunk
		{
			internal int State;

			internal int Start;

			internal int Count;

			internal readonly float[] Samples;

			internal Chunk(int channels)
			{
				Samples = new float[4096 * channels];
			}
		}

		internal sealed class Reader
		{
			private readonly StreamedMp3 owner;

			private int cursor;

			private int generation;

			internal int Cursor => Volatile.Read(in cursor);

			internal int Generation => Volatile.Read(in generation);

			internal Reader(StreamedMp3 owner)
			{
				this.owner = owner;
			}

			internal void SetPosition(int position)
			{
				position = Math.Max(0, Math.Min(owner.Frames - 1, position));
				int num = Volatile.Read(in cursor);
				Interlocked.Increment(ref generation);
				Volatile.Write(ref cursor, position);
				if (position != num)
				{
					owner.Request(position);
				}
			}

			internal void Read(float[] data)
			{
				Array.Clear(data, 0, data.Length);
				if (!owner.disposed)
				{
					int observedGeneration = Volatile.Read(in generation);
					int num = Volatile.Read(in cursor);
					int num2 = data.Length / owner.Channels;
					owner.Copy(num, data, num2);
					int advanced = ((num > owner.Frames - num2) ? owner.Frames : (num + num2));
					CommitRead(observedGeneration, num, advanced);
				}
			}

			internal void CommitRead(int observedGeneration, int start, int advanced)
			{
				if (Volatile.Read(in generation) == observedGeneration)
				{
					Interlocked.CompareExchange(ref cursor, advanced, start);
				}
			}
		}

		private const int ChunkFrames = 4096;

		private const int WindowSeconds = 20;

		private const int AheadSeconds = 10;

		private const int SeekPrerollSeconds = 5;

		private MpegFile decoder;

		private Stream input;

		private readonly string path;

		private readonly CancellationTokenSource cancellation;

		private readonly Chunk[] chunks;

		private readonly Task worker;

		private long requestedFrame;

		private Exception fault;

		private volatile bool disposed;

		internal readonly int Channels;

		internal readonly int SampleRate;

		internal readonly int Frames;

		internal int BufferSamples => chunks.Length * 4096 * Channels;

		internal bool WorkerCompleted => worker.IsCompleted;

		internal Exception Fault => Volatile.Read(in fault);

		internal static StreamedMp3 Open(string path, int initialFrame, CancellationToken token)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			token.ThrowIfCancellationRequested();
			CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(new CancellationToken[1] { token });
			RadioPlayback.CancellableFileStream cancellableFileStream = null;
			try
			{
				cancellableFileStream = new RadioPlayback.CancellableFileStream(path, cancellationTokenSource.Token);
				if (cancellableFileStream.Length > 1073741824)
				{
					throw new IOException("MP3 exceeds the streamed file size limit");
				}
				MpegFile val = new MpegFile((Stream)cancellableFileStream);
				try
				{
					int channels = val.Channels;
					int sampleRate = val.SampleRate;
					long length = val.Length;
					if (!val.CanSeek || channels < 1 || channels > 2 || sampleRate < 8000 || sampleRate > 96000 || length <= 0 || length % (channels * 4) != 0L)
					{
						throw new IOException("MP3 cannot be streamed with a known seekable duration");
					}
					long num = length / (channels * 4);
					if (num > int.MaxValue - (long)sampleRate * 2L)
					{
						throw new IOException("MP3 duration exceeds Unity's sample-position limit");
					}
					return new StreamedMp3(path, cancellableFileStream, val, cancellationTokenSource, channels, sampleRate, (int)num, initialFrame);
				}
				catch
				{
					val.Dispose();
					throw;
				}
			}
			catch
			{
				cancellableFileStream?.Dispose();
				cancellationTokenSource.Dispose();
				throw;
			}
		}

		private StreamedMp3(string path, Stream input, MpegFile decoder, CancellationTokenSource cancellation, int channels, int rate, int frames, int initialFrame)
		{
			this.path = path;
			this.input = input;
			this.decoder = decoder;
			this.cancellation = cancellation;
			Channels = channels;
			SampleRate = rate;
			Frames = frames;
			chunks = new Chunk[Math.Max(2, (20 * rate + 4096 - 1) / 4096)];
			for (int i = 0; i < chunks.Length; i++)
			{
				chunks[i] = new Chunk(channels);
			}
			requestedFrame = Math.Max(0, Math.Min(frames - 1, initialFrame));
			worker = Task.Run((Action)Run);
		}

		internal Reader CreateReader()
		{
			return new Reader(this);
		}

		internal AudioClip CreateClip(Reader reader)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_004a: Expected O, but got Unknown
			if (disposed)
			{
				throw new ObjectDisposedException("StreamedMp3");
			}
			return AudioClip.Create("Sailwind Radio streamed MP3", Frames, Channels, SampleRate, true, new PCMReaderCallback(reader.Read), new PCMSetPositionCallback(reader.SetPosition));
		}

		internal void Request(int frame)
		{
			Interlocked.Exchange(ref requestedFrame, Math.Max(0, Math.Min(Frames - 1, frame)));
		}

		internal bool Ready(int frame)
		{
			if (disposed)
			{
				return false;
			}
			frame = Math.Max(0, Math.Min(Frames - 1, frame));
			int num = (int)Math.Min(Frames, (long)frame + (long)Math.Max(1, SampleRate / 2));
			for (int num2 = frame; num2 < num; num2 = (num2 / 4096 + 1) * 4096)
			{
				Chunk chunk = chunks[num2 / 4096 % chunks.Length];
				if (Volatile.Read(in chunk.State) < 0 || num2 < chunk.Start || num2 >= chunk.Start + chunk.Count)
				{
					return false;
				}
			}
			return true;
		}

		private void Copy(int frame, float[] destination, int frames)
		{
			if (frame < 0 || frame >= Frames)
			{
				return;
			}
			int i = Math.Max(0, frame);
			int num3;
			for (int num = (int)Math.Min(Frames, (long)Math.Max(0, frame) + (long)frames); i < num; i += num3)
			{
				int num2 = i / 4096 % chunks.Length;
				Chunk chunk = chunks[num2];
				num3 = Math.Min(num - i, 4096 - i % 4096);
				int num4;
				do
				{
					num4 = Volatile.Read(in chunk.State);
				}
				while (num4 >= 0 && Interlocked.CompareExchange(ref chunk.State, num4 + 1, num4) != num4);
				if (num4 < 0)
				{
					continue;
				}
				try
				{
					if (i >= chunk.Start && i + num3 <= chunk.Start + chunk.Count)
					{
						Array.Copy(chunk.Samples, (i - chunk.Start) * Channels, destination, (i - frame) * Channels, num3 * Channels);
					}
				}
				finally
				{
					Interlocked.Decrement(ref chunk.State);
				}
			}
		}

		private void Run()
		{
			int num = -1;
			try
			{
				while (!cancellation.IsCancellationRequested)
				{
					int num2 = (int)Interlocked.Read(in requestedFrame);
					int num3 = (int)Math.Min(Frames, (long)num2 + (long)(10 * SampleRate));
					if (num < num2 - SampleRate * 2 || num > num3 || num < 0 || (num >= num3 && !Ready(num2)))
					{
						bool num4 = num >= 0;
						num = num2 / 4096 * 4096;
						if (num4)
						{
							Reopen();
						}
						int num5 = Math.Max(0, num - 5 * SampleRate);
						if (num5 > 0)
						{
							decoder.Position = (long)num5 * (long)Channels * 4;
						}
						long num6 = decoder.Position / (Channels * 4);
						if (num5 > 0)
						{
							num6 += ((SampleRate >= 32000) ? 1152 : 576);
						}
						if (num6 > num)
						{
							throw new IOException("MP3 decoder seek passed the requested sample");
						}
						float[] array = new float[4096 * Channels];
						int num8;
						for (; num6 < num; num6 += num8 / Channels)
						{
							cancellation.Token.ThrowIfCancellationRequested();
							int num7 = (int)Math.Min(num - num6, 4096L) * Channels;
							num8 = decoder.ReadSamples(array, 0, num7);
							if (num8 <= 0 || num8 % Channels != 0)
							{
								throw new IOException("MP3 decoder could not finish seek");
							}
						}
					}
					if (num >= num3 || num >= Frames)
					{
						cancellation.Token.WaitHandle.WaitOne(20);
						continue;
					}
					Chunk chunk = chunks[num / 4096 % chunks.Length];
					while (Interlocked.CompareExchange(ref chunk.State, -1, 0) != 0)
					{
						cancellation.Token.ThrowIfCancellationRequested();
						cancellation.Token.WaitHandle.WaitOne(1);
					}
					int num9 = Math.Min(4096, Frames - num) * Channels;
					int i = 0;
					try
					{
						int num10;
						for (; i < num9; i += num10)
						{
							cancellation.Token.ThrowIfCancellationRequested();
							num10 = decoder.ReadSamples(chunk.Samples, i, num9 - i);
							if (num10 <= 0)
							{
								break;
							}
						}
						if (i == 0)
						{
							throw new IOException("MP3 ended before its reported duration");
						}
						if (i % Channels != 0)
						{
							throw new IOException("MP3 decoder returned an incomplete frame");
						}
						for (int j = 0; j < i; j++)
						{
							if (float.IsNaN(chunk.Samples[j]) || float.IsInfinity(chunk.Samples[j]))
							{
								chunk.Samples[j] = 0f;
							}
							else
							{
								chunk.Samples[j] = Math.Max(-1f, Math.Min(1f, chunk.Samples[j]));
							}
						}
						chunk.Start = num;
						chunk.Count = i / Channels;
					}
					finally
					{
						Volatile.Write(ref chunk.State, 0);
					}
					num += i / Channels;
				}
			}
			catch (OperationCanceledException)
			{
			}
			catch (Exception value)
			{
				Volatile.Write(ref fault, value);
			}
			finally
			{
				decoder.Dispose();
				input.Dispose();
			}
		}

		private void Reopen()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			decoder.Dispose();
			input.Dispose();
			input = new RadioPlayback.CancellableFileStream(path, cancellation.Token);
			decoder = new MpegFile(input);
		}

		public void Dispose()
		{
			if (disposed)
			{
				return;
			}
			disposed = true;
			cancellation.Cancel();
			worker.ContinueWith(delegate(Task done)
			{
				if (done.IsFaulted)
				{
					_ = done.Exception;
				}
				cancellation.Dispose();
			}, TaskScheduler.Default);
		}
	}
	[BepInPlugin("local.sailwind.radio", "Sailwind Radio", "1.0.1")]
	[BepInProcess("Sailwind.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "local.sailwind.radio";

		public const string Version = "1.0.1";

		private static Plugin instance;

		private Harmony harmony;

		private RadioWorldService world;

		private RadioAcousticsService acoustics;

		private RadioShopService shops;

		private ConfigEntry<string> musicFolders;

		private ConfigEntry<bool> continueWhileSleeping;

		private LibraryScanner library;

		private RadioMenus menus;

		private bool libraryReady;

		private readonly Dictionary<RadioItemController, RadioPlayback> playback = new Dictionary<RadioItemController, RadioPlayback>();

		private readonly Dictionary<RadioItemController, RadioQueue> queues = new Dictionary<RadioItemController, RadioQueue>();

		private readonly HashSet<RadioItemController> seen = new HashSet<RadioItemController>();

		private readonly List<RadioItemController> removed = new List<RadioItemController>();

		private bool ready;

		private bool applicationPaused;

		private bool focused = true;

		private bool Suspended
		{
			get
			{
				if (GameState.playing && !GameState.currentlyLoading && GameState.loadingScenes <= 0 && (!GameState.sleeping || continueWhileSleeping.Value) && (!(Time.timeScale <= 0f) || (GameState.sleeping && continueWhileSleeping.Value)) && !AudioListener.pause && !applicationPaused)
				{
					if (!focused)
					{
						return !Application.runInBackground;
					}
					return false;
				}
				return true;
			}
		}

		private void Awake()
		{
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Expected O, but got Unknown
			instance = this;
			try
			{
				musicFolders = ((BaseUnityPlugin)this).Config.Bind<string>("Music", "MusicFolders", "", "Music folders separated by |. Each folder is one collection including all its subfolders. Example: D:\\Music | E:\\Sailing Music");
				continueWhileSleeping = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "ContinueWhileSleeping", false, "Keep music playing while the player sleeps. Loading still suspends playback.");
				ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Development", "SpawnRadio", "", "Retired developer spawn shortcut.");
				((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val).Definition);
				ConfigEntry<int> val2 = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "SpawnDefaultRevision", 0, "Retired spawn shortcut migration marker.");
				((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val2).Definition);
				ConfigEntry<string> val3 = ((BaseUnityPlugin)this).Config.Bind<string>("Music", "MusicFile", "", "Retired single-file music setting.");
				bool num = !string.IsNullOrWhiteSpace(val3.Value) && string.IsNullOrWhiteSpace(musicFolders.Value);
				((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val3).Definition);
				ConfigEntry<bool> val4 = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "StormInterferenceEnabled", true, "Retired interference setting.");
				((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val4).Definition);
				ConfigEntry<float> val5 = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "StormInterferenceStrength", 0.35f, "Retired interference setting.");
				((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val5).Definition);
				ConfigEntry<bool> val6 = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "ContinueWhilePaused", false, "Retired pause setting.");
				((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val6).Definition);
				((BaseUnityPlugin)this).Config.Save();
				if (num)
				{
					Warn("MusicFile has been retired. Set MusicFolders to a folder containing your music.");
				}
				harmony = new Harmony("local.sailwind.radio");
				acoustics = new RadioAcousticsService();
				library = new LibraryScanner();
				menus = new RadioMenus();
				world = new RadioWorldService(harmony, Warn);
				world.BeforeSave += CapturePositions;
				world.ActionRequested += HandleAction;
				shops = new RadioShopService(world, Warn);
				menus.CollectionsChanged += SelectCollections;
				library.RequestScan(musicFolders.Value);
				InstallSuspendBoundary(typeof(StartMenu), "GameToSettings");
				InstallSuspendBoundary(typeof(Sleep), "FallAsleep");
				ready = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Sailwind Radio 1.0.1 ready. Configure MusicFolders to load music.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Radio initialization failed: " + ex));
				Shutdown();
				((Behaviour)this).enabled = false;
			}
		}

		private void InstallSuspendBoundary(Type type, string name)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0087: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, Type.EmptyTypes, (Type[])null);
			if (methodInfo == null)
			{
				Warn("Immediate radio pause hook unavailable for " + type.Name + "." + name + ". Game state pause checks remain active.");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "ReleaseControlBoundary", (Type[])null), new HarmonyMethod(typeof(Plugin), "SuspendBoundary", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void ReleaseControlBoundary()
		{
			if (Object.op_Implicit((Object)(object)instance) && instance.ready)
			{
				instance.ReleaseRadioControls();
			}
		}

		private static void SuspendBoundary()
		{
			if (Object.op_Implicit((Object)(object)instance) && instance.ready && instance.Suspended)
			{
				instance.SuspendNow();
			}
		}

		private void Update()
		{
			if (!ready)
			{
				return;
			}
			try
			{
				acoustics.Tick();
				world.Tick();
				TickShops();
				SynchronizePlayback();
				if (library.Poll())
				{
					libraryReady = true;
					foreach (string warning in library.Snapshot.Warnings)
					{
						Warn(warning);
					}
					foreach (KeyValuePair<RadioItemController, RadioQueue> queue in queues)
					{
						if (queue.Value.ApplySnapshot(library.Snapshot))
						{
							playback[queue.Key].SetTrack(queue.Key.State.TrackPath);
						}
					}
					if (Object.op_Implicit((Object)(object)menus.CollectionRadio))
					{
						ShowCollections(menus.CollectionRadio);
					}
				}
				menus.Tick();
				bool suspended = Suspended;
				PlaybackOrder.Tick(playback, world.ActiveRadioId, (KeyValuePair<RadioItemController, RadioPlayback> pair) => Object.op_Implicit((Object)(object)pair.Key) ? pair.Key.InstanceId : 0, TickPlayback, suspended);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Radio stopped after a runtime error: " + ex));
				Shutdown();
				((Behaviour)this).enabled = false;
			}
		}

		private void SynchronizePlayback()
		{
			seen.Clear();
			IReadOnlyList<RadioItemController> items = world.Items;
			for (int i = 0; i < items.Count; i++)
			{
				RadioItemController item = items[i];
				if (!Object.op_Implicit((Object)(object)item) || item.State.Kind != 0)
				{
					continue;
				}
				seen.Add(item);
				if (!playback.ContainsKey(item))
				{
					RadioQueue radioQueue = new RadioQueue(item.State);
					if (libraryReady)
					{
						radioQueue.ApplySnapshot(library.Snapshot);
					}
					queues.Add(item, radioQueue);
					RadioPlayback engine = new RadioPlayback((MonoBehaviour)(object)this, item.State, Warn)
					{
						RepeatTrack = false
					};
					playback.Add(item, engine);
					item.CapturePosition = engine.CapturePosition;
					item.SuspendPlayback = delegate
					{
						//IL_000c: Unknown result type (might be due to invalid IL or missing references)
						engine.Tick(item.VisualAudioPosition, suspended: true);
					};
				}
			}
			removed.Clear();
			foreach (KeyValuePair<RadioItemController, RadioPlayback> item2 in playback)
			{
				if (!Object.op_Implicit((Object)(object)item2.Key) || !seen.Contains(item2.Key))
				{
					item2.Value.Dispose();
					if (Object.op_Implicit((Object)(object)item2.Key))
					{
						item2.Key.CapturePosition = null;
						item2.Key.SuspendPlayback = null;
					}
					removed.Add(item2.Key);
				}
			}
			foreach (RadioItemController item3 in removed)
			{
				playback.Remove(item3);
				queues.Remove(item3);
			}
		}

		private void TickShops()
		{
			if (shops == null)
			{
				return;
			}
			try
			{
				shops.Tick();
			}
			catch (Exception ex)
			{
				Warn("Radio shops stopped after an error: " + ex.Message);
				RadioShopService radioShopService = shops;
				shops = null;
				try
				{
					radioShopService.Dispose();
				}
				catch (Exception ex2)
				{
					Warn("Could not release radio shops: " + ex2.Message);
				}
			}
		}

		private void TickPlayback(KeyValuePair<RadioItemController, RadioPlayback> pair, bool suspended)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)pair.Key))
			{
				return;
			}
			Vector3 visualAudioPosition = pair.Key.VisualAudioPosition;
			Vector3 val = pair.Key.SoundPosition;
			bool usesPlayerPosition = pair.Key.UsesPlayerPosition;
			if (usesPlayerPosition && acoustics.ListenerKnown)
			{
				val = acoustics.ListenerPosition;
			}
			float obstruction = (pair.Key.State.Powered ? acoustics.ObstructionAt(val, usesPlayerPosition) : 0f);
			pair.Value.SetAcoustics(acoustics.ListenerPosition, acoustics.ListenerKnown, obstruction);
			pair.Value.SetCarried(usesPlayerPosition);
			pair.Value.BeginEndpoints();
			if (pair.Key.InstanceId == world.ActiveRadioId && pair.Key.State.Powered)
			{
				DeviceVessel vessel = pair.Key.Vessel;
				foreach (RadioItemController item in world.Items)
				{
					if (Object.op_Implicit((Object)(object)item) && item.State.Kind != 0 && item.State.SpeakerEnabled)
					{
						DeviceVessel vessel2 = item.Vessel;
						bool usesPlayerPosition2 = item.UsesPlayerPosition;
						Vector3 visualAudioPosition2 = item.VisualAudioPosition;
						if (DeviceVessels.CanConnect(vessel, vessel2, visualAudioPosition, visualAudioPosition2))
						{
							Vector3 val2 = ((usesPlayerPosition2 && acoustics.ListenerKnown) ? acoustics.ListenerPosition : item.SoundPosition);
							pair.Value.SetEndpoint(item.InstanceId, val2, usesPlayerPosition2, item.State.Kind, (item.State.Kind == 3) ? 1f : item.State.Volume, item.State.Bass, acoustics.ObstructionAt(val2, usesPlayerPosition2));
						}
					}
				}
			}
			pair.Value.EndEndpoints();
			pair.Value.Tick(val, suspended);
			if (!suspended && pair.Key.State.Powered && !pair.Key.State.Paused)
			{
				RadioQueue radioQueue = queues[pair.Key];
				bool num;
				if (!pair.Value.LoadFailed)
				{
					if (!pair.Value.TrackEnded)
					{
						goto IL_02c8;
					}
					num = radioQueue.TrackEnded();
				}
				else
				{
					num = radioQueue.TrackFailed(pair.Value.FailedPath);
				}
				if (num)
				{
					pair.Value.SetTrack(pair.Key.State.TrackPath);
				}
			}
			goto IL_02c8;
			IL_02c8:
			pair.Value.PreloadTrack((pair.Key.InstanceId == world.ActiveRadioId && pair.Key.State.Powered) ? queues[pair.Key].PeekNext() : "");
			TrackInfo trackInfo = library.Snapshot.GetTrackInfo(pair.Key.State.TrackPath);
			pair.Key.SetTrackInfo(trackInfo.Title, trackInfo.Artist, trackInfo.Album);
		}

		private void HandleAction(RadioItemController item, RadioAction action)
		{
			if (!ready || !Object.op_Implicit((Object)(object)item) || item.State.Kind != 0)
			{
				return;
			}
			if (action == RadioAction.Power)
			{
				if (item.State.Powered)
				{
					library.RequestScan(musicFolders.Value);
				}
			}
			else
			{
				if (!playback.TryGetValue(item, out var value) || !queues.TryGetValue(item, out var value2))
				{
					return;
				}
				bool flag = false;
				switch (action)
				{
				case RadioAction.PlayPause:
					if (!item.State.Powered)
					{
						item.TogglePower();
						break;
					}
					value.CapturePosition();
					item.State.Paused = !item.State.Paused;
					if (item.State.Paused)
					{
						item.SuspendPlayback?.Invoke();
					}
					break;
				case RadioAction.Previous:
					flag = value2.Previous();
					break;
				case RadioAction.Next:
					flag = value2.Next();
					break;
				case RadioAction.Shuffle:
					flag = value2.SetShuffle(!item.State.Shuffle);
					break;
				case RadioAction.Collections:
					ShowCollections(item);
					break;
				}
				if (flag)
				{
					value.SetTrack(item.State.TrackPath);
				}
			}
		}

		private void ShowCollections(RadioItemController item)
		{
			if (!Object.op_Implicit((Object)(object)item))
			{
				return;
			}
			List<CollectionChoice> list = new List<CollectionChoice>();
			HashSet<string> hashSet = new HashSet<string>(item.State.SelectedCollections ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
			foreach (MusicCollection collection in library.Snapshot.Collections)
			{
				list.Add(new CollectionChoice(collection.Id, collection.Label, hashSet.Contains(collection.Id)));
			}
			menus.ShowCollections(item, list);
		}

		private void SelectCollections(RadioItemController item, string[] selected)
		{
			if (Object.op_Implicit((Object)(object)item) && queues.TryGetValue(item, out var value) && value.SetCollections(library.Snapshot, selected))
			{
				playback[item].SetTrack(item.State.TrackPath);
			}
		}

		private void OnGUI()
		{
			if (ready)
			{
				menus?.Draw();
			}
		}

		private void CapturePositions()
		{
			foreach (RadioPlayback value in playback.Values)
			{
				try
				{
					value.CapturePosition();
				}
				catch (Exception ex)
				{
					Warn("Could not capture a radio position: " + ex.Message);
				}
			}
		}

		private void SuspendNow()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<RadioItemController, RadioPlayback> item in playback)
			{
				if (Object.op_Implicit((Object)(object)item.Key))
				{
					try
					{
						item.Value.Tick(item.Key.VisualAudioPosition, suspended: true);
					}
					catch (Exception ex)
					{
						Warn("Could not suspend a radio: " + ex.Message);
					}
				}
			}
		}

		private void ReleaseRadioControls()
		{
			menus?.Close();
			foreach (RadioItemController item in world?.Items ?? Array.Empty<RadioItemController>())
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					try
					{
						item.ReleaseControls();
					}
					catch (Exception ex)
					{
						Warn("Could not release radio controls: " + ex.Message);
					}
				}
			}
		}

		private void OnApplicationPause(bool pause)
		{
			applicationPaused = pause;
			if (pause)
			{
				ReleaseRadioControls();
			}
			if (pause && ready)
			{
				SuspendNow();
			}
		}

		private void OnApplicationFocus(bool focus)
		{
			focused = focus;
			acoustics?.Invalidate();
			if (!focus)
			{
				ReleaseRadioControls();
			}
			if (!focus && !Application.runInBackground && ready)
			{
				SuspendNow();
			}
		}

		private void Warn(string message)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)message);
		}

		private void OnDisable()
		{
			Shutdown();
		}

		private void OnDestroy()
		{
			Shutdown();
		}

		private void Shutdown()
		{
			ready = false;
			ReleaseRadioControls();
			CapturePositions();
			foreach (KeyValuePair<RadioItemController, RadioPlayback> item in playback)
			{
				if (Object.op_Implicit((Object)(object)item.Key))
				{
					item.Key.CapturePosition = null;
					item.Key.SuspendPlayback = null;
				}
				try
				{
					item.Value.Dispose();
				}
				catch (Exception ex)
				{
					Warn("Could not release a radio player: " + ex.Message);
				}
			}
			playback.Clear();
			queues.Clear();
			library?.Dispose();
			library = null;
			menus?.Dispose();
			menus = null;
			try
			{
				shops?.Dispose();
			}
			catch (Exception ex2)
			{
				Warn("Could not release radio shops: " + ex2.Message);
			}
			shops = null;
			try
			{
				world?.Dispose();
			}
			catch (Exception ex3)
			{
				Warn("Could not release radio item hooks: " + ex3.Message);
			}
			world = null;
			acoustics?.Dispose();
			acoustics = null;
			try
			{
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
			}
			catch (Exception ex4)
			{
				Warn("Could not remove radio hooks: " + ex4.Message);
			}
			harmony = null;
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
	[Serializable]
	public sealed class RadioState
	{
		public int Kind;

		public float Bass = 0.5f;

		public float LocalVolume = 1f;

		public bool SpeakerEnabled = true;

		public bool Shuffle;

		public bool CollectionsInitialized;

		public string[] SelectedCollections = Array.Empty<string>();

		public string TrackPath = "";

		public double PositionSeconds;

		public bool Powered;

		public bool Paused;

		public float Volume = 0.5f;
	}
}
namespace SailwindRadio.UI
{
	internal sealed class MenuInputLease
	{
		private Object character;

		private Object controller;

		private Object crosshair;

		private bool crosshairActive;

		private bool mouseLook;

		private bool cursorVisible;

		private CursorLockMode cursorLock;

		internal bool Owned { get; private set; }

		internal static bool GameplayAvailable
		{
			get
			{
				if (GameState.playing && !GameState.currentlyLoading && GameState.loadingScenes == 0 && !GameState.justStarted && !GameState.sleeping && !Object.op_Implicit((Object)(object)GameState.inBed) && !BoatCamera.on)
				{
					return Time.timeScale > 0f;
				}
				return false;
			}
		}

		internal bool Acquire()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			if (Owned)
			{
				return true;
			}
			if (!GameplayAvailable || !Application.isFocused || GameState.inCursorMenu || !Object.op_Implicit((Object)(object)Refs.charController) || !Object.op_Implicit((Object)(object)Refs.ovrController) || !Object.op_Implicit((Object)(object)Refs.mouseCrosshair) || !((Collider)Refs.charController).enabled || !((Behaviour)Refs.ovrController).enabled)
			{
				return false;
			}
			character = (Object)(object)Refs.charController;
			controller = (Object)(object)Refs.ovrController;
			crosshair = (Object)(object)Refs.mouseCrosshair;
			crosshairActive = Refs.mouseCrosshair.activeSelf;
			mouseLook = MouseLook.MouseLookIsEnabled();
			cursorVisible = Cursor.visible;
			cursorLock = Cursor.lockState;
			Owned = true;
			MouseLook.ToggleMouseLook(false);
			MouseLook.ToggleMouseLookAndCursor(false);
			((Collider)Refs.charController).enabled = false;
			((Behaviour)Refs.ovrController).enabled = false;
			Refs.mouseCrosshair.SetActive(false);
			return true;
		}

		internal void Release()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (!Owned)
			{
				return;
			}
			Owned = false;
			if (!GameState.currentlyLoading && GameState.playing && !GameState.sleeping && !Object.op_Implicit((Object)(object)GameState.inBed))
			{
				if (Object.op_Implicit((Object)(object)Refs.charController) && (Object)(object)Refs.charController == character)
				{
					((Collider)Refs.charController).enabled = true;
				}
				if (Object.op_Implicit((Object)(object)Refs.ovrController) && (Object)(object)Refs.ovrController == controller)
				{
					((Behaviour)Refs.ovrController).enabled = true;
				}
				if ((Object)(object)Refs.charController == character && (Object)(object)Refs.ovrController == controller)
				{
					MouseLook.ToggleMouseLook(mouseLook);
					MouseLook.ToggleMouseLookAndCursor(true);
					Cursor.visible = cursorVisible;
					Cursor.lockState = cursorLock;
					if (!BoatCamera.on && Object.op_Implicit((Object)(object)Refs.mouseCrosshair) && (Object)(object)Refs.mouseCrosshair == crosshair)
					{
						Refs.mouseCrosshair.SetActive(crosshairActive);
					}
				}
			}
			character = (controller = (crosshair = null));
		}
	}
	public sealed class CollectionChoice
	{
		public readonly string Id;

		public readonly string Label;

		public readonly bool Selected;

		public CollectionChoice(string id, string label, bool selected)
		{
			Id = id;
			Label = label;
			Selected = selected;
		}
	}
	public sealed class RadioMenus : IDisposable
	{
		private readonly MenuInputLease lease = new MenuInputLease();

		private readonly List<CollectionChoice> choices = new List<CollectionChoice>();

		private readonly Dictionary<string, bool> selected = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

		private Vector2 scroll;

		private bool disposed;

		public bool IsOpen => lease.Owned;

		public RadioItemController CollectionRadio { get; private set; }

		public event Action<RadioItemController, string[]> CollectionsChanged;

		public void ShowCollections(RadioItemController radio, IReadOnlyList<CollectionChoice> available)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (disposed || !Object.op_Implicit((Object)(object)radio) || radio.State.Kind != 0)
			{
				return;
			}
			if (!IsOpen || !((Object)(object)CollectionRadio == (Object)(object)radio))
			{
				Close();
				radio.ReleaseControls();
				if (!lease.Acquire())
				{
					return;
				}
				selected.Clear();
				scroll = Vector2.zero;
			}
			CollectionRadio = radio;
			choices.Clear();
			if (available == null)
			{
				return;
			}
			foreach (CollectionChoice item in available)
			{
				if (item != null && !string.IsNullOrEmpty(item.Id))
				{
					choices.Add(item);
					if (!selected.ContainsKey(item.Id))
					{
						selected.Add(item.Id, item.Selected);
					}
				}
			}
		}

		public void Tick()
		{
			if (IsOpen)
			{
				if (!MenuInputLease.GameplayAvailable || !Application.isFocused || !GameState.inCursorMenu || Input.GetKeyDown((KeyCode)27))
				{
					Close();
				}
				else if (Object.op_Implicit((Object)(object)CollectionRadio) && (!CollectionRadio.IsPlacedForControls || !CollectionRadio.WithinMenuReach))
				{
					Close();
				}
				else if (!Object.op_Implicit((Object)(object)CollectionRadio))
				{
					Close();
				}
			}
		}

		public void Draw()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen)
			{
				float num = Mathf.Min(440, Screen.width - 24);
				float num2 = Mathf.Min(430, Screen.height - 24);
				GUILayout.Window(194043, new Rect(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2), new WindowFunction(DrawWindow), "Radio collections", Array.Empty<GUILayoutOption>());
			}
		}

		private void DrawWindow(int id)
		{
			//IL_0021: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)CollectionRadio))
			{
				GUILayout.Label("Choose which music collections this radio plays", Array.Empty<GUILayoutOption>());
				scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height((float)Mathf.Min(280, Screen.height - 160)) });
				if (choices.Count == 0)
				{
					GUILayout.Label("No collections available yet", Array.Empty<GUILayoutOption>());
				}
				foreach (CollectionChoice choice in choices)
				{
					selected[choice.Id] = GUILayout.Toggle(selected[choice.Id], choice.Label ?? choice.Id, Array.Empty<GUILayoutOption>());
				}
				GUILayout.EndScrollView();
				if (GUILayout.Button("Apply", Array.Empty<GUILayoutOption>()))
				{
					RadioItemController collectionRadio = CollectionRadio;
					List<string> list = new List<string>();
					foreach (CollectionChoice choice2 in choices)
					{
						if (selected[choice2.Id] && !list.Contains(choice2.Id))
						{
							list.Add(choice2.Id);
						}
					}
					Close();
					this.CollectionsChanged?.Invoke(collectionRadio, list.ToArray());
				}
			}
			if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
			{
				Close();
			}
		}

		public void Close()
		{
			lease.Release();
			CollectionRadio = null;
			choices.Clear();
			selected.Clear();
		}

		public void Dispose()
		{
			if (!disposed)
			{
				Close();
				disposed = true;
			}
		}
	}
}
namespace SailwindRadio.Shops
{
	internal static class NativeShopContract
	{
		private sealed class Instruction
		{
			internal OpCode Code;

			internal MemberInfo Member;
		}

		internal static bool KeeperReady(ShopArea area)
		{
			Shopkeeper shopkeeper = area.GetShopkeeper();
			if (!Object.op_Implicit((Object)(object)shopkeeper))
			{
				return false;
			}
			FieldInfo? field = typeof(Shopkeeper).GetField("parentRegion", BindingFlags.Instance | BindingFlags.NonPublic);
			FieldInfo field2 = typeof(Shopkeeper).GetField("shop", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field?.GetValue(shopkeeper) is Region)
			{
				return field2?.GetValue(shopkeeper) == area;
			}
			return false;
		}

		internal static bool Supports(MethodInfo sale, MethodInfo sell)
		{
			try
			{
				List<Instruction> list = Read(sell);
				int num = list.FindIndex((Instruction i) => i.Code == OpCodes.Stfld && i.Member?.Name == "sold" && i.Member.DeclaringType == typeof(ShipItem));
				int num2 = list.FindIndex((Instruction i) => i.Member is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(SaveablePrefab) && methodInfo.Name == "RegisterToSave");
				List<Instruction> list2 = Read(sale);
				int num3 = list2.FindIndex((Instruction i) => object.Equals(i.Member, sell));
				int num4 = list2.FindIndex((Instruction i) => i.Member is FieldInfo fieldInfo && fieldInfo.DeclaringType == typeof(PlayerGold) && fieldInfo.Name == "currency");
				int num5 = list2.FindIndex((Instruction i) => i.Code == OpCodes.Stelem_I4 || i.Code == OpCodes.Stind_I4);
				return num >= 0 && num2 > num && num3 >= 0 && num4 > num3 && num5 > num4;
			}
			catch
			{
				return false;
			}
		}

		private static List<Instruction> Read(MethodInfo method)
		{
			byte[] array = method?.GetMethodBody()?.GetILAsByteArray();
			if (array == null)
			{
				throw new InvalidOperationException("Native method body unavailable");
			}
			Dictionary<short, OpCode> dictionary = new Dictionary<short, OpCode>();
			FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.FieldType == typeof(OpCode))
				{
					OpCode value = (OpCode)fieldInfo.GetValue(null);
					dictionary[value.Value] = value;
				}
			}
			List<Instruction> list = new List<Instruction>();
			int num = 0;
			while (num < array.Length)
			{
				short num2 = array[num++];
				if (num2 == 254)
				{
					num2 = (short)(0xFE00 | array[num++]);
				}
				OpCode code = dictionary[num2];
				Instruction instruction = new Instruction
				{
					Code = code
				};
				int num3;
				switch (code.OperandType)
				{
				case OperandType.InlineNone:
					num3 = 0;
					break;
				case OperandType.ShortInlineBrTarget:
				case OperandType.ShortInlineI:
				case OperandType.ShortInlineVar:
					num3 = 1;
					break;
				case OperandType.InlineVar:
					num3 = 2;
					break;
				case OperandType.InlineI8:
				case OperandType.InlineR:
					num3 = 8;
					break;
				case OperandType.InlineSwitch:
					num3 = 4 + 4 * BitConverter.ToInt32(array, num);
					break;
				default:
					num3 = 4;
					break;
				}
				if (code.OperandType == OperandType.InlineMethod || code.OperandType == OperandType.InlineField)
				{
					instruction.Member = method.Module.ResolveMember(BitConverter.ToInt32(array, num));
				}
				num += num3;
				list.Add(instruction);
			}
			return list;
		}
	}
	internal static class RadioShopCatalog
	{
		internal static readonly int[] StockKinds = new int[7] { 3, 2, 2, 0, 0, 1, 1 };

		internal static int BasePrice(int kind)
		{
			return kind switch
			{
				3 => 2632, 
				2 => 1579, 
				1 => 526, 
				0 => 789, 
				_ => 0, 
			};
		}
	}
	internal static class RadioShopPlacement
	{
		internal static bool TryStand(IslandSceneryScene scenery, out Vector3 position, out Quaternion rotation, out string reason)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			position = default(Vector3);
			rotation = Quaternion.identity;
			reason = "not an authored capital scene";
			if (!Object.op_Implicit((Object)(object)scenery) || !RadioStandLayout.TryAnchor(scenery.parentIslandIndex, out var sceneryLocalPosition, out var yaw))
			{
				return false;
			}
			Vector3 val = ((Component)scenery).transform.TransformPoint(sceneryLocalPosition);
			rotation = ((Component)scenery).transform.rotation * Quaternion.Euler(0f, yaw, 0f);
			float height;
			bool flag = Ground(val, out height);
			bool flag2 = (scenery.parentIslandIndex == 1 || scenery.parentIslandIndex == 15) && flag && height <= val.y + 0.02f && height >= val.y - 0.3f;
			float num = ((scenery.parentIslandIndex == 1) ? (-0.1f) : 0f);
			position = new Vector3(val.x, (flag2 ? height : (val.y + 0.02f)) + num, val.z);
			string text = (flag ? "" : "no level static ground at the authored anchor");
			if (flag && !flag2 && Mathf.Abs(height - val.y) > 0.15f)
			{
				text = Append(text, "nearby support height differs from authored height by " + (height - val.y));
			}
			bool flag3 = false;
			float[] array = new float[4] { -1.1f, 1.1f, 1.39f, 2.21f };
			foreach (float num2 in array)
			{
				float[] array2 = new float[2] { -0.39f, 0.39f };
				foreach (float num3 in array2)
				{
					if (!Ground(position + rotation * new Vector3(num2, 0f, num3), out var height2) || Mathf.Abs(height2 - position.y) > 0.045f)
					{
						flag3 = true;
					}
				}
			}
			if (flag3)
			{
				text = Append(text, "uneven or missing ground beneath the display");
			}
			Vector3 envelopeHalf = RadioStandLayout.EnvelopeHalf;
			if (scenery.parentIslandIndex == 1)
			{
				envelopeHalf.x += 0.15f;
			}
			string text2 = Blocker(position + rotation * RadioStandLayout.EnvelopeCenter, envelopeHalf, rotation, null);
			if (text2 != null)
			{
				text = Append(text, "display footprint overlaps " + text2);
			}
			text2 = Blocker(position + rotation * new Vector3(0.55f, 0.91f, -1.02f), new Vector3(1.8f, 0.85f, 0.38f), rotation, null);
			if (text2 != null)
			{
				text = Append(text, "customer approach overlaps " + text2);
			}
			reason = text;
			return true;
		}

		internal static bool SlotClear(RadioShopStand stand, int index, int kind, out string reason)
		{
			//IL_0025: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			IslandSceneryScene componentInParent = ((Component)stand).GetComponentInParent<IslandSceneryScene>();
			Vector3 val = ((Component)stand).transform.TransformPoint(RadioStandLayout.Slot(Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.parentIslandIndex : (-1), index, stand.UsesNativeGoldRockCounter));
			Vector3 half = RadioDevice.Size(kind) * 0.5f + new Vector3(0.02f, 0.008f, 0.025f);
			Quaternion val2 = ((Component)stand).transform.rotation * RadioStandLayout.SlotRotation(kind);
			reason = Blocker(val + val2 * RadioDevice.Center(kind), half, val2, ((Component)stand).transform);
			return true;
		}

		private static string Append(string previous, string message)
		{
			if (previous.Length != 0)
			{
				return previous + "; " + message;
			}
			return message;
		}

		private static bool Ground(Vector3 expected, out float height)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (mi

BepInEx/plugins/SailwindRadio/NLayer.dll

Decompiled 6 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