Decompiled source of Spotilyss v1.1.0

Newtonsoft.Json.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Schema, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")]
[assembly: CLSCompliant(true)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Newtonsoft")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © James Newton-King 2008")]
[assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")]
[assembly: AssemblyFileVersion("13.0.3.27908")]
[assembly: AssemblyInformationalVersion("13.0.3+0a2e291c0d9c0c7675d445703e51750363a549ef")]
[assembly: AssemblyProduct("Json.NET")]
[assembly: AssemblyTitle("Json.NET .NET 4.5")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JamesNK/Newtonsoft.Json")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("13.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
	internal sealed class NotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class NotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public NotNullWhenAttribute(bool returnValue)
		{
			ReturnValue = returnValue;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
	internal sealed class MaybeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
	internal sealed class AllowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	internal class DoesNotReturnIfAttribute : Attribute
	{
		public bool ParameterValue { get; }

		public DoesNotReturnIfAttribute(bool parameterValue)
		{
			ParameterValue = parameterValue;
		}
	}
}
namespace Newtonsoft.Json
{
	public enum ConstructorHandling
	{
		Default,
		AllowNonPublicDefaultConstructor
	}
	public enum DateFormatHandling
	{
		IsoDateFormat,
		MicrosoftDateFormat
	}
	public enum DateParseHandling
	{
		None,
		DateTime,
		DateTimeOffset
	}
	public enum DateTimeZoneHandling
	{
		Local,
		Utc,
		Unspecified,
		RoundtripKind
	}
	public class DefaultJsonNameTable : JsonNameTable
	{
		private class Entry
		{
			internal readonly string Value;

			internal readonly int HashCode;

			internal Entry Next;

			internal Entry(string value, int hashCode, Entry next)
			{
				Value = value;
				HashCode = hashCode;
				Next = next;
			}
		}

		private static readonly int HashCodeRandomizer;

		private int _count;

		private Entry[] _entries;

		private int _mask = 31;

		static DefaultJsonNameTable()
		{
			HashCodeRandomizer = Environment.TickCount;
		}

		public DefaultJsonNameTable()
		{
			_entries = new Entry[_mask + 1];
		}

		public override string? Get(char[] key, int start, int length)
		{
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			num += (num << 7) ^ key[start];
			int num2 = start + length;
			for (int i = start + 1; i < num2; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			int num3 = Volatile.Read(ref _mask);
			int num4 = num & num3;
			for (Entry entry = _entries[num4]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && TextEquals(entry.Value, key, start, length))
				{
					return entry.Value;
				}
			}
			return null;
		}

		public string Add(string key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			int length = key.Length;
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			for (int i = 0; i < key.Length; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			for (Entry entry = _entries[num & _mask]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && entry.Value.Equals(key, StringComparison.Ordinal))
				{
					return entry.Value;
				}
			}
			return AddEntry(key, num);
		}

		private string AddEntry(string str, int hashCode)
		{
			int num = hashCode & _mask;
			Entry entry = new Entry(str, hashCode, _entries[num]);
			_entries[num] = entry;
			if (_count++ == _mask)
			{
				Grow();
			}
			return entry.Value;
		}

		private void Grow()
		{
			Entry[] entries = _entries;
			int num = _mask * 2 + 1;
			Entry[] array = new Entry[num + 1];
			for (int i = 0; i < entries.Length; i++)
			{
				Entry entry = entries[i];
				while (entry != null)
				{
					int num2 = entry.HashCode & num;
					Entry next = entry.Next;
					entry.Next = array[num2];
					array[num2] = entry;
					entry = next;
				}
			}
			_entries = array;
			Volatile.Write(ref _mask, num);
		}

		private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
		{
			if (str1.Length != str2Length)
			{
				return false;
			}
			for (int i = 0; i < str1.Length; i++)
			{
				if (str1[i] != str2[str2Start + i])
				{
					return false;
				}
			}
			return true;
		}
	}
	[Flags]
	public enum DefaultValueHandling
	{
		Include = 0,
		Ignore = 1,
		Populate = 2,
		IgnoreAndPopulate = 3
	}
	public enum FloatFormatHandling
	{
		String,
		Symbol,
		DefaultValue
	}
	public enum FloatParseHandling
	{
		Double,
		Decimal
	}
	public enum Formatting
	{
		None,
		Indented
	}
	public interface IArrayPool<T>
	{
		T[] Rent(int minimumLength);

		void Return(T[]? array);
	}
	public interface IJsonLineInfo
	{
		int LineNumber { get; }

		int LinePosition { get; }

		bool HasLineInfo();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonArrayAttribute : JsonContainerAttribute
	{
		private bool _allowNullItems;

		public bool AllowNullItems
		{
			get
			{
				return _allowNullItems;
			}
			set
			{
				_allowNullItems = value;
			}
		}

		public JsonArrayAttribute()
		{
		}

		public JsonArrayAttribute(bool allowNullItems)
		{
			_allowNullItems = allowNullItems;
		}

		public JsonArrayAttribute(string id)
			: base(id)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
	public sealed class JsonConstructorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public abstract class JsonContainerAttribute : Attribute
	{
		internal bool? _isReference;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		private Type? _namingStrategyType;

		private object[]? _namingStrategyParameters;

		public string? Id { get; set; }

		public string? Title { get; set; }

		public string? Description { get; set; }

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType
		{
			get
			{
				return _namingStrategyType;
			}
			set
			{
				_namingStrategyType = value;
				NamingStrategyInstance = null;
			}
		}

		public object[]? NamingStrategyParameters
		{
			get
			{
				return _namingStrategyParameters;
			}
			set
			{
				_namingStrategyParameters = value;
				NamingStrategyInstance = null;
			}
		}

		internal NamingStrategy? NamingStrategyInstance { get; set; }

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		protected JsonContainerAttribute()
		{
		}

		protected JsonContainerAttribute(string id)
		{
			Id = id;
		}
	}
	public static class JsonConvert
	{
		public static readonly string True = "true";

		public static readonly string False = "false";

		public static readonly string Null = "null";

		public static readonly string Undefined = "undefined";

		public static readonly string PositiveInfinity = "Infinity";

		public static readonly string NegativeInfinity = "-Infinity";

		public static readonly string NaN = "NaN";

		public static Func<JsonSerializerSettings>? DefaultSettings { get; set; }

		public static string ToString(DateTime value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
		}

		public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
		{
			DateTime value2 = DateTimeUtils.EnsureDateTime(value, timeZoneHandling);
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeString(stringWriter, value2, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(DateTimeOffset value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat);
		}

		public static string ToString(DateTimeOffset value, DateFormatHandling format)
		{
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeOffsetString(stringWriter, value, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(bool value)
		{
			if (!value)
			{
				return False;
			}
			return True;
		}

		public static string ToString(char value)
		{
			return ToString(char.ToString(value));
		}

		public static string ToString(Enum value)
		{
			return value.ToString("D");
		}

		public static string ToString(int value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(short value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ushort value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(uint value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(long value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		private static string ToStringInternal(BigInteger value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ulong value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(float value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			if (floatFormatHandling == FloatFormatHandling.Symbol || (!double.IsInfinity(value) && !double.IsNaN(value)))
			{
				return text;
			}
			if (floatFormatHandling == FloatFormatHandling.DefaultValue)
			{
				if (nullable)
				{
					return Null;
				}
				return "0.0";
			}
			return quoteChar + text + quoteChar;
		}

		public static string ToString(double value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureDecimalPlace(double value, string text)
		{
			if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		private static string EnsureDecimalPlace(string text)
		{
			if (StringUtils.IndexOf(text, '.') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		public static string ToString(byte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(sbyte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(decimal value)
		{
			return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
		}

		public static string ToString(Guid value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(Guid value, char quoteChar)
		{
			string text = value.ToString("D", CultureInfo.InvariantCulture);
			string text2 = quoteChar.ToString(CultureInfo.InvariantCulture);
			return text2 + text + text2;
		}

		public static string ToString(TimeSpan value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(TimeSpan value, char quoteChar)
		{
			return ToString(value.ToString(), quoteChar);
		}

		public static string ToString(Uri? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ToString(value, '"');
		}

		internal static string ToString(Uri value, char quoteChar)
		{
			return ToString(value.OriginalString, quoteChar);
		}

		public static string ToString(string? value)
		{
			return ToString(value, '"');
		}

		public static string ToString(string? value, char delimiter)
		{
			return ToString(value, delimiter, StringEscapeHandling.Default);
		}

		public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling)
		{
			if (delimiter != '"' && delimiter != '\'')
			{
				throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter");
			}
			return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, appendDelimiters: true, stringEscapeHandling);
		}

		public static string ToString(object? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ConvertUtils.GetTypeCode(value.GetType()) switch
			{
				PrimitiveTypeCode.String => ToString((string)value), 
				PrimitiveTypeCode.Char => ToString((char)value), 
				PrimitiveTypeCode.Boolean => ToString((bool)value), 
				PrimitiveTypeCode.SByte => ToString((sbyte)value), 
				PrimitiveTypeCode.Int16 => ToString((short)value), 
				PrimitiveTypeCode.UInt16 => ToString((ushort)value), 
				PrimitiveTypeCode.Int32 => ToString((int)value), 
				PrimitiveTypeCode.Byte => ToString((byte)value), 
				PrimitiveTypeCode.UInt32 => ToString((uint)value), 
				PrimitiveTypeCode.Int64 => ToString((long)value), 
				PrimitiveTypeCode.UInt64 => ToString((ulong)value), 
				PrimitiveTypeCode.Single => ToString((float)value), 
				PrimitiveTypeCode.Double => ToString((double)value), 
				PrimitiveTypeCode.DateTime => ToString((DateTime)value), 
				PrimitiveTypeCode.Decimal => ToString((decimal)value), 
				PrimitiveTypeCode.DBNull => Null, 
				PrimitiveTypeCode.DateTimeOffset => ToString((DateTimeOffset)value), 
				PrimitiveTypeCode.Guid => ToString((Guid)value), 
				PrimitiveTypeCode.Uri => ToString((Uri)value), 
				PrimitiveTypeCode.TimeSpan => ToString((TimeSpan)value), 
				PrimitiveTypeCode.BigInteger => ToStringInternal((BigInteger)value), 
				_ => throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())), 
			};
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value)
		{
			return SerializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting)
		{
			return SerializeObject(value, formatting, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			jsonSerializer.Formatting = formatting;
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer)
		{
			StringWriter stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
			using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter))
			{
				jsonTextWriter.Formatting = jsonSerializer.Formatting;
				jsonSerializer.Serialize(jsonTextWriter, value, type);
			}
			return stringWriter.ToString();
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value)
		{
			return DeserializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, JsonSerializerSettings settings)
		{
			return DeserializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type)
		{
			return DeserializeObject(value, type, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value)
		{
			return JsonConvert.DeserializeObject<T>(value, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
		{
			return DeserializeObject<T>(value);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject, JsonSerializerSettings settings)
		{
			return DeserializeObject<T>(value, settings);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, params JsonConverter[] converters)
		{
			return (T)DeserializeObject(value, typeof(T), converters);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, JsonSerializerSettings? settings)
		{
			return (T)DeserializeObject(value, typeof(T), settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return DeserializeObject(value, type, settings);
		}

		public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings)
		{
			ValidationUtils.ArgumentNotNull(value, "value");
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			if (!jsonSerializer.IsCheckAdditionalContentSet())
			{
				jsonSerializer.CheckAdditionalContent = true;
			}
			using JsonTextReader reader = new JsonTextReader(new StringReader(value));
			return jsonSerializer.Deserialize(reader, type);
		}

		[DebuggerStepThrough]
		public static void PopulateObject(string value, object target)
		{
			PopulateObject(value, target, null);
		}

		public static void PopulateObject(string value, object target, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			using JsonReader jsonReader = new JsonTextReader(new StringReader(value));
			jsonSerializer.Populate(jsonReader, target);
			if (settings == null || !settings.CheckAdditionalContent)
			{
				return;
			}
			while (jsonReader.Read())
			{
				if (jsonReader.TokenType != JsonToken.Comment)
				{
					throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object.");
				}
			}
		}

		public static string SerializeXmlNode(XmlNode? node)
		{
			return SerializeXmlNode(node, Formatting.None);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XmlDocument? DeserializeXmlNode(string value)
		{
			return DeserializeXmlNode(value, null);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), xmlNodeConverter);
		}

		public static string SerializeXNode(XObject? node)
		{
			return SerializeXNode(node, Formatting.None);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting)
		{
			return SerializeXNode(node, formatting, omitRootObject: false);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XDocument? DeserializeXNode(string value)
		{
			return DeserializeXNode(value, null);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XDocument)DeserializeObject(value, typeof(XDocument), xmlNodeConverter);
		}
	}
	public abstract class JsonConverter
	{
		public virtual bool CanRead => true;

		public virtual bool CanWrite => true;

		public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);

		public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

		public abstract bool CanConvert(Type objectType);
	}
	public abstract class JsonConverter<T> : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (!((value != null) ? (value is T) : ReflectionUtils.IsNullable(typeof(T))))
			{
				throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			WriteJson(writer, (T)value, serializer);
		}

		public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			bool flag = existingValue == null;
			if (!flag && !(existingValue is T))
			{
				throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			return ReadJson(reader, objectType, flag ? default(T) : ((T)existingValue), !flag, serializer);
		}

		public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);

		public sealed override bool CanConvert(Type objectType)
		{
			return typeof(T).IsAssignableFrom(objectType);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonConverterAttribute : Attribute
	{
		private readonly Type _converterType;

		public Type ConverterType => _converterType;

		public object[]? ConverterParameters { get; }

		public JsonConverterAttribute(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			_converterType = converterType;
		}

		public JsonConverterAttribute(Type converterType, params object[] converterParameters)
			: this(converterType)
		{
			ConverterParameters = converterParameters;
		}
	}
	public class JsonConverterCollection : Collection<JsonConverter>
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonDictionaryAttribute : JsonContainerAttribute
	{
		public JsonDictionaryAttribute()
		{
		}

		public JsonDictionaryAttribute(string id)
			: base(id)
		{
		}
	}
	[Serializable]
	public class JsonException : Exception
	{
		public JsonException()
		{
		}

		public JsonException(string message)
			: base(message)
		{
		}

		public JsonException(string message, Exception? innerException)
			: base(message, innerException)
		{
		}

		public JsonException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			return new JsonException(message);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public class JsonExtensionDataAttribute : Attribute
	{
		public bool WriteData { get; set; }

		public bool ReadData { get; set; }

		public JsonExtensionDataAttribute()
		{
			WriteData = true;
			ReadData = true;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonIgnoreAttribute : Attribute
	{
	}
	public abstract class JsonNameTable
	{
		public abstract string? Get(char[] key, int start, int length);
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonObjectAttribute : JsonContainerAttribute
	{
		private MemberSerialization _memberSerialization;

		internal MissingMemberHandling? _missingMemberHandling;

		internal Required? _itemRequired;

		internal NullValueHandling? _itemNullValueHandling;

		public MemberSerialization MemberSerialization
		{
			get
			{
				return _memberSerialization;
			}
			set
			{
				_memberSerialization = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public NullValueHandling ItemNullValueHandling
		{
			get
			{
				return _itemNullValueHandling.GetValueOrDefault();
			}
			set
			{
				_itemNullValueHandling = value;
			}
		}

		public Required ItemRequired
		{
			get
			{
				return _itemRequired.GetValueOrDefault();
			}
			set
			{
				_itemRequired = value;
			}
		}

		public JsonObjectAttribute()
		{
		}

		public JsonObjectAttribute(MemberSerialization memberSerialization)
		{
			MemberSerialization = memberSerialization;
		}

		public JsonObjectAttribute(string id)
			: base(id)
		{
		}
	}
	internal enum JsonContainerType
	{
		None,
		Object,
		Array,
		Constructor
	}
	internal struct JsonPosition
	{
		private static readonly char[] SpecialCharacters = new char[18]
		{
			'.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t',
			'\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029'
		};

		internal JsonContainerType Type;

		internal int Position;

		internal string? PropertyName;

		internal bool HasIndex;

		public JsonPosition(JsonContainerType type)
		{
			Type = type;
			HasIndex = TypeHasIndex(type);
			Position = -1;
			PropertyName = null;
		}

		internal int CalculateLength()
		{
			switch (Type)
			{
			case JsonContainerType.Object:
				return PropertyName.Length + 5;
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				return MathUtils.IntLength((ulong)Position) + 2;
			default:
				throw new ArgumentOutOfRangeException("Type");
			}
		}

		internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer)
		{
			switch (Type)
			{
			case JsonContainerType.Object:
			{
				string propertyName = PropertyName;
				if (propertyName.IndexOfAny(SpecialCharacters) != -1)
				{
					sb.Append("['");
					if (writer == null)
					{
						writer = new StringWriter(sb);
					}
					JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', appendDelimiters: false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
					sb.Append("']");
				}
				else
				{
					if (sb.Length > 0)
					{
						sb.Append('.');
					}
					sb.Append(propertyName);
				}
				break;
			}
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				sb.Append('[');
				sb.Append(Position);
				sb.Append(']');
				break;
			}
		}

		internal static bool TypeHasIndex(JsonContainerType type)
		{
			if (type != JsonContainerType.Array)
			{
				return type == JsonContainerType.Constructor;
			}
			return true;
		}

		internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition)
		{
			int num = 0;
			if (positions != null)
			{
				for (int i = 0; i < positions.Count; i++)
				{
					num += positions[i].CalculateLength();
				}
			}
			if (currentPosition.HasValue)
			{
				num += currentPosition.GetValueOrDefault().CalculateLength();
			}
			StringBuilder stringBuilder = new StringBuilder(num);
			StringWriter writer = null;
			char[] buffer = null;
			if (positions != null)
			{
				foreach (JsonPosition position in positions)
				{
					position.WriteTo(stringBuilder, ref writer, ref buffer);
				}
			}
			currentPosition?.WriteTo(stringBuilder, ref writer, ref buffer);
			return stringBuilder.ToString();
		}

		internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message)
		{
			if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
			{
				message = message.Trim();
				if (!StringUtils.EndsWith(message, '.'))
				{
					message += ".";
				}
				message += " ";
			}
			message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
			}
			message += ".";
			return message;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonPropertyAttribute : Attribute
	{
		internal NullValueHandling? _nullValueHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal bool? _isReference;

		internal int? _order;

		internal Required? _required;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType { get; set; }

		public object[]? NamingStrategyParameters { get; set; }

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameHandling = value;
			}
		}

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public int Order
		{
			get
			{
				return _order.GetValueOrDefault();
			}
			set
			{
				_order = value;
			}
		}

		public Required Required
		{
			get
			{
				return _required.GetValueOrDefault();
			}
			set
			{
				_required = value;
			}
		}

		public string? PropertyName { get; set; }

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public JsonPropertyAttribute()
		{
		}

		public JsonPropertyAttribute(string propertyName)
		{
			PropertyName = propertyName;
		}
	}
	public abstract class JsonReader : IDisposable
	{
		protected internal enum State
		{
			Start,
			Complete,
			Property,
			ObjectStart,
			Object,
			ArrayStart,
			Array,
			Closed,
			PostValue,
			ConstructorStart,
			Constructor,
			Error,
			Finished
		}

		private JsonToken _tokenType;

		private object? _value;

		internal char _quoteChar;

		internal State _currentState;

		private JsonPosition _currentPosition;

		private CultureInfo? _culture;

		private DateTimeZoneHandling _dateTimeZoneHandling;

		private int? _maxDepth;

		private bool _hasExceededMaxDepth;

		internal DateParseHandling _dateParseHandling;

		internal FloatParseHandling _floatParseHandling;

		private string? _dateFormatString;

		private List<JsonPosition>? _stack;

		protected State CurrentState => _currentState;

		public bool CloseInput { get; set; }

		public bool SupportMultipleContent { get; set; }

		public virtual char QuoteChar
		{
			get
			{
				return _quoteChar;
			}
			protected internal set
			{
				_quoteChar = value;
			}
		}

		public DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling;
			}
			set
			{
				if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateTimeZoneHandling = value;
			}
		}

		public DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling;
			}
			set
			{
				if (value < DateParseHandling.None || value > DateParseHandling.DateTimeOffset)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateParseHandling = value;
			}
		}

		public FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling;
			}
			set
			{
				if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_floatParseHandling = value;
			}
		}

		public string? DateFormatString
		{
			get
			{
				return _dateFormatString;
			}
			set
			{
				_dateFormatString = value;
			}
		}

		public int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
			}
		}

		public virtual JsonToken TokenType => _tokenType;

		public virtual object? Value => _value;

		public virtual Type? ValueType => _value?.GetType();

		public virtual int Depth
		{
			get
			{
				int num = _stack?.Count ?? 0;
				if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
				{
					return num;
				}
				return num + 1;
			}
		}

		public virtual string Path
		{
			get
			{
				if (_currentPosition.Type == JsonContainerType.None)
				{
					return string.Empty;
				}
				JsonPosition? currentPosition = ((_currentState != State.ArrayStart && _currentState != State.ConstructorStart && _currentState != State.ObjectStart) ? new JsonPosition?(_currentPosition) : null);
				return JsonPosition.BuildPath(_stack, currentPosition);
			}
		}

		public CultureInfo Culture
		{
			get
			{
				return _culture ?? CultureInfo.InvariantCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool>() ?? Read().ToAsync();
		}

		public async Task SkipAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (TokenType == JsonToken.PropertyName)
			{
				await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false) && depth < Depth)
				{
				}
			}
		}

		internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken)
		{
			if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
			{
				throw CreateUnexpectedEndException();
			}
		}

		public virtual Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool?>() ?? Task.FromResult(ReadAsBoolean());
		}

		public virtual Task<byte[]?> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<byte[]>() ?? Task.FromResult(ReadAsBytes());
		}

		internal async Task<byte[]?> ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken)
		{
			List<byte> buffer = new List<byte>();
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(buffer));
			byte[] array = buffer.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		public virtual Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTime?>() ?? Task.FromResult(ReadAsDateTime());
		}

		public virtual Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTimeOffset?>() ?? Task.FromResult(ReadAsDateTimeOffset());
		}

		public virtual Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<decimal?>() ?? Task.FromResult(ReadAsDecimal());
		}

		public virtual Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return Task.FromResult(ReadAsDouble());
		}

		public virtual Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<int?>() ?? Task.FromResult(ReadAsInt32());
		}

		public virtual Task<string?> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<string>() ?? Task.FromResult(ReadAsString());
		}

		internal async Task<bool> ReadAndMoveToContentAsync(CancellationToken cancellationToken)
		{
			bool flag = await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			if (flag)
			{
				flag = await MoveToContentAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			return flag;
		}

		internal Task<bool> MoveToContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType = TokenType;
			if (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				return MoveToContentFromNonContentAsync(cancellationToken);
			}
			return AsyncUtils.True;
		}

		private async Task<bool> MoveToContentFromNonContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType;
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					return false;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment);
			return true;
		}

		internal JsonPosition GetPosition(int depth)
		{
			if (_stack != null && depth < _stack.Count)
			{
				return _stack[depth];
			}
			return _currentPosition;
		}

		protected JsonReader()
		{
			_currentState = State.Start;
			_dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
			_dateParseHandling = DateParseHandling.DateTime;
			_floatParseHandling = FloatParseHandling.Double;
			_maxDepth = 64;
			CloseInput = true;
		}

		private void Push(JsonContainerType value)
		{
			UpdateScopeWithFinishedValue();
			if (_currentPosition.Type == JsonContainerType.None)
			{
				_currentPosition = new JsonPosition(value);
				return;
			}
			if (_stack == null)
			{
				_stack = new List<JsonPosition>();
			}
			_stack.Add(_currentPosition);
			_currentPosition = new JsonPosition(value);
			if (!_maxDepth.HasValue || !(Depth + 1 > _maxDepth) || _hasExceededMaxDepth)
			{
				return;
			}
			_hasExceededMaxDepth = true;
			throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
		}

		private JsonContainerType Pop()
		{
			JsonPosition currentPosition;
			if (_stack != null && _stack.Count > 0)
			{
				currentPosition = _currentPosition;
				_currentPosition = _stack[_stack.Count - 1];
				_stack.RemoveAt(_stack.Count - 1);
			}
			else
			{
				currentPosition = _currentPosition;
				_currentPosition = default(JsonPosition);
			}
			if (_maxDepth.HasValue && Depth <= _maxDepth)
			{
				_hasExceededMaxDepth = false;
			}
			return currentPosition.Type;
		}

		private JsonContainerType Peek()
		{
			return _currentPosition.Type;
		}

		public abstract bool Read();

		public virtual int? ReadAsInt32()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is int)
				{
					return (int)value;
				}
				int num;
				if (value is BigInteger bigInteger)
				{
					num = (int)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToInt32(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Integer, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadInt32String(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal int? ReadInt32String(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (int.TryParse(s, NumberStyles.Integer, Culture, out var result))
			{
				SetToken(JsonToken.Integer, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual string? ReadAsString()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.String:
				return (string)Value;
			default:
				if (JsonTokenUtils.IsPrimitiveToken(contentToken))
				{
					object value = Value;
					if (value != null)
					{
						string text = ((!(value is IFormattable formattable)) ? ((value is Uri uri) ? uri.OriginalString : value.ToString()) : formattable.ToString(null, Culture));
						SetToken(JsonToken.String, text, updateIndex: false);
						return text;
					}
				}
				throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		public virtual byte[]? ReadAsBytes()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.StartObject:
			{
				ReadIntoWrappedTypeObject();
				byte[] array2 = ReadAsBytes();
				ReaderReadAndAssert();
				if (TokenType != JsonToken.EndObject)
				{
					throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
				}
				SetToken(JsonToken.Bytes, array2, updateIndex: false);
				return array2;
			}
			case JsonToken.String:
			{
				string text = (string)Value;
				Guid g;
				byte[] array3 = ((text.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((!ConvertUtils.TryConvertGuid(text, out g)) ? Convert.FromBase64String(text) : g.ToByteArray()));
				SetToken(JsonToken.Bytes, array3, updateIndex: false);
				return array3;
			}
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Bytes:
				if (Value is Guid guid)
				{
					byte[] array = guid.ToByteArray();
					SetToken(JsonToken.Bytes, array, updateIndex: false);
					return array;
				}
				return (byte[])Value;
			case JsonToken.StartArray:
				return ReadArrayIntoByteArray();
			default:
				throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal byte[] ReadArrayIntoByteArray()
		{
			List<byte> list = new List<byte>();
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(list));
			byte[] array = list.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		private bool ReadArrayElementIntoByteArrayReportDone(List<byte> buffer)
		{
			switch (TokenType)
			{
			case JsonToken.None:
				throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
			case JsonToken.Integer:
				buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
				return false;
			case JsonToken.EndArray:
				return true;
			case JsonToken.Comment:
				return false;
			default:
				throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		public virtual double? ReadAsDouble()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is double)
				{
					return (double)value;
				}
				double num = ((!(value is BigInteger bigInteger)) ? Convert.ToDouble(value, CultureInfo.InvariantCulture) : ((double)bigInteger));
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDoubleString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal double? ReadDoubleString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual bool? ReadAsBoolean()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				bool flag = ((!(Value is BigInteger bigInteger)) ? Convert.ToBoolean(Value, CultureInfo.InvariantCulture) : (bigInteger != 0L));
				SetToken(JsonToken.Boolean, flag, updateIndex: false);
				return flag;
			}
			case JsonToken.String:
				return ReadBooleanString((string)Value);
			case JsonToken.Boolean:
				return (bool)Value;
			default:
				throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal bool? ReadBooleanString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (bool.TryParse(s, out var result))
			{
				SetToken(JsonToken.Boolean, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual decimal? ReadAsDecimal()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is decimal)
				{
					return (decimal)value;
				}
				decimal num;
				if (value is BigInteger bigInteger)
				{
					num = (decimal)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToDecimal(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDecimalString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal decimal? ReadDecimalString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (decimal.TryParse(s, NumberStyles.Number, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			if (ConvertUtils.DecimalTryParse(s.ToCharArray(), 0, s.Length, out result) == ParseResult.Success)
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTime? ReadAsDateTime()
		{
			switch (GetContentToken())
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTimeOffset dateTimeOffset)
				{
					SetToken(JsonToken.Date, dateTimeOffset.DateTime, updateIndex: false);
				}
				return (DateTime)Value;
			case JsonToken.String:
				return ReadDateTimeString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		internal DateTime? ReadDateTimeString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out var dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTimeOffset? ReadAsDateTimeOffset()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTime dateTime)
				{
					SetToken(JsonToken.Date, new DateTimeOffset(dateTime), updateIndex: false);
				}
				return (DateTimeOffset)Value;
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadDateTimeOffsetString(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal DateTimeOffset? ReadDateTimeOffsetString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out var dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		internal void ReaderReadAndAssert()
		{
			if (!Read())
			{
				throw CreateUnexpectedEndException();
			}
		}

		internal JsonReaderException CreateUnexpectedEndException()
		{
			return JsonReaderException.Create(this, "Unexpected end when reading JSON.");
		}

		internal void ReadIntoWrappedTypeObject()
		{
			ReaderReadAndAssert();
			if (Value != null && Value.ToString() == "$type")
			{
				ReaderReadAndAssert();
				if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
				{
					ReaderReadAndAssert();
					if (Value.ToString() == "$value")
					{
						return;
					}
				}
			}
			throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
		}

		public void Skip()
		{
			if (TokenType == JsonToken.PropertyName)
			{
				Read();
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (Read() && depth < Depth)
				{
				}
			}
		}

		protected void SetToken(JsonToken newToken)
		{
			SetToken(newToken, null, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value)
		{
			SetToken(newToken, value, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value, bool updateIndex)
		{
			_tokenType = newToken;
			_value = value;
			switch (newToken)
			{
			case JsonToken.StartObject:
				_currentState = State.ObjectStart;
				Push(JsonContainerType.Object);
				break;
			case JsonToken.StartArray:
				_currentState = State.ArrayStart;
				Push(JsonContainerType.Array);
				break;
			case JsonToken.StartConstructor:
				_currentState = State.ConstructorStart;
				Push(JsonContainerType.Constructor);
				break;
			case JsonToken.EndObject:
				ValidateEnd(JsonToken.EndObject);
				break;
			case JsonToken.EndArray:
				ValidateEnd(JsonToken.EndArray);
				break;
			case JsonToken.EndConstructor:
				ValidateEnd(JsonToken.EndConstructor);
				break;
			case JsonToken.PropertyName:
				_currentState = State.Property;
				_currentPosition.PropertyName = (string)value;
				break;
			case JsonToken.Raw:
			case JsonToken.Integer:
			case JsonToken.Float:
			case JsonToken.String:
			case JsonToken.Boolean:
			case JsonToken.Null:
			case JsonToken.Undefined:
			case JsonToken.Date:
			case JsonToken.Bytes:
				SetPostValueState(updateIndex);
				break;
			case JsonToken.Comment:
				break;
			}
		}

		internal void SetPostValueState(bool updateIndex)
		{
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
			if (updateIndex)
			{
				UpdateScopeWithFinishedValue();
			}
		}

		private void UpdateScopeWithFinishedValue()
		{
			if (_currentPosition.HasIndex)
			{
				_currentPosition.Position++;
			}
		}

		private void ValidateEnd(JsonToken endToken)
		{
			JsonContainerType jsonContainerType = Pop();
			if (GetTypeForCloseToken(endToken) != jsonContainerType)
			{
				throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, jsonContainerType));
			}
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
		}

		protected void SetStateBasedOnCurrent()
		{
			JsonContainerType jsonContainerType = Peek();
			switch (jsonContainerType)
			{
			case JsonContainerType.Object:
				_currentState = State.Object;
				break;
			case JsonContainerType.Array:
				_currentState = State.Array;
				break;
			case JsonContainerType.Constructor:
				_currentState = State.Constructor;
				break;
			case JsonContainerType.None:
				SetFinished();
				break;
			default:
				throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, jsonContainerType));
			}
		}

		private void SetFinished()
		{
			_currentState = ((!SupportMultipleContent) ? State.Finished : State.Start);
		}

		private JsonContainerType GetTypeForCloseToken(JsonToken token)
		{
			return token switch
			{
				JsonToken.EndObject => JsonContainerType.Object, 
				JsonToken.EndArray => JsonContainerType.Array, 
				JsonToken.EndConstructor => JsonContainerType.Constructor, 
				_ => throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token)), 
			};
		}

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

		protected virtual void Dispose(bool disposing)
		{
			if (_currentState != State.Closed && disposing)
			{
				Close();
			}
		}

		public virtual void Close()
		{
			_currentState = State.Closed;
			_tokenType = JsonToken.None;
			_value = null;
		}

		internal void ReadAndAssert()
		{
			if (!Read())
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter)
		{
			if (!ReadForType(contract, hasConverter))
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal bool ReadForType(JsonContract? contract, bool hasConverter)
		{
			if (hasConverter)
			{
				return Read();
			}
			switch (contract?.InternalReadType ?? ReadType.Read)
			{
			case ReadType.Read:
				return ReadAndMoveToContent();
			case ReadType.ReadAsInt32:
				ReadAsInt32();
				break;
			case ReadType.ReadAsInt64:
			{
				bool result = ReadAndMoveToContent();
				if (TokenType == JsonToken.Undefined)
				{
					throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long)));
				}
				return result;
			}
			case ReadType.ReadAsDecimal:
				ReadAsDecimal();
				break;
			case ReadType.ReadAsDouble:
				ReadAsDouble();
				break;
			case ReadType.ReadAsBytes:
				ReadAsBytes();
				break;
			case ReadType.ReadAsBoolean:
				ReadAsBoolean();
				break;
			case ReadType.ReadAsString:
				ReadAsString();
				break;
			case ReadType.ReadAsDateTime:
				ReadAsDateTime();
				break;
			case ReadType.ReadAsDateTimeOffset:
				ReadAsDateTimeOffset();
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			return TokenType != JsonToken.None;
		}

		internal bool ReadAndMoveToContent()
		{
			if (Read())
			{
				return MoveToContent();
			}
			return false;
		}

		internal bool MoveToContent()
		{
			JsonToken tokenType = TokenType;
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				if (!Read())
				{
					return false;
				}
				tokenType = TokenType;
			}
			return true;
		}

		private JsonToken GetContentToken()
		{
			JsonToken tokenType;
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
					return JsonToken.None;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.Comment);
			return tokenType;
		}
	}
	[Serializable]
	public class JsonReaderException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonReaderException()
		{
		}

		public JsonReaderException(string message)
			: base(message)
		{
		}

		public JsonReaderException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonReaderException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonReaderException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonReaderException(message, path, lineNumber, linePosition, ex);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonRequiredAttribute : Attribute
	{
	}
	[Serializable]
	public class JsonSerializationException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonSerializationException()
		{
		}

		public JsonSerializationException(string message)
			: base(message)
		{
		}

		public JsonSerializationException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonSerializationException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonSerializationException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonSerializationException(message, path, lineNumber, linePosition, ex);
		}
	}
	public class JsonSerializer
	{
		internal TypeNameHandling _typeNameHandling;

		internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling;

		internal PreserveReferencesHandling _preserveReferencesHandling;

		internal ReferenceLoopHandling _referenceLoopHandling;

		internal MissingMemberHandling _missingMemberHandling;

		internal ObjectCreationHandling _objectCreationHandling;

		internal NullValueHandling _nullValueHandling;

		internal DefaultValueHandling _defaultValueHandling;

		internal ConstructorHandling _constructorHandling;

		internal MetadataPropertyHandling _metadataPropertyHandling;

		internal JsonConverterCollection? _converters;

		internal IContractResolver _contractResolver;

		internal ITraceWriter? _traceWriter;

		internal IEqualityComparer? _equalityComparer;

		internal ISerializationBinder _serializationBinder;

		internal StreamingContext _context;

		private IReferenceResolver? _referenceResolver;

		private Formatting? _formatting;

		private DateFormatHandling? _dateFormatHandling;

		private DateTimeZoneHandling? _dateTimeZoneHandling;

		private DateParseHandling? _dateParseHandling;

		private FloatFormatHandling? _floatFormatHandling;

		private FloatParseHandling? _floatParseHandling;

		private StringEscapeHandling? _stringEscapeHandling;

		private CultureInfo _culture;

		private int? _maxDepth;

		private bool _maxDepthSet;

		private bool? _checkAdditionalContent;

		private string? _dateFormatString;

		private bool _dateFormatStringSet;

		public virtual IReferenceResolver? ReferenceResolver
		{
			get
			{
				return GetReferenceResolver();
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Reference resolver cannot be null.");
				}
				_referenceResolver = value;
			}
		}

		[Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
		public virtual SerializationBinder Binder
		{
			get
			{
				if (_serializationBinder is SerializationBinder result)
				{
					return result;
				}
				if (_serializationBinder is SerializationBinderAdapter serializationBinderAdapter)
				{
					return serializationBinderAdapter.SerializationBinder;
				}
				throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = (value as ISerializationBinder) ?? new SerializationBinderAdapter(value);
			}
		}

		public virtual ISerializationBinder SerializationBinder
		{
			get
			{
				return _serializationBinder;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = value;
			}
		}

		public virtual ITraceWriter? TraceWriter
		{
			get
			{
				return _traceWriter;
			}
			set
			{
				_traceWriter = value;
			}
		}

		public virtual IEqualityComparer? EqualityComparer
		{
			get
			{
				return _equalityComparer;
			}
			set
			{
				_equalityComparer = value;
			}
		}

		public virtual TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling;
			}
			set
			{
				if (value < TypeNameHandling.None || value > TypeNameHandling.Auto)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameHandling = value;
			}
		}

		[Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
		public virtual FormatterAssemblyStyle TypeNameAssemblyFormat
		{
			get
			{
				return (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
			}
		}

		public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
		{
			get
			{
				return _typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = value;
			}
		}

		public virtual PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling;
			}
			set
			{
				if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_preserveReferencesHandling = value;
			}
		}

		public virtual ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling;
			}
			set
			{
				if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_referenceLoopHandling = value;
			}
		}

		public virtual MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling;
			}
			set
			{
				if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_missingMemberHandling = value;
			}
		}

		public virtual NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling;
			}
			set
			{
				if (value < NullValueHandling.Include || value > NullValueHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_nullValueHandling = value;
			}
		}

		public virtual DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling;
			}
			set
			{
				if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_defaultValueHandling = value;
			}
		}

		public virtual ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling;
			}
			set
			{
				if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_objectCreationHandling = value;
			}
		}

		public virtual ConstructorHandling ConstructorHandling
		{
			get
			{
				return _constructorHandling;
			}
			set
			{
				if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_constructorHandling = value;
			}
		}

		public virtual MetadataPropertyHandling MetadataPropertyHandling
		{
			get
			{
				return _metadataPropertyHandling;
			}
			set
			{
				if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_metadataPropertyHandling = value;
			}
		}

		public virtual JsonConverterCollection Converters
		{
			get
			{
				if (_converters == null)
				{
					_converters = new JsonConverterCollection();
				}
				return _converters;
			}
		}

		public virtual IContractResolver ContractResolver
		{
			get
			{
				return _contractResolver;
			}
			set
			{
				_contractResolver = value ?? DefaultContractResolver.Instance;
			}
		}

		public virtual StreamingContext Context
		{
			get
			{
				return _context;
			}
			set
			{
				_context = value;
			}
		}

		public virtual Formatting Formatting
		{
			get
			{
				return _formatting.GetValueOrDefault();
			}
			set
			{
				_formatting = value;
			}
		}

		public virtual DateFormatHandling DateFormatHandling
		{
			get
			{
				return _dateFormatHandling.GetValueOrDefault();
			}
			set
			{
				_dateFormatHandling = value;
			}
		}

		public virtual DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling ?? DateTimeZoneHandling.RoundtripKind;
			}
			set
			{
				_dateTimeZoneHandling = value;
			}
		}

		public virtual DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling ?? DateParseHandling.DateTime;
			}
			set
			{
				_dateParseHandling = value;
			}
		}

		public virtual FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling.GetValueOrDefault();
			}
			set
			{
				_floatParseHandling = value;
			}
		}

		public virtual FloatFormatHandling FloatFormatHandling
		{
			get
			{
				return _floatFormatHandling.GetValueOrDefault();
			}
			set
			{
				_floatFormatHandling = value;
			}
		}

		public virtual StringEscapeHandling StringEscapeHandling
		{
			get
			{
				return _stringEscapeHandling.GetValueOrDefault();
			}
			set
			{
				_stringEscapeHandling = value;
			}
		}

		public virtual string DateFormatString
		{
			get
			{
				return _dateFormatString ?? "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
			}
			set
			{
				_dateFormatString = value;
				_dateFormatStringSet = true;
			}
		}

		public virtual CultureInfo Culture
		{
			get
			{
				return _culture ?? JsonSerializerSettings.DefaultCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
				_maxDepthSet = true;
			}
		}

		public virtual bool CheckAdditionalContent
		{
			get
			{
				return _checkAdditionalContent.GetValueOrDefault();
			}
			set
			{
				_checkAdditionalContent = value;
			}
		}

		public virtual event EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs>? Error;

		internal bool IsCheckAdditionalContentSet()
		{
			return _checkAdditionalContent.HasValue;
		}

		public JsonSerializer()
		{
			_referenceLoopHandling = ReferenceLoopHandling.Error;
			_missingMemberHandling = MissingMemberHandling.Ignore;
			_nullValueHandling = NullValueHandling.Include;
			_defaultValueHandling = DefaultValueHandling.Include;
			_objectCreationHandling = ObjectCreationHandling.Auto;
			_preserveReferencesHandling = PreserveReferencesHandling.None;
			_constructorHandling = ConstructorHandling.Default;
			_typeNameHandling = TypeNameHandling.None;
			_metadataPropertyHandling = MetadataPropertyHandling.Default;
			_context = JsonSerializerSettings.DefaultContext;
			_serializationBinder = DefaultSerializationBinder.Instance;
			_culture = JsonSerializerSettings.DefaultCulture;
			_contractResolver = DefaultContractResolver.Instance;
		}

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

		public static JsonSerializer Create(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = Create();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		public static JsonSerializer CreateDefault()
		{
			return Create(JsonConvert.DefaultSettings?.Invoke());
		}

		public static JsonSerializer CreateDefault(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = CreateDefault();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings)
		{
			if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
			{
				for (int i = 0; i < settings.Converters.Count; i++)
				{
					serializer.Converters.Insert(i, settings.Converters[i]);
				}
			}
			if (settings._typeNameHandling.HasValue)
			{
				serializer.TypeNameHandling = settings.TypeNameHandling;
			}
			if (settings._metadataPropertyHandling.HasValue)
			{
				serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling;
			}
			if (settings._typeNameAssemblyFormatHandling.HasValue)
			{
				serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling;
			}
			if (settings._preserveReferencesHandling.HasValue)
			{
				serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
			}
			if (settings._referenceLoopHandling.HasValue)
			{
				serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
			}
			if (settings._missingMemberHandling.HasValue)
			{
				serializer.MissingMemberHandling = settings.MissingMemberHandling;
			}
			if (settings._objectCreationHandling.HasValue)
			{
				serializer.ObjectCreationHandling = settings.ObjectCreationHandling;
			}
			if (settings._nullValueHandling.HasValue)
			{
				serializer.NullValueHandling = settings.NullValueHandling;
			}
			if (settings._defaultValueHandling.HasValue)
			{
				serializer.DefaultValueHandling = settings.DefaultValueHandling;
			}
			if (settings._constructorHandling.HasValue)
			{
				serializer.ConstructorHandling = settings.ConstructorHandling;
			}
			if (settings._context.HasValue)
			{
				serializer.Context = settings.Context;
			}
			if (settings._checkAdditionalContent.HasValue)
			{
				serializer._checkAdditionalContent = settings._checkAdditionalContent;
			}
			if (settings.Error != null)
			{
				serializer.Error += settings.Error;
			}
			if (settings.ContractResolver != null)
			{
				serializer.ContractResolver = settings.ContractResolver;
			}
			if (settings.ReferenceResolverProvider != null)
			{
				serializer.ReferenceResolver = settings.ReferenceResolverProvider();
			}
			if (settings.TraceWriter != null)
			{
				serializer.TraceWriter = settings.TraceWriter;
			}
			if (settings.EqualityComparer != null)
			{
				serializer.EqualityComparer = settings.EqualityComparer;
			}
			if (settings.SerializationBinder != null)
			{
				serializer.SerializationBinder = settings.SerializationBinder;
			}
			if (settings._formatting.HasValue)
			{
				serializer._formatting = settings._formatting;
			}
			if (settings._dateFormatHandling.HasValue)
			{
				serializer._dateFormatHandling = settings._dateFormatHandling;
			}
			if (settings._dateTimeZoneHandling.HasValue)
			{
				serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling;
			}
			if (settings._dateParseHandling.HasValue)
			{
				serializer._dateParseHandling = settings._dateParseHandling;
			}
			if (settings._dateFormatStringSet)
			{
				serializer._dateFormatString = settings._dateFormatString;
				serializer._dateFormatStringSet = settings._dateFormatStringSet;
			}
			if (settings._floatFormatHandling.HasValue)
			{
				serializer._floatFormatHandling = settings._floatFormatHandling;
			}
			if (settings._floatParseHandling.HasValue)
			{
				serializer._floatParseHandling = settings._floatParseHandling;
			}
			if (settings._stringEscapeHandling.HasValue)
			{
				serializer._stringEscapeHandling = settings._stringEscapeHandling;
			}
			if (settings._culture != null)
			{
				serializer._culture = settings._culture;
			}
			if (settings._maxDepthSet)
			{
				serializer._maxDepth = settings._maxDepth;
				serializer._maxDepthSet = settings._maxDepthSet;
			}
		}

		[DebuggerStepThrough]
		public void Populate(TextReader reader, object target)
		{
			Populate(new JsonTextReader(reader), target);
		}

		[DebuggerStepThrough]
		public void Populate(JsonReader reader, object target)
		{
			PopulateInternal(reader, target);
		}

		internal virtual void PopulateInternal(JsonReader reader, object target)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			ValidationUtils.ArgumentNotNull(target, "target");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			new JsonSerializerInternalReader(this).Populate(traceJsonReader ?? reader, target);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader)
		{
			return Deserialize(reader, null);
		}

		[DebuggerStepThrough]
		public object? Deserialize(TextReader reader, Type objectType)
		{
			return Deserialize(new JsonTextReader(reader), objectType);
		}

		[DebuggerStepThrough]
		public T? Deserialize<T>(JsonReader reader)
		{
			return (T)Deserialize(reader, typeof(T));
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader, Type? objectType)
		{
			return DeserializeInternal(reader, objectType);
		}

		internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			object? result = new JsonSerializerInternalReader(this).Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
			return result;
		}

		internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
		{
			if (_culture != null && !_culture.Equals(reader.Culture))
			{
				previousCulture = reader.Culture;
				reader.Culture = _culture;
			}
			else
			{
				previousCulture = null;
			}
			if (_dateTimeZoneHandling.HasValue && reader.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				previousDateTimeZoneHandling = reader.DateTimeZoneHandling;
				reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			else
			{
				previousDateTimeZoneHandling = null;
			}
			if (_dateParseHandling.HasValue && reader.DateParseHandling != _dateParseHandling)
			{
				previousDateParseHandling = reader.DateParseHandling;
				reader.DateParseHandling = _dateParseHandling.GetValueOrDefault();
			}
			else
			{
				previousDateParseHandling = null;
			}
			if (_floatParseHandling.HasValue && reader.FloatParseHandling != _floatParseHandling)
			{
				previousFloatParseHandling = reader.FloatParseHandling;
				reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault();
			}
			else
			{
				previousFloatParseHandling = null;
			}
			if (_maxDepthSet && reader.MaxDepth != _maxDepth)
			{
				previousMaxDepth = reader.MaxDepth;
				reader.MaxDepth = _maxDepth;
			}
			else
			{
				previousMaxDepth = null;
			}
			if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString)
			{
				previousDateFormatString = reader.DateFormatString;
				reader.DateFormatString = _dateFormatString;
			}
			else
			{
				previousDateFormatString = null;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver defaultContractResolver)
			{
				jsonTextReader.PropertyNameTable = defaultContractResolver.GetNameTable();
			}
		}

		private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString)
		{
			if (previousCulture != null)
			{
				reader.Culture = previousCulture;
			}
			if (previousDateTimeZoneHandling.HasValue)
			{
				reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
			}
			if (previousDateParseHandling.HasValue)
			{
				reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault();
			}
			if (previousFloatParseHandling.HasValue)
			{
				reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault();
			}
			if (_maxDepthSet)
			{
				reader.MaxDepth = previousMaxDepth;
			}
			if (_dateFormatStringSet)
			{
				reader.DateFormatString = previousDateFormatString;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable != null && _contractResolver is DefaultContractResolver defaultContractResolver && jsonTextReader.PropertyNameTable == defaultContractResolver.GetNameTable())
			{
				jsonTextReader.PropertyNameTable = null;
			}
		}

		public void Serialize(TextWriter textWriter, object? value)
		{
			Serialize(new JsonTextWriter(textWriter), value);
		}

		public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			SerializeInternal(jsonWriter, value, objectType);
		}

		public void Serialize(TextWriter textWriter, object? value, Type objectType)
		{
			Serialize(new JsonTextWriter(textWriter), value, objectType);
		}

		public void Serialize(JsonWriter jsonWriter, object? value)
		{
			SerializeInternal(jsonWriter, value, null);
		}

		private TraceJsonReader CreateTraceJsonReader(JsonReader reader)
		{
			TraceJsonReader traceJsonReader = new TraceJsonReader(reader);
			if (reader.TokenType != 0)
			{
				traceJsonReader.WriteCurrentToken();
			}
			return traceJsonReader;
		}

		internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
			Formatting? formatting = null;
			if (_formatting.HasValue && jsonWriter.Formatting != _formatting)
			{
				formatting = jsonWriter.Formatting;
				jsonWriter.Formatting = _formatting.GetValueOrDefault();
			}
			DateFormatHandling? dateFormatHandling = null;
			if (_dateFormatHandling.HasValue && jsonWriter.DateFormatHandling != _dateFormatHandling)
			{
				dateFormatHandling = jsonWriter.DateFormatHandling;
				jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault();
			}
			DateTimeZoneHandling? dateTimeZoneHandling = null;
			if (_dateTimeZoneHandling.HasValue && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				dateTimeZoneHandling = jsonWriter.DateTimeZoneHandling;
				jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			FloatFormatHandling? floatFormatHandling = null;
			if (_floatFormatHandling.HasValue && jsonWriter.FloatFormatHandling != _floatFormatHandling)
			{
				floatFormatHandling = jsonWriter.FloatFormatHandling;
				jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault();
			}
			StringEscapeHandling? stringEscapeHandling = null;
			if (_stringEscapeHandling.HasValue && jsonWriter.StringEscapeHandling != _stringEscapeHandling)
			{
				stringEscapeHandling = jsonWriter.StringEscapeHandling;
				jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault();
			}
			CultureInfo cultureInfo = null;
			if (_culture != null && !_culture.Equals(jsonWriter.Culture))
			{
				cultureInfo = jsonWriter.Culture;
				jsonWriter.Culture = _culture;
			}
			string dateFormatString = null;
			if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString)
			{
				dateFormatString = jsonWriter.DateFormatString;
				jsonWriter.DateFormatString = _dateFormatString;
			}
			TraceJsonWriter traceJsonWriter = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null);
			new JsonSerializerInternalWriter(this).Serialize(traceJsonWriter ?? jsonWriter, value, objectType);
			if (traceJsonWriter != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null);
			}
			if (formatting.HasValue)
			{
				jsonWriter.Formatting = formatting.GetValueOrDefault();
			}
			if (dateFormatHandling.HasValue)
			{
				jsonWriter.DateFormatHandling = dateFormatHandling.GetValueOrDefault();
			}
			if (dateTimeZoneHandling.HasValue)
			{
				jsonWriter.DateTimeZoneHandling = dateTimeZoneHandling.GetValueOrDefault();
			}
			if (floatFormatHandling.HasValue)
			{
				jsonWriter.FloatFormatHandling = floatFormatHandling.GetValueOrDefault();
			}
			if (stringEscapeHandling.HasValue)
			{
				jsonWriter.StringEscapeHandling = stringEscapeHandling.GetValueOrDefault();
			}
			if (_dateFormatStringSet)
			{
				jsonWriter.DateFormatString = dateFormatString;
			}
			if (cultureInfo != null)
			{
				jsonWriter.Culture = cultureInfo;
			}
		}

		internal IReferenceResolver GetReferenceResolver()
		{
			if (_referenceResolver == null)
			{
				_referenceResolver = new DefaultReferenceResolver();
			}
			return _referenceResolver;
		}

		internal JsonConverter? GetMatchingConverter(Type type)
		{
			return GetMatchingConverter(_converters, type);
		}

		internal static JsonConverter? GetMatchingConverter(IList<JsonConverter>? converters, Type objectType)
		{
			if (converters != null)
			{
				for (int i = 0; i < converters.Count; i++)
				{
					JsonConverter jsonConverter = converters[i];
					if (jsonConverter.CanConvert(objectType))
					{
						return jsonConverter;
					}
				}
			}
			return null;
		}

		internal void OnError(Newtonsoft.Json.Serialization.ErrorEventArgs e)
		{
			this.Error?.Invoke(this, e);
		}
	}
	public class JsonSerializerSettings
	{
		internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error;

		internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore;

		internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;

		internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;

		internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;

		internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;

		internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;

		internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;

		internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default;

		internal static readonly StreamingContext DefaultContext;

		internal const Formatting DefaultFormatting = Formatting.None;

		internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;

		internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;

		internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime;

		internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double;

		internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String;

		internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default;

		internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;

		internal static readonly CultureInfo DefaultCulture;

		internal const bool DefaultCheckAdditionalContent = false;

		internal const string DefaultDateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";

		internal const int DefaultMaxDepth = 64;

		internal Formatting? _formatting;

		internal DateFormatHandling? _dateFormatHandling;

		internal DateTimeZoneHandling? _dateTimeZoneHandling;

		internal DateParseHandling? _dateParseHandling;

		internal FloatFormatHandling? _floatFormatHandling;

		internal FloatParseHandling? _floatParseHandling;

		internal StringEscapeHandling? _stringEscapeHandling;

		internal CultureInfo? _culture;

		internal bool? _checkAdditionalContent;

		internal int? _maxDepth;

		internal bool _maxDepthSet;

		internal string? _dateFormatString;

		internal bool _dateFormatStringSet;

		internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal PreserveReferencesHandling? _preserveReferencesHandling;

		internal NullValueHandling? _nullValueHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal MissingMemberHandling? _missingMemberHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal StreamingContext? _context;

		internal ConstructorHandling? _constructorHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal MetadataPropertyHandling? _metadataPropertyHandling;

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public IList<JsonConverter> Converters { get; set; }

		public PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling.GetValueOrDef

SpotifyAPI.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using SpotifyAPI.Responses;

[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyCopyright("-")]
[assembly: Guid("4eafb96e-8d2b-436a-86ef-1363f2a648dc")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyTrademark("-")]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyTitle("SpotifyAPI")]
[assembly: AssemblyDescription("SpotifyAPI")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Tim Potze")]
[assembly: AssemblyProduct("SpotifyAPI")]
[assembly: AssemblyVersion("1.2.0.0")]
namespace SpotifyAPI
{
	public abstract class ResourcePromise<T> where T : ResourcePromise<T>.BaseResource
	{
		public abstract class BaseResource
		{
			[JsonProperty("href")]
			public string Href { get; set; }

			[JsonProperty("id")]
			public string Id { get; set; }

			[JsonProperty("name")]
			public string Name { get; set; }

			[JsonProperty("type")]
			public string Type { get; set; }

			[JsonProperty("uri")]
			public string URI { get; set; }
		}

		protected T PartialResource;

		private T _info;

		public string Name { get; private set; }

		public string URI { get; private set; }

		public string OpenURL => $"http://open.spotify.com/{Type}/{Identifier}";

		public string Identifier => URI.Split(new char[1] { ':' }).LastOrDefault();

		public string Type => URI.Split(new char[1] { ':' }).FirstOrDefault((string part) => part != "spotify");

		private T Info
		{
			get
			{
				if (_info != null)
				{
					return _info;
				}
				using HttpClient httpClient = new HttpClient();
				string text = httpClient.GetAsync($"https://api.spotify.com/v1/{Type}s/{Identifier}").Result.Content.ReadAsStringAsync().Result.Replace("\\n", string.Empty);
				return _info = JsonConvert.DeserializeObject<T>(text);
			}
			set
			{
				_info = value;
			}
		}

		internal T this[string key]
		{
			get
			{
				if (PartialResource == null || typeof(T).GetProperty(key).GetMethod.Invoke(PartialResource, null) == null)
				{
					return Info;
				}
				return PartialResource;
			}
		}

		protected ResourcePromise(string name, string uri)
		{
			Name = name;
			URI = uri;
		}

		protected ResourcePromise(T partialResource)
		{
			PartialResource = partialResource;
			Name = partialResource.Name;
			URI = partialResource.URI;
		}

		public override string ToString()
		{
			return Name;
		}
	}
	public class Album : ResourcePromise<Album.Resource>
	{
		public class Resource : BaseResource
		{
			[JsonProperty("artists")]
			public Artist.Resource[] Artists { get; set; }

			[JsonProperty("genres")]
			public string[] Genres { get; set; }

			[JsonProperty("images")]
			public ImageResource[] Images { get; set; }

			[JsonProperty("tracks")]
			public TrackListPart.Resource Tracks { get; set; }

			[JsonProperty("release_date")]
			public string ReleaseDate { get; set; }

			[JsonProperty("release_date_precision")]
			public string ReleaseDatePrecision { get; set; }
		}

		public IEnumerable<string> Genres => base["Genres"].Genres;

		public IEnumerable<Artist> Artists => base["Artists"].Artists.Select((Artist.Resource r) => new Artist(r));

		public IEnumerable<ImageResource> Images => base["Images"].Images;

		public TrackList Tracks => new TrackList(new TrackListPart(base["Tracks"].Tracks, this));

		public string ReleaseDate => base["ReleaseDate"].ReleaseDate;

		public string ReleaseDatePrecision => base["ReleaseDatePrecision"].ReleaseDatePrecision;

		internal Album(string name, string uri)
			: base(name, uri)
		{
		}

		internal Album(Resource partialResource)
			: base(partialResource)
		{
		}
	}
	public class Artist : ResourcePromise<Artist.Resource>
	{
		public class Resource : BaseResource
		{
			[JsonProperty("genres")]
			public string[] Genres { get; set; }

			[JsonProperty("images")]
			public ImageResource[] Images { get; set; }
		}

		public IEnumerable<string> Genres => base["Genres"].Genres;

		public IEnumerable<ImageResource> Images => base["Images"].Images;

		internal Artist(string name, string uri)
			: base(name, uri)
		{
		}

		internal Artist(Resource partialResource)
			: base(partialResource)
		{
		}
	}
	public class ImageResource
	{
		[JsonProperty("width")]
		public int Width { get; set; }

		[JsonProperty("height")]
		public int Height { get; set; }

		[JsonProperty("url")]
		public string URL { get; set; }

		public ImageResource(int width, int height, string url)
		{
			Width = width;
			Height = height;
			URL = url;
		}
	}
}
namespace SpotifyAPI.Responses
{
	internal class CFIDResponse
	{
		[JsonProperty("error")]
		public Error Error { get; set; }

		[JsonProperty("token")]
		public string Token { get; set; }

		[JsonProperty("version")]
		public string Version { get; set; }

		[JsonProperty("client_version")]
		public string ClientVersion { get; set; }

		[JsonProperty("running")]
		public bool Running { get; set; }
	}
	internal class Error
	{
		[JsonProperty("type")]
		public string Type { get; set; }

		[JsonProperty("message")]
		public string Message { get; set; }
	}
	internal class TrackResource
	{
		[JsonProperty("name")]
		public string Name { get; set; }

		[JsonProperty("uri")]
		public string URI { get; set; }
	}
}
namespace SpotifyAPI
{
	public class Spotify
	{
		private string _csrfToken;

		private Track _currentTrack;

		private bool _lastPlaying;

		private double _lastPlayingTime;

		private double _lastVolume;

		private string _oauthToken;

		private Timer timer;

		public Track CurrentTrack
		{
			get
			{
				return _currentTrack;
			}
			set
			{
				if (value != null)
				{
					Process.Start(value.URI);
				}
			}
		}

		public bool IsPlaying { get; private set; }

		public bool IsShuffling { get; private set; }

		public bool IsRepeating { get; private set; }

		public bool IsPlayEnabled { get; private set; }

		public bool IsPreviousEnabled { get; private set; }

		public bool IsNextEnabled { get; private set; }

		public bool IsOnline { get; private set; }

		public bool IsAvailable { get; private set; }

		public double PlayingTime { get; private set; }

		public double Volume { get; private set; }

		public static bool IsRunning => Process.GetProcessesByName("spotify").Length >= 1;

		public static bool IsHelperRunning => Process.GetProcessesByName("SpotifyWebHelper").Length >= 1;

		public event EventHandler TrackChanged;

		public event EventHandler VolumeChanged;

		public event EventHandler PlayStateChanged;

		public event EventHandler PlayingTimeChanged;

		public event EventHandler AvailabilityChanged;

		public Spotify()
		{
			RunHelper();
			Update().Wait();
		}

		private async Task Boot()
		{
			Task<string> csrf = GetCFIDToken();
			Task<string> oauth = GetOAuthToken();
			_csrfToken = await csrf;
			_oauthToken = await oauth;
		}

		public void AutoUpdate(int interval)
		{
			Update();
			if (timer == null)
			{
				timer = new Timer(delegate
				{
					Update().Wait();
				}, this, 0, interval);
			}
		}

		public void StopAutoUpdate()
		{
			if (timer != null)
			{
				timer.Dispose();
			}
		}

		public async Task Update()
		{
			if ((!IsRunning || !IsHelperRunning) && IsAvailable)
			{
				IsAvailable = false;
				if (this.AvailabilityChanged != null)
				{
					this.AvailabilityChanged(this, EventArgs.Empty);
				}
			}
			if (IsRunning && IsHelperRunning && !IsAvailable)
			{
				IsAvailable = true;
				if (this.AvailabilityChanged != null)
				{
					this.AvailabilityChanged(this, EventArgs.Empty);
				}
				await Boot();
			}
			if (IsRunning && !IsHelperRunning)
			{
				RunHelper();
			}
			else
			{
				if (!IsAvailable)
				{
					return;
				}
				StatusResponse status = await QueryStatus();
				if (_currentTrack == null || _currentTrack.URI != status.TrackInfo.TrackResource.URI)
				{
					_currentTrack = new Track(status.TrackInfo.TrackResource.Name, status.TrackInfo.TrackResource.URI, status.TrackInfo.Length, new Artist(status.TrackInfo.ArtistResource.Name, status.TrackInfo.ArtistResource.URI), new Album(status.TrackInfo.AlbumResource.Name, status.TrackInfo.AlbumResource.URI));
					if (this.TrackChanged != null)
					{
						this.TrackChanged(this, EventArgs.Empty);
					}
				}
				IsPlaying = status.Playing;
				IsShuffling = status.Shuffle;
				IsRepeating = status.Repeat;
				IsPlayEnabled = status.PlayEnabled;
				IsPreviousEnabled = status.PrevEnabled;
				IsNextEnabled = status.NextEnabled;
				IsOnline = status.Online;
				PlayingTime = status.PlayingPosition;
				Volume = status.Volume;
				if (_lastVolume != Volume && this.VolumeChanged != null)
				{
					this.VolumeChanged(this, EventArgs.Empty);
				}
				if (_lastPlaying != IsPlaying && this.PlayStateChanged != null)
				{
					this.PlayStateChanged(this, EventArgs.Empty);
				}
				if (_lastPlayingTime != PlayingTime && this.PlayingTimeChanged != null)
				{
					this.PlayingTimeChanged(this, EventArgs.Empty);
				}
				_lastPlaying = IsPlaying;
				_lastVolume = Volume;
				_lastPlayingTime = PlayingTime;
			}
		}

		public override string ToString()
		{
			return string.Format("Spotify(PlayingTime: {1}:{2:00}, CurrentTrack: {0})", CurrentTrack, (int)PlayingTime / 60, (int)PlayingTime % 60);
		}

		public static void RunHelper()
		{
			if (!IsHelperRunning)
			{
				Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Spotify\\Data\\SpotifyWebHelper.exe");
			}
		}

		public static void Run()
		{
			if (!IsRunning)
			{
				Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Spotify\\spotify.exe");
			}
		}

		internal async Task<string> GetCFIDToken()
		{
			string text = (await Query("simplecsrf/token.json", oauth: false, cfid: false)).Replace("\\", "");
			string raw = text;
			CFIDResponse response = JsonConvert.DeserializeObject<CFIDResponse>(raw);
			if (response == null || response.Error != null)
			{
				throw new Exception("CFID couldn't be loaded");
			}
			return response.Token;
		}

		internal async Task<string> GetOAuthToken()
		{
			string raw;
			using (HttpClient wc = new HttpClient())
			{
				raw = await wc.GetStringAsync("http://open.spotify.com/token");
			}
			Dictionary<string, object> response = JsonConvert.DeserializeObject<Dictionary<string, object>>(raw);
			return (string)response["t"];
		}

		internal async Task<StatusResponse> QueryStatus()
		{
			string response = await Query("remote/status.json", oauth: true, cfid: true);
			if (string.IsNullOrEmpty(response))
			{
				return null;
			}
			return JsonConvert.DeserializeObject<StatusResponse>(response);
		}

		internal async Task<string> Query(string request, bool oauth, bool cfid)
		{
			string parameters = "?ref=&cors=&_=" + Timestamp.Generate();
			if (oauth)
			{
				parameters = parameters + "&oauth=" + _oauthToken;
			}
			if (cfid)
			{
				parameters = parameters + "&csrf=" + _csrfToken;
			}
			string a = "http://localhost:4380/" + request + parameters;
			using HttpClient httpClient = new HttpClient();
			httpClient.DefaultRequestHeaders.Add("Origin", "https://embed.spotify.com");
			return (await httpClient.GetStringAsync(a)).Replace("\\n", string.Empty);
		}
	}
}
namespace SpotifyAPI.Responses
{
	internal class StatusResponse
	{
		[JsonProperty("version")]
		public string Version { get; set; }

		[JsonProperty("client_version")]
		public string ClientVersion { get; set; }

		[JsonProperty("running")]
		public bool Running { get; set; }

		[JsonProperty("playing")]
		public bool Playing { get; set; }

		[JsonProperty("shuffle")]
		public bool Shuffle { get; set; }

		[JsonProperty("repeat")]
		public bool Repeat { get; set; }

		[JsonProperty("play_enabled")]
		public bool PlayEnabled { get; set; }

		[JsonProperty("prev_enabled")]
		public bool PrevEnabled { get; set; }

		[JsonProperty("next_enabled")]
		public bool NextEnabled { get; set; }

		[JsonProperty("track")]
		public TrackInfo TrackInfo { get; set; }

		[JsonProperty("playing_position")]
		public double PlayingPosition { get; set; }

		[JsonProperty("server_time")]
		public int ServerTime { get; set; }

		[JsonProperty("volume")]
		public double Volume { get; set; }

		[JsonProperty("online")]
		public bool Online { get; set; }
	}
}
namespace SpotifyAPI
{
	public class Track : ResourcePromise<Track.Resource>
	{
		public class Resource : BaseResource
		{
			[JsonProperty("album")]
			public Album.Resource Album { get; set; }

			[JsonProperty("artists")]
			public Artist.Resource[] Artists { get; set; }

			[JsonProperty("duration_ms")]
			public int Duration { get; set; }
		}

		private Artist _artist;

		public Artist Artist
		{
			get
			{
				return _artist ?? Artists.FirstOrDefault();
			}
			private set
			{
				_artist = value;
			}
		}

		public Album Album { get; private set; }

		public int Length { get; private set; }

		public ImageResource[] AlbumImages => base["Album"].Album.Images;

		public IEnumerable<Artist> Artists => base["Artists"].Artists.Select((Artist.Resource r) => new Artist(r));

		internal Track(string name, string uri, int length, Artist artist, Album album)
			: base(name, uri)
		{
			Length = length * 1000;
			Artist = artist;
			Album = album;
		}

		internal Track(Resource partialResource)
			: base(partialResource)
		{
			Length = base["Duration"].Duration;
		}

		internal Track(Resource partialResource, Album album)
			: this(partialResource)
		{
			Album = album;
		}

		public override string ToString()
		{
			return string.Format("{1} - {0} ({2}) ({3}:{4:00})", base.Name, Artist, Album, Length / 1000 / 60, Length / 1000 % 60);
		}

		public override bool Equals(object obj)
		{
			if (object.ReferenceEquals(null, obj))
			{
				return false;
			}
			if (object.ReferenceEquals(this, obj))
			{
				return true;
			}
			if (obj.GetType() != GetType())
			{
				return false;
			}
			return Equals((Track)obj);
		}

		protected bool Equals(Track other)
		{
			if (other != null)
			{
				return other.Identifier == base.Identifier;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return base.Identifier.GetHashCode();
		}
	}
	internal static class Timestamp
	{
		public static int Generate()
		{
			return Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);
		}
	}
}
namespace SpotifyAPI.Responses
{
	internal class TrackInfo
	{
		[JsonProperty("track_resource")]
		public TrackResource TrackResource { get; set; }

		[JsonProperty("artist_resource")]
		public TrackResource ArtistResource { get; set; }

		[JsonProperty("album_resource")]
		public TrackResource AlbumResource { get; set; }

		[JsonProperty("length")]
		public int Length { get; set; }

		[JsonProperty("track_type")]
		public string TrackType { get; set; }
	}
}
namespace SpotifyAPI
{
	public class TrackList : IEnumerable<Track>, IEnumerable
	{
		private readonly List<TrackListPart> _parts = new List<TrackListPart>();

		public int Count => _parts.First().Total;

		public Track this[int index]
		{
			get
			{
				if (index < 0 || index >= Count)
				{
					throw new IndexOutOfRangeException();
				}
				TrackListPart trackListPart = _parts.FirstOrDefault((TrackListPart p) => p.Offset <= index && p.Offset + p.Tracks.Count() > index);
				if (trackListPart != null)
				{
					return trackListPart.Tracks.ElementAt(index - trackListPart.Offset);
				}
				TrackListPart trackListPart2 = _parts.Last();
				while (trackListPart2.Offset + trackListPart2.Tracks.Count() < index)
				{
					trackListPart2 = trackListPart2.Next;
					_parts.Add(trackListPart2);
				}
				return trackListPart2.Tracks.ElementAt(index - trackListPart2.Offset);
			}
		}

		internal TrackList(TrackListPart first)
		{
			while (first.Offset != 0)
			{
				_parts.Insert(0, first);
				first = first.Previous;
			}
			_parts.Insert(0, first);
		}

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

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	public class TrackListPart : ResourcePromise<TrackListPart.Resource>
	{
		public class Resource : BaseResource
		{
			[JsonProperty("items")]
			public Track.Resource[] Items { get; set; }

			[JsonProperty("next")]
			public string Next { get; set; }

			[JsonProperty("previous")]
			public string Previous { get; set; }

			[JsonProperty("offset")]
			public int Offset { get; set; }

			[JsonProperty("total")]
			public int Total { get; set; }
		}

		private readonly Album _album;

		private TrackListPart _next;

		private TrackListPart _previous;

		public IEnumerable<Track> Tracks => base["Items"].Items.Select((Track.Resource r) => new Track(r, _album));

		public TrackListPart Next
		{
			get
			{
				object obj = _next;
				if (obj == null)
				{
					if (base["Next"].Next != null)
					{
						return _next = new TrackListPart(base["Next"].Next, _album);
					}
					obj = null;
				}
				return (TrackListPart)obj;
			}
		}

		public TrackListPart Previous
		{
			get
			{
				object obj = _previous;
				if (obj == null)
				{
					if (base["Previous"].Previous != null)
					{
						return _previous = new TrackListPart(base["Previous"].Previous, _album);
					}
					obj = null;
				}
				return (TrackListPart)obj;
			}
		}

		public int Offset => base["Offset"].Offset;

		public int Total => base["Total"].Total;

		internal TrackListPart(string url, Album album)
			: base((string)null, (string)null)
		{
			_album = album;
			using WebClient webClient = new WebClient();
			string text = webClient.DownloadString(url);
			PartialResource = JsonConvert.DeserializeObject<Resource>(text);
		}

		internal TrackListPart(Resource partialResource, Album album)
			: base(partialResource)
		{
			_album = album;
		}
	}
}

SpotifyAPI.Web.Auth.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using EmbedIO;
using EmbedIO.Actions;
using EmbedIO.Files;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("SpotifyAPI.Web.Tests")]
[assembly: CLSCompliant(true)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Jonas Dellinger")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("\n      An embedded Web Server, based on EmbeddedIO, for Spotify Web API Authorization flows\n\n      For more infos, visit https://github.com/JohnnyCrazy/SpotifyAPI-NET\n    ")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+29d01ac201eb5eab49f0c69c76a976fc7fdcd948")]
[assembly: AssemblyProduct("SpotifyAPI.Web.Auth")]
[assembly: AssemblyTitle("SpotifyAPI.Web.Auth")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JohnnyCrazy/SpotifyAPI-NET")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SpotifyAPI.Web
{
	internal static class Ensure
	{
		public static void ArgumentNotNull(object value, string name)
		{
			if (value != null)
			{
				return;
			}
			throw new ArgumentNullException(name);
		}

		public static void ArgumentNotNullOrEmptyString(string value, string name)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return;
			}
			throw new ArgumentException("String is empty or null", name);
		}

		public static void ArgumentNotNullOrEmptyList<T>(IEnumerable<T> value, string name)
		{
			if (value != null && value.Any())
			{
				return;
			}
			throw new ArgumentException("List is empty or null", name);
		}
	}
}
namespace SpotifyAPI.Web.Auth
{
	[Serializable]
	public class AuthException : Exception
	{
		public string? Error { get; set; }

		public string? State { get; set; }

		public AuthException(string? error, string? state)
		{
			Error = error;
			State = state;
		}

		public AuthException(string message)
			: base(message)
		{
		}

		public AuthException(string message, Exception inner)
			: base(message, inner)
		{
		}

		protected AuthException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	public static class BrowserUtil
	{
		public static void Open(Uri uri)
		{
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				string text = uri.ToString().Replace("&", "^&");
				Process.Start(new ProcessStartInfo("cmd", "/c start " + text));
			}
			else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
			{
				Process.Start("xdg-open", uri.ToString());
			}
			else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
			{
				Process.Start("open", uri.ToString());
			}
		}
	}
	public class EmbedIOAuthServer : IAuthServer, IDisposable
	{
		private const string AssetsResourcePath = "SpotifyAPI.Web.Auth.Resources.auth_assets";

		private const string DefaultResourcePath = "SpotifyAPI.Web.Auth.Resources.default_site";

		private CancellationTokenSource? _cancelTokenSource;

		private readonly WebServer _webServer;

		public Uri BaseUri { get; }

		public int Port { get; }

		public event Func<object, AuthorizationCodeResponse, Task>? AuthorizationCodeReceived;

		public event Func<object, ImplictGrantResponse, Task>? ImplictGrantReceived;

		public event Func<object, string, string?, Task>? ErrorReceived;

		public EmbedIOAuthServer(Uri baseUri, int port)
			: this(baseUri, port, Assembly.GetExecutingAssembly(), "SpotifyAPI.Web.Auth.Resources.default_site")
		{
		}

		public EmbedIOAuthServer(Uri baseUri, int port, Assembly resourceAssembly, string resourcePath)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0042: Expected O, but got Unknown
			Ensure.ArgumentNotNull(baseUri, "baseUri");
			BaseUri = baseUri;
			Port = port;
			_webServer = WebModuleContainerExtensions.WithEmbeddedResources<WebServer>(WebModuleContainerExtensions.WithEmbeddedResources<WebServer>(WebModuleContainerExtensions.WithModule<WebServer>(new WebServer(port), (IWebModule)new ActionModule("/", (HttpVerbs)6, (RequestHandlerCallback)delegate(IHttpContext ctx)
			{
				NameValueCollection queryString = ctx.Request.QueryString;
				string text = queryString["error"];
				if (text != null)
				{
					this.ErrorReceived?.Invoke(this, text, queryString["state"]);
					throw new AuthException(text, queryString["state"]);
				}
				string? text2 = queryString.Get("request_type");
				if (text2 == "token")
				{
					this.ImplictGrantReceived?.Invoke(this, new ImplictGrantResponse(queryString["access_token"], queryString["token_type"], int.Parse(queryString["expires_in"]))
					{
						State = queryString["state"]
					});
				}
				if (text2 == "code")
				{
					this.AuthorizationCodeReceived?.Invoke(this, new AuthorizationCodeResponse(queryString["code"])
					{
						State = queryString["state"]
					});
				}
				return HttpContextExtensions.SendStringAsync(ctx, "OK", "text/plain", Encoding.UTF8);
			})), "/auth_assets", Assembly.GetExecutingAssembly(), "SpotifyAPI.Web.Auth.Resources.auth_assets", (Action<FileModule>)null), baseUri.AbsolutePath, resourceAssembly, resourcePath, (Action<FileModule>)null);
		}

		public Task Start()
		{
			_cancelTokenSource = new CancellationTokenSource();
			WebServerExtensions.Start((IWebServer)(object)_webServer, _cancelTokenSource.Token);
			return Task.CompletedTask;
		}

		public Task Stop()
		{
			_cancelTokenSource?.Cancel();
			return Task.CompletedTask;
		}

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

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				((WebServerBase<WebServerOptions>)(object)_webServer)?.Dispose();
			}
		}
	}
	public interface IAuthServer : IDisposable
	{
		Uri BaseUri { get; }

		event Func<object, AuthorizationCodeResponse, Task> AuthorizationCodeReceived;

		event Func<object, ImplictGrantResponse, Task> ImplictGrantReceived;

		Task Start();

		Task Stop();
	}
	public class AuthorizationCodeResponse
	{
		public string Code { get; set; }

		public string? State { get; set; }

		public AuthorizationCodeResponse(string code)
		{
			Ensure.ArgumentNotNullOrEmptyString(code, "code");
			Code = code;
		}
	}
	public class ImplictGrantResponse
	{
		public string AccessToken { get; set; }

		public string TokenType { get; set; }

		public int ExpiresIn { get; set; }

		public string? State { get; set; }

		public DateTime CreatedAt { get; set; } = DateTime.UtcNow;


		public bool IsExpired => CreatedAt.AddSeconds(ExpiresIn) <= DateTime.UtcNow;

		public ImplictGrantResponse(string accessToken, string tokenType, int expiresIn)
		{
			Ensure.ArgumentNotNullOrEmptyString(accessToken, "accessToken");
			Ensure.ArgumentNotNullOrEmptyString(tokenType, "tokenType");
			AccessToken = accessToken;
			TokenType = tokenType;
			ExpiresIn = expiresIn;
		}
	}
}

SpotifyAPI.Web.dll

Decompiled 6 days ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using SpotifyAPI.Web.Http;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("SpotifyAPI.Web.Tests")]
[assembly: CLSCompliant(true)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Jonas Dellinger")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("\n      A Client for Spotify's Web API, written in .NET\n\n      For more infos, visit https://github.com/JohnnyCrazy/SpotifyAPI-NET\n    ")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+29d01ac201eb5eab49f0c69c76a976fc7fdcd948")]
[assembly: AssemblyProduct("SpotifyAPI.Web")]
[assembly: AssemblyTitle("SpotifyAPI.Web")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JohnnyCrazy/SpotifyAPI-NET")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SpotifyAPI.Web
{
	public class AuthorizationCodeAuthenticator : IAuthenticator
	{
		public string ClientId { get; }

		public string ClientSecret { get; }

		public AuthorizationCodeTokenResponse InitialToken { get; }

		public event EventHandler<AuthorizationCodeTokenResponse>? TokenRefreshed;

		public AuthorizationCodeAuthenticator(string clientId, string clientSecret, AuthorizationCodeTokenResponse initialToken)
		{
			Ensure.ArgumentNotNull(clientId, "clientId");
			Ensure.ArgumentNotNull(clientSecret, "clientSecret");
			Ensure.ArgumentNotNull(initialToken, "initialToken");
			InitialToken = initialToken;
			ClientId = clientId;
			ClientSecret = clientSecret;
		}

		public async Task Apply(IRequest request, IAPIConnector apiConnector)
		{
			Ensure.ArgumentNotNull(request, "request");
			if (InitialToken.IsExpired)
			{
				AuthorizationCodeRefreshResponse authorizationCodeRefreshResponse = await OAuthClient.RequestToken(new AuthorizationCodeRefreshRequest(ClientId, ClientSecret, InitialToken.RefreshToken), apiConnector).ConfigureAwait(continueOnCapturedContext: false);
				InitialToken.AccessToken = authorizationCodeRefreshResponse.AccessToken;
				InitialToken.CreatedAt = authorizationCodeRefreshResponse.CreatedAt;
				InitialToken.ExpiresIn = authorizationCodeRefreshResponse.ExpiresIn;
				InitialToken.Scope = authorizationCodeRefreshResponse.Scope;
				InitialToken.TokenType = authorizationCodeRefreshResponse.TokenType;
				if (authorizationCodeRefreshResponse.RefreshToken != null)
				{
					InitialToken.RefreshToken = authorizationCodeRefreshResponse.RefreshToken;
				}
				this.TokenRefreshed?.Invoke(this, InitialToken);
			}
			request.Headers["Authorization"] = InitialToken.TokenType + " " + InitialToken.AccessToken;
		}
	}
	public class ClientCredentialsAuthenticator : IAuthenticator
	{
		public ClientCredentialsTokenResponse? Token { get; private set; }

		public string ClientId { get; }

		public string ClientSecret { get; }

		public ClientCredentialsAuthenticator(string clientId, string clientSecret)
			: this(clientId, clientSecret, null)
		{
		}

		public ClientCredentialsAuthenticator(string clientId, string clientSecret, ClientCredentialsTokenResponse? token)
		{
			Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
			Ensure.ArgumentNotNullOrEmptyString(clientSecret, "clientSecret");
			ClientId = clientId;
			ClientSecret = clientSecret;
			Token = token;
		}

		public async Task Apply(IRequest request, IAPIConnector apiConnector)
		{
			Ensure.ArgumentNotNull(request, "request");
			if (Token == null || Token.IsExpired)
			{
				Token = await OAuthClient.RequestToken(new ClientCredentialsRequest(ClientId, ClientSecret), apiConnector).ConfigureAwait(continueOnCapturedContext: false);
			}
			request.Headers["Authorization"] = Token.TokenType + " " + Token.AccessToken;
		}
	}
	public interface IAuthenticator
	{
		Task Apply(IRequest request, IAPIConnector apiConnector);
	}
	public class PKCEAuthenticator : IAuthenticator
	{
		public string ClientId { get; }

		public PKCETokenResponse InitialToken { get; }

		public event EventHandler<PKCETokenResponse>? TokenRefreshed;

		public PKCEAuthenticator(string clientId, PKCETokenResponse initialToken)
		{
			Ensure.ArgumentNotNull(clientId, "clientId");
			Ensure.ArgumentNotNull(initialToken, "initialToken");
			InitialToken = initialToken;
			ClientId = clientId;
		}

		public async Task Apply(IRequest request, IAPIConnector apiConnector)
		{
			Ensure.ArgumentNotNull(request, "request");
			if (InitialToken.IsExpired)
			{
				PKCETokenResponse pKCETokenResponse = await OAuthClient.RequestToken(new PKCETokenRefreshRequest(ClientId, InitialToken.RefreshToken), apiConnector).ConfigureAwait(continueOnCapturedContext: false);
				InitialToken.AccessToken = pKCETokenResponse.AccessToken;
				InitialToken.CreatedAt = pKCETokenResponse.CreatedAt;
				InitialToken.ExpiresIn = pKCETokenResponse.ExpiresIn;
				InitialToken.Scope = pKCETokenResponse.Scope;
				InitialToken.TokenType = pKCETokenResponse.TokenType;
				InitialToken.RefreshToken = pKCETokenResponse.RefreshToken;
				this.TokenRefreshed?.Invoke(this, InitialToken);
			}
			request.Headers["Authorization"] = InitialToken.TokenType + " " + InitialToken.AccessToken;
		}
	}
	public class TokenAuthenticator : IAuthenticator
	{
		public string Token { get; set; }

		public string TokenType { get; set; }

		public TokenAuthenticator(string token, string tokenType)
		{
			Token = token;
			TokenType = tokenType;
		}

		public Task Apply(IRequest request, IAPIConnector apiConnector)
		{
			Ensure.ArgumentNotNull(request, "request");
			request.Headers["Authorization"] = TokenType + " " + Token;
			return Task.CompletedTask;
		}
	}
	public class AlbumsClient : APIClient, IAlbumsClient
	{
		public AlbumsClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<FullAlbum> Get(string albumId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(albumId, "albumId");
			return base.API.Get<FullAlbum>(SpotifyUrls.Album(albumId), cancel);
		}

		public Task<FullAlbum> Get(string albumId, AlbumRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(albumId, "albumId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullAlbum>(SpotifyUrls.Album(albumId), request.BuildQueryParams(), cancel);
		}

		public Task<AlbumsResponse> GetSeveral(AlbumsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<AlbumsResponse>(SpotifyUrls.Albums(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SimpleTrack>> GetTracks(string albumId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(albumId, "albumId");
			return base.API.Get<Paging<SimpleTrack>>(SpotifyUrls.AlbumTracks(albumId), cancel);
		}

		public Task<Paging<SimpleTrack>> GetTracks(string albumId, AlbumTracksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(albumId, "albumId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SimpleTrack>>(SpotifyUrls.AlbumTracks(albumId), request.BuildQueryParams(), cancel);
		}
	}
	public abstract class APIClient
	{
		protected IAPIConnector API { get; set; }

		protected APIClient(IAPIConnector apiConnector)
		{
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			API = apiConnector;
		}
	}
	public class ArtistsClient : APIClient, IArtistsClient
	{
		public ArtistsClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<FullArtist> Get(string artistId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(artistId, "artistId");
			return base.API.Get<FullArtist>(SpotifyUrls.Artist(artistId), cancel);
		}

		public Task<FullArtist> Get(string artistId, ArtistRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(artistId, "artistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullArtist>(SpotifyUrls.Artist(artistId), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SimpleAlbum>> GetAlbums(string artistId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(artistId, "artistId");
			return base.API.Get<Paging<SimpleAlbum>>(SpotifyUrls.ArtistAlbums(artistId), cancel);
		}

		public Task<Paging<SimpleAlbum>> GetAlbums(string artistId, ArtistsAlbumsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(artistId, "artistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SimpleAlbum>>(SpotifyUrls.ArtistAlbums(artistId), request.BuildQueryParams(), cancel);
		}

		public Task<ArtistsRelatedArtistsResponse> GetRelatedArtists(string artistId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(artistId, "artistId");
			return base.API.Get<ArtistsRelatedArtistsResponse>(SpotifyUrls.ArtistRelatedArtists(artistId), cancel);
		}

		public Task<ArtistsRelatedArtistsResponse> GetRelatedArtists(string artistId, ArtistsRelatedArtistsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(artistId, "artistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<ArtistsRelatedArtistsResponse>(SpotifyUrls.ArtistRelatedArtists(artistId), request.BuildQueryParams(), cancel);
		}

		public Task<ArtistsResponse> GetSeveral(ArtistsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<ArtistsResponse>(SpotifyUrls.Artists(), request.BuildQueryParams(), cancel);
		}

		public Task<ArtistsTopTracksResponse> GetTopTracks(string artistId, ArtistsTopTracksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(artistId, "artistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<ArtistsTopTracksResponse>(SpotifyUrls.ArtistTopTracks(artistId), request.BuildQueryParams(), cancel);
		}
	}
	public class AudiobooksClient : APIClient, IAudiobooksClient
	{
		public AudiobooksClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<FullAudiobook> Get(string audiobookId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(audiobookId, "audiobookId");
			return base.API.Get<FullAudiobook>(SpotifyUrls.Audiobook(audiobookId), cancel);
		}

		public Task<FullAudiobook> Get(string audiobookId, AudiobookRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(audiobookId, "audiobookId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullAudiobook>(SpotifyUrls.Audiobook(audiobookId), request.BuildQueryParams(), cancel);
		}

		public Task<AudiobooksResponse> GetSeveral(AudiobooksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<AudiobooksResponse>(SpotifyUrls.Audiobooks(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SimpleAudiobookChapter>> GetChapters(string audiobookId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(audiobookId, "audiobookId");
			return base.API.Get<Paging<SimpleAudiobookChapter>>(SpotifyUrls.AudiobookChapters(audiobookId), cancel);
		}

		public Task<Paging<SimpleAudiobookChapter>> GetChapters(string audiobookId, AudiobookChaptersRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(audiobookId, "audiobookId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SimpleAudiobookChapter>>(SpotifyUrls.AudiobookChapters(audiobookId), request.BuildQueryParams(), cancel);
		}
	}
	public class BrowseClient : APIClient, IBrowseClient
	{
		public BrowseClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<CategoriesResponse> GetCategories(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<CategoriesResponse>(SpotifyUrls.Categories(), cancel);
		}

		public Task<CategoriesResponse> GetCategories(CategoriesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<CategoriesResponse>(SpotifyUrls.Categories(), request.BuildQueryParams(), cancel);
		}

		public Task<Category> GetCategory(string categoryId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(categoryId, "categoryId");
			return base.API.Get<Category>(SpotifyUrls.Category(categoryId), cancel);
		}

		public Task<Category> GetCategory(string categoryId, CategoryRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(categoryId, "categoryId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Category>(SpotifyUrls.Category(categoryId), request.BuildQueryParams(), cancel);
		}

		public Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(categoryId, "categoryId");
			return base.API.Get<CategoryPlaylistsResponse>(SpotifyUrls.CategoryPlaylists(categoryId), cancel);
		}

		public Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId, CategoriesPlaylistsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(categoryId, "categoryId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<CategoryPlaylistsResponse>(SpotifyUrls.CategoryPlaylists(categoryId), request.BuildQueryParams(), cancel);
		}

		public Task<RecommendationsResponse> GetRecommendations(RecommendationsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<RecommendationsResponse>(SpotifyUrls.Recommendations(), request.BuildQueryParams(), cancel);
		}

		public Task<RecommendationGenresResponse> GetRecommendationGenres(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<RecommendationGenresResponse>(SpotifyUrls.RecommendationGenres(), cancel);
		}

		public Task<NewReleasesResponse> GetNewReleases(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<NewReleasesResponse>(SpotifyUrls.NewReleases(), cancel);
		}

		public Task<NewReleasesResponse> GetNewReleases(NewReleasesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<NewReleasesResponse>(SpotifyUrls.NewReleases(), request.BuildQueryParams(), cancel);
		}

		public Task<FeaturedPlaylistsResponse> GetFeaturedPlaylists(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<FeaturedPlaylistsResponse>(SpotifyUrls.FeaturedPlaylists(), cancel);
		}

		public Task<FeaturedPlaylistsResponse> GetFeaturedPlaylists(FeaturedPlaylistsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FeaturedPlaylistsResponse>(SpotifyUrls.FeaturedPlaylists(), request.BuildQueryParams(), cancel);
		}
	}
	public class ChaptersClient : APIClient, IChaptersClient
	{
		public ChaptersClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<FullAudiobookChapter> Get(string chapterId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(chapterId, "chapterId");
			return base.API.Get<FullAudiobookChapter>(SpotifyUrls.Chapter(chapterId), cancel);
		}

		public Task<FullAudiobookChapter> Get(string chapterId, ChapterRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(chapterId, "chapterId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullAudiobookChapter>(SpotifyUrls.Chapter(chapterId), request.BuildQueryParams(), cancel);
		}

		public Task<ChaptersResponse> GetSeveral(ChaptersRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<ChaptersResponse>(SpotifyUrls.Chapters(), request.BuildQueryParams(), cancel);
		}
	}
	public class EpisodesClient : APIClient, IEpisodesClient
	{
		public EpisodesClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<FullEpisode> Get(string episodeId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(episodeId, "episodeId");
			return base.API.Get<FullEpisode>(SpotifyUrls.Episode(episodeId), cancel);
		}

		public Task<FullEpisode> Get(string episodeId, EpisodeRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(episodeId, "episodeId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullEpisode>(SpotifyUrls.Episode(episodeId), request.BuildQueryParams(), cancel);
		}

		public Task<EpisodesResponse> GetSeveral(EpisodesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<EpisodesResponse>(SpotifyUrls.Episodes(), request.BuildQueryParams(), cancel);
		}
	}
	public class FollowClient : APIClient, IFollowClient
	{
		public FollowClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<List<bool>> CheckCurrentUser(FollowCheckCurrentUserRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<List<bool>>(SpotifyUrls.CurrentUserFollowerContains(), request.BuildQueryParams(), cancel);
		}

		public Task<List<bool>> CheckPlaylist(string playlistId, FollowCheckPlaylistRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<List<bool>>(SpotifyUrls.PlaylistFollowersContains(playlistId), request.BuildQueryParams(), cancel);
		}

		public async Task<bool> Follow(FollowRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.CurrentUserFollower(), request.BuildQueryParams(), request.BuildBodyParams(), cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> FollowPlaylist(string playlistId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlaylistFollowers(playlistId), null, null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> FollowPlaylist(string playlistId, FollowPlaylistRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlaylistFollowers(playlistId), null, request.BuildBodyParams(), cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public Task<FollowedArtistsResponse> OfCurrentUser(CancellationToken cancel = default(CancellationToken))
		{
			FollowOfCurrentUserRequest request = new FollowOfCurrentUserRequest();
			return OfCurrentUser(request, cancel);
		}

		public Task<FollowedArtistsResponse> OfCurrentUser(FollowOfCurrentUserRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FollowedArtistsResponse>(SpotifyUrls.CurrentUserFollower(), request.BuildQueryParams(), cancel);
		}

		public async Task<bool> Unfollow(UnfollowRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Delete(SpotifyUrls.CurrentUserFollower(), request.BuildQueryParams(), request.BuildBodyParams(), cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> UnfollowPlaylist(string playlistId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Delete(SpotifyUrls.PlaylistFollowers(playlistId), null, null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}
	}
	public interface IAlbumsClient
	{
		Task<AlbumsResponse> GetSeveral(AlbumsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<FullAlbum> Get(string albumId, CancellationToken cancel = default(CancellationToken));

		Task<FullAlbum> Get(string albumId, AlbumRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleTrack>> GetTracks(string albumId, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleTrack>> GetTracks(string albumId, AlbumTracksRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IArtistsClient
	{
		Task<ArtistsResponse> GetSeveral(ArtistsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<FullArtist> Get(string artistId, CancellationToken cancel = default(CancellationToken));

		Task<FullArtist> Get(string artistId, ArtistRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleAlbum>> GetAlbums(string artistId, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleAlbum>> GetAlbums(string artistId, ArtistsAlbumsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<ArtistsTopTracksResponse> GetTopTracks(string artistId, ArtistsTopTracksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<ArtistsRelatedArtistsResponse> GetRelatedArtists(string artistId, CancellationToken cancel = default(CancellationToken));

		Task<ArtistsRelatedArtistsResponse> GetRelatedArtists(string artistId, ArtistsRelatedArtistsRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IAudiobooksClient
	{
		Task<FullAudiobook> Get(string audiobookId, CancellationToken cancel = default(CancellationToken));

		Task<FullAudiobook> Get(string audiobookId, AudiobookRequest request, CancellationToken cancel = default(CancellationToken));

		Task<AudiobooksResponse> GetSeveral(AudiobooksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleAudiobookChapter>> GetChapters(string audiobookId, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleAudiobookChapter>> GetChapters(string audiobookId, AudiobookChaptersRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IBrowseClient
	{
		Task<CategoriesResponse> GetCategories(CancellationToken cancel = default(CancellationToken));

		Task<CategoriesResponse> GetCategories(CategoriesRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Category> GetCategory(string categoryId, CancellationToken cancel = default(CancellationToken));

		Task<Category> GetCategory(string categoryId, CategoryRequest request, CancellationToken cancel = default(CancellationToken));

		Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId, CancellationToken cancel = default(CancellationToken));

		Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId, CategoriesPlaylistsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<RecommendationsResponse> GetRecommendations(RecommendationsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<RecommendationGenresResponse> GetRecommendationGenres(CancellationToken cancel = default(CancellationToken));

		Task<NewReleasesResponse> GetNewReleases(CancellationToken cancel = default(CancellationToken));

		Task<NewReleasesResponse> GetNewReleases(NewReleasesRequest request, CancellationToken cancel = default(CancellationToken));

		Task<FeaturedPlaylistsResponse> GetFeaturedPlaylists(CancellationToken cancel = default(CancellationToken));

		Task<FeaturedPlaylistsResponse> GetFeaturedPlaylists(FeaturedPlaylistsRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IChaptersClient
	{
		Task<FullAudiobookChapter> Get(string chapterId, CancellationToken cancel = default(CancellationToken));

		Task<FullAudiobookChapter> Get(string chapterId, ChapterRequest request, CancellationToken cancel = default(CancellationToken));

		Task<ChaptersResponse> GetSeveral(ChaptersRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IEpisodesClient
	{
		Task<FullEpisode> Get(string episodeId, CancellationToken cancel = default(CancellationToken));

		Task<FullEpisode> Get(string episodeId, EpisodeRequest request, CancellationToken cancel = default(CancellationToken));

		Task<EpisodesResponse> GetSeveral(EpisodesRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IFollowClient
	{
		Task<List<bool>> CheckCurrentUser(FollowCheckCurrentUserRequest request, CancellationToken cancel = default(CancellationToken));

		Task<List<bool>> CheckPlaylist(string playlistId, FollowCheckPlaylistRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> Follow(FollowRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> FollowPlaylist(string playlistId, CancellationToken cancel = default(CancellationToken));

		Task<bool> FollowPlaylist(string playlistId, FollowPlaylistRequest request, CancellationToken cancel = default(CancellationToken));

		Task<FollowedArtistsResponse> OfCurrentUser(CancellationToken cancel = default(CancellationToken));

		Task<FollowedArtistsResponse> OfCurrentUser(FollowOfCurrentUserRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> Unfollow(UnfollowRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> UnfollowPlaylist(string playlistId, CancellationToken cancel = default(CancellationToken));
	}
	public interface ILibraryClient
	{
		Task<bool> RemoveAlbums(LibraryRemoveAlbumsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> RemoveTracks(LibraryRemoveTracksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> RemoveShows(LibraryRemoveShowsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> RemoveEpisodes(LibraryRemoveEpisodesRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> RemoveAudiobooks(LibraryRemoveAudiobooksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SaveTracks(LibrarySaveTracksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SaveAlbums(LibrarySaveAlbumsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SaveShows(LibrarySaveShowsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SaveEpisodes(LibrarySaveEpisodesRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SaveAudiobooks(LibrarySaveAudiobooksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<List<bool>> CheckTracks(LibraryCheckTracksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<List<bool>> CheckAlbums(LibraryCheckAlbumsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<List<bool>> CheckShows(LibraryCheckShowsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<List<bool>> CheckEpisodes(LibraryCheckEpisodesRequest request, CancellationToken cancel = default(CancellationToken));

		Task<List<bool>> CheckAudiobooks(LibraryCheckAudiobooksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedTrack>> GetTracks(CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedTrack>> GetTracks(LibraryTracksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedAlbum>> GetAlbums(CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedAlbum>> GetAlbums(LibraryAlbumsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedShow>> GetShows(CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedShow>> GetShows(LibraryShowsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedEpisodes>> GetEpisodes(CancellationToken cancel = default(CancellationToken));

		Task<Paging<SavedEpisodes>> GetEpisodes(LibraryEpisodesRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleAudiobook>> GetAudiobooks(LibraryAudiobooksRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IMarketsClient
	{
		Task<AvailableMarketsResponse> AvailableMarkets(CancellationToken cancel = default(CancellationToken));
	}
	public interface IOAuthClient
	{
		Task<ClientCredentialsTokenResponse> RequestToken(ClientCredentialsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<AuthorizationCodeRefreshResponse> RequestToken(AuthorizationCodeRefreshRequest request, CancellationToken cancel = default(CancellationToken));

		Task<AuthorizationCodeTokenResponse> RequestToken(AuthorizationCodeTokenRequest request, CancellationToken cancel = default(CancellationToken));

		Task<AuthorizationCodeTokenResponse> RequestToken(TokenSwapTokenRequest request, CancellationToken cancel = default(CancellationToken));

		Task<AuthorizationCodeRefreshResponse> RequestToken(TokenSwapRefreshRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IPaginator
	{
		Task<IList<T>> PaginateAll<T>(IPaginatable<T> firstPage, IAPIConnector connector, CancellationToken cancel = default(CancellationToken));

		Task<IList<T>> PaginateAll<T, TNext>(IPaginatable<T, TNext> firstPage, Func<TNext, IPaginatable<T, TNext>> mapper, IAPIConnector connector, CancellationToken cancel = default(CancellationToken));
	}
	public interface IPersonalizationClient
	{
		Task<Paging<FullTrack>> GetTopTracks(CancellationToken cancel = default(CancellationToken));

		Task<Paging<FullTrack>> GetTopTracks(PersonalizationTopRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<FullArtist>> GetTopArtists(CancellationToken cancel = default(CancellationToken));

		Task<Paging<FullArtist>> GetTopArtists(PersonalizationTopRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IPlayerClient
	{
		Task<bool> SkipNext(CancellationToken cancel = default(CancellationToken));

		Task<bool> SkipNext(PlayerSkipNextRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SetRepeat(PlayerSetRepeatRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> TransferPlayback(PlayerTransferPlaybackRequest request, CancellationToken cancel = default(CancellationToken));

		Task<CurrentlyPlaying> GetCurrentlyPlaying(PlayerCurrentlyPlayingRequest request, CancellationToken cancel = default(CancellationToken));

		Task<CurrentlyPlayingContext> GetCurrentPlayback(CancellationToken cancel = default(CancellationToken));

		Task<CurrentlyPlayingContext> GetCurrentPlayback(PlayerCurrentPlaybackRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SeekTo(PlayerSeekToRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SkipPrevious(CancellationToken cancel = default(CancellationToken));

		Task<bool> SkipPrevious(PlayerSkipPreviousRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> ResumePlayback(CancellationToken cancel = default(CancellationToken));

		Task<bool> ResumePlayback(PlayerResumePlaybackRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> PausePlayback(CancellationToken cancel = default(CancellationToken));

		Task<bool> PausePlayback(PlayerPausePlaybackRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> SetVolume(PlayerVolumeRequest request, CancellationToken cancel = default(CancellationToken));

		Task<CursorPaging<PlayHistoryItem>> GetRecentlyPlayed(CancellationToken cancel = default(CancellationToken));

		Task<CursorPaging<PlayHistoryItem>> GetRecentlyPlayed(PlayerRecentlyPlayedRequest request, CancellationToken cancel = default(CancellationToken));

		Task<DeviceResponse> GetAvailableDevices(CancellationToken cancel = default(CancellationToken));

		Task<bool> SetShuffle(PlayerShuffleRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> AddToQueue(PlayerAddToQueueRequest request, CancellationToken cancel = default(CancellationToken));

		Task<QueueResponse> GetQueue(CancellationToken cancel = default(CancellationToken));
	}
	public interface IPlaylistsClient
	{
		Task<SnapshotResponse> RemoveItems(string playlistId, PlaylistRemoveItemsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<SnapshotResponse> AddItems(string playlistId, PlaylistAddItemsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<PlaylistTrack<IPlayableItem>>> GetItems(string playlistId, CancellationToken cancel = default(CancellationToken));

		Task<Paging<PlaylistTrack<IPlayableItem>>> GetItems(string playlistId, PlaylistGetItemsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<FullPlaylist> Create(string userId, PlaylistCreateRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> UploadCover(string playlistId, string base64JpgData, CancellationToken cancel = default(CancellationToken));

		Task<List<Image>> GetCovers(string playlistId, CancellationToken cancel = default(CancellationToken));

		Task<Paging<FullPlaylist>> GetUsers(string userId, CancellationToken cancel = default(CancellationToken));

		Task<Paging<FullPlaylist>> GetUsers(string userId, PlaylistGetUsersRequest request, CancellationToken cancel = default(CancellationToken));

		Task<FullPlaylist> Get(string playlistId, CancellationToken cancel = default(CancellationToken));

		Task<FullPlaylist> Get(string playlistId, PlaylistGetRequest request, CancellationToken cancel = default(CancellationToken));

		Task<SnapshotResponse> ReplaceItems(string playlistId, PlaylistReplaceItemsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<FullPlaylist>> CurrentUsers(CancellationToken cancel = default(CancellationToken));

		Task<Paging<FullPlaylist>> CurrentUsers(PlaylistCurrentUsersRequest request, CancellationToken cancel = default(CancellationToken));

		Task<bool> ChangeDetails(string playlistId, PlaylistChangeDetailsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<SnapshotResponse> ReorderItems(string playlistId, PlaylistReorderItemsRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface ISearchClient
	{
		Task<SearchResponse> Item(SearchRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IShowsClient
	{
		Task<FullShow> Get(string showId, CancellationToken cancel = default(CancellationToken));

		Task<FullShow> Get(string showId, ShowRequest request, CancellationToken cancel = default(CancellationToken));

		Task<ShowsResponse> GetSeveral(ShowsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleEpisode>> GetEpisodes(string showId, CancellationToken cancel = default(CancellationToken));

		Task<Paging<SimpleEpisode>> GetEpisodes(string showId, ShowEpisodesRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface ISpotifyClient
	{
		IPaginator DefaultPaginator { get; }

		IUserProfileClient UserProfile { get; }

		IBrowseClient Browse { get; }

		IShowsClient Shows { get; }

		IPlaylistsClient Playlists { get; }

		ISearchClient Search { get; }

		IFollowClient Follow { get; }

		ITracksClient Tracks { get; }

		IPlayerClient Player { get; }

		IAlbumsClient Albums { get; }

		IArtistsClient Artists { get; }

		IPersonalizationClient Personalization { get; }

		IEpisodesClient Episodes { get; }

		ILibraryClient Library { get; }

		IAudiobooksClient Audiobooks { get; }

		IChaptersClient Chapters { get; }

		IResponse? LastResponse { get; }

		Task<IList<T>> PaginateAll<T>(IPaginatable<T> firstPage, IPaginator? paginator = null, CancellationToken cancellationToken = default(CancellationToken));

		Task<IList<T>> PaginateAll<T, TNext>(IPaginatable<T, TNext> firstPage, Func<TNext, IPaginatable<T, TNext>> mapper, IPaginator? paginator = null, CancellationToken cancellationToken = default(CancellationToken));

		Task<Paging<T>> NextPage<T>(Paging<T> paging);

		Task<CursorPaging<T>> NextPage<T>(CursorPaging<T> cursorPaging);

		Task<TNext> NextPage<T, TNext>(IPaginatable<T, TNext> paginatable);

		Task<Paging<T>> PreviousPage<T>(Paging<T> paging);

		Task<TNext> PreviousPage<T, TNext>(Paging<T, TNext> paging);
	}
	public interface ITracksClient
	{
		Task<TracksResponse> GetSeveral(TracksRequest request, CancellationToken cancel = default(CancellationToken));

		Task<TrackAudioAnalysis> GetAudioAnalysis(string trackId, CancellationToken cancel = default(CancellationToken));

		Task<TrackAudioFeatures> GetAudioFeatures(string trackId, CancellationToken cancel = default(CancellationToken));

		Task<FullTrack> Get(string trackId, CancellationToken cancel = default(CancellationToken));

		Task<FullTrack> Get(string trackId, TrackRequest request, CancellationToken cancel = default(CancellationToken));

		Task<TracksAudioFeaturesResponse> GetSeveralAudioFeatures(TracksAudioFeaturesRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public interface IUserProfileClient
	{
		Task<PrivateUser> Current(CancellationToken cancel = default(CancellationToken));

		Task<PublicUser> Get(string userId, CancellationToken cancel = default(CancellationToken));

		Task<UsersTopTracksResponse> GetTopTracks(UsersTopItemsRequest request, CancellationToken cancel = default(CancellationToken));

		Task<UsersTopArtistsResponse> GetTopArtists(UsersTopItemsRequest request, CancellationToken cancel = default(CancellationToken));
	}
	public class LibraryClient : APIClient, ILibraryClient
	{
		public LibraryClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<List<bool>> CheckAlbums(LibraryCheckAlbumsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<List<bool>>(SpotifyUrls.LibraryAlbumsContains(), request.BuildQueryParams(), cancel);
		}

		public Task<List<bool>> CheckShows(LibraryCheckShowsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<List<bool>>(SpotifyUrls.LibraryShowsContains(), request.BuildQueryParams(), cancel);
		}

		public Task<List<bool>> CheckTracks(LibraryCheckTracksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<List<bool>>(SpotifyUrls.LibraryTracksContains(), request.BuildQueryParams(), cancel);
		}

		public Task<List<bool>> CheckEpisodes(LibraryCheckEpisodesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<List<bool>>(SpotifyUrls.LibraryEpisodesContains(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SavedAlbum>> GetAlbums(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<Paging<SavedAlbum>>(SpotifyUrls.LibraryAlbums(), cancel);
		}

		public Task<Paging<SavedAlbum>> GetAlbums(LibraryAlbumsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SavedAlbum>>(SpotifyUrls.LibraryAlbums(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SavedShow>> GetShows(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<Paging<SavedShow>>(SpotifyUrls.LibraryShows(), cancel);
		}

		public Task<Paging<SavedShow>> GetShows(LibraryShowsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SavedShow>>(SpotifyUrls.LibraryShows(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SavedTrack>> GetTracks(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<Paging<SavedTrack>>(SpotifyUrls.LibraryTracks(), cancel);
		}

		public Task<Paging<SavedTrack>> GetTracks(LibraryTracksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SavedTrack>>(SpotifyUrls.LibraryTracks(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SavedEpisodes>> GetEpisodes(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<Paging<SavedEpisodes>>(SpotifyUrls.LibraryEpisodes(), cancel);
		}

		public Task<Paging<SavedEpisodes>> GetEpisodes(LibraryEpisodesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SavedEpisodes>>(SpotifyUrls.LibraryEpisodes(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SimpleAudiobook>> GetAudiobooks(LibraryAudiobooksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SimpleAudiobook>>(SpotifyUrls.LibraryAudiobooks(), request.BuildQueryParams(), cancel);
		}

		public async Task<bool> RemoveAlbums(LibraryRemoveAlbumsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Delete(SpotifyUrls.LibraryAlbums(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> RemoveShows(LibraryRemoveShowsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Delete(SpotifyUrls.LibraryShows(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> RemoveTracks(LibraryRemoveTracksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Delete(SpotifyUrls.LibraryTracks(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> RemoveEpisodes(LibraryRemoveEpisodesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Delete(SpotifyUrls.LibraryEpisodes(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SaveAlbums(LibrarySaveAlbumsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.LibraryAlbums(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SaveShows(LibrarySaveShowsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.LibraryShows(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SaveTracks(LibrarySaveTracksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.LibraryTracks(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SaveEpisodes(LibrarySaveEpisodesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.LibraryEpisodes(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SaveAudiobooks(LibrarySaveAudiobooksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.LibraryAudiobooks(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> RemoveAudiobooks(LibraryRemoveAudiobooksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Delete(SpotifyUrls.LibraryAudiobooks(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public Task<List<bool>> CheckAudiobooks(LibraryCheckAudiobooksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<List<bool>>(SpotifyUrls.LibraryAudiobooksContains(), request.BuildQueryParams(), cancel);
		}
	}
	public class MarketsClient : APIClient, IMarketsClient
	{
		public MarketsClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<AvailableMarketsResponse> AvailableMarkets(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<AvailableMarketsResponse>(SpotifyUrls.Markets(), cancel);
		}
	}
	public class OAuthClient : APIClient, IOAuthClient
	{
		public OAuthClient()
			: this(SpotifyClientConfig.CreateDefault())
		{
		}

		public OAuthClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public OAuthClient(SpotifyClientConfig config)
			: base(ValidateConfig(config))
		{
		}

		public Task<PKCETokenResponse> RequestToken(PKCETokenRequest request, CancellationToken cancel = default(CancellationToken))
		{
			return RequestToken(request, base.API, cancel);
		}

		public Task<PKCETokenResponse> RequestToken(PKCETokenRefreshRequest request, CancellationToken cancel = default(CancellationToken))
		{
			return RequestToken(request, base.API, cancel);
		}

		public Task<ClientCredentialsTokenResponse> RequestToken(ClientCredentialsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			return RequestToken(request, base.API, cancel);
		}

		public Task<AuthorizationCodeRefreshResponse> RequestToken(AuthorizationCodeRefreshRequest request, CancellationToken cancel = default(CancellationToken))
		{
			return RequestToken(request, base.API, cancel);
		}

		public Task<AuthorizationCodeTokenResponse> RequestToken(AuthorizationCodeTokenRequest request, CancellationToken cancel = default(CancellationToken))
		{
			return RequestToken(request, base.API, cancel);
		}

		public Task<AuthorizationCodeTokenResponse> RequestToken(TokenSwapTokenRequest request, CancellationToken cancel = default(CancellationToken))
		{
			return RequestToken(request, base.API, cancel);
		}

		public Task<AuthorizationCodeRefreshResponse> RequestToken(TokenSwapRefreshRequest request, CancellationToken cancel = default(CancellationToken))
		{
			return RequestToken(request, base.API, cancel);
		}

		public static Task<PKCETokenResponse> RequestToken(PKCETokenRequest request, IAPIConnector apiConnector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			List<KeyValuePair<string, string>> form = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("client_id", request.ClientId),
				new KeyValuePair<string, string>("grant_type", "authorization_code"),
				new KeyValuePair<string, string>("code", request.Code),
				new KeyValuePair<string, string>("redirect_uri", request.RedirectUri.ToString()),
				new KeyValuePair<string, string>("code_verifier", request.CodeVerifier)
			};
			return SendOAuthRequest<PKCETokenResponse>(apiConnector, form, null, null, cancel);
		}

		public static Task<PKCETokenResponse> RequestToken(PKCETokenRefreshRequest request, IAPIConnector apiConnector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			List<KeyValuePair<string, string>> form = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("client_id", request.ClientId),
				new KeyValuePair<string, string>("grant_type", "refresh_token"),
				new KeyValuePair<string, string>("refresh_token", request.RefreshToken)
			};
			return SendOAuthRequest<PKCETokenResponse>(apiConnector, form, null, null, cancel);
		}

		public static Task<AuthorizationCodeRefreshResponse> RequestToken(TokenSwapRefreshRequest request, IAPIConnector apiConnector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			List<KeyValuePair<string, string>> nameValueCollection = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("refresh_token", request.RefreshToken)
			};
			return apiConnector.Post<AuthorizationCodeRefreshResponse>(request.RefreshUri, null, new FormUrlEncodedContent(nameValueCollection), cancel);
		}

		public static Task<AuthorizationCodeTokenResponse> RequestToken(TokenSwapTokenRequest request, IAPIConnector apiConnector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			List<KeyValuePair<string, string>> nameValueCollection = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("code", request.Code)
			};
			return apiConnector.Post<AuthorizationCodeTokenResponse>(request.TokenUri, null, new FormUrlEncodedContent(nameValueCollection), cancel);
		}

		public static Task<ClientCredentialsTokenResponse> RequestToken(ClientCredentialsRequest request, IAPIConnector apiConnector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			List<KeyValuePair<string, string>> form = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("grant_type", "client_credentials")
			};
			return SendOAuthRequest<ClientCredentialsTokenResponse>(apiConnector, form, request.ClientId, request.ClientSecret, cancel);
		}

		public static Task<AuthorizationCodeRefreshResponse> RequestToken(AuthorizationCodeRefreshRequest request, IAPIConnector apiConnector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			List<KeyValuePair<string, string>> form = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("grant_type", "refresh_token"),
				new KeyValuePair<string, string>("refresh_token", request.RefreshToken)
			};
			return SendOAuthRequest<AuthorizationCodeRefreshResponse>(apiConnector, form, request.ClientId, request.ClientSecret, cancel);
		}

		public static Task<AuthorizationCodeTokenResponse> RequestToken(AuthorizationCodeTokenRequest request, IAPIConnector apiConnector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			List<KeyValuePair<string, string>> form = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("grant_type", "authorization_code"),
				new KeyValuePair<string, string>("code", request.Code),
				new KeyValuePair<string, string>("redirect_uri", request.RedirectUri.ToString())
			};
			return SendOAuthRequest<AuthorizationCodeTokenResponse>(apiConnector, form, request.ClientId, request.ClientSecret, cancel);
		}

		private static Task<T> SendOAuthRequest<T>(IAPIConnector apiConnector, List<KeyValuePair<string?, string?>> form, string? clientId, string? clientSecret, CancellationToken cancel = default(CancellationToken))
		{
			Dictionary<string, string> headers = BuildAuthHeader(clientId, clientSecret);
			return apiConnector.Post<T>(SpotifyUrls.OAuthToken, null, new FormUrlEncodedContent(form), headers, cancel);
		}

		private static Dictionary<string, string> BuildAuthHeader(string? clientId, string? clientSecret)
		{
			if (clientId == null || clientSecret == null)
			{
				return new Dictionary<string, string>();
			}
			string text = Convert.ToBase64String(Encoding.UTF8.GetBytes(clientId + ":" + clientSecret));
			return new Dictionary<string, string> { 
			{
				"Authorization",
				"Basic " + text
			} };
		}

		private static APIConnector ValidateConfig(SpotifyClientConfig config)
		{
			Ensure.ArgumentNotNull(config, "config");
			return new APIConnector(config.BaseAddress, config.Authenticator, config.JSONSerializer, config.HTTPClient, config.RetryHandler, config.HTTPLogger);
		}
	}
	public class PersonalizationClient : APIClient, IPersonalizationClient
	{
		public PersonalizationClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<Paging<FullArtist>> GetTopArtists(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<Paging<FullArtist>>(SpotifyUrls.PersonalizationTop("artists"), cancel);
		}

		public Task<Paging<FullArtist>> GetTopArtists(PersonalizationTopRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<FullArtist>>(SpotifyUrls.PersonalizationTop("artists"), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<FullTrack>> GetTopTracks(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<Paging<FullTrack>>(SpotifyUrls.PersonalizationTop("tracks"), cancel);
		}

		public Task<Paging<FullTrack>> GetTopTracks(PersonalizationTopRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<FullTrack>>(SpotifyUrls.PersonalizationTop("tracks"), request.BuildQueryParams(), cancel);
		}
	}
	public class PlayerClient : APIClient, IPlayerClient
	{
		public PlayerClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public async Task<bool> AddToQueue(PlayerAddToQueueRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Post(SpotifyUrls.PlayerQueue(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public Task<QueueResponse> GetQueue(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<QueueResponse>(SpotifyUrls.PlayerQueue(), cancel);
		}

		public Task<DeviceResponse> GetAvailableDevices(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<DeviceResponse>(SpotifyUrls.PlayerDevices(), cancel);
		}

		public Task<CurrentlyPlaying> GetCurrentlyPlaying(PlayerCurrentlyPlayingRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<CurrentlyPlaying>(SpotifyUrls.PlayerCurrentlyPlaying(), request.BuildQueryParams(), cancel);
		}

		public Task<CurrentlyPlayingContext> GetCurrentPlayback(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<CurrentlyPlayingContext>(SpotifyUrls.Player(), cancel);
		}

		public Task<CurrentlyPlayingContext> GetCurrentPlayback(PlayerCurrentPlaybackRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<CurrentlyPlayingContext>(SpotifyUrls.Player(), request.BuildQueryParams(), cancel);
		}

		public Task<CursorPaging<PlayHistoryItem>> GetRecentlyPlayed(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<CursorPaging<PlayHistoryItem>>(SpotifyUrls.PlayerRecentlyPlayed(), cancel);
		}

		public Task<CursorPaging<PlayHistoryItem>> GetRecentlyPlayed(PlayerRecentlyPlayedRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<CursorPaging<PlayHistoryItem>>(SpotifyUrls.PlayerRecentlyPlayed(), request.BuildQueryParams(), cancel);
		}

		public async Task<bool> PausePlayback(CancellationToken cancel = default(CancellationToken))
		{
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerPause(), null, null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> PausePlayback(PlayerPausePlaybackRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerPause(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> ResumePlayback(CancellationToken cancel = default(CancellationToken))
		{
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerResume(), null, null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> ResumePlayback(PlayerResumePlaybackRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerResume(), request.BuildQueryParams(), request.BuildBodyParams(), cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SeekTo(PlayerSeekToRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerSeek(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SetRepeat(PlayerSetRepeatRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerRepeat(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SetShuffle(PlayerShuffleRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerShuffle(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SetVolume(PlayerVolumeRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.PlayerVolume(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SkipNext(CancellationToken cancel = default(CancellationToken))
		{
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Post(SpotifyUrls.PlayerNext(), null, null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SkipNext(PlayerSkipNextRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Post(SpotifyUrls.PlayerNext(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SkipPrevious(CancellationToken cancel = default(CancellationToken))
		{
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Post(SpotifyUrls.PlayerPrevious(), null, null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> SkipPrevious(PlayerSkipPreviousRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Post(SpotifyUrls.PlayerPrevious(), request.BuildQueryParams(), null, cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public async Task<bool> TransferPlayback(PlayerTransferPlaybackRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.Player(), null, request.BuildBodyParams(), cancel).ConfigureAwait(continueOnCapturedContext: false));
		}
	}
	public class PlaylistsClient : APIClient, IPlaylistsClient
	{
		public PlaylistsClient(IAPIConnector connector)
			: base(connector)
		{
		}

		public Task<SnapshotResponse> RemoveItems(string playlistId, PlaylistRemoveItemsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Delete<SnapshotResponse>(SpotifyUrls.PlaylistTracks(playlistId), null, request.BuildBodyParams(), cancel);
		}

		public Task<SnapshotResponse> AddItems(string playlistId, PlaylistAddItemsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Post<SnapshotResponse>(SpotifyUrls.PlaylistTracks(playlistId), null, request.BuildBodyParams(), cancel);
		}

		public Task<Paging<PlaylistTrack<IPlayableItem>>> GetItems(string playlistId, CancellationToken cancel = default(CancellationToken))
		{
			PlaylistGetItemsRequest request = new PlaylistGetItemsRequest();
			return GetItems(playlistId, request, cancel);
		}

		public Task<Paging<PlaylistTrack<IPlayableItem>>> GetItems(string playlistId, PlaylistGetItemsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<PlaylistTrack<IPlayableItem>>>(SpotifyUrls.PlaylistTracks(playlistId), request.BuildQueryParams(), cancel);
		}

		public Task<FullPlaylist> Create(string userId, PlaylistCreateRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(userId, "userId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Post<FullPlaylist>(SpotifyUrls.UserPlaylists(userId), null, request.BuildBodyParams(), cancel);
		}

		public async Task<bool> UploadCover(string playlistId, string base64JpgData, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNullOrEmptyString(base64JpgData, "base64JpgData");
			return await base.API.PutRaw(SpotifyUrls.PlaylistImages(playlistId), null, base64JpgData, cancel).ConfigureAwait(continueOnCapturedContext: false) == HttpStatusCode.Accepted;
		}

		public Task<List<Image>> GetCovers(string playlistId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			return base.API.Get<List<Image>>(SpotifyUrls.PlaylistImages(playlistId), cancel);
		}

		public Task<Paging<FullPlaylist>> GetUsers(string userId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(userId, "userId");
			return base.API.Get<Paging<FullPlaylist>>(SpotifyUrls.UserPlaylists(userId), cancel);
		}

		public Task<Paging<FullPlaylist>> GetUsers(string userId, PlaylistGetUsersRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(userId, "userId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<FullPlaylist>>(SpotifyUrls.UserPlaylists(userId), request.BuildQueryParams(), cancel);
		}

		public Task<FullPlaylist> Get(string playlistId, CancellationToken cancel = default(CancellationToken))
		{
			PlaylistGetRequest request = new PlaylistGetRequest();
			return Get(playlistId, request, cancel);
		}

		public Task<FullPlaylist> Get(string playlistId, PlaylistGetRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullPlaylist>(SpotifyUrls.Playlist(playlistId), request.BuildQueryParams(), cancel);
		}

		public Task<SnapshotResponse> ReplaceItems(string playlistId, PlaylistReplaceItemsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Put<SnapshotResponse>(SpotifyUrls.PlaylistTracks(playlistId), null, request.BuildBodyParams(), cancel);
		}

		public Task<Paging<FullPlaylist>> CurrentUsers(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<Paging<FullPlaylist>>(SpotifyUrls.CurrentUserPlaylists(), cancel);
		}

		public Task<Paging<FullPlaylist>> CurrentUsers(PlaylistCurrentUsersRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<FullPlaylist>>(SpotifyUrls.CurrentUserPlaylists(), request.BuildQueryParams(), cancel);
		}

		public async Task<bool> ChangeDetails(string playlistId, PlaylistChangeDetailsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return HTTPUtil.StatusCodeIsSuccess(await base.API.Put(SpotifyUrls.Playlist(playlistId), null, request.BuildBodyParams(), cancel).ConfigureAwait(continueOnCapturedContext: false));
		}

		public Task<SnapshotResponse> ReorderItems(string playlistId, PlaylistReorderItemsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(playlistId, "playlistId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Put<SnapshotResponse>(SpotifyUrls.PlaylistTracks(playlistId), null, request.BuildBodyParams(), cancel);
		}
	}
	public class SearchClient : APIClient, ISearchClient
	{
		public SearchClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<SearchResponse> Item(SearchRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<SearchResponse>(SpotifyUrls.Search(), request.BuildQueryParams(), cancel);
		}
	}
	public class ShowsClient : APIClient, IShowsClient
	{
		public ShowsClient(IAPIConnector connector)
			: base(connector)
		{
		}

		public Task<FullShow> Get(string showId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(showId, "showId");
			return base.API.Get<FullShow>(SpotifyUrls.Show(showId), cancel);
		}

		public Task<FullShow> Get(string showId, ShowRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(showId, "showId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullShow>(SpotifyUrls.Show(showId), request.BuildQueryParams(), cancel);
		}

		public Task<ShowsResponse> GetSeveral(ShowsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<ShowsResponse>(SpotifyUrls.Shows(), request.BuildQueryParams(), cancel);
		}

		public Task<Paging<SimpleEpisode>> GetEpisodes(string showId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(showId, "showId");
			return base.API.Get<Paging<SimpleEpisode>>(SpotifyUrls.ShowEpisodes(showId), cancel);
		}

		public Task<Paging<SimpleEpisode>> GetEpisodes(string showId, ShowEpisodesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(showId, "showId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<Paging<SimpleEpisode>>(SpotifyUrls.ShowEpisodes(showId), request.BuildQueryParams(), cancel);
		}
	}
	public class SimplePaginator : IPaginator
	{
		protected virtual Task<bool> ShouldContinue<T>(List<T> results, IPaginatable<T> page)
		{
			return Task.FromResult(result: true);
		}

		protected virtual Task<bool> ShouldContinue<T, TNext>(List<T> results, IPaginatable<T, TNext> page)
		{
			return Task.FromResult(result: true);
		}

		public async Task<IList<T>> PaginateAll<T>(IPaginatable<T> firstPage, IAPIConnector connector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(firstPage, "firstPage");
			Ensure.ArgumentNotNull(connector, "connector");
			IPaginatable<T> page = firstPage;
			List<T> results = new List<T>();
			if (page.Items != null)
			{
				results.AddRange(page.Items);
			}
			while (true)
			{
				bool flag = page.Next != null;
				if (flag)
				{
					flag = await ShouldContinue(results, page).ConfigureAwait(continueOnCapturedContext: false);
				}
				if (!flag)
				{
					break;
				}
				page = await connector.Get<Paging<T>>(new Uri(page.Next, UriKind.Absolute), cancel).ConfigureAwait(continueOnCapturedContext: false);
				if (page.Items != null)
				{
					results.AddRange(page.Items);
				}
			}
			return results;
		}

		public async Task<IList<T>> PaginateAll<T, TNext>(IPaginatable<T, TNext> firstPage, Func<TNext, IPaginatable<T, TNext>> mapper, IAPIConnector connector, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(firstPage, "firstPage");
			Ensure.ArgumentNotNull(mapper, "mapper");
			Ensure.ArgumentNotNull(connector, "connector");
			IPaginatable<T, TNext> page = firstPage;
			List<T> results = new List<T>();
			if (page.Items != null)
			{
				results.AddRange(page.Items);
			}
			while (true)
			{
				bool flag = page.Next != null;
				if (flag)
				{
					flag = await ShouldContinue(results, page).ConfigureAwait(continueOnCapturedContext: false);
				}
				if (!flag)
				{
					break;
				}
				page = mapper(await connector.Get<TNext>(new Uri(page.Next, UriKind.Absolute), cancel).ConfigureAwait(continueOnCapturedContext: false));
				if (page.Items != null)
				{
					results.AddRange(page.Items);
				}
			}
			return results;
		}
	}
	public class SpotifyClient : ISpotifyClient
	{
		private readonly IAPIConnector _apiConnector;

		public IPaginator DefaultPaginator { get; }

		public IUserProfileClient UserProfile { get; }

		public IBrowseClient Browse { get; }

		public IShowsClient Shows { get; }

		public IPlaylistsClient Playlists { get; }

		public ISearchClient Search { get; }

		public IFollowClient Follow { get; }

		public ITracksClient Tracks { get; }

		public IPlayerClient Player { get; }

		public IAlbumsClient Albums { get; }

		public IArtistsClient Artists { get; }

		public IPersonalizationClient Personalization { get; }

		public IEpisodesClient Episodes { get; }

		public ILibraryClient Library { get; }

		public IMarketsClient Markets { get; }

		public IAudiobooksClient Audiobooks { get; }

		public IChaptersClient Chapters { get; }

		public IResponse? LastResponse { get; private set; }

		public SpotifyClient(IToken token)
			: this(SpotifyClientConfig.CreateDefault(token?.AccessToken ?? throw new ArgumentNullException("token"), token.TokenType))
		{
		}

		public SpotifyClient(string token, string tokenType = "Bearer")
			: this(SpotifyClientConfig.CreateDefault(token, tokenType))
		{
		}

		public SpotifyClient(SpotifyClientConfig config)
		{
			Ensure.ArgumentNotNull(config, "config");
			if (config.Authenticator == null)
			{
				throw new ArgumentNullException("Authenticator in config is null. Please supply it via `WithAuthenticator` or `WithToken`");
			}
			_apiConnector = config.BuildAPIConnector();
			_apiConnector.ResponseReceived += delegate(object sender, IResponse response)
			{
				LastResponse = response;
			};
			DefaultPaginator = config.DefaultPaginator;
			UserProfile = new UserProfileClient(_apiConnector);
			Browse = new BrowseClient(_apiConnector);
			Shows = new ShowsClient(_apiConnector);
			Playlists = new PlaylistsClient(_apiConnector);
			Search = new SearchClient(_apiConnector);
			Follow = new FollowClient(_apiConnector);
			Tracks = new TracksClient(_apiConnector);
			Player = new PlayerClient(_apiConnector);
			Albums = new AlbumsClient(_apiConnector);
			Artists = new ArtistsClient(_apiConnector);
			Personalization = new PersonalizationClient(_apiConnector);
			Episodes = new EpisodesClient(_apiConnector);
			Library = new LibraryClient(_apiConnector);
			Markets = new MarketsClient(_apiConnector);
			Audiobooks = new AudiobooksClient(_apiConnector);
			Chapters = new ChaptersClient(_apiConnector);
		}

		public Task<IList<T>> PaginateAll<T>(IPaginatable<T> firstPage, IPaginator? paginator = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			return (paginator ?? DefaultPaginator).PaginateAll(firstPage, _apiConnector, cancellationToken);
		}

		public Task<IList<T>> PaginateAll<T, TNext>(IPaginatable<T, TNext> firstPage, Func<TNext, IPaginatable<T, TNext>> mapper, IPaginator? paginator = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			return (paginator ?? DefaultPaginator).PaginateAll(firstPage, mapper, _apiConnector, cancellationToken);
		}

		private Task<T> FetchPage<T>(string? nextUrl)
		{
			if (nextUrl == null)
			{
				throw new APIPagingException("The paging object has no next page");
			}
			return _apiConnector.Get<T>(new Uri(nextUrl, UriKind.Absolute));
		}

		public Task<Paging<T>> NextPage<T>(Paging<T> paging)
		{
			Ensure.ArgumentNotNull(paging, "paging");
			return FetchPage<Paging<T>>(paging.Next);
		}

		public Task<CursorPaging<T>> NextPage<T>(CursorPaging<T> cursorPaging)
		{
			Ensure.ArgumentNotNull(cursorPaging, "cursorPaging");
			return FetchPage<CursorPaging<T>>(cursorPaging.Next);
		}

		public Task<TNext> NextPage<T, TNext>(IPaginatable<T, TNext> paginatable)
		{
			Ensure.ArgumentNotNull(paginatable, "paginatable");
			return FetchPage<TNext>(paginatable.Next);
		}

		public Task<Paging<T>> PreviousPage<T>(Paging<T> paging)
		{
			Ensure.ArgumentNotNull(paging, "paging");
			return FetchPage<Paging<T>>(paging.Previous);
		}

		public Task<TNext> PreviousPage<T, TNext>(Paging<T, TNext> paging)
		{
			Ensure.ArgumentNotNull(paging, "paging");
			return FetchPage<TNext>(paging.Previous);
		}
	}
	public class SpotifyClientConfig
	{
		public Uri BaseAddress { get; private set; }

		public IAuthenticator? Authenticator { get; private set; }

		public IJSONSerializer JSONSerializer { get; private set; }

		public IHTTPClient HTTPClient { get; private set; }

		public IHTTPLogger? HTTPLogger { get; private set; }

		public IRetryHandler? RetryHandler { get; private set; }

		public IPaginator DefaultPaginator { get; private set; }

		public IAPIConnector? APIConnector { get; private set; }

		public SpotifyClientConfig(Uri baseAddress, IAuthenticator? authenticator, IJSONSerializer jsonSerializer, IHTTPClient httpClient, IRetryHandler? retryHandler, IHTTPLogger? httpLogger, IPaginator defaultPaginator, IAPIConnector? apiConnector = null)
		{
			BaseAddress = baseAddress;
			Authenticator = authenticator;
			JSONSerializer = jsonSerializer;
			HTTPClient = httpClient;
			RetryHandler = retryHandler;
			HTTPLogger = httpLogger;
			DefaultPaginator = defaultPaginator;
			APIConnector = apiConnector;
		}

		public SpotifyClientConfig WithToken(string token, string tokenType = "Bearer")
		{
			Ensure.ArgumentNotNull(token, "token");
			return new SpotifyClientConfig(BaseAddress, new TokenAuthenticator(token, tokenType), JSONSerializer, HTTPClient, RetryHandler, HTTPLogger, DefaultPaginator);
		}

		public SpotifyClientConfig WithRetryHandler(IRetryHandler retryHandler)
		{
			return new SpotifyClientConfig(BaseAddress, Authenticator, JSONSerializer, HTTPClient, retryHandler, HTTPLogger, DefaultPaginator);
		}

		public SpotifyClientConfig WithAuthenticator(IAuthenticator authenticator)
		{
			Ensure.ArgumentNotNull(authenticator, "authenticator");
			return new SpotifyClientConfig(BaseAddress, authenticator, JSONSerializer, HTTPClient, RetryHandler, HTTPLogger, DefaultPaginator);
		}

		public SpotifyClientConfig WithHTTPLogger(IHTTPLogger httpLogger)
		{
			return new SpotifyClientConfig(BaseAddress, Authenticator, JSONSerializer, HTTPClient, RetryHandler, httpLogger, DefaultPaginator);
		}

		public SpotifyClientConfig WithHTTPClient(IHTTPClient httpClient)
		{
			Ensure.ArgumentNotNull(httpClient, "httpClient");
			return new SpotifyClientConfig(BaseAddress, Authenticator, JSONSerializer, httpClient, RetryHandler, HTTPLogger, DefaultPaginator);
		}

		public SpotifyClientConfig WithJSONSerializer(IJSONSerializer jsonSerializer)
		{
			Ensure.ArgumentNotNull(jsonSerializer, "jsonSerializer");
			return new SpotifyClientConfig(BaseAddress, Authenticator, jsonSerializer, HTTPClient, RetryHandler, HTTPLogger, DefaultPaginator);
		}

		public SpotifyClientConfig WithDefaultPaginator(IPaginator defaultPaginator)
		{
			Ensure.ArgumentNotNull(defaultPaginator, "defaultPaginator");
			return new SpotifyClientConfig(BaseAddress, Authenticator, JSONSerializer, HTTPClient, RetryHandler, HTTPLogger, defaultPaginator);
		}

		public SpotifyClientConfig WithAPIConnector(IAPIConnector apiConnector)
		{
			Ensure.ArgumentNotNull(apiConnector, "apiConnector");
			return new SpotifyClientConfig(BaseAddress, Authenticator, JSONSerializer, HTTPClient, RetryHandler, HTTPLogger, DefaultPaginator, apiConnector);
		}

		public IAPIConnector BuildAPIConnector()
		{
			return APIConnector ?? new APIConnector(BaseAddress, Authenticator, JSONSerializer, HTTPClient, RetryHandler, HTTPLogger);
		}

		public static SpotifyClientConfig CreateDefault(string token, string tokenType = "Bearer")
		{
			return CreateDefault().WithAuthenticator(new TokenAuthenticator(token, tokenType));
		}

		public static SpotifyClientConfig CreateDefault()
		{
			return new SpotifyClientConfig(SpotifyUrls.APIV1, null, new NewtonsoftJSONSerializer(), new NetHttpClient(), null, null, new SimplePaginator());
		}
	}
	public class TracksClient : APIClient, ITracksClient
	{
		public TracksClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<FullTrack> Get(string trackId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(trackId, "trackId");
			return base.API.Get<FullTrack>(SpotifyUrls.Track(trackId), cancel);
		}

		public Task<FullTrack> Get(string trackId, TrackRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(trackId, "trackId");
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<FullTrack>(SpotifyUrls.Track(trackId), request.BuildQueryParams(), cancel);
		}

		public Task<TrackAudioAnalysis> GetAudioAnalysis(string trackId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(trackId, "trackId");
			return base.API.Get<TrackAudioAnalysis>(SpotifyUrls.AudioAnalysis(trackId), cancel);
		}

		public Task<TrackAudioFeatures> GetAudioFeatures(string trackId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(trackId, "trackId");
			return base.API.Get<TrackAudioFeatures>(SpotifyUrls.AudioFeatures(trackId), cancel);
		}

		public Task<TracksResponse> GetSeveral(TracksRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<TracksResponse>(SpotifyUrls.Tracks(), request.BuildQueryParams(), cancel);
		}

		public Task<TracksAudioFeaturesResponse> GetSeveralAudioFeatures(TracksAudioFeaturesRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<TracksAudioFeaturesResponse>(SpotifyUrls.AudioFeatures(), request.BuildQueryParams(), cancel);
		}
	}
	public class UserProfileClient : APIClient, IUserProfileClient
	{
		public UserProfileClient(IAPIConnector apiConnector)
			: base(apiConnector)
		{
		}

		public Task<PrivateUser> Current(CancellationToken cancel = default(CancellationToken))
		{
			return base.API.Get<PrivateUser>(SpotifyUrls.Me(), cancel);
		}

		public Task<PublicUser> Get(string userId, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNullOrEmptyString(userId, "userId");
			return base.API.Get<PublicUser>(SpotifyUrls.User(userId), cancel);
		}

		public Task<UsersTopTracksResponse> GetTopTracks(UsersTopItemsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<UsersTopTracksResponse>(SpotifyUrls.TopTracks(), request.BuildQueryParams(), cancel);
		}

		public Task<UsersTopArtistsResponse> GetTopArtists(UsersTopItemsRequest request, CancellationToken cancel = default(CancellationToken))
		{
			Ensure.ArgumentNotNull(request, "request");
			return base.API.Get<UsersTopArtistsResponse>(SpotifyUrls.TopArtists(), request.BuildQueryParams(), cancel);
		}
	}
	[Serializable]
	public class APIException : Exception
	{
		public IResponse? Response { get; set; }

		public APIException(IResponse response)
			: base(ParseAPIErrorMessage(response))
		{
			Ensure.ArgumentNotNull(response, "response");
			Response = response;
		}

		public APIException()
		{
		}

		public APIException(string message)
			: base(message)
		{
		}

		public APIException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected APIException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			Response = info.GetValue("APIException.Response", typeof(IResponse)) as IResponse;
		}

		private static string? ParseAPIErrorMessage(IResponse response)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			string text = response.Body as string;
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			try
			{
				JToken val = ((JToken)JObject.Parse(text)).Value<JToken>((object)"error");
				if (val == null)
				{
					return null;
				}
				if ((int)val.Type == 8)
				{
					return ((object)val).ToString();
				}
				if ((int)val.Type == 1)
				{
					return val.Value<string>((object)"message");
				}
			}
			catch (JsonReaderException)
			{
				return null;
			}
			return null;
		}

		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			base.GetObjectData(info, context);
			info.AddValue("APIException.Response", Response);
		}
	}
	[Serializable]
	public class APIPagingException : APIException
	{
		public TimeSpan RetryAfter { get; }

		public APIPagingException(IResponse response)
			: base(response)
		{
			Ensure.ArgumentNotNull(response, "response");
			if (response.Headers.TryGetValue("Retry-After", out string value))
			{
				RetryAfter = TimeSpan.FromSeconds(int.Parse(value, CultureInfo.InvariantCulture));
			}
		}

		public APIPagingException()
		{
		}

		public APIPagingException(string message)
			: base(message)
		{
		}

		public APIPagingException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected APIPagingException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	[Serializable]
	public class APITooManyRequestsException : APIException
	{
		public TimeSpan RetryAfter { get; }

		public APITooManyRequestsException(IResponse response)
			: base(response)
		{
			Ensure.ArgumentNotNull(response, "response");
			if (response.Headers.TryGetValue("Retry-After", out string value))
			{
				RetryAfter = TimeSpan.FromSeconds(int.Parse(value, CultureInfo.InvariantCulture));
			}
		}

		public APITooManyRequestsException()
		{
		}

		public APITooManyRequestsException(string message)
			: base(message)
		{
		}

		public APITooManyRequestsException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected APITooManyRequestsException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	[Serializable]
	public class APIUnauthorizedException : APIException
	{
		public APIUnauthorizedException(IResponse response)
			: base(response)
		{
		}

		public APIUnauthorizedException()
		{
		}

		public APIUnauthorizedException(string message)
			: base(message)
		{
		}

		public APIUnauthorizedException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected APIUnauthorizedException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	public interface IProxyConfig
	{
		string Host { get; }

		int Port { get; }

		string? User { get; }

		string? Password { get; }

		bool SkipSSLCheck { get; }

		bool BypassProxyOnLocal { get; }
	}
	public class ProxyConfig : IProxyConfig
	{
		public string Host { get; }

		public int Port { get; }

		public string? User { get; set; }

		public string? Password { get; set; }

		public bool BypassProxyOnLocal { get; set; }

		public bool SkipSSLCheck { get; set; }

		public ProxyConfig(string host, int port)
		{
			Ensure.ArgumentNotNullOrEmptyString(host, "host");
			Host = host;
			Port = port;
		}
	}
	public class DoubleToIntConverter : JsonConverter<int>
	{
		public override void WriteJson(JsonWriter? writer, int value, JsonSerializer serializer)
		{
			if (writer != null)
			{
				writer.WriteValue(value);
			}
		}

		public override int ReadJson(JsonReader? reader, Type objectType, int existingValue, bool hasExistingValue, JsonSerializer serializer)
		{
			if (reader == null)
			{
				return 0;
			}
			return Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
		}
	}
	public class PlayableItemConverter : JsonConverter
	{
		public override bool CanWrite => false;

		public override bool CanConvert(Type objectType)
		{
			return true;
		}

		public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			Ensure.ArgumentNotNull(serializer, "serializer");
			JToken obj = JToken.ReadFrom(reader);
			JObject val = (JObject)(object)((obj is JObject) ? obj : null);
			if (val == null)
			{
				return null;
			}
			JToken value = val.GetValue("type", StringComparison.OrdinalIgnoreCase);
			string text = ((value != null) ? Extensions.Value<string>((IEnumerable<JToken>)value) : null);
			if (string.Equals(text, "track", StringComparison.OrdinalIgnoreCase))
			{
				FullTrack fullTrack = new FullTrack();
				serializer.Populate(((JToken)val).CreateReader(), (object)fullTrack);
				return fullTrack;
			}
			if (string.Equals(text, "episode", StringComparison.OrdinalIgnoreCase))
			{
				FullEpisode fullEpisode = new FullEpisode();
				serializer.Populate(((JToken)val).CreateReader(), (object)fullEpisode);
				return fullEpisode;
			}
			throw new APIException("Received unkown playlist element type: " + text + ".\nIf you're requesting a subset of available fields via the fields query paramter,\nmake sure to include at least the type field. Often it's `items(track(type))` or `item(type)`");
		}

		public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			throw new NotSupportedException();
		}
	}
	public interface IPaginatable<T>
	{
		string? Next { get; set; }

		List<T>? Items { get; set; }
	}
	public interface IPaginatable<T, TNext>
	{
		string? Next { get; set; }

		List<T>? Items { get; set; }
	}
	public class AlbumRequest : RequestParams
	{
		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class AlbumsRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		public AlbumsRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			Ids = ids;
		}
	}
	public class AlbumTracksRequest : RequestParams
	{
		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class ArtistRequest : RequestParams
	{
		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class ArtistsAlbumsRequest : RequestParams
	{
		[Flags]
		public enum IncludeGroups
		{
			[String("album")]
			Album = 1,
			[String("single")]
			Single = 2,
			[String("appears_on")]
			AppearsOn = 4,
			[String("compilation")]
			Compilation = 8
		}

		[QueryParam("include_groups")]
		public IncludeGroups? IncludeGroupsParam { get; set; }

		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }
	}
	public class ArtistsRelatedArtistsRequest : RequestParams
	{
		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class ArtistsRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		public ArtistsRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			Ids = ids;
		}
	}
	public class ArtistsTopTracksRequest : RequestParams
	{
		[QueryParam("market")]
		public string Market { get; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		public ArtistsTopTracksRequest(string market)
		{
			Ensure.ArgumentNotNullOrEmptyString(market, "market");
			Market = market;
		}
	}
	public class AudiobookChaptersRequest : RequestParams
	{
		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class AudiobookRequest : RequestParams
	{
		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class AudiobooksRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		public AudiobooksRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			Ids = ids;
		}
	}
	public class AuthorizationCodeRefreshRequest
	{
		public string RefreshToken { get; }

		public string ClientId { get; }

		public string ClientSecret { get; }

		public AuthorizationCodeRefreshRequest(string clientId, string clientSecret, string refreshToken)
		{
			Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
			Ensure.ArgumentNotNullOrEmptyString(clientSecret, "clientSecret");
			Ensure.ArgumentNotNullOrEmptyString(refreshToken, "refreshToken");
			ClientId = clientId;
			ClientSecret = clientSecret;
			RefreshToken = refreshToken;
		}
	}
	public class AuthorizationCodeTokenRequest
	{
		public string ClientId { get; }

		public string ClientSecret { get; }

		public string Code { get; }

		public Uri RedirectUri { get; }

		public AuthorizationCodeTokenRequest(string clientId, string clientSecret, string code, Uri redirectUri)
		{
			Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
			Ensure.ArgumentNotNullOrEmptyString(clientSecret, "clientSecret");
			Ensure.ArgumentNotNullOrEmptyString(code, "code");
			Ensure.ArgumentNotNull(redirectUri, "redirectUri");
			ClientId = clientId;
			ClientSecret = clientSecret;
			Code = code;
			RedirectUri = redirectUri;
		}
	}
	public class CategoriesRequest : RequestParams
	{
		[QueryParam("country")]
		public string? Country { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }
	}
	public class CategoriesPlaylistsRequest : RequestParams
	{
		[QueryParam("country")]
		public string? Country { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }
	}
	public class CategoryRequest : RequestParams
	{
		[QueryParam("country")]
		public string? Country { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class ChapterRequest : RequestParams
	{
		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class ChaptersRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		public ChaptersRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			Ids = ids;
		}
	}
	public class ClientCredentialsRequest
	{
		public string ClientId { get; }

		public string ClientSecret { get; }

		public ClientCredentialsRequest(string clientId, string clientSecret)
		{
			Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
			Ensure.ArgumentNotNullOrEmptyString(clientSecret, "clientSecret");
			ClientId = clientId;
			ClientSecret = clientSecret;
		}
	}
	public class EpisodeRequest : RequestParams
	{
		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class EpisodesRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		public EpisodesRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			Ids = ids;
		}
	}
	public class FeaturedPlaylistsRequest : RequestParams
	{
		[QueryParam("country")]
		public string? Country { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }

		public DateTime? Timestamp { get; set; }

		[QueryParam("timestamp")]
		protected string? TimestampFormatted => Timestamp?.ToString("o", CultureInfo.InvariantCulture);
	}
	public class FollowCheckCurrentUserRequest : RequestParams
	{
		public enum Type
		{
			[String("artist")]
			Artist,
			[String("user")]
			User
		}

		[QueryParam("type")]
		public Type TypeParam { get; }

		[QueryParam("ids")]
		public IList<string> Ids { get; }

		public FollowCheckCurrentUserRequest(Type type, IList<string> ids)
		{
			Ensure.ArgumentNotNull(type, "type");
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			TypeParam = type;
			Ids = ids;
		}
	}
	public class FollowCheckPlaylistRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		public FollowCheckPlaylistRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			Ids = ids;
		}
	}
	public class FollowOfCurrentUserRequest : RequestParams
	{
		public enum Type
		{
			[String("artist")]
			Artist
		}

		[QueryParam("type")]
		public Type TypeParam { get; set; }

		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }

		[QueryParam("after")]
		public string? After { get; set; }

		public FollowOfCurrentUserRequest(Type type = Type.Artist)
		{
			TypeParam = type;
		}
	}
	public class FollowPlaylistRequest : RequestParams
	{
		[BodyParam("public")]
		public bool? Public { get; set; }
	}
	public class FollowRequest : RequestParams
	{
		public enum Type
		{
			[String("artist")]
			Artist,
			[String("user")]
			User
		}

		[QueryParam("type")]
		public Type? TypeParam { get; set; }

		[BodyParam("ids")]
		public IList<string> Ids { get; }

		public FollowRequest(Type type, IList<string> ids)
		{
			Ensure.ArgumentNotNull(type, "type");
			Ensure.ArgumentNotNullOrEmptyList(ids, "ids");
			TypeParam = type;
			Ids = ids;
		}
	}
	public class LibraryAlbumsRequest : RequestParams
	{
		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }

		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class LibraryAudiobooksRequest : RequestParams
	{
		[QueryParam("limit")]
		public int? Limit { get; set; }

		[QueryParam("offset")]
		public int? Offset { get; set; }

		[QueryParam("market")]
		public string? Market { get; set; }

		[QueryParam("locale")]
		public string? Locale { get; set; }
	}
	public class LibraryCheckAlbumsRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		public LibraryCheckAlbumsRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNull(ids, "ids");
			Ids = ids;
		}
	}
	public class LibraryCheckAudiobooksRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		public LibraryCheckAudiobooksRequest(IList<string> ids)
		{
			Ensure.ArgumentNotNull(ids, "ids");
			Ids = ids;
		}
	}
	public class LibraryCheckEpisodesRequest : RequestParams
	{
		[QueryParam("ids")]
		public IList<string> Ids { get; }

		public LibraryCheckEp

Spotilyss.dll

Decompiled 6 days ago
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using SpotifyAPI.Web;
using SpotifyAPI.Web.Http;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Spotilyss")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Spotilyss")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("74040868-682F-4D6F-80EC-925F6758CC30")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
}
[BepInPlugin("com.s0apysh0wer.spotilyss", "Spotilyss", "1.1.0")]
[BepInProcess("ATLYSS.exe")]
public class Plugin : BaseUnityPlugin
{
	private enum AuthState
	{
		NotAuthenticated,
		AwaitingManualCallback,
		Authenticated,
		Failed
	}

	private ConfigEntry<string> _spotifyRedirectUri;

	private ConfigEntry<string> _clientId;

	private ConfigEntry<string> _clientSecret;

	private ConfigEntry<string> _refreshToken;

	private ConfigEntry<bool> _announceInChat;

	private ConfigEntry<bool> _showText;

	private ConfigEntry<ChatChannel> _announceChannel;

	private ConfigEntry<KeyCode> _menuKey;

	private SpotifyClient _spotifyClient;

	private string _displayText = "Spotilyss [API]: Initializing...";

	private string _lastSongId = "";

	private float _timer;

	private const float UpdateInterval = 5f;

	private bool _showSettingsWindow;

	private GUIStyle _textStyle;

	private GUIStyle _windowStyle;

	private GUIStyle _boldLabelStyle;

	private GUIStyle _buttonStyle;

	private GUIStyle _textFieldStyle;

	private GUIStyle _toggleStyle;

	private Vector2 _settingsScrollPos;

	private bool _stylesInitialized;

	private bool _isBindingKey;

	private string _pastedCallbackUrl = "";

	private readonly Color _spotifyGreen = new Color(0.11f, 0.73f, 0.33f);

	private readonly Color _spotifyBlack = new Color(0.07f, 0.07f, 0.07f);

	private readonly Color _spotifyDarkGray = new Color(0.18f, 0.18f, 0.18f);

	private readonly Color _spotifyLightGray = new Color(0.24f, 0.24f, 0.24f);

	private AuthState _authState;

	private void Awake()
	{
		CreateConfigEntries();
		Task.Run(() => InitializeSpotify());
	}

	private void CreateConfigEntries()
	{
		_spotifyRedirectUri = ((BaseUnityPlugin)this).Config.Bind<string>("Credentials", "Spotify Redirect URI", "https://example.com/callback", "The Redirect URI registered in your Spotify Developer Dashboard. Must be a non-loopback address for this flow.");
		_clientId = ((BaseUnityPlugin)this).Config.Bind<string>("Credentials", "Spotify Client ID", "CLIENT_ID", "Your Client ID from the Spotify Developer Dashboard.");
		_clientSecret = ((BaseUnityPlugin)this).Config.Bind<string>("Credentials", "Spotify Client Secret", "CLIENT_SECRET", "Your Client Secret from the Spotify Developer Dashboard.");
		_refreshToken = ((BaseUnityPlugin)this).Config.Bind<string>("Credentials", "Refresh Token", "", "Spotify Refresh Token. Automatically saved after first login.");
		_showText = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show On-Screen Text", false, "Toggle the song display UI.");
		_menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Display", "Menu Key", (KeyCode)277, "Key to open the settings menu.");
		_announceInChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "Announce Songs in Chat", false, "Announce new songs in the in-game chat.");
		_announceChannel = ((BaseUnityPlugin)this).Config.Bind<ChatChannel>("Behavior", "Announcement Channel", (ChatChannel)0, "Channel for song announcements.");
	}

	private async Task InitializeSpotify()
	{
		if (!string.IsNullOrEmpty(_refreshToken.Value))
		{
			try
			{
				AuthorizationCodeAuthenticator val = new AuthorizationCodeAuthenticator(_clientId.Value, _clientSecret.Value, new AuthorizationCodeTokenResponse
				{
					RefreshToken = _refreshToken.Value
				});
				val.TokenRefreshed += delegate(object sender, AuthorizationCodeTokenResponse token)
				{
					_refreshToken.Value = token.RefreshToken;
					((BaseUnityPlugin)this).Config.Save();
				};
				SpotifyClientConfig val2 = SpotifyClientConfig.CreateDefault().WithAuthenticator((IAuthenticator)(object)val);
				_spotifyClient = new SpotifyClient(val2);
				await _spotifyClient.UserProfile.Current(default(CancellationToken));
				_authState = AuthState.Authenticated;
				_displayText = "Spotify: Re-Authenticated!";
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Successfully re-authenticated with Spotify using refresh token.");
				await UpdateSongTitle();
				return;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not re-authenticate with refresh token: " + ex.Message));
				_refreshToken.Value = "";
				((BaseUnityPlugin)this).Config.Save();
			}
		}
		if (string.IsNullOrEmpty(_clientId.Value) || _clientId.Value == "CLIENT_ID")
		{
			_displayText = $"ERROR: See Log. Press {_menuKey.Value} to set credentials.";
			((BaseUnityPlugin)this).Logger.LogError((object)$"Client ID/Secret not set. Press {_menuKey.Value} to configure.");
		}
		else
		{
			await StartManualAuthentication();
		}
	}

	private Task StartManualAuthentication()
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Expected O, but got Unknown
		try
		{
			if (!Uri.TryCreate(_spotifyRedirectUri.Value, UriKind.Absolute, out Uri result) || result.IsLoopback)
			{
				_displayText = "ERROR: Invalid Redirect URI for this flow.";
				((BaseUnityPlugin)this).Logger.LogError((object)("Invalid Redirect URI for manual flow. It must be a valid, non-loopback URI like https://example.com. Current: " + _spotifyRedirectUri.Value));
				_authState = AuthState.Failed;
				return Task.CompletedTask;
			}
			LoginRequest val = new LoginRequest(result, _clientId.Value, (ResponseType)0);
			val.Scope = new string[2] { "user-read-currently-playing", "user-read-playback-state" };
			Process.Start(new ProcessStartInfo(val.ToUri().AbsoluteUri)
			{
				UseShellExecute = true
			});
			_authState = AuthState.AwaitingManualCallback;
			_displayText = "Spotilyss: Login required. Open settings menu to continue.";
			((BaseUnityPlugin)this).Logger.LogInfo((object)"A browser has been opened. Please authorize the app, then copy the full URL you are redirected to and paste it in the settings menu.");
			_showSettingsWindow = true;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}
		catch (Exception ex)
		{
			_authState = AuthState.Failed;
			_displayText = "Spotify: Initialization failed";
			((BaseUnityPlugin)this).Logger.LogError((object)("Manual authentication setup failed: " + ex.Message));
		}
		return Task.CompletedTask;
	}

	private async Task ProcessPastedCallbackUrl(string callbackUrl)
	{
		_displayText = "Spotify: Processing code...";
		if (string.IsNullOrWhiteSpace(callbackUrl))
		{
			_displayText = "ERROR: Pasted URL is empty.";
			return;
		}
		try
		{
			string query = new Uri(callbackUrl).Query;
			string text = null;
			if (!string.IsNullOrEmpty(query))
			{
				string[] array = query.TrimStart(new char[1] { '?' }).Split(new char[1] { '&' });
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { '=' });
					if (array2.Length == 2 && array2[0] == "code")
					{
						text = Uri.UnescapeDataString(array2[1]);
						break;
					}
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				_authState = AuthState.Failed;
				_displayText = "ERROR: No authorization code found in URL.";
				((BaseUnityPlugin)this).Logger.LogError((object)"Could not find 'code' parameter in the pasted URL.");
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Received code, attempting token exchange...");
			AuthorizationCodeTokenRequest val = new AuthorizationCodeTokenRequest(_clientId.Value, _clientSecret.Value, text, new Uri(_spotifyRedirectUri.Value));
			AuthorizationCodeTokenResponse val2 = await new OAuthClient().RequestToken(val, default(CancellationToken));
			if (!string.IsNullOrEmpty(val2.RefreshToken))
			{
				_refreshToken.Value = val2.RefreshToken;
				((BaseUnityPlugin)this).Config.Save();
			}
			_spotifyClient = new SpotifyClient(SpotifyClientConfig.CreateDefault(val2.AccessToken, "Bearer"));
			_authState = AuthState.Authenticated;
			_displayText = "Spotify: Authenticated!";
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Successfully authenticated with Spotify!");
			_showSettingsWindow = false;
			await UpdateSongTitle();
		}
		catch (UriFormatException)
		{
			_authState = AuthState.Failed;
			_displayText = "ERROR: Invalid URL format.";
		}
		catch (APIException val3)
		{
			APIException e = val3;
			HandleAuthError(e);
		}
		catch (Exception ex2)
		{
			_authState = AuthState.Failed;
			_displayText = "Spotify: Unexpected error";
			((BaseUnityPlugin)this).Logger.LogError((object)("Error processing callback: " + ex2.Message));
		}
	}

	private void HandleAuthError(APIException e)
	{
		_authState = AuthState.Failed;
		if (((Exception)(object)e).Message.Contains("invalid_client"))
		{
			_displayText = "ERROR: Invalid Client ID/Secret";
			((BaseUnityPlugin)this).Logger.LogError((object)"Invalid credentials - verify Client ID/Secret in config matches Spotify Dashboard");
		}
		else if (((Exception)(object)e).Message.Contains("invalid_grant"))
		{
			_displayText = "ERROR: Invalid authorization code";
			((BaseUnityPlugin)this).Logger.LogError((object)"Invalid grant - The authorization code might have expired or was already used.");
		}
		else
		{
			_displayText = "Spotify: Auth failed - " + ((Exception)(object)e).Message;
			((BaseUnityPlugin)this).Logger.LogError((object)("Token request failed: " + ((Exception)(object)e).Message));
		}
	}

	private async Task UpdateSongTitle()
	{
		if (_spotifyClient == null)
		{
			return;
		}
		try
		{
			CurrentlyPlaying obj = await _spotifyClient.Player.GetCurrentlyPlaying(new PlayerCurrentlyPlayingRequest((AdditionalTypes)3), default(CancellationToken));
			IPlayableItem obj2 = ((obj != null) ? obj.Item : null);
			FullTrack val = (FullTrack)(object)((obj2 is FullTrack) ? obj2 : null);
			if (val != null)
			{
				string text = (_displayText = string.Join(", ", val.Artists.Select((SimpleArtist a) => a.Name)) + " - " + val.Name);
				if (val.Id != _lastSongId && _announceInChat.Value)
				{
					_lastSongId = val.Id;
					Chat("[Spotilyss] Now Playing: " + text, _announceChannel.Value);
				}
			}
			else
			{
				_displayText = "Spotify: Paused";
				_lastSongId = "";
			}
		}
		catch (APIException val2)
		{
			APIException val3 = val2;
			_displayText = "Spotify: API Error (check console)";
			((BaseUnityPlugin)this).Logger.LogError((object)("API Error: " + ((Exception)(object)val3).Message));
			IResponse response = val3.Response;
			if (response != null && response.StatusCode == HttpStatusCode.Unauthorized)
			{
				_refreshToken.Value = "";
				((BaseUnityPlugin)this).Config.Save();
				_spotifyClient = null;
				_authState = AuthState.Failed;
				Task.Run(() => InitializeSpotify());
			}
		}
		catch (Exception ex)
		{
			_displayText = "Spotify: Error (check console)";
			((BaseUnityPlugin)this).Logger.LogError((object)("An unexpected error occurred while updating song title: " + ex.Message));
		}
	}

	private void Update()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		if (Input.GetKeyDown(_menuKey.Value))
		{
			_showSettingsWindow = !_showSettingsWindow;
			if (_showSettingsWindow)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
			else
			{
				_isBindingKey = false;
			}
		}
		if (_spotifyClient == null)
		{
			return;
		}
		_timer += Time.deltaTime;
		if (_timer > 5f)
		{
			_timer = 0f;
			Task.Run(() => UpdateSongTitle());
		}
	}

	private void OnGUI()
	{
		InitializeStyles();
		DrawSongDisplay();
		if (_showSettingsWindow)
		{
			DrawSettingsWindow();
		}
	}

	private void DrawSongDisplay()
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Expected O, but got Unknown
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		if (_showText.Value)
		{
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(10f, (float)(Screen.height - 60), 400f, 50f);
			GUIStyle val2 = new GUIStyle(_textStyle);
			val2.normal.textColor = _spotifyBlack;
			GUIStyle val3 = val2;
			GUI.Label(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), _displayText, val3);
			GUI.Label(val, _displayText, _textStyle);
		}
	}

	private void DrawSettingsWindow()
	{
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Expected O, but got Unknown
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		GUISkin skin = GUI.skin;
		try
		{
			GUI.skin = null;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor((float)(Screen.width / 2 - 250), (float)(Screen.height / 2 - 225), 500f, 450f);
			Rect val2 = new Rect(((Rect)(ref val)).x - 5f, ((Rect)(ref val)).y - 5f, ((Rect)(ref val)).width + 10f, ((Rect)(ref val)).height + 10f);
			GUIStyle val3 = new GUIStyle();
			val3.normal.background = MakeTex(2, 2, _spotifyDarkGray);
			GUI.Box(val2, "", val3);
			GUILayout.Window(0, val, new WindowFunction(SettingsWindow), "Spotilyss Settings", _windowStyle, Array.Empty<GUILayoutOption>());
		}
		finally
		{
			GUI.skin = skin;
		}
	}

	private void SettingsWindow(int windowID)
	{
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0293: Unknown result type (might be due to invalid IL or missing references)
		//IL_0298: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Invalid comparison between Unknown and I4
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_036b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0390: Expected I4, but got Unknown
		if (_isBindingKey && Event.current.isKey && (int)Event.current.keyCode != 0)
		{
			if ((int)Event.current.keyCode == 27)
			{
				_isBindingKey = false;
			}
			else
			{
				_menuKey.Value = Event.current.keyCode;
				_isBindingKey = false;
				((BaseUnityPlugin)this).Config.Save();
			}
			Event.current.Use();
		}
		if (_authState == AuthState.AwaitingManualCallback)
		{
			GUILayout.Label("Complete Authentication", _boldLabelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("1. A browser window has opened. Please log in and grant access.", Array.Empty<GUILayoutOption>());
			GUILayout.Label("2. You will be redirected. Copy the FULL URL from your browser's address bar.", Array.Empty<GUILayoutOption>());
			GUILayout.Label("3. Paste the URL below and click 'Submit'.", Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label("Pasted URL:", Array.Empty<GUILayoutOption>());
			_pastedCallbackUrl = GUILayout.TextField(_pastedCallbackUrl, _textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) });
			GUILayout.Space(10f);
			if (GUILayout.Button("Submit Authentication Code", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				Task.Run(() => ProcessPastedCallbackUrl(_pastedCallbackUrl));
			}
			return;
		}
		_settingsScrollPos = GUILayout.BeginScrollView(_settingsScrollPos, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Credentials", _boldLabelStyle, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Redirect URI:", Array.Empty<GUILayoutOption>());
		_spotifyRedirectUri.Value = GUILayout.TextField(_spotifyRedirectUri.Value, _textFieldStyle, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Client ID:", Array.Empty<GUILayoutOption>());
		_clientId.Value = GUILayout.TextField(_clientId.Value, _textFieldStyle, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Client Secret:", Array.Empty<GUILayoutOption>());
		_clientSecret.Value = GUILayout.PasswordField(_clientSecret.Value, '*', _textFieldStyle, Array.Empty<GUILayoutOption>());
		GUILayout.Space(15f);
		GUILayout.Label("Display Settings", _boldLabelStyle, Array.Empty<GUILayoutOption>());
		_showText.Value = GUILayout.Toggle(_showText.Value, " Show Current Song", _toggleStyle, Array.Empty<GUILayoutOption>());
		GUILayout.Space(10f);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label("Open Menu Key:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
		object obj;
		if (!_isBindingKey)
		{
			KeyCode value = _menuKey.Value;
			obj = ((object)(KeyCode)(ref value)).ToString();
		}
		else
		{
			obj = "Press any key...";
		}
		if (GUILayout.Button((string)obj, _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }))
		{
			_isBindingKey = !_isBindingKey;
		}
		GUILayout.EndHorizontal();
		GUILayout.Space(15f);
		GUILayout.Label("Behavior Settings", _boldLabelStyle, Array.Empty<GUILayoutOption>());
		_announceInChat.Value = GUILayout.Toggle(_announceInChat.Value, " Announce Songs in Chat", _toggleStyle, Array.Empty<GUILayoutOption>());
		if (_announceInChat.Value)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Announcement Channel:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			_announceChannel.Value = (ChatChannel)(byte)GUILayout.SelectionGrid((int)_announceChannel.Value, Enum.GetNames(typeof(ChatChannel)), 3, _buttonStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
		}
		GUILayout.FlexibleSpace();
		if (GUILayout.Button("Save and Re-Authenticate", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			((BaseUnityPlugin)this).Config.Save();
			_spotifyClient = null;
			_isBindingKey = false;
			Task.Run(() => InitializeSpotify());
		}
		GUILayout.EndScrollView();
	}

	private void InitializeStyles()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: 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_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Expected O, but got Unknown
		//IL_00ee: Expected O, but got Unknown
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Expected O, but got Unknown
		//IL_0179: Expected O, but got Unknown
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Expected O, but got Unknown
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0257: Unknown result type (might be due to invalid IL or missing references)
		//IL_0261: Expected O, but got Unknown
		//IL_0266: Expected O, but got Unknown
		//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fb: Expected O, but got Unknown
		//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0300: Unknown result type (might be due to invalid IL or missing references)
		//IL_030a: Expected O, but got Unknown
		//IL_030f: Expected O, but got Unknown
		//IL_0331: Unknown result type (might be due to invalid IL or missing references)
		//IL_0336: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0344: Unknown result type (might be due to invalid IL or missing references)
		//IL_034e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0355: Unknown result type (might be due to invalid IL or missing references)
		//IL_035f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0365: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0375: Unknown result type (might be due to invalid IL or missing references)
		//IL_037f: Expected O, but got Unknown
		//IL_037f: Unknown result type (might be due to invalid IL or missing references)
		//IL_038b: Expected O, but got Unknown
		//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
		if (!_stylesInitialized)
		{
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 18,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)6
			};
			val.normal.textColor = Color.white;
			val.normal.background = MakeTex(2, 2, _spotifyBlack);
			_textStyle = val;
			GUIStyle val2 = new GUIStyle(GUI.skin.window)
			{
				fontSize = 14,
				padding = new RectOffset(10, 10, 20, 10)
			};
			val2.normal.background = MakeTex(2, 2, _spotifyDarkGray);
			val2.normal.textColor = Color.white;
			val2.onNormal.background = MakeTex(2, 2, _spotifyDarkGray);
			val2.onNormal.textColor = Color.white;
			val2.border = new RectOffset(5, 5, 5, 5);
			_windowStyle = val2;
			((Object)_windowStyle.normal.background).hideFlags = (HideFlags)61;
			((Object)_windowStyle.onNormal.background).hideFlags = (HideFlags)61;
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontStyle = (FontStyle)1,
				fontSize = 16
			};
			val3.normal.textColor = _spotifyGreen;
			val3.normal.background = MakeTex(2, 2, _spotifyDarkGray);
			val3.padding = new RectOffset(0, 0, 5, 5);
			_boldLabelStyle = val3;
			((Object)_boldLabelStyle.normal.background).hideFlags = (HideFlags)61;
			GUIStyle val4 = new GUIStyle(GUI.skin.button)
			{
				fontSize = 14
			};
			val4.normal.background = MakeTex(2, 2, _spotifyGreen);
			val4.normal.textColor = Color.white;
			val4.hover.background = MakeTex(2, 2, Color.Lerp(_spotifyGreen, Color.white, 0.2f));
			val4.hover.textColor = Color.white;
			val4.active.background = MakeTex(2, 2, Color.Lerp(_spotifyGreen, Color.black, 0.2f));
			val4.active.textColor = Color.white;
			val4.padding = new RectOffset(10, 10, 5, 5);
			val4.border = new RectOffset(5, 5, 5, 5);
			_buttonStyle = val4;
			((Object)_buttonStyle.normal.background).hideFlags = (HideFlags)61;
			((Object)_buttonStyle.hover.background).hideFlags = (HideFlags)61;
			((Object)_buttonStyle.active.background).hideFlags = (HideFlags)61;
			GUIStyle val5 = new GUIStyle(GUI.skin.textField)
			{
				fontSize = 14
			};
			val5.normal.background = MakeTex(2, 2, _spotifyLightGray);
			val5.normal.textColor = Color.white;
			val5.padding = new RectOffset(5, 5, 5, 5);
			val5.border = new RectOffset(5, 5, 5, 5);
			_textFieldStyle = val5;
			((Object)_textFieldStyle.normal.background).hideFlags = (HideFlags)61;
			GUIStyle val6 = new GUIStyle(GUI.skin.toggle)
			{
				fontSize = 14
			};
			val6.normal.textColor = Color.white;
			val6.onNormal.textColor = _spotifyGreen;
			val6.hover.textColor = Color.white;
			val6.padding = new RectOffset(20, 0, 2, 2);
			val6.alignment = (TextAnchor)3;
			_toggleStyle = val6;
			_toggleStyle.normal.background = MakeTex(2, 2, new Color(0f, 0f, 0f, 0f));
			((Object)_toggleStyle.normal.background).hideFlags = (HideFlags)61;
			_stylesInitialized = true;
		}
	}

	private Texture2D MakeTex(int width, int height, Color col)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		Color[] array = (Color[])(object)new Color[width * height];
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = col;
		}
		Texture2D val = new Texture2D(width, height);
		val.SetPixels(array);
		val.Apply();
		return val;
	}

	private static void Chat(string msg, ChatChannel cc)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)Player._mainPlayer?._chatBehaviour == (Object)null))
		{
			Player._mainPlayer._chatBehaviour.Cmd_SendChatMessage(msg, cc);
		}
	}
}

Swan.Lite.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Swan.Collections;
using Swan.Configuration;
using Swan.Formatters;
using Swan.Logging;
using Swan.Mappers;
using Swan.Net.Internal;
using Swan.Reflection;
using Swan.Threading;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyCompany("Unosquare")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2016-2020 - Unosquare")]
[assembly: AssemblyDescription("Repeating code and reinventing the wheel is generally considered bad practice. At Unosquare we are committed to beautiful code and great software. Swan is a collection of classes and extension methods that we and other good developers have developed and evolved over the years. We found ourselves copying and pasting the same code for every project every time we started it. We decide to kill that cycle once and for all. This is the result of that idea. Our philosophy is that SWAN should have no external dependencies, it should be cross-platform, and it should be useful.")]
[assembly: AssemblyFileVersion("3.1.0.0")]
[assembly: AssemblyInformationalVersion("3.1.0")]
[assembly: AssemblyProduct("Swan.Lite")]
[assembly: AssemblyTitle("Unosquare SWAN")]
[assembly: AssemblyVersion("3.1.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Swan
{
	public static class CompositeHashCode
	{
		private const int InitialSeed = 17;

		private const int Multiplier = 29;

		public static int Using(params object[] fields)
		{
			return fields.Where((object f) => f != null).Aggregate(17, (int current, object field) => 29 * current + field.GetHashCode());
		}
	}
	public struct DateTimeSpan
	{
		private enum Phase
		{
			Years,
			Months,
			Days,
			Done
		}

		public int Years { get; }

		public int Months { get; }

		public int Days { get; }

		public int Hours { get; }

		public int Minutes { get; }

		public int Seconds { get; }

		public int Milliseconds { get; }

		public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
		{
			Years = years;
			Months = months;
			Days = days;
			Hours = hours;
			Minutes = minutes;
			Seconds = seconds;
			Milliseconds = milliseconds;
		}

		internal static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
		{
			if (date2 < date1)
			{
				DateTime dateTime = date1;
				date1 = date2;
				date2 = dateTime;
			}
			DateTime dateTime2 = date1;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			Phase phase = Phase.Years;
			DateTimeSpan result = default(DateTimeSpan);
			int day = dateTime2.Day;
			while (true)
			{
				switch (phase)
				{
				case Phase.Years:
					if (dateTime2.AddYears(num + 1) > date2)
					{
						phase = Phase.Months;
						dateTime2 = dateTime2.AddYears(num);
					}
					else
					{
						num++;
					}
					break;
				case Phase.Months:
					if (dateTime2.AddMonths(num2 + 1) > date2)
					{
						phase = Phase.Days;
						dateTime2 = dateTime2.AddMonths(num2);
						if (dateTime2.Day < day && day <= DateTime.DaysInMonth(dateTime2.Year, dateTime2.Month))
						{
							dateTime2 = dateTime2.AddDays(day - dateTime2.Day);
						}
					}
					else
					{
						num2++;
					}
					break;
				case Phase.Days:
					if (dateTime2.AddDays(num3 + 1) > date2)
					{
						dateTime2 = dateTime2.AddDays(num3);
						TimeSpan timeSpan = date2 - dateTime2;
						result = new DateTimeSpan(num, num2, num3, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, timeSpan.Milliseconds);
						phase = Phase.Done;
					}
					else
					{
						num3++;
					}
					break;
				case Phase.Done:
					return result;
				}
			}
		}
	}
	public static class Definitions
	{
		public static readonly Encoding Windows1252Encoding;

		public static readonly Encoding CurrentAnsiEncoding;

		public static readonly Lazy<Dictionary<Type, ExtendedTypeInfo>> BasicTypesInfo;

		public static IReadOnlyCollection<Type> AllBasicTypes { get; }

		public static IReadOnlyCollection<Type> AllNumericTypes { get; }

		public static IReadOnlyCollection<Type> AllNumericValueTypes { get; }

		public static IReadOnlyCollection<Type> AllBasicValueTypes { get; }

		public static IReadOnlyCollection<Type> AllBasicValueAndStringTypes { get; }

		public static IReadOnlyCollection<Type> AllBasicNullableValueTypes { get; }

		static Definitions()
		{
			BasicTypesInfo = new Lazy<Dictionary<Type, ExtendedTypeInfo>>(() => new Dictionary<Type, ExtendedTypeInfo>
			{
				{
					typeof(DateTime),
					new ExtendedTypeInfo<DateTime>()
				},
				{
					typeof(byte),
					new ExtendedTypeInfo<byte>()
				},
				{
					typeof(sbyte),
					new ExtendedTypeInfo<sbyte>()
				},
				{
					typeof(int),
					new ExtendedTypeInfo<int>()
				},
				{
					typeof(uint),
					new ExtendedTypeInfo<uint>()
				},
				{
					typeof(short),
					new ExtendedTypeInfo<short>()
				},
				{
					typeof(ushort),
					new ExtendedTypeInfo<ushort>()
				},
				{
					typeof(long),
					new ExtendedTypeInfo<long>()
				},
				{
					typeof(ulong),
					new ExtendedTypeInfo<ulong>()
				},
				{
					typeof(float),
					new ExtendedTypeInfo<float>()
				},
				{
					typeof(double),
					new ExtendedTypeInfo<double>()
				},
				{
					typeof(char),
					new ExtendedTypeInfo<char>()
				},
				{
					typeof(bool),
					new ExtendedTypeInfo<bool>()
				},
				{
					typeof(decimal),
					new ExtendedTypeInfo<decimal>()
				},
				{
					typeof(Guid),
					new ExtendedTypeInfo<Guid>()
				},
				{
					typeof(string),
					new ExtendedTypeInfo<string>()
				},
				{
					typeof(DateTime?),
					new ExtendedTypeInfo<DateTime?>()
				},
				{
					typeof(byte?),
					new ExtendedTypeInfo<byte?>()
				},
				{
					typeof(sbyte?),
					new ExtendedTypeInfo<sbyte?>()
				},
				{
					typeof(int?),
					new ExtendedTypeInfo<int?>()
				},
				{
					typeof(uint?),
					new ExtendedTypeInfo<uint?>()
				},
				{
					typeof(short?),
					new ExtendedTypeInfo<short?>()
				},
				{
					typeof(ushort?),
					new ExtendedTypeInfo<ushort?>()
				},
				{
					typeof(long?),
					new ExtendedTypeInfo<long?>()
				},
				{
					typeof(ulong?),
					new ExtendedTypeInfo<ulong?>()
				},
				{
					typeof(float?),
					new ExtendedTypeInfo<float?>()
				},
				{
					typeof(double?),
					new ExtendedTypeInfo<double?>()
				},
				{
					typeof(char?),
					new ExtendedTypeInfo<char?>()
				},
				{
					typeof(bool?),
					new ExtendedTypeInfo<bool?>()
				},
				{
					typeof(decimal?),
					new ExtendedTypeInfo<decimal?>()
				},
				{
					typeof(Guid?),
					new ExtendedTypeInfo<Guid?>()
				},
				{
					typeof(TimeSpan),
					new ExtendedTypeInfo<TimeSpan>()
				},
				{
					typeof(TimeSpan?),
					new ExtendedTypeInfo<TimeSpan?>()
				},
				{
					typeof(IPAddress),
					new ExtendedTypeInfo<IPAddress>()
				}
			});
			AllBasicTypes = new ReadOnlyCollection<Type>(BasicTypesInfo.Value.Keys.ToArray());
			AllNumericTypes = new ReadOnlyCollection<Type>((from kvp in BasicTypesInfo.Value
				where kvp.Value.IsNumeric
				select kvp.Key).ToArray());
			AllNumericValueTypes = new ReadOnlyCollection<Type>((from kvp in BasicTypesInfo.Value
				where kvp.Value.IsNumeric && !kvp.Value.IsNullableValueType
				select kvp.Key).ToArray());
			AllBasicValueTypes = new ReadOnlyCollection<Type>((from kvp in BasicTypesInfo.Value
				where kvp.Value.IsValueType
				select kvp.Key).ToArray());
			AllBasicValueAndStringTypes = new ReadOnlyCollection<Type>((from kvp in BasicTypesInfo.Value
				where kvp.Value.IsValueType || kvp.Key == typeof(string)
				select kvp.Key).ToArray());
			AllBasicNullableValueTypes = new ReadOnlyCollection<Type>((from kvp in BasicTypesInfo.Value
				where kvp.Value.IsNullableValueType
				select kvp.Key).ToArray());
			CurrentAnsiEncoding = Encoding.GetEncoding(0);
			try
			{
				Windows1252Encoding = Encoding.GetEncoding(1252);
			}
			catch
			{
				Windows1252Encoding = CurrentAnsiEncoding;
			}
		}
	}
	public class EnumHelper : SingletonBase<CollectionCacheRepository<Tuple<string, object>>>
	{
		public static IEnumerable<Tuple<string, object>> Retrieve<T>() where T : struct, IConvertible
		{
			return SingletonBase<CollectionCacheRepository<Tuple<string, object>>>.Instance.Retrieve(typeof(T), delegate(Type t)
			{
				Type t2 = t;
				return from object item in Enum.GetValues(t2)
					select Tuple.Create(Enum.GetName(t2, item), item);
			});
		}

		public static IEnumerable<Tuple<int, string>> GetItemsWithValue<T>(bool humanize = true) where T : struct, IConvertible
		{
			return from x in Retrieve<T>()
				select Tuple.Create((int)x.Item2, humanize ? x.Item1.Humanize() : x.Item1);
		}

		public static IEnumerable<int> GetFlagValues<TEnum>(int value, bool ignoreZero = false) where TEnum : struct, IConvertible
		{
			return from x in (from x in Retrieve<TEnum>()
					select (int)x.Item2).When(() => ignoreZero, (IEnumerable<int> q) => q.Where((int f) => f != 0))
				where (x & value) == x
				select x;
		}

		public static IEnumerable<long> GetFlagValues<TEnum>(long value, bool ignoreZero = false) where TEnum : struct, IConvertible
		{
			return from x in (from x in Retrieve<TEnum>()
					select (long)x.Item2).When(() => ignoreZero, (IEnumerable<long> q) => q.Where((long f) => f != 0))
				where (x & value) == x
				select x;
		}

		public static IEnumerable<byte> GetFlagValues<TEnum>(byte value, bool ignoreZero = false) where TEnum : struct, IConvertible
		{
			return from x in (from x in Retrieve<TEnum>()
					select (byte)x.Item2).When(() => ignoreZero, (IEnumerable<byte> q) => q.Where((byte f) => f != 0))
				where (x & value) == x
				select x;
		}

		public static IEnumerable<string> GetFlagNames<TEnum>(int value, bool ignoreZero = false, bool humanize = true) where TEnum : struct, IConvertible
		{
			return from x in Retrieve<TEnum>().When(() => ignoreZero, (IEnumerable<Tuple<string, object>> q) => q.Where((Tuple<string, object> f) => (int)f.Item2 != 0))
				where ((int)x.Item2 & value) == (int)x.Item2
				select (!humanize) ? x.Item1 : x.Item1.Humanize();
		}

		public static IEnumerable<string> GetFlagNames<TEnum>(long value, bool ignoreZero = false, bool humanize = true) where TEnum : struct, IConvertible
		{
			return from x in Retrieve<TEnum>().When(() => ignoreZero, (IEnumerable<Tuple<string, object>> q) => q.Where((Tuple<string, object> f) => (long)f.Item2 != 0))
				where ((long)x.Item2 & value) == (long)x.Item2
				select (!humanize) ? x.Item1 : x.Item1.Humanize();
		}

		public static IEnumerable<string> GetFlagNames<TEnum>(byte value, bool ignoreZero = false, bool humanize = true) where TEnum : struct, IConvertible
		{
			return from x in Retrieve<TEnum>().When(() => ignoreZero, (IEnumerable<Tuple<string, object>> q) => q.Where((Tuple<string, object> f) => (byte)f.Item2 != 0))
				where ((byte)x.Item2 & value) == (byte)x.Item2
				select (!humanize) ? x.Item1 : x.Item1.Humanize();
		}

		public static IEnumerable<Tuple<int, string>> GetItemsWithIndex<T>(bool humanize = true) where T : struct, IConvertible
		{
			int i = 0;
			return from x in Retrieve<T>()
				select Tuple.Create(i++, humanize ? x.Item1.Humanize() : x.Item1);
		}
	}
	public enum OperatingSystem
	{
		Unknown,
		Windows,
		Unix,
		Osx
	}
	public enum Endianness
	{
		Big,
		Little
	}
	public static class ByteArrayExtensions
	{
		public static string ToLowerHex(this byte[] bytes, bool addPrefix = false)
		{
			return ToHex(bytes, addPrefix, "x2");
		}

		public static string ToUpperHex(this byte[] bytes, bool addPrefix = false)
		{
			return ToHex(bytes, addPrefix, "X2");
		}

		public static string ToDashedHex(this byte[] bytes)
		{
			return BitConverter.ToString(bytes);
		}

		public static string ToBase64(this byte[] bytes)
		{
			return Convert.ToBase64String(bytes);
		}

		public static byte[] ConvertHexadecimalToBytes(this string @this)
		{
			string this2 = @this;
			if (string.IsNullOrWhiteSpace(this2))
			{
				throw new ArgumentNullException("this");
			}
			return (from x in Enumerable.Range(0, this2.Length / 2)
				select Convert.ToByte(this2.Substring(x * 2, 2), 16)).ToArray();
		}

		public static byte GetBitValueAt(this byte @this, byte offset, byte length = 1)
		{
			return (byte)((@this >> (int)offset) & ~(255 << (int)length));
		}

		public static byte SetBitValueAt(this byte @this, byte offset, byte length, byte value)
		{
			int num = ~(255 << (int)length);
			return (byte)(((byte)(value & num) << (int)offset) | (@this & ~(num << (int)offset)));
		}

		public static byte SetBitValueAt(this byte @this, byte offset, byte value)
		{
			return @this.SetBitValueAt(offset, 1, value);
		}

		public static List<byte[]> Split(this byte[] @this, int offset, params byte[] sequence)
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			if (sequence == null)
			{
				throw new ArgumentNullException("sequence");
			}
			int i = offset.Clamp(0, @this.Length - 1);
			List<byte[]> list = new List<byte[]>();
			byte[] array;
			for (; i < @this.Length; i += array.Length)
			{
				int indexOf = @this.GetIndexOf(sequence, i);
				if (indexOf >= 0)
				{
					array = new byte[indexOf - i + sequence.Length];
					Array.Copy(@this, i, array, 0, array.Length);
					list.Add(array);
					continue;
				}
				byte[] array2 = new byte[@this.Length - i];
				Array.Copy(@this, i, array2, 0, array2.Length);
				list.Add(array2);
				break;
			}
			return list;
		}

		public static byte[] DeepClone(this byte[] @this)
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			byte[] array = new byte[@this.Length];
			Array.Copy(@this, array, @this.Length);
			return array;
		}

		public static byte[] TrimStart(this byte[] buffer, params byte[] sequence)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			if (!buffer.StartsWith(sequence))
			{
				return buffer.DeepClone();
			}
			byte[] array = new byte[buffer.Length - sequence.Length];
			Array.Copy(buffer, sequence.Length, array, 0, array.Length);
			return array;
		}

		public static byte[] TrimEnd(this byte[] buffer, params byte[] sequence)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			if (!buffer.EndsWith(sequence))
			{
				return buffer.DeepClone();
			}
			byte[] array = new byte[buffer.Length - sequence.Length];
			Array.Copy(buffer, 0, array, 0, array.Length);
			return array;
		}

		public static byte[] Trim(this byte[] buffer, params byte[] sequence)
		{
			return buffer.TrimStart(sequence).TrimEnd(sequence);
		}

		public static bool EndsWith(this byte[] buffer, params byte[] sequence)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			int num = buffer.Length - sequence.Length;
			return buffer.GetIndexOf(sequence, num) == num;
		}

		public static bool StartsWith(this byte[] buffer, params byte[] sequence)
		{
			return buffer.GetIndexOf(sequence) == 0;
		}

		public static bool Contains(this byte[] buffer, params byte[] sequence)
		{
			return buffer.GetIndexOf(sequence) >= 0;
		}

		public static bool IsEqualTo(this byte[] buffer, params byte[] sequence)
		{
			if (buffer == sequence)
			{
				return true;
			}
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			if (buffer.Length == sequence.Length)
			{
				return buffer.GetIndexOf(sequence) == 0;
			}
			return false;
		}

		public static int GetIndexOf(this byte[] buffer, byte[] sequence, int offset = 0)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			if (sequence == null)
			{
				throw new ArgumentNullException("sequence");
			}
			if (sequence.Length == 0)
			{
				return -1;
			}
			if (sequence.Length > buffer.Length)
			{
				return -1;
			}
			int num = ((offset >= 0) ? offset : 0);
			int num2 = 0;
			for (int i = num; i < buffer.Length; i++)
			{
				num2 = ((buffer[i] == sequence[num2]) ? (num2 + 1) : 0);
				if (num2 == sequence.Length)
				{
					return i - (num2 - 1);
				}
			}
			return -1;
		}

		public static MemoryStream Append(this MemoryStream stream, byte[] buffer)
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			stream.Write(buffer, 0, buffer.Length);
			return stream;
		}

		public static MemoryStream Append(this MemoryStream stream, IEnumerable<byte> buffer)
		{
			return stream.Append(buffer?.ToArray());
		}

		public static MemoryStream Append(this MemoryStream stream, IEnumerable<byte[]> buffers)
		{
			if (buffers == null)
			{
				throw new ArgumentNullException("buffers");
			}
			foreach (byte[] buffer in buffers)
			{
				stream.Append(buffer);
			}
			return stream;
		}

		public static string ToText(this IEnumerable<byte> buffer, Encoding encoding)
		{
			if (encoding != null)
			{
				return encoding.GetString(buffer.ToArray());
			}
			throw new ArgumentNullException("encoding");
		}

		public static string ToText(this IEnumerable<byte> buffer)
		{
			return buffer.ToText(Encoding.UTF8);
		}

		public static async Task<byte[]> ReadBytesAsync(this Stream stream, long length, int bufferLength, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			using MemoryStream dest = new MemoryStream();
			try
			{
				byte[] buff = new byte[bufferLength];
				while (length > 0)
				{
					if (length < bufferLength)
					{
						bufferLength = (int)length;
					}
					int num = await stream.ReadAsync(buff, 0, bufferLength, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					if (num != 0)
					{
						dest.Write(buff, 0, num);
						length -= num;
						continue;
					}
					break;
				}
			}
			catch
			{
			}
			return dest.ToArray();
		}

		public static async Task<byte[]> ReadBytesAsync(this Stream stream, int length, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			byte[] buff = new byte[length];
			int offset = 0;
			try
			{
				while (length > 0)
				{
					int num = await stream.ReadAsync(buff, offset, length, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					if (num != 0)
					{
						offset += num;
						length -= num;
						continue;
					}
					break;
				}
			}
			catch
			{
			}
			return Enumerable.ToArray(new ArraySegment<byte>(buff, 0, offset));
		}

		private static string ToHex(byte[] bytes, bool addPrefix, string format)
		{
			if (bytes == null)
			{
				throw new ArgumentNullException("bytes");
			}
			StringBuilder stringBuilder = new StringBuilder(bytes.Length * 2);
			foreach (byte b in bytes)
			{
				stringBuilder.Append(b.ToString(format, CultureInfo.InvariantCulture));
			}
			return string.Format("{0}{1}", addPrefix ? "0x" : string.Empty, stringBuilder);
		}
	}
	public static class Extensions
	{
		public static int CopyPropertiesTo<T>(this T source, object target, params string[]? ignoreProperties) where T : class
		{
			return ObjectMapper.Copy(source, target, target.GetCopyableProperties(), ignoreProperties);
		}

		public static int CopyOnlyPropertiesTo(this object source, object target, params string[]? propertiesToCopy)
		{
			return ObjectMapper.Copy(source, target, propertiesToCopy);
		}

		public static T CopyPropertiesToNew<T>(this object source, string[]? ignoreProperties = null) where T : class
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			T val = Activator.CreateInstance<T>();
			ObjectMapper.Copy(source, val, val.GetCopyableProperties(), ignoreProperties);
			return val;
		}

		public static T CopyOnlyPropertiesToNew<T>(this object source, params string[] propertiesToCopy) where T : class
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			T val = Activator.CreateInstance<T>();
			ObjectMapper.Copy(source, val, propertiesToCopy);
			return val;
		}

		public static int CopyKeyValuePairTo(this IDictionary<string, object> source, object? target, params string[] ignoreKeys)
		{
			if (source != null)
			{
				return ObjectMapper.Copy(source, target, null, ignoreKeys);
			}
			throw new ArgumentNullException("source");
		}

		public static T CopyKeyValuePairToNew<T>(this IDictionary<string, object> source, params string[] ignoreKeys)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			T val = Activator.CreateInstance<T>();
			source.CopyKeyValuePairTo(val, ignoreKeys);
			return val;
		}

		public static void Retry(this Action action, TimeSpan retryInterval = default(TimeSpan), int retryCount = 3)
		{
			Action action2 = action;
			if (action2 == null)
			{
				throw new ArgumentNullException("action");
			}
			((Func<object>)delegate
			{
				action2();
				return null;
			}).Retry(retryInterval, retryCount);
		}

		public static T Retry<T>(this Func<T> action, TimeSpan retryInterval = default(TimeSpan), int retryCount = 3)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			if (retryInterval == default(TimeSpan))
			{
				retryInterval = TimeSpan.FromSeconds(1.0);
			}
			List<Exception> list = new List<Exception>();
			for (int i = 0; i < retryCount; i++)
			{
				try
				{
					if (i > 0)
					{
						Task.Delay(retryInterval).Wait();
					}
					return action();
				}
				catch (Exception item)
				{
					list.Add(item);
				}
			}
			throw new AggregateException(list);
		}

		public static IEnumerable<string> GetCopyableProperties(this object @this)
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			IEnumerable<PropertyInfo> source = PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(@this.GetType(), onlyPublic: true);
			IEnumerable<string> enumerable = from x in source
				select new
				{
					Name = x.Name,
					HasAttribute = (AttributeCache.DefaultCache.Value.RetrieveOne<CopyableAttribute>(x) != null)
				} into x
				where x.HasAttribute
				select x.Name;
			if (!enumerable.Any())
			{
				return source.Select((PropertyInfo x) => x.Name);
			}
			return enumerable;
		}

		internal static void CreateTarget(this object source, Type targetType, bool includeNonPublic, ref object? target)
		{
			if (source is string)
			{
				return;
			}
			if (source is IList list && targetType.IsArray)
			{
				Type elementType = targetType.GetElementType();
				if (elementType != null)
				{
					target = Array.CreateInstance(elementType, list.Count);
				}
				return;
			}
			IEnumerable<Tuple<ConstructorInfo, ParameterInfo[]>> source2 = ConstructorTypeCache.DefaultCache.Value.RetrieveAllConstructors(targetType, includeNonPublic);
			if (source2.Any((Tuple<ConstructorInfo, ParameterInfo[]> x) => x.Item2.Length == 0))
			{
				target = Activator.CreateInstance(targetType, includeNonPublic);
				return;
			}
			target = Activator.CreateInstance(targetType, source2.OrderBy((Tuple<ConstructorInfo, ParameterInfo[]> x) => x.Item2.Length).FirstOrDefault()?.Item2.Select((ParameterInfo arg) => arg.GetType().GetDefault()).ToArray());
		}

		internal static string GetNameWithCase(this string name, JsonSerializerCase jsonSerializerCase)
		{
			return jsonSerializerCase switch
			{
				JsonSerializerCase.PascalCase => char.ToUpperInvariant(name[0]) + name.Substring(1), 
				JsonSerializerCase.CamelCase => char.ToLowerInvariant(name[0]) + name.Substring(1), 
				JsonSerializerCase.None => name, 
				_ => throw new ArgumentOutOfRangeException("jsonSerializerCase", jsonSerializerCase, null), 
			};
		}

		public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default(TValue))
		{
			if (dict == null)
			{
				throw new ArgumentNullException("dict");
			}
			if (!dict.ContainsKey(key))
			{
				return defaultValue;
			}
			return dict[key];
		}

		public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, Func<TKey, TValue> valueFactory)
		{
			if (dict == null)
			{
				throw new ArgumentNullException("dict");
			}
			if (valueFactory == null)
			{
				throw new ArgumentNullException("valueFactory");
			}
			if (!dict.ContainsKey(key))
			{
				TValue val = valueFactory(key);
				if (object.Equals(val, null))
				{
					return default(TValue);
				}
				dict[key] = val;
			}
			return dict[key];
		}

		public static void ForEach<TKey, TValue>(this IDictionary<TKey, TValue> dict, Action<TKey, TValue> itemAction)
		{
			if (dict == null)
			{
				throw new ArgumentNullException("dict");
			}
			foreach (KeyValuePair<TKey, TValue> item in dict)
			{
				itemAction(item.Key, item.Value);
			}
		}
	}
	public static class DateExtensions
	{
		private static readonly Dictionary<string, int> DateRanges = new Dictionary<string, int>
		{
			{ "minute", 59 },
			{ "hour", 23 },
			{ "dayOfMonth", 31 },
			{ "month", 12 },
			{ "dayOfWeek", 6 }
		};

		public static string ToSortableDate(this DateTime @this)
		{
			return $"{@this.Year:0000}-{@this.Month:00}-{@this.Day:00}";
		}

		public static string ToSortableDateTime(this DateTime @this)
		{
			return $"{@this.Year:0000}-{@this.Month:00}-{@this.Day:00} {@this.Hour:00}:{@this.Minute:00}:{@this.Second:00}";
		}

		public static DateTime ToDateTime(this string @this)
		{
			if (string.IsNullOrWhiteSpace(@this))
			{
				throw new ArgumentNullException("this");
			}
			int hour = 0;
			int minute = 0;
			int second = 0;
			string[] array = @this.Split(new char[1] { ' ' });
			try
			{
				if (array.Length != 1 && array.Length != 2)
				{
					throw new Exception();
				}
				string[] array2 = array[0].Split(new char[1] { '-' });
				if (array2.Length != 3)
				{
					throw new Exception();
				}
				int year = int.Parse(array2[0]);
				int month = int.Parse(array2[1]);
				int day = int.Parse(array2[2]);
				if (array.Length > 1)
				{
					string[] array3 = array[1].Split(new char[1] { ':' });
					if (array3.Length != 3)
					{
						throw new Exception();
					}
					hour = int.Parse(array3[0]);
					minute = int.Parse(array3[1]);
					second = int.Parse(array3[2]);
				}
				return new DateTime(year, month, day, hour, minute, second);
			}
			catch (Exception)
			{
				throw new ArgumentException("Unable to parse sortable date and time.", "this");
			}
		}

		public static IEnumerable<DateTime> DateRange(this DateTime startDate, DateTime endDate)
		{
			return from d in Enumerable.Range(0, (endDate - startDate).Days + 1)
				select startDate.AddDays(d);
		}

		public static DateTime RoundUp(this DateTime date, TimeSpan timeSpan)
		{
			return new DateTime((date.Ticks + timeSpan.Ticks - 1) / timeSpan.Ticks * timeSpan.Ticks);
		}

		public static long ToUnixEpochDate(this DateTime @this)
		{
			return new DateTimeOffset(@this).ToUniversalTime().ToUnixTimeSeconds();
		}

		public static DateTimeSpan GetDateTimeSpan(this DateTime dateStart, DateTime dateEnd)
		{
			return DateTimeSpan.CompareDates(dateStart, dateEnd);
		}

		public static bool AsCronCanRun(this DateTime @this, int? minute = null, int? hour = null, int? dayOfMonth = null, int? month = null, int? dayOfWeek = null)
		{
			return new List<bool?>
			{
				GetElementParts(minute, @this.Minute),
				GetElementParts(hour, @this.Hour),
				GetElementParts(dayOfMonth, @this.Day),
				GetElementParts(month, @this.Month),
				GetElementParts(dayOfWeek, (int)@this.DayOfWeek)
			}.Any((bool? x) => x != false);
		}

		public static bool AsCronCanRun(this DateTime @this, string minute = "*", string hour = "*", string dayOfMonth = "*", string month = "*", string dayOfWeek = "*")
		{
			return new List<bool?>
			{
				GetElementParts(minute, "minute", @this.Minute),
				GetElementParts(hour, "hour", @this.Hour),
				GetElementParts(dayOfMonth, "dayOfMonth", @this.Day),
				GetElementParts(month, "month", @this.Month),
				GetElementParts(dayOfWeek, "dayOfWeek", (int)@this.DayOfWeek)
			}.Any((bool? x) => x != false);
		}

		public static string ToRfc1123String(this DateTime @this)
		{
			return @this.ToUniversalTime().ToString("R", CultureInfo.InvariantCulture);
		}

		private static bool? GetElementParts(int? status, int value)
		{
			if (!status.HasValue)
			{
				return null;
			}
			return status.Value == value;
		}

		private static bool? GetElementParts(string parts, string type, int value)
		{
			if (string.IsNullOrWhiteSpace(parts) || parts == "*")
			{
				return null;
			}
			if (parts.Contains(","))
			{
				return parts.Split(new char[1] { ',' }).Select(int.Parse).Contains(value);
			}
			int num = DateRanges[type];
			if (parts.Contains("/"))
			{
				int num2 = int.Parse(parts.Split(new char[1] { '/' }).Last());
				for (int i = ((type == "dayOfMonth" || type == "month") ? 1 : 0); i <= num; i += num2)
				{
					if (i == value)
					{
						return true;
					}
				}
				return false;
			}
			if (parts.Contains("-"))
			{
				string[] source = parts.Split(new char[1] { '-' });
				int num3 = int.Parse(source.First());
				num = Math.Max(num, int.Parse(source.Last()));
				if ((type == "dayOfMonth" || type == "month") && num3 == 0)
				{
					num3 = 1;
				}
				for (int j = num3; j <= num; j++)
				{
					if (j == value)
					{
						return true;
					}
				}
				return false;
			}
			return int.Parse(parts) == value;
		}
	}
	public static class EnumerableExtensions
	{
		public static IEnumerable<TSource> UnionExcludingNulls<TSource>(this IEnumerable<TSource> @this, IEnumerable<TSource> second)
		{
			return (@this ?? Enumerable.Empty<TSource>()).Union(second ?? Enumerable.Empty<TSource>());
		}

		public static IEnumerable<TSource> UnionExcludingNulls<TSource>(this IEnumerable<TSource> @this, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
		{
			return (@this ?? Enumerable.Empty<TSource>()).Union(second ?? Enumerable.Empty<TSource>(), comparer);
		}
	}
	public static class ExceptionExtensions
	{
		public static bool IsCriticalException(this Exception @this)
		{
			if (!@this.IsCriticalExceptionCore())
			{
				Exception? innerException = @this.InnerException;
				if (innerException == null || !innerException.IsCriticalException())
				{
					if (@this is AggregateException ex)
					{
						return ex.InnerExceptions.Any((Exception e) => e.IsCriticalException());
					}
					return false;
				}
			}
			return true;
		}

		public static bool IsFatalException(this Exception @this)
		{
			if (!@this.IsFatalExceptionCore())
			{
				Exception? innerException = @this.InnerException;
				if (innerException == null || !innerException.IsFatalException())
				{
					if (@this is AggregateException ex)
					{
						return ex.InnerExceptions.Any((Exception e) => e.IsFatalException());
					}
					return false;
				}
			}
			return true;
		}

		public static InternalErrorException RethrowPreservingStackTrace(this Exception @this)
		{
			ExceptionDispatchInfo.Capture(@this).Throw();
			return SelfCheck.Failure("Reached unreachable code.", "C:\\Unosquare\\swan\\src\\Swan.Lite\\Extensions.Exceptions.cs", 49);
		}

		private static bool IsCriticalExceptionCore(this Exception @this)
		{
			if (!@this.IsFatalExceptionCore() && !(@this is AppDomainUnloadedException) && !(@this is BadImageFormatException) && !(@this is CannotUnloadAppDomainException) && !(@this is InvalidProgramException))
			{
				return @this is NullReferenceException;
			}
			return true;
		}

		private static bool IsFatalExceptionCore(this Exception @this)
		{
			if (!(@this is StackOverflowException) && !(@this is OutOfMemoryException) && !(@this is ThreadAbortException))
			{
				return @this is AccessViolationException;
			}
			return true;
		}
	}
	public static class FunctionalExtensions
	{
		public static IQueryable<T> When<T>(this IQueryable<T> list, Func<bool> condition, Func<IQueryable<T>, IQueryable<T>> fn)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			if (condition == null)
			{
				throw new ArgumentNullException("condition");
			}
			if (fn == null)
			{
				throw new ArgumentNullException("fn");
			}
			if (!condition())
			{
				return list;
			}
			return fn(list);
		}

		public static IEnumerable<T> When<T>(this IEnumerable<T> list, Func<bool> condition, Func<IEnumerable<T>, IEnumerable<T>> fn)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			if (condition == null)
			{
				throw new ArgumentNullException("condition");
			}
			if (fn == null)
			{
				throw new ArgumentNullException("fn");
			}
			if (!condition())
			{
				return list;
			}
			return fn(list);
		}

		public static IList<T> AddWhen<T>(this IList<T> list, Func<bool> condition, Func<T> value)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			if (condition == null)
			{
				throw new ArgumentNullException("condition");
			}
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			if (condition())
			{
				list.Add(value());
			}
			return list;
		}

		public static IList<T> AddWhen<T>(this IList<T> list, bool condition, T value)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			if (condition)
			{
				list.Add(value);
			}
			return list;
		}

		public static List<T> AddRangeWhen<T>(this List<T> list, Func<bool> condition, Func<IEnumerable<T>> value)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			if (condition == null)
			{
				throw new ArgumentNullException("condition");
			}
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			if (condition())
			{
				list.AddRange(value());
			}
			return list;
		}
	}
	public static class IEnumerableExtensions
	{
		public static IEnumerable<T> UnionNull<T>(this IEnumerable<T> @this, IEnumerable<T> second)
		{
			if (@this == null)
			{
				return second;
			}
			if (second != null)
			{
				return @this.Union(second);
			}
			return @this;
		}
	}
	public static class PropertyProxyExtensions
	{
		private static readonly object SyncLock = new object();

		private static readonly Dictionary<Type, Dictionary<string, IPropertyProxy>> ProxyCache = new Dictionary<Type, Dictionary<string, IPropertyProxy>>(32);

		public static Dictionary<string, IPropertyProxy> PropertyProxies(this Type t)
		{
			if (t == null)
			{
				throw new ArgumentNullException("t");
			}
			lock (SyncLock)
			{
				if (ProxyCache.ContainsKey(t))
				{
					return ProxyCache[t];
				}
				PropertyInfo[] properties = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
				Dictionary<string, IPropertyProxy> dictionary = new Dictionary<string, IPropertyProxy>(properties.Length, StringComparer.InvariantCultureIgnoreCase);
				PropertyInfo[] array = properties;
				foreach (PropertyInfo propertyInfo in array)
				{
					dictionary[propertyInfo.Name] = new PropertyInfoProxy(t, propertyInfo);
				}
				ProxyCache[t] = dictionary;
				return dictionary;
			}
		}

		public static Dictionary<string, IPropertyProxy> PropertyProxies<T>(this T obj)
		{
			return (obj?.GetType() ?? typeof(T)).PropertyProxies();
		}

		public static IPropertyProxy PropertyProxy(this Type t, string propertyName)
		{
			Dictionary<string, IPropertyProxy> dictionary = t.PropertyProxies();
			if (!dictionary.ContainsKey(propertyName))
			{
				return null;
			}
			return dictionary[propertyName];
		}

		public static IPropertyProxy PropertyProxy<T>(this T obj, string propertyName)
		{
			if (propertyName == null)
			{
				throw new ArgumentNullException("propertyName");
			}
			Dictionary<string, IPropertyProxy> dictionary = (obj?.GetType() ?? typeof(T)).PropertyProxies();
			if (dictionary == null || !dictionary.ContainsKey(propertyName))
			{
				return null;
			}
			return dictionary[propertyName];
		}

		public static IPropertyProxy PropertyProxy<T, V>(this T obj, Expression<Func<T, V>> propertyExpression)
		{
			if (propertyExpression == null)
			{
				throw new ArgumentNullException("propertyExpression");
			}
			Dictionary<string, IPropertyProxy> dictionary = (obj?.GetType() ?? typeof(T)).PropertyProxies();
			string key = propertyExpression.PropertyName();
			if (dictionary == null || !dictionary.ContainsKey(key))
			{
				return null;
			}
			return dictionary[key];
		}

		public static V ReadProperty<T, V>(this T obj, Expression<Func<T, V>> propertyExpression)
		{
			if (obj == null)
			{
				throw new ArgumentNullException("obj");
			}
			return (V)(obj.PropertyProxy(propertyExpression)?.GetValue(obj));
		}

		public static object? ReadProperty<T>(this T obj, string propertyName)
		{
			if (obj == null)
			{
				throw new ArgumentNullException("obj");
			}
			return obj.PropertyProxy(propertyName)?.GetValue(obj);
		}

		public static void WriteProperty<T, TV>(this T obj, Expression<Func<T, TV>> propertyExpression, TV value)
		{
			obj.PropertyProxy(propertyExpression)?.SetValue(obj, value);
		}

		public static void WriteProperty<T>(this T obj, string propertyName, object? value)
		{
			obj.PropertyProxy(propertyName)?.SetValue(obj, value);
		}

		private static string PropertyName<T, TV>(this Expression<Func<T, TV>> propertyExpression)
		{
			return ((!(propertyExpression.Body is MemberExpression)) ? ((propertyExpression.Body as UnaryExpression).Operand as MemberExpression) : (propertyExpression.Body as MemberExpression)).Member.Name;
		}
	}
	public static class ReflectionExtensions
	{
		public static IEnumerable<Type> GetAllTypes(this Assembly assembly)
		{
			if (assembly == null)
			{
				throw new ArgumentNullException("assembly");
			}
			try
			{
				return assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				return ex.Types.Where((Type t) => t != null);
			}
		}

		public static object? GetDefault(this Type type)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (!type.IsValueType)
			{
				return null;
			}
			return Activator.CreateInstance(type);
		}

		public static bool IsCollection(this Type sourceType)
		{
			if (sourceType == null)
			{
				throw new ArgumentNullException("sourceType");
			}
			if (sourceType != typeof(string))
			{
				return typeof(IEnumerable).IsAssignableFrom(sourceType);
			}
			return false;
		}

		public static MethodInfo GetMethod(this Type type, BindingFlags bindingFlags, string methodName, Type[] genericTypes, Type[] parameterTypes)
		{
			string methodName2 = methodName;
			Type[] genericTypes2 = genericTypes;
			Type[] parameterTypes2 = parameterTypes;
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (methodName2 == null)
			{
				throw new ArgumentNullException("methodName");
			}
			if (genericTypes2 == null)
			{
				throw new ArgumentNullException("genericTypes");
			}
			if (parameterTypes2 == null)
			{
				throw new ArgumentNullException("parameterTypes");
			}
			List<MethodInfo> list = (from mi in type.GetMethods(bindingFlags)
				where string.Equals(methodName2, mi.Name, StringComparison.Ordinal)
				where mi.ContainsGenericParameters
				where mi.GetGenericArguments().Length == genericTypes2.Length
				where mi.GetParameters().Length == parameterTypes2.Length
				select mi.MakeGenericMethod(genericTypes2) into mi
				where (from pi in mi.GetParameters()
					select pi.ParameterType).SequenceEqual(parameterTypes2)
				select mi).ToList();
			if (list.Count <= 1)
			{
				return list.FirstOrDefault();
			}
			throw new AmbiguousMatchException();
		}

		public static bool IsIEnumerable(this Type type)
		{
			if (!(type == null))
			{
				if (type.IsGenericType)
				{
					return type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
				}
				return false;
			}
			throw new ArgumentNullException("type");
		}

		public static bool TryParseBasicType(this Type type, object value, out object? result)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (type != typeof(bool))
			{
				return type.TryParseBasicType(value.ToStringInvariant(), out result);
			}
			result = value.ToBoolean();
			return true;
		}

		public static bool TryParseBasicType(this Type type, string value, out object? result)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			result = null;
			if (Definitions.BasicTypesInfo.Value.ContainsKey(type))
			{
				return Definitions.BasicTypesInfo.Value[type].TryParse(value, out result);
			}
			return false;
		}

		public static bool TrySetBasicType(this PropertyInfo propertyInfo, object value, object target)
		{
			if (propertyInfo == null)
			{
				throw new ArgumentNullException("propertyInfo");
			}
			try
			{
				if (propertyInfo.PropertyType.TryParseBasicType(value, out object result))
				{
					propertyInfo.SetValue(target, result);
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		public static bool TrySetArrayBasicType(this Type type, object value, Array target, int index)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (target == null)
			{
				return false;
			}
			try
			{
				if (value == null)
				{
					target.SetValue(null, index);
					return true;
				}
				if (type.TryParseBasicType(value, out object result))
				{
					target.SetValue(result, index);
					return true;
				}
				if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
				{
					target.SetValue(null, index);
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		public static bool TrySetArray(this PropertyInfo propertyInfo, IEnumerable<object>? value, object obj)
		{
			if (propertyInfo == null)
			{
				throw new ArgumentNullException("propertyInfo");
			}
			Type elementType = propertyInfo.PropertyType.GetElementType();
			if (elementType == null || value == null)
			{
				return false;
			}
			Array array = Array.CreateInstance(elementType, value.Count());
			int num = 0;
			foreach (object item in value)
			{
				if (!elementType.TrySetArrayBasicType(item, array, num++))
				{
					return false;
				}
			}
			propertyInfo.SetValue(obj, array);
			return true;
		}

		public static bool ToBoolean(this string str)
		{
			try
			{
				return Convert.ToBoolean(str);
			}
			catch (FormatException)
			{
			}
			try
			{
				return Convert.ToBoolean(Convert.ToInt32(str));
			}
			catch
			{
			}
			return false;
		}

		public static bool ToBoolean(this object value)
		{
			return value.ToStringInvariant().ToBoolean();
		}
	}
	public static class StringExtensions
	{
		private const RegexOptions StandardRegexOptions = RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.CultureInvariant;

		private static readonly string[] ByteSuffixes = new string[5] { "B", "KB", "MB", "GB", "TB" };

		private static readonly Lazy<Regex> SplitLinesRegex = new Lazy<Regex>(() => new Regex("\r\n|\r|\n", RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.CultureInvariant));

		private static readonly Lazy<Regex> UnderscoreRegex = new Lazy<Regex>(() => new Regex("_", RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.CultureInvariant));

		private static readonly Lazy<Regex> CamelCaseRegEx = new Lazy<Regex>(() => new Regex("[a-z][A-Z]", RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.CultureInvariant));

		private static readonly Lazy<MatchEvaluator> SplitCamelCaseString = new Lazy<MatchEvaluator>(() => delegate(Match m)
		{
			string text = m.ToString();
			return text[0] + " " + text.Substring(1, text.Length - 1);
		});

		private static readonly Lazy<string[]> InvalidFilenameChars = new Lazy<string[]>(() => (from c in Path.GetInvalidFileNameChars()
			select c.ToStringInvariant()).ToArray());

		public static string ToStringInvariant(this object? @this)
		{
			if (@this == null)
			{
				return string.Empty;
			}
			Type type = @this.GetType();
			if (type == typeof(string))
			{
				return (@this as string) ?? string.Empty;
			}
			if (!Definitions.BasicTypesInfo.Value.ContainsKey(type))
			{
				return @this.ToString();
			}
			return Definitions.BasicTypesInfo.Value[type].ToStringInvariant(@this);
		}

		public static string ToStringInvariant<T>(this T item)
		{
			if (!(typeof(string) == typeof(T)))
			{
				return ((object?)item).ToStringInvariant();
			}
			return (item as string) ?? string.Empty;
		}

		public static string RemoveControlChars(this string value, params char[]? excludeChars)
		{
			char[] excludeChars2 = excludeChars;
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			if (excludeChars2 == null)
			{
				excludeChars2 = Array.Empty<char>();
			}
			return new string(value.Where((char c) => !char.IsControl(c) || excludeChars2.Contains(c)).ToArray());
		}

		public static string ToJson(this object @this, bool format = true)
		{
			if (@this != null)
			{
				return Json.Serialize(@this, format, null, false, null);
			}
			return string.Empty;
		}

		public static string Stringify(this object @this)
		{
			if (@this == null)
			{
				return "(null)";
			}
			try
			{
				return new HumanizeJson(Json.Deserialize(Json.Serialize(@this, false, "$type", false, null)), 0).GetResult();
			}
			catch
			{
				return @this.ToStringInvariant();
			}
		}

		public static string Slice(this string @this, int startIndex, int endIndex)
		{
			if (@this == null)
			{
				return string.Empty;
			}
			int num = endIndex.Clamp(startIndex, @this.Length - 1);
			if (startIndex < num)
			{
				return @this.Substring(startIndex, num - startIndex + 1);
			}
			return string.Empty;
		}

		public static string SliceLength(this string @this, int startIndex, int length)
		{
			if (@this == null)
			{
				return string.Empty;
			}
			int num = startIndex.Clamp(0, @this.Length - 1);
			int num2 = length.Clamp(0, @this.Length - num);
			if (num2 != 0)
			{
				return @this.Substring(num, num2);
			}
			return string.Empty;
		}

		public static string[] ToLines(this string @this)
		{
			if (@this != null)
			{
				return SplitLinesRegex.Value.Split(@this);
			}
			return Array.Empty<string>();
		}

		public static string Humanize(this string value)
		{
			if (value == null)
			{
				return string.Empty;
			}
			string input = UnderscoreRegex.Value.Replace(value, " ");
			return CamelCaseRegEx.Value.Replace(input, SplitCamelCaseString.Value);
		}

		public static string Humanize(this bool value)
		{
			if (!value)
			{
				return "No";
			}
			return "Yes";
		}

		public static string Humanize(this object value)
		{
			if (!(value is string value2))
			{
				if (value is bool value3)
				{
					return value3.Humanize();
				}
				return value.Stringify();
			}
			return value2.Humanize();
		}

		public static string Indent(this string value, int spaces = 4)
		{
			if (value == null)
			{
				value = string.Empty;
			}
			if (spaces <= 0)
			{
				return value;
			}
			string[] array = value.ToLines();
			StringBuilder stringBuilder = new StringBuilder();
			string text = new string(' ', spaces);
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				stringBuilder.AppendLine(text + text2);
			}
			return stringBuilder.ToString().TrimEnd(Array.Empty<char>());
		}

		public static Tuple<int, int> TextPositionAt(this string value, int charIndex)
		{
			if (value == null)
			{
				return Tuple.Create(0, 0);
			}
			int num = charIndex.Clamp(0, value.Length - 1);
			int num2 = 0;
			int num3 = 0;
			for (int i = 0; i <= num; i++)
			{
				if (value[i] == '\n')
				{
					num2++;
					num3 = 0;
				}
				else if (value[i] != '\r')
				{
					num3++;
				}
			}
			return Tuple.Create(num2 + 1, num3);
		}

		public static string ToSafeFilename(this string value)
		{
			if (value != null)
			{
				return InvalidFilenameChars.Value.Aggregate(value, (string current, string c) => current.Replace(c, string.Empty)).Slice(0, 220);
			}
			throw new ArgumentNullException("value");
		}

		public static string FormatBytes(this long bytes)
		{
			return ((ulong)bytes).FormatBytes();
		}

		public static string FormatBytes(this ulong bytes)
		{
			double num = bytes;
			int num2 = 0;
			while (num2 < ByteSuffixes.Length && bytes >= 1024)
			{
				num = (double)bytes / 1024.0;
				num2++;
				bytes /= 1024;
			}
			return $"{num:0.##} {ByteSuffixes[num2]}";
		}

		public static string? Truncate(this string value, int maximumLength)
		{
			return value.Truncate(maximumLength, string.Empty);
		}

		public static string? Truncate(this string value, int maximumLength, string omission)
		{
			if (value == null)
			{
				return null;
			}
			if (value.Length <= maximumLength)
			{
				return value;
			}
			return value.Substring(0, maximumLength) + (omission ?? string.Empty);
		}

		public static bool Contains(this string value, params char[] chars)
		{
			if (chars != null)
			{
				if (chars.Length != 0)
				{
					if (!string.IsNullOrEmpty(value))
					{
						return value.IndexOfAny(chars) > -1;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		public static string ReplaceAll(this string value, string replaceValue, params char[] chars)
		{
			string replaceValue2 = replaceValue;
			return chars.Aggregate(value, (string current, char c) => current.Replace(new string(new char[1] { c }), replaceValue2));
		}

		public static int Hex2Int(this char value)
		{
			if (value < '0' || value > '9')
			{
				if (value < 'A' || value > 'F')
				{
					if (value < 'a' || value > 'f')
					{
						return -1;
					}
					return value - 97 + 10;
				}
				return value - 65 + 10;
			}
			return value - 48;
		}
	}
	public static class TaskExtensions
	{
		public static void Await(this Task @this)
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			@this.GetAwaiter().GetResult();
		}

		public static TResult Await<TResult>(this Task<TResult> @this)
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			return @this.GetAwaiter().GetResult();
		}

		public static void Await(this Task @this, bool continueOnCapturedContext)
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			@this.ConfigureAwait(continueOnCapturedContext).GetAwaiter().GetResult();
		}

		public static TResult Await<TResult>(this Task<TResult> @this, bool continueOnCapturedContext)
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			return @this.ConfigureAwait(continueOnCapturedContext).GetAwaiter().GetResult();
		}
	}
	public static class ValueTypeExtensions
	{
		public static T Clamp<T>(this T @this, T min, T max) where T : struct, IComparable
		{
			if (@this.CompareTo(min) < 0)
			{
				return min;
			}
			if (@this.CompareTo(max) <= 0)
			{
				return @this;
			}
			return max;
		}

		public static int Clamp(this int @this, int min, int max)
		{
			if (@this >= min)
			{
				if (@this <= max)
				{
					return @this;
				}
				return max;
			}
			return min;
		}

		public static bool IsBetween<T>(this T @this, T min, T max) where T : struct, IComparable
		{
			if (@this.CompareTo(min) >= 0)
			{
				return @this.CompareTo(max) <= 0;
			}
			return false;
		}

		public static T ToStruct<T>(this byte[] @this) where T : struct
		{
			if (@this != null)
			{
				return @this.ToStruct<T>(0, @this.Length);
			}
			throw new ArgumentNullException("this");
		}

		public static T ToStruct<T>(this byte[] @this, int offset, int length) where T : struct
		{
			if (@this == null)
			{
				throw new ArgumentNullException("this");
			}
			byte[] array = new byte[length];
			Array.Copy(@this, offset, array, 0, array.Length);
			GCHandle gCHandle = GCHandle.Alloc(GetStructBytes<T>(array), GCHandleType.Pinned);
			try
			{
				return Marshal.PtrToStructure<T>(gCHandle.AddrOfPinnedObject());
			}
			finally
			{
				gCHandle.Free();
			}
		}

		public static byte[] ToBytes<T>(this T @this) where T : struct
		{
			byte[] array = new byte[Marshal.SizeOf(@this)];
			GCHandle gCHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
			try
			{
				Marshal.StructureToPtr(@this, gCHandle.AddrOfPinnedObject(), fDeleteOld: false);
				return GetStructBytes<T>(array);
			}
			finally
			{
				gCHandle.Free();
			}
		}

		public static uint SwapEndianness(this ulong @this)
		{
			return (uint)(((@this & 0xFF) << 24) + ((@this & 0xFF00) << 8) + ((@this & 0xFF0000) >> 8) + ((@this & 0xFF000000u) >> 24));
		}

		private static byte[] GetStructBytes<T>(byte[] data)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			FieldInfo[] fields = typeof(T).GetTypeInfo().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			StructEndiannessAttribute structEndiannessAttribute = AttributeCache.DefaultCache.Value.RetrieveOne<StructEndiannessAttribute, T>();
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				if (structEndiannessAttribute != null || fieldInfo.IsDefined(typeof(StructEndiannessAttribute), inherit: false))
				{
					int index = Marshal.OffsetOf<T>(fieldInfo.Name).ToInt32();
					int length = Marshal.SizeOf(fieldInfo.FieldType);
					if (structEndiannessAttribute == null)
					{
						structEndiannessAttribute = AttributeCache.DefaultCache.Value.RetrieveOne<StructEndiannessAttribute>(fieldInfo);
					}
					if (structEndiannessAttribute != null && ((structEndiannessAttribute.Endianness == Endianness.Big && BitConverter.IsLittleEndian) || (structEndiannessAttribute.Endianness == Endianness.Little && !BitConverter.IsLittleEndian)))
					{
						Array.Reverse((Array)data, index, length);
					}
				}
			}
			return data;
		}
	}
	public static class FromString
	{
		private static readonly MethodInfo ConvertFromInvariantStringMethod = new Func<string, object>(TypeDescriptor.GetConverter(typeof(int)).ConvertFromInvariantString).Method;

		private static readonly MethodInfo TryConvertToInternalMethod = typeof(FromString).GetMethod("TryConvertToInternal", BindingFlags.Static | BindingFlags.NonPublic);

		private static readonly MethodInfo ConvertToInternalMethod = typeof(FromString).GetMethod("ConvertToInternal", BindingFlags.Static | BindingFlags.NonPublic);

		private static readonly ConcurrentDictionary<Type, Func<string[], (bool Success, object Result)>> GenericTryConvertToMethods = new ConcurrentDictionary<Type, Func<string[], (bool, object)>>();

		private static readonly ConcurrentDictionary<Type, Func<string[], object>> GenericConvertToMethods = new ConcurrentDictionary<Type, Func<string[], object>>();

		public static bool CanConvertTo(Type type)
		{
			return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string));
		}

		public static bool CanConvertTo<TResult>()
		{
			return TypeDescriptor.GetConverter(typeof(TResult)).CanConvertFrom(typeof(string));
		}

		public static bool TryConvertTo(Type type, string str, out object? result)
		{
			TypeConverter converter = TypeDescriptor.GetConverter(type);
			if (!converter.CanConvertFrom(typeof(string)))
			{
				result = null;
				return false;
			}
			try
			{
				result = converter.ConvertFromInvariantString(str);
				return true;
			}
			catch (Exception @this) when (!@this.IsCriticalException())
			{
				result = null;
				return false;
			}
		}

		public static bool TryConvertTo<TResult>(string str, out TResult result)
		{
			TypeConverter converter = TypeDescriptor.GetConverter(typeof(TResult));
			if (!converter.CanConvertFrom(typeof(string)))
			{
				result = default(TResult);
				return false;
			}
			try
			{
				result = (TResult)converter.ConvertFromInvariantString(str);
				return true;
			}
			catch (Exception @this) when (!@this.IsCriticalException())
			{
				result = default(TResult);
				return false;
			}
		}

		public static object ConvertTo(Type type, string str)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			try
			{
				return TypeDescriptor.GetConverter(type).ConvertFromInvariantString(str);
			}
			catch (Exception ex) when (!ex.IsCriticalException())
			{
				throw new StringConversionException(type, ex);
			}
		}

		public static TResult ConvertTo<TResult>(string str)
		{
			try
			{
				return (TResult)TypeDescriptor.GetConverter(typeof(TResult)).ConvertFromInvariantString(str);
			}
			catch (Exception ex) when (!ex.IsCriticalException())
			{
				throw new StringConversionException(typeof(TResult), ex);
			}
		}

		public static bool TryConvertTo(Type type, string[] strings, out object? result)
		{
			if (strings == null)
			{
				result = null;
				return false;
			}
			(bool, object) tuple = GenericTryConvertToMethods.GetOrAdd(type, BuildNonGenericTryConvertLambda)(strings);
			bool item = tuple.Item1;
			object item2 = tuple.Item2;
			result = item2;
			return item;
		}

		public static bool TryConvertTo<TResult>(string[] strings, out TResult[]? result)
		{
			if (strings == null)
			{
				result = null;
				return false;
			}
			TypeConverter converter = TypeDescriptor.GetConverter(typeof(TResult));
			if (!converter.CanConvertFrom(typeof(string)))
			{
				result = null;
				return false;
			}
			try
			{
				result = new TResult[strings.Length];
				int num = 0;
				foreach (string text in strings)
				{
					result[num++] = (TResult)converter.ConvertFromInvariantString(text);
				}
				return true;
			}
			catch (Exception @this) when (!@this.IsCriticalException())
			{
				result = null;
				return false;
			}
		}

		public static object? ConvertTo(Type type, string[] strings)
		{
			if (strings == null)
			{
				return null;
			}
			return GenericConvertToMethods.GetOrAdd(type, BuildNonGenericConvertLambda)(strings);
		}

		public static TResult[]? ConvertTo<TResult>(string[] strings)
		{
			if (strings == null)
			{
				return null;
			}
			TypeConverter converter = TypeDescriptor.GetConverter(typeof(TResult));
			TResult[] array = new TResult[strings.Length];
			int num = 0;
			try
			{
				foreach (string text in strings)
				{
					array[num++] = (TResult)converter.ConvertFromInvariantString(text);
				}
				return array;
			}
			catch (Exception ex) when (!ex.IsCriticalException())
			{
				throw new StringConversionException(typeof(TResult), ex);
			}
		}

		public static Expression? ConvertExpressionTo(Type type, Expression str)
		{
			TypeConverter converter = TypeDescriptor.GetConverter(type);
			if (!converter.CanConvertFrom(typeof(string)))
			{
				return null;
			}
			return Expression.Convert(Expression.Call(Expression.Constant(converter), ConvertFromInvariantStringMethod, str), type);
		}

		private static Func<string[], (bool Success, object Result)> BuildNonGenericTryConvertLambda(Type type)
		{
			MethodInfo method = TryConvertToInternalMethod.MakeGenericMethod(type);
			ParameterExpression parameterExpression = Expression.Parameter(typeof(string[]));
			return Expression.Lambda<Func<string[], (bool, object)>>(Expression.Call(method, parameterExpression), new ParameterExpression[1] { parameterExpression }).Compile();
		}

		private static (bool Success, object? Result) TryConvertToInternal<TResult>(string[] strings)
		{
			TypeConverter converter = TypeDescriptor.GetConverter(typeof(TResult));
			if (!converter.CanConvertFrom(typeof(string)))
			{
				return (false, null);
			}
			TResult[] array = new TResult[strings.Length];
			int num = 0;
			try
			{
				foreach (string text in strings)
				{
					array[num++] = (TResult)converter.ConvertFromInvariantString(text);
				}
				return (true, array);
			}
			catch (Exception @this) when (!@this.IsCriticalException())
			{
				return (false, null);
			}
		}

		private static Func<string[], object> BuildNonGenericConvertLambda(Type type)
		{
			MethodInfo method = ConvertToInternalMethod.MakeGenericMethod(type);
			ParameterExpression parameterExpression = Expression.Parameter(typeof(string[]));
			return Expression.Lambda<Func<string[], object>>(Expression.Call(method, parameterExpression), new ParameterExpression[1] { parameterExpression }).Compile();
		}

		private static object ConvertToInternal<TResult>(string[] strings)
		{
			TypeConverter converter = TypeDescriptor.GetConverter(typeof(TResult));
			TResult[] array = new TResult[strings.Length];
			int num = 0;
			try
			{
				foreach (string text in strings)
				{
					array[num++] = (TResult)converter.ConvertFromInvariantString(text);
				}
				return array;
			}
			catch (Exception ex) when (!ex.IsCriticalException())
			{
				throw new StringConversionException(typeof(TResult), ex);
			}
		}
	}
	[Serializable]
	public sealed class InternalErrorException : Exception
	{
		internal InternalErrorException(string message)
			: base(message)
		{
		}

		private InternalErrorException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	public static class ObjectComparer
	{
		public static bool AreEqual<T>(T left, T right)
		{
			return AreEqual(left, right, typeof(T));
		}

		public static bool AreEqual(object left, object right, Type targetType)
		{
			if (targetType == null)
			{
				throw new ArgumentNullException("targetType");
			}
			if (Definitions.BasicTypesInfo.Value.ContainsKey(targetType))
			{
				return object.Equals(left, right);
			}
			if (!targetType.IsValueType && !targetType.IsArray)
			{
				return AreObjectsEqual(left, right, targetType);
			}
			return AreStructsEqual(left, right, targetType);
		}

		public static bool AreObjectsEqual<T>(T left, T right) where T : class
		{
			return AreObjectsEqual(left, right, typeof(T));
		}

		public static bool AreObjectsEqual(object left, object right, Type targetType)
		{
			if (targetType == null)
			{
				throw new ArgumentNullException("targetType");
			}
			PropertyInfo[] array = PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(targetType).ToArray();
			foreach (PropertyInfo propertyInfo in array)
			{
				if (propertyInfo.PropertyType.IsArray)
				{
					IEnumerable left2 = left.ReadProperty(propertyInfo.Name) as IEnumerable;
					IEnumerable right2 = right.ReadProperty(propertyInfo.Name) as IEnumerable;
					if (!AreEnumerationsEquals(left2, right2))
					{
						return false;
					}
				}
				else if (!object.Equals(left.ReadProperty(propertyInfo.Name), right.ReadProperty(propertyInfo.Name)))
				{
					return false;
				}
			}
			return true;
		}

		public static bool AreStructsEqual<T>(T left, T right) where T : struct
		{
			return AreStructsEqual(left, right, typeof(T));
		}

		public static bool AreStructsEqual(object left, object right, Type targetType)
		{
			if (targetType == null)
			{
				throw new ArgumentNullException("targetType");
			}
			foreach (MemberInfo item in new List<MemberInfo>(FieldTypeCache.DefaultCache.Value.RetrieveAllFields(targetType)).Union(PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(targetType)))
			{
				if (!(item is FieldInfo fieldInfo))
				{
					if (item is PropertyInfo propertyInfo && !object.Equals(left.ReadProperty(propertyInfo.Name), right.ReadProperty(propertyInfo.Name)))
					{
						return false;
					}
				}
				else if (!object.Equals(fieldInfo.GetValue(left), fieldInfo.GetValue(right)))
				{
					return false;
				}
			}
			return true;
		}

		public static bool AreEnumerationsEquals<T>(T left, T right) where T : IEnumerable?
		{
			if (object.Equals(left, default(T)))
			{
				throw new ArgumentNullException("left");
			}
			if (object.Equals(right, default(T)))
			{
				throw new ArgumentNullException("right");
			}
			object[] array = left.Cast<object>().ToArray();
			object[] array2 = right.Cast<object>().ToArray();
			if (array.Length != array2.Length)
			{
				return false;
			}
			for (int i = 0; i < array.Length; i++)
			{
				object obj = array[i];
				object right2 = array2[i];
				if (!AreEqual(obj, right2, obj.GetType()))
				{
					return false;
				}
			}
			return true;
		}
	}
	public class Paginator
	{
		public int PageSize { get; }

		public int TotalCount { get; }

		public int PageCount { get; }

		public Paginator(int totalCount, int pageSize)
		{
			TotalCount = totalCount;
			PageSize = pageSize;
			PageCount = ComputePageCount();
		}

		public int GetFirstItemIndex(int pageIndex)
		{
			pageIndex = FixPageIndex(pageIndex);
			return pageIndex * PageSize;
		}

		public int GetLastItemIndex(int pageIndex)
		{
			return Math.Min(GetFirstItemIndex(pageIndex) + PageSize - 1, TotalCount - 1);
		}

		public int GetItemCount(int pageIndex)
		{
			pageIndex = FixPageIndex(pageIndex);
			if (pageIndex < PageCount - 1)
			{
				return PageSize;
			}
			return GetLastItemIndex(pageIndex) - GetFirstItemIndex(pageIndex) + 1;
		}

		private int FixPageIndex(int pageIndex)
		{
			if (pageIndex < 0)
			{
				return 0;
			}
			if (pageIndex < PageCount)
			{
				return pageIndex;
			}
			return PageCount - 1;
		}

		private int ComputePageCount()
		{
			if (TotalCount == 0)
			{
				return 0;
			}
			if (TotalCount % PageSize == 0)
			{
				return TotalCount / PageSize;
			}
			return TotalCount / PageSize + 1;
		}
	}
	public static class SelfCheck
	{
		public static InternalErrorException Failure(string message, [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0)
		{
			return new InternalErrorException(BuildMessage(message, filePath, lineNumber));
		}

		private static string BuildMessage(string message, string filePath, int lineNumber)
		{
			StackFrame[] frames = new StackTrace().GetFrames();
			if (frames == null)
			{
				return message;
			}
			try
			{
				filePath = Path.GetFileName(filePath);
			}
			catch (ArgumentException)
			{
			}
			StackFrame stackFrame = frames.FirstOrDefault((StackFrame f) => f.GetMethod().ReflectedType != typeof(SelfCheck));
			StringBuilder stringBuilder = new StringBuilder().Append('[').Append(stackFrame?.GetType().Assembly.GetName().Name ?? "<unknown>");
			if (!string.IsNullOrEmpty(filePath))
			{
				stringBuilder.Append(": ").Append(filePath);
				if (lineNumber > 0)
				{
					stringBuilder.Append('(').Append(lineNumber).Append(')');
				}
			}
			return stringBuilder.Append("] ").Append(message).ToString();
		}
	}
	public abstract class SingletonBase<T> : IDisposable where T : class
	{
		protected static readonly Lazy<T> LazyInstance = new Lazy<T>(() => Activator.CreateInstance(typeof(T), nonPublic: true) as T, isThreadSafe: true);

		private bool _isDisposing;

		public static T Instance => LazyInstance.Value;

		public void Dispose()
		{
			Dispose(disposeManaged: true);
		}

		protected virtual void Dispose(bool disposeManaged)
		{
			if (_isDisposing)
			{
				return;
			}
			_isDisposing = true;
			if (LazyInstance == null)
			{
				return;
			}
			try
			{
				(LazyInstance.Value as IDisposable)?.Dispose();
			}
			catch
			{
			}
		}
	}
	[Serializable]
	public class StringConversionException : Exception
	{
		public StringConversionException()
		{
		}

		public StringConversionException(string message)
			: base(message)
		{
		}

		public StringConversionException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public StringConversionException(Type type)
			: base(BuildStandardMessageForType(type))
		{
		}

		public StringConversionException(Type type, Exception innerException)
			: base(BuildStandardMessageForType(type), innerException)
		{
		}

		protected StringConversionException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		private static string BuildStandardMessageForType(Type type)
		{
			return "Cannot convert a string to an instance of " + type.FullName;
		}
	}
	[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Field)]
	public class StructEndiannessAttribute : Attribute
	{
		public Endianness Endianness { get; }

		public StructEndiannessAttribute(Endianness endianness)
		{
			Endianness = endianness;
		}
	}
	public static class SwanRuntime
	{
		private static readonly Lazy<Assembly> EntryAssemblyLazy = new Lazy<Assembly>(Assembly.GetEntryAssembly);

		private static readonly Lazy<string> CompanyNameLazy = new Lazy<string>(() => (EntryAssembly.GetCustomAttribute(typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute)?.Company ?? string.Empty);

		private static readonly Lazy<string> ProductNameLazy = new Lazy<string>(() => (EntryAssembly.GetCustomAttribute(typeof(AssemblyProductAttribute)) as AssemblyProductAttribute)?.Product ?? string.Empty);

		private static readonly Lazy<string> ProductTrademarkLazy = new Lazy<string>(() => (EntryAssembly.GetCustomAttribute(typeof(AssemblyTrademarkAttribute)) as AssemblyTrademarkAttribute)?.Trademark ?? string.Empty);

		private static readonly string ApplicationMutexName = "Global\\{{" + EntryAssembly.FullName + "}}";

		private static readonly object SyncLock = new object();

		private static OperatingSystem? _oS;

		public static OperatingSystem OS
		{
			get
			{
				if (!_oS.HasValue)
				{
					string environmentVariable = Environment.GetEnvironmentVariable("windir");
					if (!string.IsNullOrEmpty(environmentVariable) && environmentVariable.Contains("\\") && Directory.Exists(environmentVariable))
					{
						_oS = OperatingSystem.Windows;
					}
					else
					{
						_oS = (File.Exists("/proc/sys/kernel/ostype") ? OperatingSystem.Unix : OperatingSystem.Osx);
					}
				}
				return _oS.GetValueOrDefault();
			}
		}

		public static bool IsTheOnlyInstance
		{
			get
			{
				lock (SyncLock)
				{
					try
					{
						using (Mutex.OpenExisting(ApplicationMutexName))
						{
						}
					}
					catch
					{
						try
						{
							using Mutex arg = new Mutex(initiallyOwned: true, ApplicationMutexName);
							$"Application Mutex created {arg} named '{ApplicationMutexName}'".Debug(typeof(SwanRuntime), null, "IsTheOnlyInstance", "C:\\Unosquare\\swan\\src\\Swan.Lite\\SwanRuntime.cs", 99);
							return true;
						}
						catch
						{
						}
					}
					return false;
				}
			}
		}

		public static bool IsUsingMonoRuntime => Type.GetType("Mono.Runtime") != null;

		public static Assembly EntryAssembly => EntryAssemblyLazy.Value;

		public static AssemblyName EntryAssemblyName => EntryAssemblyLazy.Value.GetName();

		public static Version EntryAssemblyVersion => EntryAssemblyName.Version;

		public static string EntryAssemblyDirectory => Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(EntryAssembly.CodeBase).Path));

		public static string CompanyName => CompanyNameLazy.Value;

		public static string ProductName => ProductNameLazy.Value;

		public static string ProductTrademark => ProductTrademarkLazy.Value;

		public static string LocalStoragePath
		{
			get
			{
				string text = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), EntryAssemblyName.Name), EntryAssemblyVersion.ToString());
				if (!Directory.Exists(text))
				{
					Directory.CreateDirectory(text);
				}
				return text;
			}
		}

		public static string GetDesktopFilePath(string filename)
		{
			if (string.IsNullOrWhiteSpace(filename))
			{
				throw new ArgumentNullException("filename");
			}
			return Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), filename));
		}
	}
	public static class Terminal
	{
		private sealed class OutputContext
		{
			public ConsoleColor OriginalColor { get; }

			public ConsoleColor OutputColor { get; set; }

			public char[] OutputText { get; set; }

			public TerminalWriters OutputWriters { get; set; }

			public OutputContext()
			{
				OriginalColor = Settings.DefaultColor;
				OutputWriters = (IsConsolePresent ? TerminalWriters.StandardOutput : TerminalWriters.None);
			}
		}

		private static class Table
		{
			public static void Vertical()
			{
				Write('│', Settings.BorderColor);
			}

			public static void RightTee()
			{
				Write('┤', Settings.BorderColor);
			}

			public static void TopRight()
			{
				Write('┐', Settings.BorderColor);
			}

			public static void BottomLeft()
			{
				Write('└', Settings.BorderColor);
			}

			public static void BottomTee()
			{
				Write('┴', Settings.BorderColor);
			}

			public static void TopTee()
			{
				Write('┬', Settings.BorderColor);
			}

			public static void LeftTee()
			{
				Write('├', Settings.BorderColor);
			}

			public static void Horizontal(int length)
			{
				Write(new string('─', length), Settings.BorderColor);
			}

			public static void Tee()
			{
				Write('┼', Settings.BorderColor);
			}

			public static void BottomRight()
			{
				Write('┘', Settings.BorderColor);
			}

			public static void TopLeft()
			{
				Write('┌', Settings.BorderColor);
			}
		}

		public static class Settings
		{
			public static ConsoleColor DefaultColor { get; set; } = Console.ForegroundColor;


			public static ConsoleColor BorderColor { get; } = ConsoleColor.DarkGreen;


			public static string UserInputPrefix { get; set; } = "USR";


			public static string UserOptionText { get; set; } = " Option: ";

		}

		private const int OutputFlushInterval = 15;

		private static readonly ExclusiveTimer DequeueOutputTimer;

		private static readonly object SyncLock;

		private static readonly ConcurrentQueue<OutputContext> OutputQueue;

		private static readonly ManualResetEventSlim OutputDone;

		private static readonly ManualResetEventSlim InputDone;

		private static bool? _isConsolePresent;

		public static int CursorLeft
		{
			get
			{
				if (!IsConsolePresent)
				{
					return -1;
				}
				lock (SyncLock)
				{
					Flush();
					return Console.CursorLeft;
				}
			}
			set
			{
				if (!IsConsolePresent)
				{
					return;
				}
				lock (SyncLock)
				{
					Flush();
					Console.CursorLeft = value;
				}
			}
		}

		public static int CursorTop
		{
			get
			{
				if (!IsConsolePresent)
				{
					return -1;
				}
				lock (SyncLock)
				{
					Flush();
					return Console.CursorTop;
				}
			}
			set
			{
				if (!IsConsolePresent)
				{
					return;
				}
				lock (SyncLock)
				{
					Flush();
					Console.CursorTop = value;
				}
			}
		}

		public static bool IsConsolePresent
		{
			get
			{
				if (!_isConsolePresent.HasValue)
				{
					_isConsolePresent = true;
					try
					{
						int windowHeight = Console.WindowHeight;
						_isConsolePresent = windowHeight >= 0;
					}
					catch
					{
						_isConsolePresent = false;
					}
				}
				return _isConsolePresent.Value;
			}
		}

		public static TerminalWriters AvailableWriters
		{
			get
			{
				if (!IsConsolePresent)
				{
					return TerminalWriters.None;
				}
				return TerminalWriters.All;
			}
		}

		public static Encoding OutputEncoding
		{
			get
			{
				return Console.OutputEncoding;
			}
			set
			{
				Console.OutputEncoding = value;
			}
		}

		static Terminal()
		{
			SyncLock = new object();
			OutputQueue = new ConcurrentQueue<OutputContext>();
			OutputDone = new ManualResetEventSlim(initialState: false);
			InputDone = new ManualResetEventSlim(initialState: true);
			lock (SyncLock)
			{
				if (DequeueOutputTimer == null)
				{
					if (IsConsolePresent)
					{
						Console.CursorVisible = false;
					}
					DequeueOutputTimer = new ExclusiveTimer(DequeueOutputCycle);
					DequeueOutputTimer.Resume(15);
				}
			}
		}

		public static void Flush(TimeSpan? timeout = null)
		{
			if (!timeout.HasValue)
			{
				timeout = TimeSpan.Zero;
			}
			DateTime utcNow = DateTime.UtcNow;
			while (OutputQueue.Count > 0)
			{
				DequeueOutputTimer.Change(0, 15);
				if (OutputDone.Wait(15) || (!(timeout.Value == TimeSpan.Zero) && DateTime.UtcNow.Subtract(utcNow) >= timeout.Value))
				{
					break;
				}
			}
		}

		public static void SetCursorPosition(int left, int top)
		{
			if (!IsConsolePresent)
			{
				return;
			}
			lock (SyncLock)
			{
				Flush();
				Console.SetCursorPosition(left.Clamp(0, left), top.Clamp(0, top));
			}
		}

		public static void BacklineCursor()
		{
			SetCursorPosition(0, CursorTop - 1);
		}

		public static void WriteWelcomeBanner(ConsoleColor color = ConsoleColor.Gray)
		{
			WriteLine($"{SwanRuntime.CompanyName} {SwanRuntime.ProductName} [Version {SwanRuntime.EntryAssemblyVersion}]", color);
			WriteLine(SwanRuntime.ProductTrademark ?? "", color);
		}

		private static void EnqueueOutput(OutputContext context)
		{
			lock (SyncLock)
			{
				TerminalWriters availableWriters = AvailableWriters;
				if (availableWriters == TerminalWriters.None || context.OutputWriters == TerminalWriters.None)
				{
					OutputDone.Set();
				}
				else if ((context.OutputWriters & availableWriters) != 0)
				{
					OutputDone.Reset();
					OutputQueue.Enqueue(context);
				}
			}
		}

		private static void DequeueOutputCycle()
		{
			if (AvailableWriters == TerminalWriters.None)
			{
				OutputDone.Set();
				return;
			}
			InputDone.Wait();
			if (OutputQueue.Count <= 0)
			{
				OutputDone.Set();
				return;
			}
			OutputDone.Reset();
			while (OutputQueue.Count > 0)
			{
				if (OutputQueue.TryDequeue(out OutputContext result) && IsConsolePresent)
				{
					Console.ForegroundColor = result.OutputColor;
					if (result.OutputWriters.HasFlag(TerminalWriters.StandardOutput))
					{
						Console.Out.Write(result.OutputText);
					}
					if (result.OutputWriters.HasFlag(TerminalWriters.StandardError))
					{
						Console.Error.Write(result.OutputText);
					}
					Console.ResetColor();
					Console.ForegroundColor = result.OriginalColor;
				}
			}
		}

		public static ConsoleKeyInfo ReadKey(bool intercept, bool disableLocking = false)
		{
			if (!IsConsolePresent)
			{
				return default(ConsoleKeyInfo);
			}
			if (disableLocking)
			{
				return Console.ReadKey(intercept);
			}
			lock (SyncLock)
			{
				Flush();
				InputDone.Reset();
				try
				{
					Console.CursorVisible = true;
					return Console.ReadKey(intercept);
				}
				finally
				{
					Console.CursorVisible = false;
					InputDone.Set();
				}
			}
		}

		public static ConsoleKeyInfo ReadKey(string prompt, bool preventEcho = true)
		{
			if (!IsConsolePresent)
			{
				return default(ConsoleKeyInfo);
			}
			lock (SyncLock)
			{
				if (prompt != null)
				{
					Write(GetNowFormatted() + Settings.UserInputPrefix + " << " + prompt + " ", ConsoleColor.White);
				}
				ConsoleKeyInfo result = ReadKey(intercept: true);
				WriteLine(preventEcho ? string.Empty : result.Key.ToString());
				return result;
			}
		}

		public static void Clear()
		{
			Flush();
			Console.Clear();
		}

		public static string? ReadLine()
		{
			if (!IsConsolePresent)
			{
				return null;
			}
			lock (SyncLock)
			{
				Flush();
				InputDone.Reset();
				try
				{
					Console.CursorVisible = true;
					return Console.ReadLine();
				}
				finally
				{
					Console.CursorVisible = false;
					InputDone.Set();
				}
			}
		}

		public static string? ReadLine(string prompt)
		{
			if (!IsConsolePresent)
			{
				return null;
			}
			lock (SyncLock)
			{
				Write(GetNowFormatted() + Settings.UserInputPrefix + " << " + prompt + ": ", ConsoleColor.White);
				return ReadLine();
			}
		}

		public static int ReadNumber(string prompt, int defaultNumber)
		{
			if (!IsConsolePresent)
			{
				return defaultNumber;
			}
			lock (SyncLock)
			{
				Write($"{GetNowFormatted()}{Settings.UserInputPrefix} << {prompt} (default is {defaultNumber}): ", ConsoleColor.White);
				int result;
				return int.TryParse(ReadLine(), out result) ? result : defaultNumber;
			}
		}

		public static ConsoleKeyInfo ReadPrompt(string title, IDictionary<ConsoleKey, string> options, string anyKeyOption)
		{
			if (!IsConsolePresent)
			{
				return default(ConsoleKeyInfo);
			}
			if (options == null)
			{
				throw new ArgumentNullException("options");
			}
			int windowWidth = Console.WindowWidth;
			int num = -(windowWidth - 2);
			string format = "{0," + num + "}";
			lock (SyncLock)
			{
				Table.TopLeft();
				Table.Horizontal(-num);
				Table.TopRight();
				Table.Vertical();
				Write(string.Format(CultureInfo.CurrentCulture, format, string.IsNullOrWhiteSpace(title) ? " Select an option from the list below." : (" " + title)), ConsoleColor.White);
				Table.Vertical();
				Table.LeftTee();
				Table.Horizontal(windowWidth - 2);
				Table.RightTee();
				foreach (KeyValuePair<ConsoleKey, string> option in options)
				{
					Table.Vertical();
					Write(string.Format(CultureInfo.CurrentCulture, format, string.Format("    {0,-10}  {1}", "[ " + option.Key.ToString() + " ]", option.Value)), ConsoleColor.White);
					Table.Vertical();
				}
				if (!string.IsNullOrWhiteSpace(anyKeyOption))
				{
					Table.Vertical();
					Write(string.Format(CultureInfo.CurrentCulture, format, " "), ConsoleColor.Gray);
					Table.Vertical();
					Table.Vertical();
					Write(string.Format(CultureInfo.CurrentCulture, format, string.Format("    {0,-10}  {1}", " ", anyKeyOption)), ConsoleColor.Gray);
					Table.Vertical();
				}
				Table.LeftTee();
				Table.Horizontal(windowWidth - 2);
				Table.RightTee();
				Table.Vertical();
				Write(string.Format(CultureInfo.CurrentCulture, format, Settings.UserOptionText), ConsoleColor.Green);
				Table.Vertical();
				Table.BottomLeft();
				Table.Horizontal(windowWidth - 2);
				Table.BottomRight();
			}
			SetCursorPosition(Settings.UserOptionText.Length + 3, CursorTop - 1);
			ConsoleKeyInfo result = ReadKey(intercept: true);
			Write(result.Key.ToString(), ConsoleColor.Gray);
			SetCursorPosition(0, CursorTop + 2);
			return result;
		}

		private static string GetNowFormatted()
		{
			return " " + (string.IsNullOrWhiteSpace(TextLogger.LoggingTimeFormat) ? string.Empty : (DateTime.Now.ToString(TextLogger.LoggingTimeFormat) + " "));
		}

		public static void Write(char charCode, ConsoleColor? color = null, int count = 1, bool newLine = false, TerminalWriters writerFlags = TerminalWriters.StandardOutput)
		{
			lock (SyncLock)
			{
				string text = new string(charCode, count);
				if (newLine)
				{
					text += Environment.NewLine;
				}
				byte[] bytes = OutputEncoding.GetBytes(text);
				EnqueueOutput(new OutputContext
				{
					OutputColor = (color ?? Settings.DefaultColor),
					OutputText = OutputEncoding.GetChars(bytes),
					OutputWriters = writerFlags
				});
			}
		}

		public static void Write(string? text, ConsoleColor? color = null, TerminalWriters writerFlags = TerminalWriters.StandardOutput)
		{
			if (text == null)
			{
				return;
			}
			lock (SyncLock)
			{
				byte[] bytes = OutputEncoding.GetBytes(text);
				EnqueueOutput(new OutputContext
				{
					OutputColor = (color ?? Settings.DefaultColor),
					OutputText = OutputEncoding.GetChars(bytes),
					OutputWriters = writerFlags
				});
			}
		}

		public static void WriteLine(TerminalWriters writerFlags = TerminalWriters.StandardOutput)
		{
			Write(Environment.NewLine, Settings.DefaultColor, writerFlags);
		}

		public static void WriteLine(string text, ConsoleColor? color = null, TerminalWriters writerFlags = TerminalWriters.StandardOutput)
		{
			Write((text ?? string.Empty) + Environment.NewLine, color, writerFlags);
		}

		public static void OverwriteLine(string text, ConsoleColor? color = null, TerminalWriters writerFlags = TerminalWriters.StandardOutput)
		{
			Write("\r" + (text ?? string.Empty), color, writerFlags);
			Flush();
			CursorLeft = 0;
		}
	}
	[Flags]
	public enum TerminalWriters
	{
		None = 0,
		StandardOutput = 1,
		StandardError = 2,
		All = 3
	}
}
namespace Swan.Validators
{
	public interface IValidator
	{
		string ErrorMessage { get; }

		bool IsValid<T>(T value);
	}
	public class ObjectValidationResult
	{
		public class ValidationError
		{
			public string PropertyName { get; }

			public string ErrorMessage { get; }

			public ValidationError(string propertyName, string errorMessage)
			{
				PropertyName = propertyName;
				ErrorMessage = errorMessage;
			}
		}

		private readonly List<ValidationError> _errors = new List<ValidationError>();

		public IReadOnlyList<ValidationError> Errors => _errors;

		public bool IsValid => !Errors.Any();

		public void Add(string propertyName, string errorMessage)
		{
			_errors.Add(new ValidationError(errorMessage, propertyName));
		}
	}
	public class ObjectValidator
	{
		private static readonly Lazy<ObjectValidator> LazyInstance = new Lazy<ObjectValidator>(() => new ObjectValidator());

		private readonly ConcurrentDictionary<Type, List<Tuple<Delegate, string>>> _predicates = new ConcurrentDictionary<Type, List<Tuple<Delegate, string>>>();

		public static ObjectValidator Current => LazyInstance.Value;

		public ObjectValidationResult Validate<T>(T target)
		{
			ObjectValidationResult objectValidationResult = new ObjectValidationResult();
			ValidateObject(target, returnOnError: false, objectValidationResult.Add);
			return objectValidationResult;
		}

		public bool IsValid<T>(T target)
		{
			return ValidateObject(target);
		}

		public void AddValidator<T>(Predicate<T> predicate, string message) where T : class
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			if (string.IsNullOrEmpty(message))
			{
				throw new ArgumentNullException(message);
			}
			if (!_predicates.TryGetValue(typeof(T), out List<Tuple<Delegate, string>> value))
			{
				value = new List<Tuple<Delegate, string>>();
				_predicates[typeof(T)] = value;
			}
			value.Add(Tuple.Create((Delegate)predicate, message));
		}

		private bool ValidateObject<T>(T obj, bool returnOnError = true, Action<string, string>? action = null)
		{
			if (object.Equals(obj, null))
			{
				throw new ArgumentNullException("obj");
			}
			if (_predicates.ContainsKey(typeof(T)))
			{
				foreach (var (delegate2, arg) in _predicates[typeof(T)])
				{
					if (!(bool)delegate2.DynamicInvoke(obj))
					{
						action?.Invoke(arg, string.Empty);
						if (returnOnError)
						{
							return false;
						}
					}
				}
			}
			foreach (KeyValuePair<PropertyInfo, IEnumerable<object>> item in AttributeCache.DefaultCache.Value.RetrieveFromType<T, IValidator>())
			{
				foreach (IValidator item2 in item.Value)
				{
					if (!item2.IsValid(item.Key.GetValue(obj, null)))
					{
						action?.Invoke(item2.ErrorMessage, item.Key.Name);
						if (returnOnError)
						{
							return false;
						}
					}
				}
			}
			return true;
		}
	}
	[AttributeUsage(AttributeTargets.Property)]
	public class MatchAttribute : Attribute, IValidator
	{
		public string Expression { get; }

		public string ErrorMessage { get; internal set; }

		public MatchAttribute(string regex, string? errorMessage = null)
		{
			Expression = regex ?? throw new ArgumentNullException("regex");
			ErrorMessage = errorMessage ?? "String does not match the specified regular expression";
		}

		public bool IsValid<T>(T value)
		{
			if (object.Equals(value, default(T)))
			{
				return false;
			}
			if (value is string)
			{
				return Regex.IsMatch(value.ToString(), Expression);
			}
			throw new ArgumentException("Property is not a string");
		}
	}
	[AttributeUsage(AttributeTargets.Property)]
	public class EmailAttribute : MatchAttribute
	{
		private const string EmailRegExp = "^(?(\")(\".+?(?<!\\\\)\"@)|(([0-9a-z]((\\.(?!\\.))|[-!#\\$%&'\\*\\+/=\\?\\^`\\{\\}\\|~\\w])*)(?<=[0-9a-z])@))(?(\\[)(\\[(\\d{1,3}\\.){3}\\d{1,3}\\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\\.)+[a-z0-9][\\-a-z0-9]{0,22}[a-z0-9]))$";

		public EmailAttribute(string? errorMessage = null)
			: base("^(?(\")(\".+?(?<!\\\\)\"@)|(([0-9a-z]((\\.(?!\\.))|[-!#\\$%&'\\*\\+/=\\?\\^`\\{\\}\\|~\\w])*)(?<=[0-9a-z])@))(?(\\[)(\\[(\\d{1,3}\\.){3}\\d{1,3}\\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\\.)+[a-z0-9][\\-a-z0-9]{0,22}[a-z0-9]))$", errorMessage ?? "String is not an email")
		{
		}
	}
	[AttributeUsage(AttributeTargets.Property)]
	public class NotNullAttribute : Attribute, IValidator
	{
		public string ErrorMessage => "Value is null";

		public bool IsValid<T>(T value)
		{
			return !object.Equals(default(T), value);
		}
	}
	[AttributeUsage(AttributeTargets.Property)]
	public class RangeAttribute : Attribute, IValidator
	{
		public string ErrorMessage => "Value is not within the specified range";

		public IComparable Maximum { get; }

		public IComparable Minimum { get; }

		public RangeAttribute(int min, int max)
		{
			if (min >= max)
			{
				throw new InvalidOperationException("Maximum value must be greater than minimum");
			}
			Maximum = max;
			Minimum = min;
		}

		public RangeAttribute(double min, double max)
		{
			if (min >= max)
			{
				throw new InvalidOperationException("Maximum value must be greater than minimum");
			}
			Maximum = max;
			Minimum = min;
		}

		public bool IsValid<T>(T value)
		{
			if (!((object)value is IComparable comparable))
			{
				throw new ArgumentException("value");
			}
			if (comparable.CompareTo(Minimum) >= 0)
			{
				return comparable.CompareTo(Maximum) <= 0;
			}
			return false;
		}
	}
}
namespace Swan.Threading
{
	public sealed class AtomicBoolean : AtomicTypeBase<bool>
	{
		public AtomicBoolean(bool initialValue = false)
			: base((long)(initialValue ? 1 : 0))
		{
		}

		protected override bool FromLong(long backingValue)
		{
			return backingValue != 0;
		}

		protected override long ToLong(bool value)
		{
			return value ? 1 : 0;
		}
	}
	public sealed class AtomicDateTime : AtomicTypeBase<DateTime>
	{
		public AtomicDateTime(DateTime initialValue)
			: base(initialValue.Ticks)
		{
		}

		protected override DateTime FromLong(long backingValue)
		{
			return new DateTime(backingValue);
		}

		protected override long ToLong(DateTime value)
		{
			return value.Ticks;
		}
	}
	public sealed class AtomicDouble : AtomicTypeBase<double>
	{
		public AtomicDouble(double initialValue = 0.0)
			: base(BitConverter.DoubleToInt64Bits(initialValue))
		{
		}

		protected override double FromLong(long backingValue)
		{
			return BitConverter.Int64BitsToDouble(backingValue);
		}

		protected override long ToLong(double value)
		{
			return BitConverter.DoubleToInt64Bits(value);
		}
	}
	public sealed class AtomicEnum<T> where T : struct, IConvertible
	{
		private long _backingValue;

		public T Value
		{
			get
			{
				return (T)Enum.ToObject(typeof(T), BackingValue);
			}
			set
			{
				BackingValue = Convert.ToInt64(value);
			}
		}

		private long BackingValue
		{
			get
			{
				return Interlocked.Read(ref _backingValue);
			}
			set
			{
				Interlocked.Exchange(ref _backingValue, value);
			}
		}

		public AtomicEnum(T initialValue)
		{
			if (!Enum.IsDefined(typeof(T), initialValue))
			{
				throw new ArgumentException("T must be an enumerated type");
			}
			Value = initialValue;
		}
	}
	public class AtomicInteger : AtomicTypeBase<int>
	{
		public AtomicInteger(int initialValue = 0)
			: base(Convert.ToInt64(initialValue))
		{
		}

		protected override int FromLong(long backingValue)
		{
			return Convert.ToInt32(backingValue);
		}

		protected override long ToLong(int value)
		{
			return Convert.ToInt64(value);
		}
	}
	public sealed class AtomicLong : AtomicTypeBase<long>
	{
		public AtomicLong(long initialValue = 0L)
			: base(initialValue)
		{
		}

		protected override long FromLong(long backingValue)
		{
			return backingValue;
		}

		protected override long ToLong(long value)
		{
			return value;
		}
	}
	public sealed class AtomicTimeSpan : AtomicTypeBase<TimeSpan>
	{
		public AtomicTimeSpan(TimeSpan initialValue)
			: base(initialValue.Ticks)
		{
		}

		protected override TimeSpan FromLong(long backingValue)
		{
			return TimeSpan.FromTicks(backingValue);
		}

		protected override long ToLong(TimeSpan value)
		{
			if (value.Ticks >= 0)
			{
				return value.Ticks;
			}
			return 0L;
		}
	}
	public abstract class AtomicTypeBase<T> : IComparable, IComparable<T>, IComparable<AtomicTypeBase<T>>, IEquatable<T>, IEquatable<AtomicTypeBase<T>> where T : struct, IComparable, IComparable<T>, IEquatable<T>
	{
		private long _backingValue;

		public T Value
		{
			get
			{
				return FromLong(BackingValue);
			}
			set
			{
				BackingValue = ToLong(value);
			}
		}

		protected long BackingValue
		{
			get
			{
				return Interlocked.Read(ref _backingValue);
			}
			set
			{
				Interlocked.Exchange(ref _backingValue, value);
			}
		}

		protected AtomicTypeBase(long initialValue)
		{
			BackingValue = initialValue;
		}

		public static bool operator ==(AtomicTypeBase<T> a, T b)
		{
			return a?.Equals(b) ?? false;
		}

		public static bool operator !=(AtomicTypeBase<T> a, T b)
		{
			if (a == null)
			{
				return false;
			}
			return !a.Equals(b);
		}

		public static bool operator >(AtomicTypeBase<T> a, T b)
		{
			return a.CompareTo(b) > 0;
		}

		public static bool operator <(AtomicTypeBase<T> a, T b)
		{
			return a.CompareTo(b) < 0;
		}

		public static bool operator >=(AtomicTypeBase<T> a, T b)
		{
			return a.CompareTo(b) >= 0;
		}

		public static bool operator <=(AtomicTypeBase<T> a, T b)
		{
			return a.CompareTo(b) <= 0;
		}

		public static AtomicTypeBase<T>operator ++(AtomicTypeBase<T> instance)
		{
			Interlocked.Increment(ref instance._backingValue);
			return instance;
		}

		public static AtomicTypeBase<T>operator --(AtomicTypeBase<T> instance)
		{
			Interlocked.Decrement(ref instance._backingValue);
			return instance;
		}

		public static AtomicTypeBase<T>operator +(AtomicTypeBase<T> instance, long operand)
		{
			instance.BackingValue += operand;
			return instance;
		}

		public static AtomicTypeBase<T>operator -(AtomicTypeBase<T> instance, long operand)
		{
			instance.BackingValue -= operand;
			return instance;
		}

		public int CompareTo(object other)
		{
			if (other != null)
			{
				if (!(other is AtomicTypeBase<T> atomicTypeBase))
				{
					if (other is T other2)
					{
						return Value.CompareTo(other2);
					}
					throw new ArgumentException("Incompatible comparison types");
				}
				return BackingValue.CompareTo(atomicTypeBase.BackingValue);
			}
			return 1;
		}

		public int CompareTo(T other)
		{
			return Value.CompareTo(other);
		}

		public int CompareTo(AtomicTypeBase<T> other)
		{
			return BackingValue.CompareTo(other?.BackingValue ?? 0);
		}

		public override bool Equals(object other)
		{
			if (!(other is AtomicTypeBase<T> other2))
			{
				if (other is T other3)
				{
					return Equals(other3);
				}
				return false;
			}
			return Equals(other2);
		}

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

		public bool Equals(AtomicTypeBase<T> other)
		{
			return BackingValue == (other?.BackingValue ?? 0);
		}

		public bool Equals(T other)
		{
			return object.Equals(Value, other);
		}

		protected abstract T FromLong(long backingValue);

		protected abstract long ToLong(T value);
	}
	public sealed class CancellationTokenOwner : IDisposable
	{
		private readonly object _syncLock = new object();

		private bool _isDisposed;

		private CancellationTokenSource _tokenSource = new CancellationTokenSource();

		public CancellationToken Token
		{
			get
			{
				lock (_syncLock)
				{
					return _isDisposed ? CancellationToken.None : _tokenSource.Token;
				}
			}
		}

		public void Cancel()
		{
			lock (_syncLock)
			{
				if (!_isDisposed)
				{
					_tokenSource.Cancel();
					_tokenSource.Dispose();
					_tokenSource = new CancellationTokenSource();
				}
			}
		}

		public void Dispose()
		{
			Dispose(disposing: true);
		}

		private void Dispose(bool disposing)
		{
			lock (_syncLock)
			{
				if (!_isDisposed)
				{
					if (disposing)
					{
						_tokenSource.Cancel();
						_tokenSource.Dispose();
					}
					_isDisposed = true;
				}
			}
		}
	}
	public sealed class ExclusiveTimer : IDisposable
	{
		private readonly object _syncLock;

		private readonly ManualResetEventSlim _cycleDoneEvent;

		private readonly Timer _backingTimer;

		private readonly TimerCallback _userCallback;

		private readonly AtomicBoolean _isDisposing;

		private readonly AtomicBoolean _isDisposed;

		private int _period;

		public bool IsDisposing => _isDisposing.Value;

		public bool IsDisposed => _isDisposed.Value;

		public ExclusiveTimer(TimerCallback timerCallback, object? state, int dueTime, int period)
		{
			_syncLock = new object();
			_cycleDoneEvent = new ManualResetEventSlim(initialState: true);
			_isDisposing = new AtomicBoolean();
			_isDisposed = new AtomicBoolean();
			base..ctor();
			_period = period;
			_userCallback = timerCallback;
			_backingTimer = new Timer(InternalCallback, state ?? this, dueTime, -1);
		}

		public ExclusiveTimer(TimerCallback timerCallback, object? state, TimeSpan dueTime, TimeSpan period)
			: this(timerCallback, state, Convert.ToInt32(dueTime.TotalMilliseconds), Convert.ToInt32(period.TotalMilliseconds))
		{
		}

		public ExclusiveTimer(TimerCallback timerCallback)
			: this(timerCallback, null, -1, -1)
		{
		}

		public ExclusiveTimer(Action timerCallback, int dueTime, int period)
		{
			Action timerCallback2 = timerCallback;
			this..ctor(delegate
			{
				timerCallback2?.Invoke();
			}, null, dueTime, period);
		}

		public ExclusiveTimer(Action timerCallback, TimeSpan dueTime, TimeSpan period)
		{
			Action timerCallback2 = timerCallback;
			this..ctor(delegate
			{
				timerCallback2?.Invoke();
			}, null, dueTime, period);
		}

		public ExclusiveTimer(Action timerCallback)
			: this(timerCallback, -1, -1)
		{
		}

		public static void WaitUntil(DateTime untilDate, CancellationToken cancellationToken = default(CancellationToken))
		{
			IWaitEvent delayLock = WaitEventFactory.Create(isCompleted: true);
			try
			{
				using (new ExclusiveTimer(delegate
				{
					Callback(delayLock);
				}, 0, 15))
				{
					while (!cancellationToken.IsCancellationRequested && DateTime.UtcNow < untilDate)
					{
						delayLock.Wait();
					}
				}
			}
			finally
			{
				if (delayLock != null)
				{
					delayLock.Dispose();
				}
			}
			static void Callback(IWaitEvent waitEvent)
			{
				try
				{
					waitEvent.Complete();
					waitEvent.Begin();
				}
				catch
				{
				}
			}
		}

		public static void Wait(TimeSpan waitTime, CancellationToken cancellationToken = default(CancellationToken))
		{
			WaitUntil(DateTime.UtcNow.Add(waitTime), cancellationToken);
		}

		public void Change(int dueTime, int period)
		{
			_period = period;
			_backingTimer.Change(dueTime, -1);
		}

		public void Change(TimeSpan dueTime, TimeSpan period)
		{
			Change(Convert.ToInt32(dueTime.TotalMilliseconds), Convert.ToInt32(period.TotalMilliseconds));
		}

		public void Resume(int period)
		{
			Change(0, period);
		}

		public void Resume(TimeSpan period)
		{
			Change(TimeSpan.Zero, period);
		}

		public void Pause()
		{
			Change(-1, -1);
		}

		public void Dispose()
		{
			lock (_syncLock)
			{
				if (_isDisposed == b: true || _isDisposing == b: true)
				{
					return;
				}
				_isDisposing.Value = true;
			}
			try
			{
				_cycleDoneEvent.Wait();
				_cycleDoneEvent.Dispose();
				Pause();
				_backingTimer.Dispose();
			}
			finally
			{
				_isDisposed.Value = true;
				_isDisposing.Value = false;
			}
		}

		private void InternalCallback(object state)
		{
			lock (_syncLock)
			{
				if (IsDisposed || IsDisposing)
				{
					return;
				}
			}
			if (!_cycleDoneEvent.IsSet)
			{
				return;
			}
			_cycleDoneEvent.Reset();
			try
			{
				_userCallback(state);
			}
			finally
			{
				_cycleDoneEvent?.Set();
				_backingTimer?.Change(_period, -1);
			}
		}
	}
	public interface ISyncLocker : IDisposable
	{
		IDisposable AcquireWriterLock();

		IDisposable AcquireReaderLock();
	}
	public interface IWaitEvent : IDisposable
	{
		bool IsCompleted { get; }

		bool IsInProgress { get; }

		bool IsValid { get; }

		bool IsDisposed { get; }

		void Begin();

		void Complete();

		void Wait();

		bool Wait(TimeSpan timeout);
	}
	public interface IWorker
	{
		WorkerState WorkerState { get; }

		bool IsDisposed { get; }

		bool IsDisposing { get; }

		TimeSpan Period { get; set; }

		string Name { get; }

		Task<WorkerState> StartAsync();

		Task<WorkerState> PauseAsync();

		Task<WorkerState> ResumeAsync();

		Task<WorkerState> StopAsync();
	}
	public interface IWorkerDelayProvider
	{
		void ExecuteCycleDelay(int wantedDelay, Task delayTask, CancellationToken token);
	}
	public sealed class PeriodicTask : IDisposable
	{
		public static readonly TimeSpan MinInterval = TimeSpan.FromMilliseconds(100.0);

		private readonly Func<CancellationToken, Task> _action;

		private readonly CancellationTokenSou

EmbedIO.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using EmbedIO.Actions;
using EmbedIO.Authentication;
using EmbedIO.Cors;
using EmbedIO.Files;
using EmbedIO.Files.Internal;
using EmbedIO.Internal;
using EmbedIO.Net;
using EmbedIO.Net.Internal;
using EmbedIO.Routing;
using EmbedIO.Security;
using EmbedIO.Security.Internal;
using EmbedIO.Sessions;
using EmbedIO.Sessions.Internal;
using EmbedIO.Utilities;
using EmbedIO.WebApi;
using EmbedIO.WebSockets;
using EmbedIO.WebSockets.Internal;
using Microsoft.CodeAnalysis;
using Swan;
using Swan.Configuration;
using Swan.Formatters;
using Swan.Logging;
using Swan.Threading;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Unosquare")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) Unosquare 2013-2022")]
[assembly: AssemblyDescription("A tiny, cross-platform, module based, MIT-licensed web server. Supporting NET Framework, Net Core, and Mono.")]
[assembly: AssemblyFileVersion("3.5.2.0")]
[assembly: AssemblyInformationalVersion("3.5.2")]
[assembly: AssemblyProduct("EmbedIO")]
[assembly: AssemblyTitle("EmbedIO Web Server")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/unosquare/embedio/")]
[assembly: AssemblyVersion("3.5.2.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class AllowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class DisallowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class DoesNotReturnAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class DoesNotReturnIfAttribute : Attribute
	{
		public bool ParameterValue { get; }

		public DoesNotReturnIfAttribute(bool parameterValue)
		{
			ParameterValue = parameterValue;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class MaybeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class MaybeNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public MaybeNullWhenAttribute(bool returnValue)
		{
			ReturnValue = returnValue;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class NotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class NotNullIfNotNullAttribute : Attribute
	{
		public string ParameterName { get; }

		public NotNullIfNotNullAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	[DebuggerNonUserCode]
	internal sealed class NotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public NotNullWhenAttribute(bool returnValue)
		{
			ReturnValue = returnValue;
		}
	}
}
namespace EmbedIO
{
	public enum CompressionMethod : byte
	{
		None,
		Deflate,
		Gzip
	}
	public static class CompressionMethodNames
	{
		public const string None = "identity";

		public const string Deflate = "deflate";

		public const string Gzip = "gzip";
	}
	[Serializable]
	public class EmbedIOInternalErrorException : Exception
	{
		public EmbedIOInternalErrorException()
		{
		}

		public EmbedIOInternalErrorException(string message)
			: base(message)
		{
		}

		public EmbedIOInternalErrorException(string message, Exception? innerException)
			: base(message, innerException)
		{
		}

		protected EmbedIOInternalErrorException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	public static class ExceptionHandler
	{
		public const string ExceptionTypeHeaderName = "X-Exception-Type";

		public const string ExceptionMessageHeaderName = "X-Exception-Message";

		public static string? ContactInformation { get; set; }

		public static bool IncludeStackTraces { get; set; }

		public static ExceptionHandlerCallback Default { get; } = HtmlResponse;


		public static Task EmptyResponse(IHttpContext context, Exception exception)
		{
			context.Response.SetEmptyResponse(500);
			return Task.CompletedTask;
		}

		public static Task EmptyResponseWithHeaders(IHttpContext context, Exception exception)
		{
			context.Response.SetEmptyResponse(500);
			context.Response.Headers["X-Exception-Type"] = Uri.EscapeDataString(exception.GetType().Name);
			context.Response.Headers["X-Exception-Message"] = Uri.EscapeDataString(exception.Message);
			return Task.CompletedTask;
		}

		public static Task HtmlResponse(IHttpContext context, Exception exception)
		{
			Exception exception2 = exception;
			return context.SendStandardHtmlAsync(500, delegate(TextWriter text)
			{
				text.Write("<p>The server has encountered an error and was not able to process your request.</p>");
				text.Write("<p>Please contact the server administrator");
				if (!string.IsNullOrEmpty(ContactInformation))
				{
					text.Write(" ({0})", HttpUtility.HtmlEncode(ContactInformation));
				}
				text.Write(", informing them of the time this error occurred and the action(s) you performed that resulted in this error.</p>");
				text.Write("<p>The following information may help them in finding out what happened and restoring full functionality.</p>");
				text.Write("<p><strong>Exception type:</strong> {0}<p><strong>Message:</strong> {1}", HttpUtility.HtmlEncode(exception2.GetType().FullName ?? "<unknown>"), HttpUtility.HtmlEncode(exception2.Message));
				if (IncludeStackTraces)
				{
					text.Write("</p><p><strong>Stack trace:</strong></p><br><pre>{0}</pre>", HttpUtility.HtmlEncode(exception2.StackTrace));
				}
			});
		}

		internal static async Task Handle(string logSource, IHttpContext context, Exception exception, ExceptionHandlerCallback? handler, HttpExceptionHandlerCallback? httpHandler)
		{
			if (handler == null)
			{
				ExceptionDispatchInfo.Capture(exception).Throw();
				return;
			}
			Logger.Log(exception, logSource, "[" + context.Id + "] Unhandled exception.", "Handle", "C:\\Unosquare\\embedio\\src\\EmbedIO\\ExceptionHandler.cs", 134);
			IHttpException httpException1 = default(IHttpException);
			try
			{
				context.Response.SetEmptyResponse(500);
				context.Response.DisableCaching();
				await handler(context, exception).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (OperationCanceledException) when (context.CancellationToken.IsCancellationRequested)
			{
				throw;
			}
			catch (HttpListenerException)
			{
				throw;
			}
			catch (Exception ex3) when (((Func<bool>)delegate
			{
				// Could not convert BlockContainer to single expression
				httpException1 = ex3 as IHttpException;
				return httpException1 != null;
			}).Invoke())
			{
				if (httpHandler == null)
				{
					throw;
				}
				await httpHandler(context, httpException1).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (Exception ex4)
			{
				Logger.Log(ex4, logSource, "[" + context.Id + "] Unhandled exception while handling exception.", "Handle", "C:\\Unosquare\\embedio\\src\\EmbedIO\\ExceptionHandler.cs", 160);
			}
		}
	}
	public delegate Task ExceptionHandlerCallback(IHttpContext context, Exception exception);
	public static class HttpContextExtensions
	{
		private static readonly object FormDataKey = new object();

		private static readonly object QueryDataKey = new object();

		private const string StandardHtmlHeaderFormat = "<html><head><meta charset=\"{2}\"><title>{0} - {1}</title></head><body><h1>{0} - {1}</h1>";

		private const string StandardHtmlFooter = "</body></html>";

		public static bool TryGetItem<T>(this IHttpContext @this, object key, out T value)
		{
			if (@this.Items.TryGetValue(key, out object value2) && value2 is T val)
			{
				value = val;
				return true;
			}
			value = default(T);
			return false;
		}

		public static T GetItem<T>(this IHttpContext @this, object key)
		{
			if (@this.Items.TryGetValue(key, out object value) && value is T)
			{
				return (T)value;
			}
			return default(T);
		}

		public static void Redirect(this IHttpContext @this, string location, int statusCode = 302)
		{
			location = Validate.Url("location", location, @this.Request.Url);
			if (statusCode < 300 || statusCode > 399)
			{
				throw new ArgumentException("Redirect status code is not valid.", "statusCode");
			}
			@this.Response.SetEmptyResponse(statusCode);
			@this.Response.Headers["Location"] = location;
		}

		public static async Task<byte[]> GetRequestBodyAsByteArrayAsync(this IHttpContext @this)
		{
			using MemoryStream buffer = new MemoryStream();
			using Stream stream = @this.OpenRequestStream();
			await stream.CopyToAsync(buffer, 81920, @this.CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			return buffer.ToArray();
		}

		public static async Task<MemoryStream> GetRequestBodyAsMemoryStreamAsync(this IHttpContext @this)
		{
			return new MemoryStream(await @this.GetRequestBodyAsByteArrayAsync().ConfigureAwait(continueOnCapturedContext: false), writable: false);
		}

		public static async Task<string> GetRequestBodyAsStringAsync(this IHttpContext @this)
		{
			using TextReader reader = @this.OpenRequestText();
			return await reader.ReadToEndAsync().ConfigureAwait(continueOnCapturedContext: false);
		}

		public static Task<TData> GetRequestDataAsync<TData>(this IHttpContext @this)
		{
			return RequestDeserializer.Default<TData>(@this);
		}

		public static Task<TData> GetRequestDataAsync<TData>(this IHttpContext @this, RequestDeserializerCallback<TData> deserializer)
		{
			return Validate.NotNull("deserializer", deserializer)(@this);
		}

		public static async Task<NameValueCollection> GetRequestFormDataAsync(this IHttpContext @this)
		{
			if (!@this.Items.TryGetValue(FormDataKey, out object value))
			{
				NameValueCollection nameValueCollection;
				try
				{
					using TextReader reader = @this.OpenRequestText();
					nameValueCollection = UrlEncodedDataParser.Parse(await reader.ReadToEndAsync().ConfigureAwait(continueOnCapturedContext: false), groupFlags: false);
				}
				catch (Exception value2)
				{
					@this.Items[FormDataKey] = value2;
					throw;
				}
				@this.Items[FormDataKey] = nameValueCollection;
				return nameValueCollection;
			}
			if (!(value is NameValueCollection result))
			{
				if (!(value is Exception ex))
				{
					if (value == null)
					{
						throw SelfCheck.Failure("Previous result of HttpContextExtensions.GetRequestFormDataAsync is null.", "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpContextExtensions-Requests.cs", 121);
					}
					throw SelfCheck.Failure("Previous result of HttpContextExtensions.GetRequestFormDataAsync is of unexpected type " + value.GetType().FullName, "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpContextExtensions-Requests.cs", 124);
				}
				throw ExceptionExtensions.RethrowPreservingStackTrace(ex);
			}
			return result;
		}

		public static NameValueCollection GetRequestQueryData(this IHttpContext @this)
		{
			if (!@this.Items.TryGetValue(QueryDataKey, out object value))
			{
				NameValueCollection nameValueCollection;
				try
				{
					nameValueCollection = UrlEncodedDataParser.Parse(@this.Request.Url.Query, groupFlags: false);
				}
				catch (Exception value2)
				{
					@this.Items[FormDataKey] = value2;
					throw;
				}
				@this.Items[FormDataKey] = nameValueCollection;
				return nameValueCollection;
			}
			if (!(value is NameValueCollection result))
			{
				if (!(value is Exception ex))
				{
					if (value == null)
					{
						throw SelfCheck.Failure("Previous result of HttpContextExtensions.GetRequestQueryData is null.", "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpContextExtensions-Requests.cs", 168);
					}
					throw SelfCheck.Failure("Previous result of HttpContextExtensions.GetRequestQueryData is of unexpected type " + value.GetType().FullName, "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpContextExtensions-Requests.cs", 171);
				}
				throw ExceptionExtensions.RethrowPreservingStackTrace(ex);
			}
			return result;
		}

		public static Stream OpenRequestStream(this IHttpContext @this)
		{
			Stream inputStream = @this.Request.InputStream;
			string text = @this.Request.Headers["Content-Encoding"]?.Trim();
			switch (text)
			{
			case "gzip":
				if (@this.SupportCompressedRequests)
				{
					return new GZipStream(inputStream, CompressionMode.Decompress);
				}
				break;
			case "deflate":
				if (@this.SupportCompressedRequests)
				{
					return new DeflateStream(inputStream, CompressionMode.Decompress);
				}
				break;
			case "identity":
			case null:
				return inputStream;
			}
			Logger.Warn("[" + @this.Id + "] Unsupported request content encoding \"" + text + "\", sending 400 Bad Request...", "OpenRequestStream", (object)null, "OpenRequestStream", "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpContextExtensions-RequestStream.cs", 42);
			throw HttpException.BadRequest("Unsupported content encoding \"" + text + "\"");
		}

		public static TextReader OpenRequestText(this IHttpContext @this)
		{
			return new StreamReader(@this.OpenRequestStream(), @this.Request.ContentEncoding);
		}

		public static async Task SendStringAsync(this IHttpContext @this, string content, string contentType, Encoding encoding)
		{
			content = Validate.NotNull("content", content);
			encoding = Validate.NotNull("encoding", encoding);
			if (contentType != null)
			{
				@this.Response.ContentType = contentType;
				@this.Response.ContentEncoding = encoding;
			}
			using TextWriter text = @this.OpenResponseText(encoding);
			await text.WriteAsync(content).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static Task SendStandardHtmlAsync(this IHttpContext @this, int statusCode)
		{
			return @this.SendStandardHtmlAsync(statusCode, null);
		}

		public static Task SendStandardHtmlAsync(this IHttpContext @this, int statusCode, Action<TextWriter>? writeAdditionalHtml)
		{
			if (!HttpStatusDescription.TryGet(statusCode, out string description))
			{
				throw new ArgumentException("Status code has no standard description.", "statusCode");
			}
			@this.Response.StatusCode = statusCode;
			@this.Response.StatusDescription = description;
			@this.Response.ContentType = "text/html";
			@this.Response.ContentEncoding = WebServer.DefaultEncoding;
			using (TextWriter textWriter = @this.OpenResponseText(WebServer.DefaultEncoding))
			{
				textWriter.Write("<html><head><meta charset=\"{2}\"><title>{0} - {1}</title></head><body><h1>{0} - {1}</h1>", statusCode, description, WebServer.DefaultEncoding.WebName);
				writeAdditionalHtml?.Invoke(textWriter);
				textWriter.Write("</body></html>");
			}
			return Task.CompletedTask;
		}

		public static Task SendDataAsync(this IHttpContext @this, object data)
		{
			return ResponseSerializer.Default(@this, data);
		}

		public static Task SendDataAsync(this IHttpContext @this, ResponseSerializerCallback serializer, object data)
		{
			return Validate.NotNull("serializer", serializer)(@this, data);
		}

		public static Stream OpenResponseStream(this IHttpContext @this, bool buffered = false, bool preferCompression = true)
		{
			@this.Request.TryNegotiateContentEncoding(preferCompression, out CompressionMethod compressionMethod, out Action<IHttpResponse> prepareResponse);
			prepareResponse(@this.Response);
			Stream stream = (buffered ? new BufferingResponseStream(@this.Response) : @this.Response.OutputStream);
			return compressionMethod switch
			{
				CompressionMethod.Gzip => new GZipStream(stream, CompressionMode.Compress), 
				CompressionMethod.Deflate => new DeflateStream(stream, CompressionMode.Compress), 
				_ => stream, 
			};
		}

		public static TextWriter OpenResponseText(this IHttpContext @this, Encoding? encoding = null, bool buffered = false, bool preferCompression = true)
		{
			if (encoding == null)
			{
				encoding = WebServer.DefaultEncoding;
			}
			@this.Response.ContentEncoding = encoding;
			return new StreamWriter(@this.OpenResponseStream(buffered, preferCompression), encoding);
		}

		public static IHttpContextImpl GetImplementation(this IHttpContext @this)
		{
			return (Validate.NotNull("this", @this) as IHttpContextImpl) ?? throw SelfCheck.Failure(@this.GetType().FullName + " does not implement IHttpContextImpl.", "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpContextExtensions.cs", 28);
		}
	}
	public class HttpException : Exception, IHttpException
	{
		public int StatusCode { get; }

		public object? DataObject { get; }

		string? IHttpException.Message => HttpExceptionMessage;

		private string? HttpExceptionMessage { get; }

		public static HttpException InternalServerError(string? message = null, object? data = null)
		{
			return new HttpException(HttpStatusCode.InternalServerError, message, data);
		}

		public static HttpException Unauthorized(string? message = null, object? data = null)
		{
			return new HttpException(HttpStatusCode.Unauthorized, message, data);
		}

		public static HttpException Forbidden(string? message = null, object? data = null)
		{
			return new HttpException(HttpStatusCode.Forbidden, message, data);
		}

		public static HttpException BadRequest(string? message = null, object? data = null)
		{
			return new HttpException(HttpStatusCode.BadRequest, message, data);
		}

		public static HttpException NotFound(string? message = null, object? data = null)
		{
			return new HttpException(HttpStatusCode.NotFound, message, data);
		}

		public static HttpException MethodNotAllowed(string? message = null, object? data = null)
		{
			return new HttpException(HttpStatusCode.MethodNotAllowed, message, data);
		}

		public static HttpNotAcceptableException NotAcceptable()
		{
			return new HttpNotAcceptableException();
		}

		public static HttpNotAcceptableException NotAcceptable(string vary)
		{
			return new HttpNotAcceptableException(vary);
		}

		public static HttpRangeNotSatisfiableException RangeNotSatisfiable()
		{
			return new HttpRangeNotSatisfiableException();
		}

		public static HttpRangeNotSatisfiableException RangeNotSatisfiable(long? contentLength)
		{
			return new HttpRangeNotSatisfiableException(contentLength);
		}

		public static HttpRedirectException Redirect(string location)
		{
			return new HttpRedirectException(location);
		}

		public static HttpRedirectException Redirect(string location, int statusCode)
		{
			return new HttpRedirectException(location, statusCode);
		}

		public static HttpRedirectException Redirect(string location, HttpStatusCode statusCode)
		{
			return new HttpRedirectException(location, statusCode);
		}

		public HttpException(int statusCode)
		{
			StatusCode = statusCode;
		}

		public HttpException(HttpStatusCode statusCode)
			: this((int)statusCode)
		{
		}

		public HttpException(int statusCode, string? message)
			: base(message)
		{
			StatusCode = statusCode;
			HttpExceptionMessage = message;
		}

		public HttpException(HttpStatusCode statusCode, string? message)
			: this((int)statusCode, message)
		{
		}

		public HttpException(int statusCode, string? message, object? data)
			: this(statusCode, message)
		{
			DataObject = data;
		}

		public HttpException(HttpStatusCode statusCode, string? message, object? data)
			: this((int)statusCode, message, data)
		{
		}

		public virtual void PrepareResponse(IHttpContext context)
		{
		}
	}
	public static class HttpExceptionHandler
	{
		public static HttpExceptionHandlerCallback Default { get; } = HtmlResponse;


		public static Task EmptyResponse(IHttpContext context, IHttpException httpException)
		{
			return Task.CompletedTask;
		}

		public static Task PlainTextResponse(IHttpContext context, IHttpException httpException)
		{
			return context.SendStringAsync(httpException.Message ?? string.Empty, "text/plain", WebServer.DefaultEncoding);
		}

		public static Task HtmlResponse(IHttpContext context, IHttpException httpException)
		{
			IHttpException httpException2 = httpException;
			return context.SendStandardHtmlAsync(httpException2.StatusCode, delegate(TextWriter text)
			{
				text.Write("<p><strong>Exception type:</strong> {0}<p><strong>Message:</strong> {1}", HttpUtility.HtmlEncode(httpException2.GetType().FullName ?? "<unknown>"), HttpUtility.HtmlEncode(httpException2.Message));
				text.Write("<hr><p>If this error is completely unexpected to you, and you think you should not seeing this page, please contact the server administrator");
				if (!string.IsNullOrEmpty(ExceptionHandler.ContactInformation))
				{
					text.Write(" ({0})", HttpUtility.HtmlEncode(ExceptionHandler.ContactInformation));
				}
				text.Write(", informing them of the time this error occurred and the action(s) you performed that resulted in this error.</p>");
				if (ExceptionHandler.IncludeStackTraces)
				{
					text.Write("</p><p><strong>Stack trace:</strong></p><br><pre>{0}</pre>", HttpUtility.HtmlEncode(httpException2.StackTrace));
				}
			});
		}

		public static HttpExceptionHandlerCallback DataResponse(ResponseSerializerCallback serializerCallback)
		{
			ResponseSerializerCallback serializerCallback2 = serializerCallback;
			Validate.NotNull("serializerCallback", serializerCallback2);
			return (IHttpContext context, IHttpException httpException) => serializerCallback2(context, httpException.DataObject);
		}

		public static HttpExceptionHandlerCallback FullDataResponse(ResponseSerializerCallback serializerCallback)
		{
			ResponseSerializerCallback serializerCallback2 = serializerCallback;
			Validate.NotNull("serializerCallback", serializerCallback2);
			return (IHttpContext context, IHttpException httpException) => serializerCallback2(context, new
			{
				message = httpException.Message,
				data = httpException.DataObject
			});
		}

		internal static async Task Handle(string logSource, IHttpContext context, Exception exception, HttpExceptionHandlerCallback? handler)
		{
			if (handler == null || !(exception is IHttpException httpException))
			{
				ExceptionDispatchInfo.Capture(exception).Throw();
				return;
			}
			Logger.Log(exception, logSource, $"[{context.Id}] HTTP exception {httpException.StatusCode}", "Handle", "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpExceptionHandler.cs", 129);
			try
			{
				context.Response.SetEmptyResponse(httpException.StatusCode);
				context.Response.DisableCaching();
				httpException.PrepareResponse(context);
				await handler(context, httpException).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (OperationCanceledException) when (context.CancellationToken.IsCancellationRequested)
			{
				throw;
			}
			catch (HttpListenerException)
			{
				throw;
			}
			catch (Exception ex3)
			{
				Logger.Log(ex3, logSource, $"[{context.Id}] Unhandled exception while handling HTTP exception {httpException.StatusCode}", "Handle", "C:\\Unosquare\\embedio\\src\\EmbedIO\\HttpExceptionHandler.cs", 149);
			}
		}
	}
	public delegate Task HttpExceptionHandlerCallback(IHttpContext context, IHttpException httpException);
	public static class HttpHeaderNames
	{
		public const string Accept = "Accept";

		public const string AcceptCharset = "Accept-Charset";

		public const string AcceptEncoding = "Accept-Encoding";

		public const string AcceptLanguage = "Accept-Language";

		public const string AcceptPatch = "Accept-Patch";

		public const string AcceptRanges = "Accept-Ranges";

		public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";

		public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";

		public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";

		public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";

		public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";

		public const string AccessControlMaxAge = "Access-Control-Max-Age";

		public const string AccessControlRequestHeaders = "Access-Control-Request-Headers";

		public const string AccessControlRequestMethod = "Access-Control-Request-Method";

		public const string Age = "Age";

		public const string Allow = "Allow";

		public const string AltSvc = "Alt-Svc";

		public const string Authorization = "Authorization";

		public const string CacheControl = "Cache-Control";

		public const string Connection = "Connection";

		public const string ContentDisposition = "Content-Disposition";

		public const string ContentEncoding = "Content-Encoding";

		public const string ContentLanguage = "Content-Language";

		public const string ContentLength = "Content-Length";

		public const string ContentLocation = "Content-Location";

		public const string ContentMD5 = "Content-MD5";

		public const string ContentRange = "Content-Range";

		public const string ContentSecurityPolicy = "Content-Security-Policy";

		public const string ContentType = "Content-Type";

		public const string Cookie = "Cookie";

		public const string Cookie2 = "Cookie2";

		public const string Date = "Date";

		public const string ETag = "ETag";

		public const string Expect = "Expect";

		public const string Expires = "Expires";

		public const string From = "From";

		public const string Host = "Host";

		public const string IfMatch = "If-Match";

		public const string IfModifiedSince = "If-Modified-Since";

		public const string IfNoneMatch = "If-None-Match";

		public const string IfRange = "If-Range";

		public const string IfUnmodifiedSince = "If-Unmodified-Since";

		public const string KeepAlive = "Keep-Alive";

		public const string LastModified = "Last-Modified";

		public const string Link = "Link";

		public const string Location = "Location";

		public const string MaxForwards = "Max-Forwards";

		public const string Origin = "Origin";

		public const string P3P = "P3P";

		public const string Pragma = "Pragma";

		public const string ProxyAuthenticate = "Proxy-Authenticate";

		public const string ProxyAuthorization = "Proxy-Authorization";

		public const string ProxyConnection = "Proxy-Connection";

		public const string PublicKeyPins = "Public-Key-Pins";

		public const string Range = "Range";

		public const string Referer = "Referer";

		public const string RetryAfter = "Retry-After";

		public const string SecWebSocketAccept = "Sec-WebSocket-Accept";

		public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";

		public const string SecWebSocketKey = "Sec-WebSocket-Key";

		public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";

		public const string SecWebSocketVersion = "Sec-WebSocket-Version";

		public const string Server = "Server";

		public const string SetCookie = "Set-Cookie";

		public const string SetCookie2 = "Set-Cookie2";

		public const string StrictTransportSecurity = "Strict-Transport-Security";

		public const string TE = "TE";

		public const string TSV = "TSV";

		public const string Trailer = "Trailer";

		public const string TransferEncoding = "Transfer-Encoding";

		public const string Upgrade = "Upgrade";

		public const string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";

		public const string UserAgent = "User-Agent";

		public const string Vary = "Vary";

		public const string Via = "Via";

		public const string WWWAuthenticate = "WWW-Authenticate";

		public const string Warning = "Warning";

		public const string XAspNetVersion = "X-AspNet-Version";

		public const string XContentDuration = "X-Content-Duration";

		public const string XContentTypeOptions = "X-Content-Type-Options";

		public const string XFrameOptions = "X-Frame-Options";

		public const string XMSEdgeRef = "X-MSEdge-Ref";

		public const string XPoweredBy = "X-Powered-By";

		public const string XRequestID = "X-Request-ID";

		public const string XUACompatible = "X-UA-Compatible";
	}
	public enum HttpListenerMode
	{
		EmbedIO,
		Microsoft
	}
	public class HttpNotAcceptableException : HttpException
	{
		public string? Vary { get; }

		public HttpNotAcceptableException()
			: this(null)
		{
		}

		public HttpNotAcceptableException(string? vary)
			: base(406)
		{
			Vary = (string.IsNullOrEmpty(vary) ? null : vary);
		}

		public override void PrepareResponse(IHttpContext context)
		{
			if (Vary != null)
			{
				context.Response.Headers.Add("Vary", Vary);
			}
		}
	}
	public class HttpRangeNotSatisfiableException : HttpException
	{
		public long? ContentLength { get; }

		public HttpRangeNotSatisfiableException()
			: this(null)
		{
		}

		public HttpRangeNotSatisfiableException(long? contentLength)
			: base(416)
		{
			ContentLength = contentLength;
		}

		public override void PrepareResponse(IHttpContext context)
		{
			if (ContentLength.HasValue)
			{
				context.Response.Headers.Set("Content-Range", $"bytes */{ContentLength.Value}");
			}
		}
	}
	public class HttpRedirectException : HttpException
	{
		public string Location { get; }

		public HttpRedirectException(string location, int statusCode = 302)
			: base(statusCode)
		{
			if (statusCode < 300 || statusCode > 399)
			{
				throw new ArgumentException("Redirect status code is not valid.", "statusCode");
			}
			Location = location;
		}

		public HttpRedirectException(string location, HttpStatusCode statusCode)
			: this(location, (int)statusCode)
		{
		}

		public override void PrepareResponse(IHttpContext context)
		{
			context.Redirect(Location, base.StatusCode);
		}
	}
	public static class HttpRequestExtensions
	{
		public static string SafeGetRemoteEndpointStr(this IHttpRequest @this)
		{
			IPEndPoint iPEndPoint = @this?.RemoteEndPoint;
			if (iPEndPoint != null)
			{
				return (iPEndPoint.Address?.ToString() ?? "<???>") + ":" + iPEndPoint.Port.ToString(CultureInfo.InvariantCulture);
			}
			return "<null>";
		}

		public static bool TryNegotiateContentEncoding(this IHttpRequest @this, bool preferCompression, out CompressionMethod compressionMethod, out Action<IHttpResponse> prepareResponse)
		{
			if (!new QValueList(useWildcard: true, @this.Headers.GetValues("Accept-Encoding")).TryNegotiateContentEncoding(preferCompression, out compressionMethod, out string compressionMethodName))
			{
				prepareResponse = delegate
				{
					throw HttpException.NotAcceptable("Accept-Encoding");
				};
				return false;
			}
			prepareResponse = delegate(IHttpResponse r)
			{
				r.Headers.Add("Vary", "Accept-Encoding");
				r.Headers.Set("Content-Encoding", compressionMethodName);
			};
			return true;
		}

		public static bool CheckIfNoneMatch(this IHttpRequest @this, string entityTag, out bool headerExists)
		{
			string[] values = @this.Headers.GetValues("If-None-Match");
			if (values == null)
			{
				headerExists = false;
				return false;
			}
			headerExists = true;
			return values.Select((string t) => t.Trim()).Contains(entityTag);
		}

		public static bool CheckIfModifiedSince(this IHttpRequest @this, DateTime lastModifiedUtc, out bool headerExists)
		{
			string text = @this.Headers.Get("If-Modified-Since");
			if (text == null)
			{
				headerExists = false;
				return false;
			}
			headerExists = true;
			if (HttpDate.TryParse(text, out var result))
			{
				return result.UtcDateTime >= lastModifiedUtc;
			}
			return false;
		}

		public static bool IsRangeRequest(this IHttpRequest @this, long contentLength, string entityTag, DateTime lastModifiedUtc, out long start, out long upperBound)
		{
			start = 0L;
			upperBound = contentLength - 1;
			if (@this.HttpVerb != HttpVerbs.Get)
			{
				return false;
			}
			string text = @this.Headers.Get("Range");
			if (text == null)
			{
				return false;
			}
			string text2 = @this.Headers.Get("If-Range")?.Trim();
			if (text2 != null && text2 != entityTag)
			{
				if (!HttpDate.TryParse(text2, out var result))
				{
					return false;
				}
				if (result.UtcDateTime != lastModifiedUtc)
				{
					return false;
				}
			}
			if (!RangeHeaderValue.TryParse(text, out RangeHeaderValue parsedValue))
			{
				return false;
			}
			if (parsedValue.Ranges.Count != 1)
			{
				return false;
			}
			RangeItemHeaderValue rangeItemHeaderValue = parsedValue.Ranges.First();
			start = rangeItemHeaderValue.From.GetValueOrDefault();
			upperBound = rangeItemHeaderValue.To ?? (contentLength - 1);
			if (start >= contentLength || upperBound < start || upperBound >= contentLength)
			{
				throw HttpException.RangeNotSatisfiable(contentLength);
			}
			return true;
		}
	}
	public static class HttpResponseExtensions
	{
		public static void DisableCaching(this IHttpResponse @this)
		{
			WebHeaderCollection headers = @this.Headers;
			headers.Set("Expires", "Sat, 26 Jul 1997 05:00:00 GMT");
			headers.Set("Last-Modified", HttpDate.Format(DateTime.UtcNow));
			headers.Set("Cache-Control", "no-store, no-cache, must-revalidate");
			headers.Add("Pragma", "no-cache");
		}

		public static void SetEmptyResponse(this IHttpResponse @this, int statusCode)
		{
			if (!HttpStatusDescription.TryGet(statusCode, out string description))
			{
				throw new ArgumentException("Status code has no standard description.", "statusCode");
			}
			@this.StatusCode = statusCode;
			@this.StatusDescription = description;
			@this.ContentType = "application/octet-stream";
			@this.ContentEncoding = null;
		}
	}
	public static class HttpStatusDescription
	{
		private static readonly IReadOnlyDictionary<int, string> Dictionary = new Dictionary<int, string>
		{
			{ 100, "Continue" },
			{ 101, "Switching Protocols" },
			{ 102, "Processing" },
			{ 103, "Early Hints" },
			{ 200, "OK" },
			{ 201, "Created" },
			{ 202, "Accepted" },
			{ 203, "Non-Authoritative Information" },
			{ 204, "No Content" },
			{ 205, "Reset Content" },
			{ 206, "Partial Content" },
			{ 207, "Multi-Status" },
			{ 208, "Already Reported" },
			{ 226, "IM Used" },
			{ 300, "Multiple Choices" },
			{ 301, "Moved Permanently" },
			{ 302, "Found" },
			{ 303, "See Other" },
			{ 304, "Not Modified" },
			{ 305, "Use Proxy" },
			{ 307, "Temporary Redirect" },
			{ 308, "Permanent Redirect" },
			{ 400, "Bad Request" },
			{ 401, "Unauthorized" },
			{ 402, "Payment Required" },
			{ 403, "Forbidden" },
			{ 404, "Not Found" },
			{ 405, "Method Not Allowed" },
			{ 406, "Not Acceptable" },
			{ 407, "Proxy Authentication Required" },
			{ 408, "Request Timeout" },
			{ 409, "Conflict" },
			{ 410, "Gone" },
			{ 411, "Length Required" },
			{ 412, "Precondition Failed" },
			{ 413, "Request Entity Too Large" },
			{ 414, "Request-Uri Too Long" },
			{ 415, "Unsupported Media Type" },
			{ 416, "Requested Range Not Satisfiable" },
			{ 417, "Expectation Failed" },
			{ 421, "Misdirected Request" },
			{ 422, "Unprocessable Entity" },
			{ 423, "Locked" },
			{ 424, "Failed Dependency" },
			{ 426, "Upgrade Required" },
			{ 428, "Precondition Required" },
			{ 429, "Too Many Requests" },
			{ 431, "Request Header Fields Too Large" },
			{ 451, "Unavailable For Legal Reasons" },
			{ 500, "Internal Server Error" },
			{ 501, "Not Implemented" },
			{ 502, "Bad Gateway" },
			{ 503, "Service Unavailable" },
			{ 504, "Gateway Timeout" },
			{ 505, "Http Version Not Supported" },
			{ 506, "Variant Also Negotiates" },
			{ 507, "Insufficient Storage" },
			{ 508, "Loop Detected" },
			{ 510, "Not Extended" },
			{ 511, "Network Authentication Required" }
		};

		public static bool TryGet(HttpStatusCode code, out string description)
		{
			return Dictionary.TryGetValue((int)code, out description);
		}

		public static bool TryGet(int code, out string description)
		{
			return Dictionary.TryGetValue(code, out description);
		}

		public static string Get(HttpStatusCode code)
		{
			Dictionary.TryGetValue((int)code, out string value);
			return value;
		}

		public static string Get(int code)
		{
			Dictionary.TryGetValue(code, out string value);
			return value;
		}
	}
	public enum HttpVerbs
	{
		Any,
		Delete,
		Get,
		Head,
		Options,
		Patch,
		Post,
		Put
	}
	public interface ICookieCollection : IEnumerable<Cookie>, IEnumerable, ICollection
	{
		Cookie? this[string name] { get; }

		bool Contains(Cookie cookie);

		void CopyTo(Cookie[] array, int index);

		void Add(Cookie cookie);
	}
	public interface IHttpContext : IMimeTypeProvider
	{
		string Id { get; }

		CancellationToken CancellationToken { get; }

		IPEndPoint LocalEndPoint { get; }

		IPEndPoint RemoteEndPoint { get; }

		IHttpRequest Request { get; }

		RouteMatch Route { get; }

		string RequestedPath { get; }

		IHttpResponse Response { get; }

		IPrincipal User { get; }

		ISessionProxy Session { get; }

		bool SupportCompressedRequests { get; }

		IDictionary<object, object> Items { get; }

		long Age { get; }

		bool IsHandled { get; }

		void SetHandled();

		void OnClose(Action<IHttpContext> callback);
	}
	public interface IHttpContextHandler
	{
		Task HandleContextAsync(IHttpContextImpl context);
	}
	public interface IHttpContextImpl : IHttpContext, IMimeTypeProvider
	{
		new CancellationToken CancellationToken { get; set; }

		new RouteMatch Route { get; set; }

		new ISessionProxy Session { get; set; }

		new IPrincipal User { get; set; }

		new bool SupportCompressedRequests { get; set; }

		MimeTypeProviderStack MimeTypeProviders { get; }

		void Close();

		Task<IWebSocketContext> AcceptWebSocketAsync(IEnumerable<string> requestedProtocols, string acceptedProtocol, int receiveBufferSize, TimeSpan keepAliveInterval, CancellationToken cancellationToken);
	}
	public interface IHttpException
	{
		int StatusCode { get; }

		string StackTrace { get; }

		string? Message { get; }

		object? DataObject { get; }

		void PrepareResponse(IHttpContext context);
	}
	public interface IHttpListener : IDisposable
	{
		bool IgnoreWriteExceptions { get; set; }

		List<string> Prefixes { get; }

		bool IsListening { get; }

		string Name { get; }

		void Start();

		void Stop();

		void AddPrefix(string urlPrefix);

		Task<IHttpContextImpl> GetContextAsync(CancellationToken cancellationToken);
	}
	public interface IHttpMessage
	{
		ICookieCollection Cookies { get; }

		Version ProtocolVersion { get; }
	}
	public interface IHttpRequest : IHttpMessage
	{
		NameValueCollection Headers { get; }

		bool KeepAlive { get; }

		string RawUrl { get; }

		NameValueCollection QueryString { get; }

		string HttpMethod { get; }

		HttpVerbs HttpVerb { get; }

		Uri Url { get; }

		bool HasEntityBody { get; }

		Stream InputStream { get; }

		Encoding ContentEncoding { get; }

		IPEndPoint RemoteEndPoint { get; }

		bool IsLocal { get; }

		bool IsSecureConnection { get; }

		string UserAgent { get; }

		bool IsWebSocketRequest { get; }

		IPEndPoint LocalEndPoint { get; }

		string? ContentType { get; }

		long ContentLength64 { get; }

		bool IsAuthenticated { get; }

		Uri? UrlReferrer { get; }
	}
	public interface IHttpResponse : IHttpMessage
	{
		WebHeaderCollection Headers { get; }

		int StatusCode { get; set; }

		long ContentLength64 { get; set; }

		string ContentType { get; set; }

		Stream OutputStream { get; }

		Encoding? ContentEncoding { get; set; }

		bool KeepAlive { get; set; }

		bool SendChunked { get; set; }

		string StatusDescription { get; set; }

		void SetCookie(Cookie cookie);

		void Close();
	}
	public interface IMimeTypeCustomizer : IMimeTypeProvider
	{
		void AddCustomMimeType(string extension, string mimeType);

		void PreferCompression(string mimeType, bool preferCompression);
	}
	public interface IMimeTypeProvider
	{
		string GetMimeType(string extension);

		bool TryDetermineCompression(string mimeType, out bool preferCompression);
	}
	public interface IWebModule
	{
		string BaseRoute { get; }

		bool IsFinalHandler { get; }

		ExceptionHandlerCallback? OnUnhandledException { get; set; }

		HttpExceptionHandlerCallback? OnHttpException { get; set; }

		void Start(CancellationToken cancellationToken);

		RouteMatch MatchUrlPath(string urlPath);

		Task HandleRequestAsync(IHttpContext context);
	}
	public interface IWebModuleContainer : IDisposable
	{
		IComponentCollection<IWebModule> Modules { get; }
	}
	public interface IWebServer : IWebModuleContainer, IDisposable, IMimeTypeCustomizer, IMimeTypeProvider
	{
		ExceptionHandlerCallback OnUnhandledException { get; set; }

		HttpExceptionHandlerCallback OnHttpException { get; set; }

		ISessionManager? SessionManager { get; set; }

		WebServerState State { get; }

		event WebServerStateChangedEventHandler StateChanged;

		Task RunAsync(CancellationToken cancellationToken = default(CancellationToken));
	}
	public static class MimeType
	{
		public const string Default = "application/octet-stream";

		public const string PlainText = "text/plain";

		public const string Html = "text/html";

		public const string Json = "application/json";

		internal const string UrlEncodedForm = "application/x-www-form-urlencoded";

		public static IReadOnlyDictionary<string, string> Associations { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ ".323", "text/h323" },
			{ ".3g2", "video/3gpp2" },
			{ ".3gp", "video/3gpp" },
			{ ".3gp2", "video/3gpp2" },
			{ ".3gpp", "video/3gpp" },
			{ ".7z", "application/x-7z-compressed" },
			{ ".aa", "audio/audible" },
			{ ".AAC", "audio/aac" },
			{ ".aaf", "application/octet-stream" },
			{ ".aax", "audio/vnd.audible.aax" },
			{ ".ac3", "audio/ac3" },
			{ ".aca", "application/octet-stream" },
			{ ".accda", "application/msaccess.addin" },
			{ ".accdb", "application/msaccess" },
			{ ".accdc", "application/msaccess.cab" },
			{ ".accde", "application/msaccess" },
			{ ".accdr", "application/msaccess.runtime" },
			{ ".accdt", "application/msaccess" },
			{ ".accdw", "application/msaccess.webapplication" },
			{ ".accft", "application/msaccess.ftemplate" },
			{ ".acx", "application/internet-property-stream" },
			{ ".AddIn", "text/xml" },
			{ ".ade", "application/msaccess" },
			{ ".adobebridge", "application/x-bridge-url" },
			{ ".adp", "application/msaccess" },
			{ ".ADT", "audio/vnd.dlna.adts" },
			{ ".ADTS", "audio/aac" },
			{ ".afm", "application/octet-stream" },
			{ ".ai", "application/postscript" },
			{ ".aif", "audio/aiff" },
			{ ".aifc", "audio/aiff" },
			{ ".aiff", "audio/aiff" },
			{ ".air", "application/vnd.adobe.air-application-installer-package+zip" },
			{ ".amc", "application/mpeg" },
			{ ".anx", "application/annodex" },
			{ ".apk", "application/vnd.android.package-archive" },
			{ ".application", "application/x-ms-application" },
			{ ".art", "image/x-jg" },
			{ ".asa", "application/xml" },
			{ ".asax", "application/xml" },
			{ ".ascx", "application/xml" },
			{ ".asd", "application/octet-stream" },
			{ ".asf", "video/x-ms-asf" },
			{ ".ashx", "application/xml" },
			{ ".asi", "application/octet-stream" },
			{ ".asm", "text/plain" },
			{ ".asmx", "application/xml" },
			{ ".aspx", "application/xml" },
			{ ".asr", "video/x-ms-asf" },
			{ ".asx", "video/x-ms-asf" },
			{ ".atom", "application/atom+xml" },
			{ ".au", "audio/basic" },
			{ ".avi", "video/x-msvideo" },
			{ ".axa", "audio/annodex" },
			{ ".axs", "application/olescript" },
			{ ".axv", "video/annodex" },
			{ ".bas", "text/plain" },
			{ ".bcpio", "application/x-bcpio" },
			{ ".bin", "application/octet-stream" },
			{ ".bmp", "image/bmp" },
			{ ".c", "text/plain" },
			{ ".cab", "application/octet-stream" },
			{ ".caf", "audio/x-caf" },
			{ ".calx", "application/vnd.ms-office.calx" },
			{ ".cat", "application/vnd.ms-pki.seccat" },
			{ ".cc", "text/plain" },
			{ ".cd", "text/plain" },
			{ ".cdda", "audio/aiff" },
			{ ".cdf", "application/x-cdf" },
			{ ".cer", "application/x-x509-ca-cert" },
			{ ".cfg", "text/plain" },
			{ ".chm", "application/octet-stream" },
			{ ".class", "application/x-java-applet" },
			{ ".clp", "application/x-msclip" },
			{ ".cmd", "text/plain" },
			{ ".cmx", "image/x-cmx" },
			{ ".cnf", "text/plain" },
			{ ".cod", "image/cis-cod" },
			{ ".config", "application/xml" },
			{ ".contact", "text/x-ms-contact" },
			{ ".coverage", "application/xml" },
			{ ".cpio", "application/x-cpio" },
			{ ".cpp", "text/plain" },
			{ ".crd", "application/x-mscardfile" },
			{ ".crl", "application/pkix-crl" },
			{ ".crt", "application/x-x509-ca-cert" },
			{ ".cs", "text/plain" },
			{ ".csdproj", "text/plain" },
			{ ".csh", "application/x-csh" },
			{ ".csproj", "text/plain" },
			{ ".css", "text/css" },
			{ ".csv", "text/csv" },
			{ ".cur", "application/octet-stream" },
			{ ".cxx", "text/plain" },
			{ ".dat", "application/octet-stream" },
			{ ".datasource", "application/xml" },
			{ ".dbproj", "text/plain" },
			{ ".dcr", "application/x-director" },
			{ ".def", "text/plain" },
			{ ".deploy", "application/octet-stream" },
			{ ".der", "application/x-x509-ca-cert" },
			{ ".dgml", "application/xml" },
			{ ".dib", "image/bmp" },
			{ ".dif", "video/x-dv" },
			{ ".dir", "application/x-director" },
			{ ".disco", "text/xml" },
			{ ".divx", "video/divx" },
			{ ".dll", "application/x-msdownload" },
			{ ".dll.config", "text/xml" },
			{ ".dlm", "text/dlm" },
			{ ".doc", "application/msword" },
			{ ".docm", "application/vnd.ms-word.document.macroEnabled.12" },
			{ ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
			{ ".dot", "application/msword" },
			{ ".dotm", "application/vnd.ms-word.template.macroEnabled.12" },
			{ ".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template" },
			{ ".dsp", "application/octet-stream" },
			{ ".dsw", "text/plain" },
			{ ".dtd", "text/xml" },
			{ ".dtsConfig", "text/xml" },
			{ ".dv", "video/x-dv" },
			{ ".dvi", "application/x-dvi" },
			{ ".dwf", "drawing/x-dwf" },
			{ ".dwg", "application/acad" },
			{ ".dwp", "application/octet-stream" },
			{ ".dxf", "application/x-dxf" },
			{ ".dxr", "application/x-director" },
			{ ".eml", "message/rfc822" },
			{ ".emz", "application/octet-stream" },
			{ ".eot", "application/vnd.ms-fontobject" },
			{ ".eps", "application/postscript" },
			{ ".es", "application/ecmascript" },
			{ ".etl", "application/etl" },
			{ ".etx", "text/x-setext" },
			{ ".evy", "application/envoy" },
			{ ".exe", "application/octet-stream" },
			{ ".exe.config", "text/xml" },
			{ ".fdf", "application/vnd.fdf" },
			{ ".fif", "application/fractals" },
			{ ".filters", "application/xml" },
			{ ".fla", "application/octet-stream" },
			{ ".flac", "audio/flac" },
			{ ".flr", "x-world/x-vrml" },
			{ ".flv", "video/x-flv" },
			{ ".fsscript", "application/fsharp-script" },
			{ ".fsx", "application/fsharp-script" },
			{ ".generictest", "application/xml" },
			{ ".gif", "image/gif" },
			{ ".gpx", "application/gpx+xml" },
			{ ".group", "text/x-ms-group" },
			{ ".gsm", "audio/x-gsm" },
			{ ".gtar", "application/x-gtar" },
			{ ".gz", "application/x-gzip" },
			{ ".h", "text/plain" },
			{ ".hdf", "application/x-hdf" },
			{ ".hdml", "text/x-hdml" },
			{ ".hhc", "application/x-oleobject" },
			{ ".hhk", "application/octet-stream" },
			{ ".hhp", "application/octet-stream" },
			{ ".hlp", "application/winhlp" },
			{ ".hpp", "text/plain" },
			{ ".hqx", "application/mac-binhex40" },
			{ ".hta", "application/hta" },
			{ ".htc", "text/x-component" },
			{ ".htm", "text/html" },
			{ ".html", "text/html" },
			{ ".htt", "text/webviewhtml" },
			{ ".hxa", "application/xml" },
			{ ".hxc", "application/xml" },
			{ ".hxd", "application/octet-stream" },
			{ ".hxe", "application/xml" },
			{ ".hxf", "application/xml" },
			{ ".hxh", "application/octet-stream" },
			{ ".hxi", "application/octet-stream" },
			{ ".hxk", "application/xml" },
			{ ".hxq", "application/octet-stream" },
			{ ".hxr", "application/octet-stream" },
			{ ".hxs", "application/octet-stream" },
			{ ".hxt", "text/html" },
			{ ".hxv", "application/xml" },
			{ ".hxw", "application/octet-stream" },
			{ ".hxx", "text/plain" },
			{ ".i", "text/plain" },
			{ ".ico", "image/x-icon" },
			{ ".ics", "application/octet-stream" },
			{ ".idl", "text/plain" },
			{ ".ief", "image/ief" },
			{ ".iii", "application/x-iphone" },
			{ ".inc", "text/plain" },
			{ ".inf", "application/octet-stream" },
			{ ".ini", "text/plain" },
			{ ".inl", "text/plain" },
			{ ".ins", "application/x-internet-signup" },
			{ ".ipa", "application/x-itunes-ipa" },
			{ ".ipg", "application/x-itunes-ipg" },
			{ ".ipproj", "text/plain" },
			{ ".ipsw", "application/x-itunes-ipsw" },
			{ ".iqy", "text/x-ms-iqy" },
			{ ".isp", "application/x-internet-signup" },
			{ ".ite", "application/x-itunes-ite" },
			{ ".itlp", "application/x-itunes-itlp" },
			{ ".itms", "application/x-itunes-itms" },
			{ ".itpc", "application/x-itunes-itpc" },
			{ ".IVF", "video/x-ivf" },
			{ ".jar", "application/java-archive" },
			{ ".java", "application/octet-stream" },
			{ ".jck", "application/liquidmotion" },
			{ ".jcz", "application/liquidmotion" },
			{ ".jfif", "image/pjpeg" },
			{ ".jnlp", "application/x-java-jnlp-file" },
			{ ".jpb", "application/octet-stream" },
			{ ".jpe", "image/jpeg" },
			{ ".jpeg", "image/jpeg" },
			{ ".jpg", "image/jpeg" },
			{ ".js", "application/javascript" },
			{ ".json", "application/json" },
			{ ".jsx", "text/jscript" },
			{ ".jsxbin", "text/plain" },
			{ ".latex", "application/x-latex" },
			{ ".library-ms", "application/windows-library+xml" },
			{ ".lit", "application/x-ms-reader" },
			{ ".loadtest", "application/xml" },
			{ ".lpk", "application/octet-stream" },
			{ ".lsf", "video/x-la-asf" },
			{ ".lst", "text/plain" },
			{ ".lsx", "video/x-la-asf" },
			{ ".lzh", "application/octet-stream" },
			{ ".m13", "application/x-msmediaview" },
			{ ".m14", "application/x-msmediaview" },
			{ ".m1v", "video/mpeg" },
			{ ".m2t", "video/vnd.dlna.mpeg-tts" },
			{ ".m2ts", "video/vnd.dlna.mpeg-tts" },
			{ ".m2v", "video/mpeg" },
			{ ".m3u", "audio/x-mpegurl" },
			{ ".m3u8", "audio/x-mpegurl" },
			{ ".m4a", "audio/m4a" },
			{ ".m4b", "audio/m4b" },
			{ ".m4p", "audio/m4p" },
			{ ".m4r", "audio/x-m4r" },
			{ ".m4v", "video/x-m4v" },
			{ ".mac", "image/x-macpaint" },
			{ ".mak", "text/plain" },
			{ ".man", "application/x-troff-man" },
			{ ".manifest", "application/x-ms-manifest" },
			{ ".map", "text/plain" },
			{ ".master", "application/xml" },
			{ ".mbox", "application/mbox" },
			{ ".mda", "application/msaccess" },
			{ ".mdb", "application/x-msaccess" },
			{ ".mde", "application/msaccess" },
			{ ".mdp", "application/octet-stream" },
			{ ".me", "application/x-troff-me" },
			{ ".mfp", "application/x-shockwave-flash" },
			{ ".mht", "message/rfc822" },
			{ ".mhtml", "message/rfc822" },
			{ ".mid", "audio/mid" },
			{ ".midi", "audio/mid" },
			{ ".mix", "application/octet-stream" },
			{ ".mk", "text/plain" },
			{ ".mk3d", "video/x-matroska-3d" },
			{ ".mka", "audio/x-matroska" },
			{ ".mkv", "video/x-matroska" },
			{ ".mmf", "application/x-smaf" },
			{ ".mno", "text/xml" },
			{ ".mny", "application/x-msmoney" },
			{ ".mod", "video/mpeg" },
			{ ".mov", "video/quicktime" },
			{ ".movie", "video/x-sgi-movie" },
			{ ".mp2", "video/mpeg" },
			{ ".mp2v", "video/mpeg" },
			{ ".mp3", "audio/mpeg" },
			{ ".mp4", "video/mp4" },
			{ ".mp4v", "video/mp4" },
			{ ".mpa", "video/mpeg" },
			{ ".mpe", "video/mpeg" },
			{ ".mpeg", "video/mpeg" },
			{ ".mpf", "application/vnd.ms-mediapackage" },
			{ ".mpg", "video/mpeg" },
			{ ".mpp", "application/vnd.ms-project" },
			{ ".mpv2", "video/mpeg" },
			{ ".mqv", "video/quicktime" },
			{ ".ms", "application/x-troff-ms" },
			{ ".msg", "application/vnd.ms-outlook" },
			{ ".msi", "application/octet-stream" },
			{ ".mso", "application/octet-stream" },
			{ ".mts", "video/vnd.dlna.mpeg-tts" },
			{ ".mtx", "application/xml" },
			{ ".mvb", "application/x-msmediaview" },
			{ ".mvc", "application/x-miva-compiled" },
			{ ".mxp", "application/x-mmxp" },
			{ ".nc", "application/x-netcdf" },
			{ ".nsc", "video/x-ms-asf" },
			{ ".nws", "message/rfc822" },
			{ ".ocx", "application/octet-stream" },
			{ ".oda", "application/oda" },
			{ ".odb", "application/vnd.oasis.opendocument.database" },
			{ ".odc", "application/vnd.oasis.opendocument.chart" },
			{ ".odf", "application/vnd.oasis.opendocument.formula" },
			{ ".odg", "application/vnd.oasis.opendocument.graphics" },
			{ ".odh", "text/plain" },
			{ ".odi", "application/vnd.oasis.opendocument.image" },
			{ ".odl", "text/plain" },
			{ ".odm", "application/vnd.oasis.opendocument.text-master" },
			{ ".odp", "application/vnd.oasis.opendocument.presentation" },
			{ ".ods", "application/vnd.oasis.opendocument.spreadsheet" },
			{ ".odt", "application/vnd.oasis.opendocument.text" },
			{ ".oga", "audio/ogg" },
			{ ".ogg", "audio/ogg" },
			{ ".ogv", "video/ogg" },
			{ ".ogx", "application/ogg" },
			{ ".one", "application/onenote" },
			{ ".onea", "application/onenote" },
			{ ".onepkg", "application/onenote" },
			{ ".onetmp", "application/onenote" },
			{ ".onetoc", "application/onenote" },
			{ ".onetoc2", "application/onenote" },
			{ ".opus", "audio/ogg" },
			{ ".orderedtest", "application/xml" },
			{ ".osdx", "application/opensearchdescription+xml" },
			{ ".otf", "application/font-sfnt" },
			{ ".otg", "application/vnd.oasis.opendocument.graphics-template" },
			{ ".oth", "application/vnd.oasis.opendocument.text-web" },
			{ ".otp", "application/vnd.oasis.opendocument.presentation-template" },
			{ ".ots", "application/vnd.oasis.opendocument.spreadsheet-template" },
			{ ".ott", "application/vnd.oasis.opendocument.text-template" },
			{ ".oxt", "application/vnd.openofficeorg.extension" },
			{ ".p10", "application/pkcs10" },
			{ ".p12", "application/x-pkcs12" },
			{ ".p7b", "application/x-pkcs7-certificates" },
			{ ".p7c", "application/pkcs7-mime" },
			{ ".p7m", "application/pkcs7-mime" },
			{ ".p7r", "application/x-pkcs7-certreqresp" },
			{ ".p7s", "application/pkcs7-signature" },
			{ ".pbm", "image/x-portable-bitmap" },
			{ ".pcast", "application/x-podcast" },
			{ ".pct", "image/pict" },
			{ ".pcx", "application/octet-stream" },
			{ ".pcz", "application/octet-stream" },
			{ ".pdf", "application/pdf" },
			{ ".pfb", "application/octet-stream" },
			{ ".pfm", "application/octet-stream" },
			{ ".pfx", "application/x-pkcs12" },
			{ ".pgm", "image/x-portable-graymap" },
			{ ".pic", "image/pict" },
			{ ".pict", "image/pict" },
			{ ".pkgdef", "text/plain" },
			{ ".pkgundef", "text/plain" },
			{ ".pko", "application/vnd.ms-pki.pko" },
			{ ".pls", "audio/scpls" },
			{ ".pma", "application/x-perfmon" },
			{ ".pmc", "application/x-perfmon" },
			{ ".pml", "application/x-perfmon" },
			{ ".pmr", "application/x-perfmon" },
			{ ".pmw", "application/x-perfmon" },
			{ ".png", "image/png" },
			{ ".pnm", "image/x-portable-anymap" },
			{ ".pnt", "image/x-macpaint" },
			{ ".pntg", "image/x-macpaint" },
			{ ".pnz", "image/png" },
			{ ".pot", "application/vnd.ms-powerpoint" },
			{ ".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12" },
			{ ".potx", "application/vnd.openxmlformats-officedocument.presentationml.template" },
			{ ".ppa", "application/vnd.ms-powerpoint" },
			{ ".ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12" },
			{ ".ppm", "image/x-portable-pixmap" },
			{ ".pps", "application/vnd.ms-powerpoint" },
			{ ".ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12" },
			{ ".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow" },
			{ ".ppt", "application/vnd.ms-powerpoint" },
			{ ".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12" },
			{ ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" },
			{ ".prf", "application/pics-rules" },
			{ ".prm", "application/octet-stream" },
			{ ".prx", "application/octet-stream" },
			{ ".ps", "application/postscript" },
			{ ".psc1", "application/PowerShell" },
			{ ".psd", "application/octet-stream" },
			{ ".psess", "application/xml" },
			{ ".psm", "application/octet-stream" },
			{ ".psp", "application/octet-stream" },
			{ ".pst", "application/vnd.ms-outlook" },
			{ ".pub", "application/x-mspublisher" },
			{ ".pwz", "application/vnd.ms-powerpoint" },
			{ ".qht", "text/x-html-insertion" },
			{ ".qhtm", "text/x-html-insertion" },
			{ ".qt", "video/quicktime" },
			{ ".qti", "image/x-quicktime" },
			{ ".qtif", "image/x-quicktime" },
			{ ".qtl", "application/x-quicktimeplayer" },
			{ ".qxd", "application/octet-stream" },
			{ ".ra", "audio/x-pn-realaudio" },
			{ ".ram", "audio/x-pn-realaudio" },
			{ ".rar", "application/x-rar-compressed" },
			{ ".ras", "image/x-cmu-raster" },
			{ ".rat", "application/rat-file" },
			{ ".rc", "text/plain" },
			{ ".rc2", "text/plain" },
			{ ".rct", "text/plain" },
			{ ".rdlc", "application/xml" },
			{ ".reg", "text/plain" },
			{ ".resx", "application/xml" },
			{ ".rf", "image/vnd.rn-realflash" },
			{ ".rgb", "image/x-rgb" },
			{ ".rgs", "text/plain" },
			{ ".rm", "application/vnd.rn-realmedia" },
			{ ".rmi", "audio/mid" },
			{ ".rmp", "application/vnd.rn-rn_music_package" },
			{ ".roff", "application/x-troff" },
			{ ".rpm", "audio/x-pn-realaudio-plugin" },
			{ ".rqy", "text/x-ms-rqy" },
			{ ".rtf", "application/rtf" },
			{ ".rtx", "text/richtext" },
			{ ".rvt", "application/octet-stream" },
			{ ".ruleset", "application/xml" },
			{ ".s", "text/plain" },
			{ ".safariextz", "application/x-safari-safariextz" },
			{ ".scd", "application/x-msschedule" },
			{ ".scr", "text/plain" },
			{ ".sct", "text/scriptlet" },
			{ ".sd2", "audio/x-sd2" },
			{ ".sdp", "application/sdp" },
			{ ".sea", "application/octet-stream" },
			{ ".searchConnector-ms", "application/windows-search-connector+xml" },
			{ ".setpay", "application/set-payment-initiation" },
			{ ".setreg", "application/set-registration-initiation" },
			{ ".settings", "application/xml" },
			{ ".sgimb", "application/x-sgimb" },
			{ ".sgml", "text/sgml" },
			{ ".sh", "application/x-sh" },
			{ ".shar", "application/x-shar" },
			{ ".shtml", "text/html" },
			{ ".sit", "application/x-stuffit" },
			{ ".sitemap", "application/xml" },
			{ ".skin", "application/xml" },
			{ ".skp", "application/x-koan" },
			{ ".sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12" },
			{ ".sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide" },
			{ ".slk", "application/vnd.ms-excel" },
			{ ".sln", "text/plain" },
			{ ".slupkg-ms", "application/x-ms-license" },
			{ ".smd", "audio/x-smd" },
			{ ".smi", "application/octet-stream" },
			{ ".smx", "audio/x-smd" },
			{ ".smz", "audio/x-smd" },
			{ ".snd", "audio/basic" },
			{ ".snippet", "application/xml" },
			{ ".snp", "application/octet-stream" },
			{ ".sol", "text/plain" },
			{ ".sor", "text/plain" },
			{ ".spc", "application/x-pkcs7-certificates" },
			{ ".spl", "application/futuresplash" },
			{ ".spx", "audio/ogg" },
			{ ".src", "application/x-wais-source" },
			{ ".srf", "text/plain" },
			{ ".SSISDeploymentManifest", "text/xml" },
			{ ".ssm", "application/streamingmedia" },
			{ ".sst", "application/vnd.ms-pki.certstore" },
			{ ".stl", "application/vnd.ms-pki.stl" },
			{ ".sv4cpio", "application/x-sv4cpio" },
			{ ".sv4crc", "application/x-sv4crc" },
			{ ".svc", "application/xml" },
			{ ".svg", "image/svg+xml" },
			{ ".swf", "application/x-shockwave-flash" },
			{ ".step", "application/step" },
			{ ".stp", "application/step" },
			{ ".t", "application/x-troff" },
			{ ".tar", "application/x-tar" },
			{ ".tcl", "application/x-tcl" },
			{ ".testrunconfig", "application/xml" },
			{ ".testsettings", "application/xml" },
			{ ".tex", "application/x-tex" },
			{ ".texi", "application/x-texinfo" },
			{ ".texinfo", "application/x-texinfo" },
			{ ".tgz", "application/x-compressed" },
			{ ".thmx", "application/vnd.ms-officetheme" },
			{ ".thn", "application/octet-stream" },
			{ ".tif", "image/tiff" },
			{ ".tiff", "image/tiff" },
			{ ".tlh", "text/plain" },
			{ ".tli", "text/plain" },
			{ ".toc", "application/octet-stream" },
			{ ".tr", "application/x-troff" },
			{ ".trm", "application/x-msterminal" },
			{ ".trx", "application/xml" },
			{ ".ts", "video/vnd.dlna.mpeg-tts" },
			{ ".tsv", "text/tab-separated-values" },
			{ ".ttf", "application/font-sfnt" },
			{ ".tts", "video/vnd.dlna.mpeg-tts" },
			{ ".txt", "text/plain" },
			{ ".u32", "application/octet-stream" },
			{ ".uls", "text/iuls" },
			{ ".user", "text/plain" },
			{ ".ustar", "application/x-ustar" },
			{ ".vb", "text/plain" },
			{ ".vbdproj", "text/plain" },
			{ ".vbk", "video/mpeg" },
			{ ".vbproj", "text/plain" },
			{ ".vbs", "text/vbscript" },
			{ ".vcf", "text/x-vcard" },
			{ ".vcproj", "application/xml" },
			{ ".vcs", "text/plain" },
			{ ".vcxproj", "application/xml" },
			{ ".vddproj", "text/plain" },
			{ ".vdp", "text/plain" },
			{ ".vdproj", "text/plain" },
			{ ".vdx", "application/vnd.ms-visio.viewer" },
			{ ".vml", "text/xml" },
			{ ".vscontent", "application/xml" },
			{ ".vsct", "text/xml" },
			{ ".vsd", "application/vnd.visio" },
			{ ".vsi", "application/ms-vsi" },
			{ ".vsix", "application/vsix" },
			{ ".vsixlangpack", "text/xml" },
			{ ".vsixmanifest", "text/xml" },
			{ ".vsmdi", "application/xml" },
			{ ".vspscc", "text/plain" },
			{ ".vss", "application/vnd.visio" },
			{ ".vsscc", "text/plain" },
			{ ".vssettings", "text/xml" },
			{ ".vssscc", "text/plain" },
			{ ".vst", "application/vnd.visio" },
			{ ".vstemplate", "text/xml" },
			{ ".vsto", "application/x-ms-vsto" },
			{ ".vsw", "application/vnd.visio" },
			{ ".vsx", "application/vnd.visio" },
			{ ".vtt", "text/vtt" },
			{ ".vtx", "application/vnd.visio" },
			{ ".wasm", "application/wasm" },
			{ ".wav", "audio/wav" },
			{ ".wave", "audio/wav" },
			{ ".wax", "audio/x-ms-wax" },
			{ ".wbk", "application/msword" },
			{ ".wbmp", "image/vnd.wap.wbmp" },
			{ ".wcm", "application/vnd.ms-works" },
			{ ".wdb", "application/vnd.ms-works" },
			{ ".wdp", "image/vnd.ms-photo" },
			{ ".webarchive", "application/x-safari-webarchive" },
			{ ".webm", "video/webm" },
			{ ".webp", "image/webp" },
			{ ".webtest", "application/xml" },
			{ ".wiq", "application/xml" },
			{ ".wiz", "application/msword" },
			{ ".wks", "application/vnd.ms-works" },
			{ ".WLMP", "application/wlmoviemaker" },
			{ ".wlpginstall", "application/x-wlpg-detect" },
			{ ".wlpginstall3", "application/x-wlpg3-detect" },
			{ ".wm", "video/x-ms-wm" },
			{ ".wma", "audio/x-ms-wma" },
			{ ".wmd", "application/x-ms-wmd" },
			{ ".wmf", "application/x-msmetafile" },
			{ ".wml", "text/vnd.wap.wml" },
			{ ".wmlc", "application/vnd.wap.wmlc" },
			{ ".wmls", "text/vnd.wap.wmlscript" },
			{ ".wmlsc", "application/vnd.wap.wmlscriptc" },
			{ ".wmp", "video/x-ms-wmp" },
			{ ".wmv", "video/x-ms-wmv" },
			{ ".wmx", "video/x-ms-wmx" },
			{ ".wmz", "application/x-ms-wmz" },
			{ ".woff", "application/font-woff" },
			{ ".woff2", "application/font-woff2" },
			{ ".wpl", "application/vnd.ms-wpl" },
			{ ".wps", "application/vnd.ms-works" },
			{ ".wri", "application/x-mswrite" },
			{ ".wrl", "x-world/x-vrml" },
			{ ".wrz", "x-world/x-vrml" },
			{ ".wsc", "text/scriptlet" },
			{ ".wsdl", "text/xml" },
			{ ".wvx", "video/x-ms-wvx" },
			{ ".x", "application/directx" },
			{ ".xaf", "x-world/x-vrml" },
			{ ".xaml", "application/xaml+xml" },
			{ ".xap", "application/x-silverlight-app" },
			{ ".xbap", "application/x-ms-xbap" },
			{ ".xbm", "image/x-xbitmap" },
			{ ".xdr", "text/plain" },
			{ ".xht", "application/xhtml+xml" },
			{ ".xhtml", "application/xhtml+xml" },
			{ ".xla", "application/vnd.ms-excel" },
			{ ".xlam", "application/vnd.ms-excel.addin.macroEnabled.12" },
			{ ".xlc", "application/vnd.ms-excel" },
			{ ".xld", "application/vnd.ms-excel" },
			{ ".xlk", "application/vnd.ms-excel" },
			{ ".xll", "application/vnd.ms-excel" },
			{ ".xlm", "application/vnd.ms-excel" },
			{ ".xls", "application/vnd.ms-excel" },
			{ ".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12" },
			{ ".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12" },
			{ ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
			{ ".xlt", "application/vnd.ms-excel" },
			{ ".xltm", "application/vnd.ms-excel.template.macroEnabled.12" },
			{ ".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template" },
			{ ".xlw", "application/vnd.ms-excel" },
			{ ".xml", "text/xml" },
			{ ".xmp", "application/octet-stream" },
			{ ".xmta", "application/xml" },
			{ ".xof", "x-world/x-vrml" },
			{ ".XOML", "text/plain" },
			{ ".xpm", "image/x-xpixmap" },
			{ ".xps", "application/vnd.ms-xpsdocument" },
			{ ".xrm-ms", "text/xml" },
			{ ".xsc", "application/xml" },
			{ ".xsd", "text/xml" },
			{ ".xsf", "text/xml" },
			{ ".xsl", "text/xml" },
			{ ".xslt", "text/xml" },
			{ ".xsn", "application/octet-stream" },
			{ ".xss", "application/xml" },
			{ ".xspf", "application/xspf+xml" },
			{ ".xtp", "application/octet-stream" },
			{ ".xwd", "image/x-xwindowdump" },
			{ ".z", "application/x-compress" },
			{ ".zip", "application/zip" }
		};


		public static string StripParameters(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return value;
			}
			int num = value.IndexOf(';');
			if (num >= 0)
			{
				return value.Substring(0, num).TrimEnd(Array.Empty<char>());
			}
			return value;
		}

		public static bool IsMimeType(string value, bool acceptMediaRange)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			int num = value.IndexOf('/');
			if (num < 0)
			{
				return false;
			}
			bool flag = false;
			string text = value.Substring(num + 1);
			if (text == "*")
			{
				if (!acceptMediaRange)
				{
					return false;
				}
				flag = true;
			}
			else if (!Validate.IsRfc2616Token(text))
			{
				return false;
			}
			string text2 = value.Substring(0, num);
			if (!(text2 == "*"))
			{
				return Validate.IsRfc2616Token(text2);
			}
			return acceptMediaRange && flag;
		}

		public static (string type, string subtype) Split(string mimeType)
		{
			return UnsafeSplit(Validate.MimeType("mimeType", mimeType, acceptMediaRange: true));
		}

		public static bool IsInRange(string mimeType, string mediaRange)
		{
			return UnsafeIsInRange(Validate.MimeType("mimeType", mimeType, acceptMediaRange: false), Validate.MimeType("mediaRange", mediaRange, acceptMediaRange: true));
		}

		internal static (string type, string subtype) UnsafeSplit(string mimeType)
		{
			int num = mimeType.IndexOf('/');
			return (mimeType.Substring(0, num), mimeType.Substring(num + 1));
		}

		internal static bool UnsafeIsInRange(string mimeType, string mediaRange)
		{
			if (mediaRange[0] == '*')
			{
				return true;
			}
			int num = mimeType.IndexOf('/');
			int num2 = mediaRange.IndexOf('/');
			if (num != num2)
			{
				return false;
			}
			for (int i = 0; i < num; i++)
			{
				if (mimeType[i] != mediaRange[i])
				{
					return false;
				}
			}
			if (mediaRange[num2 + 1] == '*')
			{
				return true;
			}
			if (mimeType.Length != mediaRange.Length)
			{
				return false;
			}
			for (int j = num + 1; j < mimeType.Length; j++)
			{
				if (mimeType[j] != mediaRange[j])
				{
					return false;
				}
			}
			return true;
		}
	}
	public static class MimeTypeCustomizerExtensions
	{
		public static T WithCustomMimeType<T>(this T @this, string extension, string mimeType) where T : IMimeTypeCustomizer
		{
			@this.AddCustomMimeType(extension, mimeType);
			return @this;
		}

		public static T PreferCompressionFor<T>(this T @this, string mimeType, bool preferCompression) where T : IMimeTypeCustomizer
		{
			@this.PreferCompression(mimeType, preferCompression);
			return @this;
		}

		public static T PreferCompressionFor<T>(this T @this, string mimeType) where T : IMimeTypeCustomizer
		{
			@this.PreferCompression(mimeType, preferCompression: true);
			return @this;
		}

		public static T PreferNoCompressionFor<T>(this T @this, string mimeType) where T : IMimeTypeCustomizer
		{
			@this.PreferCompression(mimeType, preferCompression: false);
			return @this;
		}
	}
	public class ModuleGroup : WebModuleBase, IDisposable, IWebModuleContainer, IMimeTypeCustomizer, IMimeTypeProvider
	{
		private readonly WebModuleCollection _modules;

		private readonly MimeTypeCustomizer _mimeTypeCustomizer = new MimeTypeCustomizer();

		public sealed override bool IsFinalHandler { get; }

		public IComponentCollection<IWebModule> Modules => _modules;

		public ModuleGroup(string baseRoute, bool isFinalHandler)
			: base(baseRoute)
		{
			IsFinalHandler = isFinalHandler;
			_modules = new WebModuleCollection("ModuleGroup");
		}

		~ModuleGroup()
		{
			try
			{
				Dispose(disposing: false);
			}
			finally
			{
				((object)this).Finalize();
			}
		}

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

		string IMimeTypeProvider.GetMimeType(string extension)
		{
			return _mimeTypeCustomizer.GetMimeType(extension);
		}

		bool IMimeTypeProvider.TryDetermineCompression(string mimeType, out bool preferCompression)
		{
			return _mimeTypeCustomizer.TryDetermineCompression(mimeType, out preferCompression);
		}

		public void AddCustomMimeType(string extension, string mimeType)
		{
			_mimeTypeCustomizer.AddCustomMimeType(extension, mimeType);
		}

		public void PreferCompression(string mimeType, bool preferCompression)
		{
			_mimeTypeCustomizer.PreferCompression(mimeType, preferCompression);
		}

		protected override Task OnRequestAsync(IHttpContext context)
		{
			return _modules.DispatchRequestAsync(context);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				_modules.Dispose();
			}
		}

		protected override void OnBeforeLockConfiguration()
		{
			((ConfiguredObject)this).OnBeforeLockConfiguration();
			_mimeTypeCustomizer.Lock();
		}

		protected override void OnStart(CancellationToken cancellationToken)
		{
			_modules.StartAll(cancellationToken);
		}
	}
	public static class RequestDeserializer
	{
		public static Task<TData> Default<TData>(IHttpContext context)
		{
			return Json<TData>(context);
		}

		public static Task<TData> Json<TData>(IHttpContext context)
		{
			return JsonInternal<TData>(context, (JsonSerializerCase)0);
		}

		public static RequestDeserializerCallback<TData> Json<TData>(JsonSerializerCase jsonSerializerCase)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return (IHttpContext context) => JsonInternal<TData>(context, jsonSerializerCase);
		}

		private static async Task<TData> JsonInternal<TData>(IHttpContext context, JsonSerializerCase jsonSerializerCase)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			string text;
			using (TextReader reader = context.OpenRequestText())
			{
				text = await reader.ReadToEndAsync().ConfigureAwait(continueOnCapturedContext: false);
			}
			try
			{
				return Json.Deserialize<TData>(text, jsonSerializerCase);
			}
			catch (FormatException)
			{
				Logger.Warn("[" + context.Id + "] Cannot convert JSON request body to " + typeof(TData).Name + ", sending 400 Bad Request...", "RequestDeserializer.Json", (object)null, "JsonInternal", "C:\\Unosquare\\embedio\\src\\EmbedIO\\RequestDeserializer.cs", 58);
				throw HttpException.BadRequest("Incorrect request data format.");
			}
		}
	}
	public delegate Task<TData> RequestDeserializerCallback<TData>(IHttpContext context);
	public static class RequestHandler
	{
		public static Exception PassThrough()
		{
			return new RequestHandlerPassThroughException();
		}

		public static RequestHandlerCallback ThrowUnauthorized(string? message = null)
		{
			string message2 = message;
			return delegate
			{
				throw HttpException.Unauthorized(message2);
			};
		}

		public static RequestHandlerCallback ThrowForbidden(string? message = null)
		{
			string message2 = message;
			return delegate
			{
				throw HttpException.Forbidden(message2);
			};
		}

		public static RequestHandlerCallback ThrowBadRequest(string? message = null)
		{
			string message2 = message;
			return delegate
			{
				throw HttpException.BadRequest(message2);
			};
		}

		public static RequestHandlerCallback ThrowNotFound(string? message = null)
		{
			string message2 = message;
			return delegate
			{
				throw HttpException.NotFound(message2);
			};
		}

		public static RequestHandlerCallback ThrowMethodNotAllowed(string? message = null)
		{
			string message2 = message;
			return delegate
			{
				throw HttpException.MethodNotAllowed(message2);
			};
		}
	}
	public delegate Task RequestHandlerCallback(IHttpContext context);
	public static class ResponseSerializer
	{
		public static readonly ResponseSerializerCallback Default = Json;

		private static readonly ResponseSerializerCallback ChunkedEncodingBaseSerializer = GetBaseSerializer(bufferResponse: false);

		private static readonly ResponseSerializerCallback BufferingBaseSerializer = GetBaseSerializer(bufferResponse: true);

		public static async Task Json(IHttpContext context, object? data)
		{
			context.Response.ContentType = "application/json";
			context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
			await ChunkedEncodingBaseSerializer(context, Json.Serialize(data, false, (string)null, false, (string[])null, Array.Empty<string>())).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static ResponseSerializerCallback Json(JsonSerializerCase jsonSerializerCase)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return async delegate(IHttpContext context, object? data)
			{
				context.Response.ContentType = "application/json";
				context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
				await ChunkedEncodingBaseSerializer(context, Json.Serialize(data, jsonSerializerCase, false, (string)null)).ConfigureAwait(continueOnCapturedContext: false);
			};
		}

		public static ResponseSerializerCallback Json(SerializerOptions serializerOptions)
		{
			SerializerOptions serializerOptions2 = serializerOptions;
			Validate.NotNull<SerializerOptions>("serializerOptions", serializerOptions2);
			return async delegate(IHttpContext context, object? data)
			{
				context.Response.ContentType = "application/json";
				context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
				await ChunkedEncodingBaseSerializer(context, Json.Serialize(data, serializerOptions2)).ConfigureAwait(continueOnCapturedContext: false);
			};
		}

		public static ResponseSerializerCallback Json(bool bufferResponse)
		{
			return async delegate(IHttpContext context, object? data)
			{
				context.Response.ContentType = "application/json";
				context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
				await None(bufferResponse)(context, Json.Serialize(data, false, (string)null, false, (string[])null, Array.Empty<string>())).ConfigureAwait(continueOnCapturedContext: false);
			};
		}

		public static ResponseSerializerCallback Json(bool bufferResponse, JsonSerializerCase jsonSerializerCase)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			return async delegate(IHttpContext context, object? data)
			{
				context.Response.ContentType = "application/json";
				context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
				await None(bufferResponse)(context, Json.Serialize(data, jsonSerializerCase, false, (string)null)).ConfigureAwait(continueOnCapturedContext: false);
			};
		}

		public static ResponseSerializerCallback Json(bool bufferResponse, SerializerOptions serializerOptions)
		{
			SerializerOptions serializerOptions2 = serializerOptions;
			Validate.NotNull<SerializerOptions>("serializerOptions", serializerOptions2);
			return async delegate(IHttpContext context, object? data)
			{
				context.Response.ContentType = "application/json";
				context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding;
				await None(bufferResponse)(context, Json.Serialize(data, serializerOptions2)).ConfigureAwait(continueOnCapturedContext: false);
			};
		}

		public static ResponseSerializerCallback None(bool bufferResponse)
		{
			if (!bufferResponse)
			{
				return ChunkedEncodingBaseSerializer;
			}
			return BufferingBaseSerializer;
		}

		private static ResponseSerializerCallback GetBaseSerializer(bool bufferResponse)
		{
			return async delegate(IHttpContext context, object? data)
			{
				if (data != null)
				{
					bool num = data is byte[];
					if (!context.TryDetermineCompression(context.Response.ContentType, out var preferCompression))
					{
						preferCompression = true;
					}
					if (num)
					{
						byte[] array = (byte[])data;
						using Stream stream = context.OpenResponseStream(bufferResponse, preferCompression);
						await stream.WriteAsync(array, 0, array.Length).ConfigureAwait(continueOnCapturedContext: false);
					}
					else
					{
						string value = ((data is string text2) ? text2 : (data.ToString() ?? string.Empty));
						using TextWriter text = context.OpenResponseText(context.Response.ContentEncoding, bufferResponse, preferCompression);
						await text.WriteAsync(value).ConfigureAwait(continueOnCapturedContext: false);
					}
				}
			};
		}
	}
	public delegate Task ResponseSerializerCallback(IHttpContext context, object? data);
	public abstract class WebModuleBase : ConfiguredObject, IWebModule
	{
		private readonly RouteMatcher _routeMatcher;

		private ExceptionHandlerCallback? _onUnhandledException;

		private HttpExceptionHandlerCallback? _onHttpException;

		public string BaseRoute { get; }

		public ExceptionHandlerCallback? OnUnhandledException
		{
			get
			{
				return _onUnhandledException;
			}
			set
			{
				((ConfiguredObject)this).EnsureConfigurationNotLocked();
				_onUnhandledException = value;
			}
		}

		public HttpExceptionHandlerCallback? OnHttpException
		{
			get
			{
				return _onHttpException;
			}
			set
			{
				((ConfiguredObject)this).EnsureConfigurationNotLocked();
				_onHttpException = value;
			}
		}

		public abstract bool IsFinalHandler { get; }

		protected string LogSource { get; }

		protected WebModuleBase(string baseRoute)
		{
			BaseRoute = Validate.Route("baseRoute", baseRoute, isBaseRoute: true);
			_routeMatcher = RouteMatcher.Parse(baseRoute, isBaseRoute: true);
			LogSource = ((object)this).GetType().Name;
		}

		public void Start(CancellationToken cancellationToken)
		{
			OnStart(cancellationToken);
			((ConfiguredObject)this).LockConfiguration();
		}

		public RouteMatch? MatchUrlPath(string urlPath)
		{
			return _routeMatcher.Match(urlPath);
		}

		public async Task HandleRequestAsync(IHttpContext context)
		{
			IHttpContextImpl contextImpl = context.GetImplementation();
			IMimeTypeProvider mimeTypeProvider = this as IMimeTypeProvider;
			if (mimeTypeProvider != null)
			{
				contextImpl?.MimeTypeProviders.Push(mimeTypeProvider);
			}
			try
			{
				await OnRequestAsync(context).ConfigureAwait(continueOnCapturedContext: false);
				if (IsFinalHandler)
				{
					context.SetHandled();
				}
			}
			catch (RequestHandlerPassThroughException)
			{
			}
			catch (OperationCanceledException) when (context.CancellationToken.IsCancellationRequested)
			{
				throw;
			}
			catch (HttpListenerException)
			{
				throw;
			}
			catch (Exception ex4) when (ex4 is IHttpException)
			{
				await HttpExceptionHandler.Handle(LogSource, context, ex4, _onHttpException).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (Exception exception)
			{
				await ExceptionHandler.Handle(LogSource, context, exception, _onUnhandledException, _onHttpException).ConfigureAwait(continueOnCapturedContext: false);
			}
			finally
			{
				if (mimeTypeProvider != null)
				{
					contextImpl?.MimeTypeProviders.Pop();
				}
			}
		}

		protected abstract Task OnRequestAsync(IHttpContext context);

		protected virtual void OnStart(CancellationToken cancellationToken)
		{
		}
	}
	public static class WebModuleContainer
	{
		public static readonly IWebModuleContainer None = DummyWebModuleContainer.Instance;
	}
	public static class WebModuleContainerExtensions
	{
		public static TContainer WithAction<TContainer>(this TContainer @this, string baseRoute, HttpVerbs verb, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			@this.Modules.Add(new ActionModule(baseRoute, verb, handler));
			return @this;
		}

		public static TContainer WithAction<TContainer>(this TContainer @this, HttpVerbs verb, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", verb, handler);
		}

		public static TContainer OnAny<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Any, handler);
		}

		public static TContainer OnAny<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Any, handler);
		}

		public static TContainer OnDelete<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Delete, handler);
		}

		public static TContainer OnDelete<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Delete, handler);
		}

		public static TContainer OnGet<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Get, handler);
		}

		public static TContainer OnGet<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Get, handler);
		}

		public static TContainer OnHead<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Head, handler);
		}

		public static TContainer OnHead<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Head, handler);
		}

		public static TContainer OnOptions<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Options, handler);
		}

		public static TContainer OnOptions<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Options, handler);
		}

		public static TContainer OnPatch<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Patch, handler);
		}

		public static TContainer OnPatch<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Patch, handler);
		}

		public static TContainer OnPost<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Post, handler);
		}

		public static TContainer OnPost<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Post, handler);
		}

		public static TContainer OnPut<TContainer>(this TContainer @this, string baseRoute, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction(baseRoute, HttpVerbs.Put, handler);
		}

		public static TContainer OnPut<TContainer>(this TContainer @this, RequestHandlerCallback handler) where TContainer : class, IWebModuleContainer
		{
			return @this.WithAction("/", HttpVerbs.Put, handler);
		}

		public static TContainer WithCors<TContainer>(this TContainer @this, string baseRoute, string origins, string headers, string methods) where TContainer : class, IWebModuleContainer
		{
			@this.Modules.Add(new CorsModule(baseRoute, origins, headers, methods));
			return @this;
		}

		public static TContainer WithCors<TContainer>(this TContainer @this, string origins = "*", string headers = "*", string methods = "*") where TContainer : class, IWebModuleContainer
		{
			return @this.WithCors("/", origins, headers, methods);
		}

		public static TContainer WithStaticFolder<TContainer>(this TContainer @this, string baseRoute, string fileSystemPath, bool isImmutable, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			return @this.WithStaticFolder(null, baseRoute, fileSystemPath, isImmutable, configure);
		}

		public static TContainer WithStaticFolder<TContainer>(this TContainer @this, string? name, string baseRoute, string fileSystemPath, bool isImmutable, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			FileSystemProvider fileSystemProvider = new FileSystemProvider(fileSystemPath, isImmutable);
			try
			{
				FileModule module = new FileModule(baseRoute, fileSystemProvider);
				return @this.WithModule(name, module, configure);
			}
			catch
			{
				fileSystemProvider.Dispose();
				throw;
			}
		}

		public static TContainer WithEmbeddedResources<TContainer>(this TContainer @this, string baseRoute, Assembly assembly, string pathPrefix, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			return @this.WithEmbeddedResources(null, baseRoute, assembly, pathPrefix, configure);
		}

		public static TContainer WithEmbeddedResources<TContainer>(this TContainer @this, string? name, string baseRoute, Assembly assembly, string pathPrefix, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			FileModule module = new FileModule(baseRoute, new ResourceFileProvider(assembly, pathPrefix));
			return @this.WithModule(name, module, configure);
		}

		public static TContainer WithZipFile<TContainer>(this TContainer @this, string baseRoute, string zipFilePath, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			return @this.WithZipFile(null, baseRoute, zipFilePath, configure);
		}

		public static TContainer WithZipFile<TContainer>(this TContainer @this, string? name, string baseRoute, string zipFilePath, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			ZipFileProvider zipFileProvider = new ZipFileProvider(zipFilePath);
			try
			{
				FileModule module = new FileModule(baseRoute, zipFileProvider);
				return @this.WithModule(name, module, configure);
			}
			catch
			{
				zipFileProvider.Dispose();
				throw;
			}
		}

		public static TContainer WithZipFileStream<TContainer>(this TContainer @this, string baseRoute, Stream zipFileStream, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			return @this.WithZipFileStream(null, baseRoute, zipFileStream, configure);
		}

		public static TContainer WithZipFileStream<TContainer>(this TContainer @this, string? name, string baseRoute, Stream zipFileStream, Action<FileModule>? configure = null) where TContainer : class, IWebModuleContainer
		{
			ZipFileProvider zipFileProvider = new ZipFileProvider(zipFileStream);
			try
			{
				FileModule module = new FileModule(baseRoute, zipFileProvider);
				return @this.WithModule(name, module, configure);
			}
			catch
			{
				zipFileProvider.Dispose();
				throw;
			}
		}

		public static TContainer WithRouting<TContainer>(this TContainer @this, string baseRoute, Action<RoutingModule> configure) where TContainer : class, IWebModuleContainer
		{
			return @this.WithRouting(null, baseRoute, configure);
		}

		public static TContainer WithRouting<TContainer>(this TContainer @this, string? name, string baseRoute, Action<RoutingModule> configure) where TContainer : class, IWebModuleContainer
		{
			configure = Validate.NotNull("configure", configure);
			RoutingModule module = new RoutingModule(baseRoute);
			return @this.WithModule(name, module, configure);
		}

		public static TContainer WithIPBanning<TContainer>(this TContainer @this, IEnumerable<string>? whiteList = null, int banMinutes = 30) where TContainer : class, IWebModuleContainer
		{
			return @this.WithIPBanning(null, whiteList, banMinutes);
		}

		public static TContainer WithIPBanning<TContainer>(this TContainer @this, Action<IPBanningModule>? configure, IEnumerable<string>? whiteList = null, int banMinutes = 30) where TContainer : class, IWebModuleContainer
		{
			return @this.WithModule(new IPBanningModule("/", whiteList, banMinutes), configure);
		}

		public static TContainer WithWebApi<TContainer>(this TContainer @this, string baseRoute, Action<WebApiModule> configure) where TContainer : class, IWebModuleContainer
		{
			return @this.WithWebApi(null, baseRoute, configure);
		}

		public static TContainer WithWebApi<TContainer>(this TContainer @this, string baseRoute, ResponseSerializerCallback serializer, Action<WebApiModule> configure) where TContainer : class, IWebModuleContainer
		{
			return @this.WithWebApi(null, baseRoute, serializer, configure);
		}

		public static TContainer WithWebApi<TContainer>(this TContainer @this, string? name, string baseRoute, Action<WebApiModule> configure) where TContainer : class, IWebModuleContainer
		{
			configure = Validate.NotNull("configure", configure);
			WebApiModule module = new WebApiModule(baseRoute);
			return @this.WithModule(name, module, configure);
		}

		public static TContainer WithWebApi<TContainer>(this TContainer @this, string? name, string baseRoute, ResponseSerializerCallback serializer, Action<WebApiModule> configure) where TContainer : class, IWebModuleContainer
		{
			configure = Validate.NotNull("configure", configure);
			WebApiModule module = new WebApiModule(baseRoute, serializer);
			return @this.WithModule(name, module, configure);
		}

		public static TContainer WithModule<TContainer>(this TContainer @this, IWebModule module) where TContainer : class, IWebModuleContainer
		{
			return @this.WithModule(null, module);
		}

		public static TContainer WithModule<TContainer>(this TContainer @this, string? name, IWebModule module) where TContainer : class, IWebModuleContainer
		{
			@this.Modules.Add(name, module);
			return @this;
		}

		public static TContainer WithModule<TContainer, TWebModule>(this TContainer @this, TWebModule module, Action<TWebModule>? configure) where TContainer : class, IWebModuleContainer where TWebModule : IWebModule
		{
			return @this.WithModule(null, module, configure);
		}

		public static TContainer WithModule<TContainer, TWebModule>(this TContainer @this, string? name, TWebModule module, Action<TWebModule>? configure) where TContainer : class, IWebModuleContainer where TWebModule : IWebModule
		{
			configure?.Invoke(module);
			@this.Modules.Add(name, module);
			return @this;
		}
	}
	public static class WebModuleExtensions
	{
		public static TWebModule HandleHttpException<TWebModule>(this TWebModule @this, HttpExceptionHandlerCallback handler) where TWebModule : IWebModule
		{
			@this.OnHttpException = handler;
			return @this;
		}

		public static TWebModule HandleUnhandledException<TWebModule>(this TWebModule @this, ExceptionHandlerCallback handler) where TWebModule : IWebModule
		{
			@this.OnUnhandledException = handler;
			return @this;
		}
	}
	public class WebServer : WebServerBase<WebServerOptions>
	{
		public const int StreamCopyBufferSize = 81920;

		public const string UriSchemeNull = "null";

		public static readonly string Signature = "EmbedIO/" + Assembly.GetExecutingAssembly().GetCustomAttributes<AssemblyInformationalVersionAttribute>().First()
			.InformationalVersion;

		public static readonly Encoding Utf8NoBomEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

		public static readonly Encoding DefaultEncoding = Utf8NoBomEncoding;

		public static readonly Uri NullUri = new Uri("null:");

		public IHttpListener Listener { get; }

		public WebServer()
			: this(80)
		{
		}

		public WebServer(int port)
			: this($"http://*:{port}/")
		{
		}

		public WebServer(params string[] urlPrefixes)
			: this(new WebServerOptions().WithUrlPrefixes(urlPrefixes))
		{
		}

		public WebServer(HttpListenerMode mode, params string[] urlPrefixes)
			: this(new WebServerOptions().WithMode(mode).WithUrlPrefixes(urlPrefixes))
		{
		}

		public WebServer(HttpListenerMode mode, X509Certificate2 certificate, params string[] urlPrefixes)
			: this(new WebServerOptions().WithMode(mode).WithCertificate(certificate).WithUrlPrefixes(urlPrefixes))
		{
		}

		public WebServer(WebServerOptions options)
			: base(options)
		{
			Listener = CreateHttpListener();
		}

		public WebServer(Action<WebServerOptions> configure)
			: base(configure)
		{
			Listener = CreateHttpListener();
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				try
				{
					Listener.Dispose();
				}
				catch (Exception ex)
				{
					Logger.Log(ex, base.LogSource, "Exception thrown while disposing HTTP listener.", "Dispose", "C:\\Unosquare\\embedio\\src\\EmbedIO\\WebServer.cs", 128);
				}
				Logger.Info("Listener closed.", base.LogSource, (object)null, "Dispose", "C:\\Unosquare\\embedio\\src\\EmbedIO\\WebServer.cs", 131);
			}
			base.Dispose(disposing);
		}

		protected override void Prepare(CancellationToken cancellationToken)
		{
			Listener.Start();
			Logger.Info("Started HTTP Listener", base.LogSource, (object)null, "Prepare", "C:\\Unosquare\\embedio\\src\\EmbedIO\\WebServer.cs", 141);
			cancellationToken.Register(delegate
			{
				Listener?.Stop();
			});
		}

		protected override async Task ProcessRequestsAsync(CancellationToken cancellationToken)
		{
			while (!cancellationToken.IsCancellationRequested && (Listener?.IsListening ?? false))
			{
				IHttpContextImpl context = await Listener.GetContextAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				context.CancellationToken = cancellationToken;
				context.Route = RouteMatch.UnsafeFromRoot(UrlPath.Normalize(context.Request.Url.AbsolutePath, isBasePath: false));
				Task.Run(() => DoHandleContextAsync(context), cancellationToken);
			}
		}

		protected override void OnFatalException()
		{
			Listener?.Dispose();
		}

		private IHttpListener CreateHttpListener()
		{
			IHttpListener httpListener = DoCreate();
			Logger.Info("Running HTTPListener: " + httpListener.Name, base.LogSource, (object)null, "CreateHttpListener", "C:\\Unosquare\\embedio\\src\\EmbedIO\\WebServer.cs", 175);
			foreach (string urlPrefix in base.Options.UrlPrefixes)
			{
				string text = new string(urlPrefix?.ToCharArray());
				if (!text.EndsWith("/"))
				{
					text += "/";
				}
				text = text.ToLowerInvariant();
				httpListener.AddPrefix(text);
				Logger.Info("Web server prefix '" + text + "' added.", base.LogSource, (object)null, "CreateHttpListener", "C:\\Unosquare\\embedio\\src\\EmbedIO\\WebServer.cs", 185);
			}
			return httpListener;
			IHttpListener DoCreate()
			{
				if (base.Options.Mode == HttpListenerMode.Microsoft)
				{
					IHttpListener result;
					if (!System.Net.HttpListener.IsSupported)
					{
						IHttpListener httpListener2 = new EmbedIO.Net.HttpListener(base.Options.Certificate);
						result = httpListener2;
					}
					else
					{
						IHttpListener httpListener2 = new SystemHttpListener(new System.Net.HttpListener());
						result = httpListener2;
					}
					return result;
				}
				return new EmbedIO.Net.HttpListener(base.Options.Certificate);
			}
		}
	}
	public abstract class WebServerBase<TOptions> : ConfiguredObject, IWebServer, IWebModuleContainer, IDisposable, IMimeTypeCustomizer, IMimeTypeProvider, IHttpContextHandler where TOptions : WebServerOptionsBase, new()
	{
		private readonly WebModuleCollection _modules;

		private readonly MimeTypeCustomizer _mimeTypeCustomizer = new MimeTypeCustomizer();

		private ExceptionHandlerCallback _onUnhandledException = ExceptionHandler.Default;

		private HttpExceptionHandlerCallback _onHttpException = HttpExceptionHandler.Default;

		private WebServerState _state;

		private ISessionManager? _sessionManager;

		public IComponentCollection<IWebModule> Modules => _modules;

		public TOptions Options { get; }

		public ExceptionHandlerCallback OnUnhandledException
		{
			get
			{
				return _onUnhandledException;
			}
			set
			{
				((ConfiguredObject)this).EnsureConfigurationNotLocked();
				_onUnhandledException = Validate.NotNull("value", value);
			}
		}

		public HttpExceptionHandlerCallback OnHttpException
		{
			get
			{
				return _onHttpException;
			}
			set
			{
				((ConfiguredObject)this).EnsureConfigurationNotLocked();
				_onHttpException = Validate.NotNull("value", value);
			}
		}

		public ISessionManager? SessionManager
		{
			get
			{
				return _sessionManager;
			}
			set
			{
				((ConfiguredObject)this).EnsureConfigurationNotLocked();
				_sessionManager = value;
			}
		}

		public WebServerState State
		{
			get
			{
				return _state;
			}
			private set
			{
				if (value != _state)
				{
					WebServerState state = _state;
					_state = value;
					if (_state != 0)
					{
						((ConfiguredObject)this).LockConfiguration();
					}
					this.StateChanged?.Invoke(this, new WebServerStateChangedEventArgs(state, value));
				}
			}
		}

		protected string LogSource { get; }

		public event WebServerStateChangedEventHandler? StateChanged;

		protected WebServerBase()
			: this(new TOptions(), (Action<TOptions>?)null)
		{
		}

		protected WebServerBase(TOptions