Decompiled source of Vs Twitch v1.0.14

lib/Microsoft.Extensions.Logging.Abstractions.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Abstractions.Internal;
using Microsoft.Extensions.Logging.Internal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("Microsoft.Extensions.Logging.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("CommitHash", "9bc79b2f25a3724376d7af19617c33749a30ea3a")]
[assembly: AssemblyMetadata("SourceCommitUrl", "https://github.com/aspnet/Extensions/tree/9bc79b2f25a3724376d7af19617c33749a30ea3a")]
[assembly: AssemblyMetadata("BuildNumber", "181110-01")]
[assembly: AssemblyCompany("Microsoft Corporation.")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyDescription("Logging abstractions for Microsoft.Extensions.Logging.\r\nCommonly used types:\r\nMicrosoft.Extensions.Logging.ILogger\r\nMicrosoft.Extensions.Logging.ILoggerFactory\r\nMicrosoft.Extensions.Logging.ILogger<TCategoryName>\r\nMicrosoft.Extensions.Logging.LogLevel\r\nMicrosoft.Extensions.Logging.Logger<T>\r\nMicrosoft.Extensions.Logging.LoggerMessage\r\nMicrosoft.Extensions.Logging.Abstractions.NullLogger")]
[assembly: AssemblyFileVersion("2.2.0.18315")]
[assembly: AssemblyInformationalVersion("2.2.0-rtm-181110-01+pb-20181110-02")]
[assembly: AssemblyProduct("Microsoft .NET Extensions")]
[assembly: AssemblyTitle("Microsoft.Extensions.Logging.Abstractions")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("2.2.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
	{
	}
}
namespace Microsoft.Extensions.Logging
{
	public readonly struct EventId
	{
		public int Id { get; }

		public string Name { get; }

		public static implicit operator EventId(int i)
		{
			return new EventId(i);
		}

		public static bool operator ==(EventId left, EventId right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(EventId left, EventId right)
		{
			return !left.Equals(right);
		}

		public EventId(int id, string name = null)
		{
			Id = id;
			Name = name;
		}

		public override string ToString()
		{
			return Name ?? Id.ToString();
		}

		public bool Equals(EventId other)
		{
			return Id == other.Id;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is EventId other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return Id;
		}
	}
	public interface IExternalScopeProvider
	{
		void ForEachScope<TState>(Action<object, TState> callback, TState state);

		IDisposable Push(object state);
	}
	public interface ILogger
	{
		void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter);

		bool IsEnabled(LogLevel logLevel);

		IDisposable BeginScope<TState>(TState state);
	}
	public interface ILoggerFactory : IDisposable
	{
		ILogger CreateLogger(string categoryName);

		void AddProvider(ILoggerProvider provider);
	}
	public interface ILogger<out TCategoryName> : ILogger
	{
	}
	public interface ILoggerProvider : IDisposable
	{
		ILogger CreateLogger(string categoryName);
	}
	public interface ISupportExternalScope
	{
		void SetScopeProvider(IExternalScopeProvider scopeProvider);
	}
	public static class LoggerExtensions
	{
		private static readonly Func<object, Exception, string> _messageFormatter = MessageFormatter;

		public static void LogDebug(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Debug, eventId, exception, message, args);
		}

		public static void LogDebug(this ILogger logger, EventId eventId, string message, params object[] args)
		{
			logger.Log(LogLevel.Debug, eventId, message, args);
		}

		public static void LogDebug(this ILogger logger, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Debug, exception, message, args);
		}

		public static void LogDebug(this ILogger logger, string message, params object[] args)
		{
			logger.Log(LogLevel.Debug, message, args);
		}

		public static void LogTrace(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Trace, eventId, exception, message, args);
		}

		public static void LogTrace(this ILogger logger, EventId eventId, string message, params object[] args)
		{
			logger.Log(LogLevel.Trace, eventId, message, args);
		}

		public static void LogTrace(this ILogger logger, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Trace, exception, message, args);
		}

		public static void LogTrace(this ILogger logger, string message, params object[] args)
		{
			logger.Log(LogLevel.Trace, message, args);
		}

		public static void LogInformation(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Information, eventId, exception, message, args);
		}

		public static void LogInformation(this ILogger logger, EventId eventId, string message, params object[] args)
		{
			logger.Log(LogLevel.Information, eventId, message, args);
		}

		public static void LogInformation(this ILogger logger, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Information, exception, message, args);
		}

		public static void LogInformation(this ILogger logger, string message, params object[] args)
		{
			logger.Log(LogLevel.Information, message, args);
		}

		public static void LogWarning(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Warning, eventId, exception, message, args);
		}

		public static void LogWarning(this ILogger logger, EventId eventId, string message, params object[] args)
		{
			logger.Log(LogLevel.Warning, eventId, message, args);
		}

		public static void LogWarning(this ILogger logger, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Warning, exception, message, args);
		}

		public static void LogWarning(this ILogger logger, string message, params object[] args)
		{
			logger.Log(LogLevel.Warning, message, args);
		}

		public static void LogError(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Error, eventId, exception, message, args);
		}

		public static void LogError(this ILogger logger, EventId eventId, string message, params object[] args)
		{
			logger.Log(LogLevel.Error, eventId, message, args);
		}

		public static void LogError(this ILogger logger, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Error, exception, message, args);
		}

		public static void LogError(this ILogger logger, string message, params object[] args)
		{
			logger.Log(LogLevel.Error, message, args);
		}

		public static void LogCritical(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Critical, eventId, exception, message, args);
		}

		public static void LogCritical(this ILogger logger, EventId eventId, string message, params object[] args)
		{
			logger.Log(LogLevel.Critical, eventId, message, args);
		}

		public static void LogCritical(this ILogger logger, Exception exception, string message, params object[] args)
		{
			logger.Log(LogLevel.Critical, exception, message, args);
		}

		public static void LogCritical(this ILogger logger, string message, params object[] args)
		{
			logger.Log(LogLevel.Critical, message, args);
		}

		public static void Log(this ILogger logger, LogLevel logLevel, string message, params object[] args)
		{
			logger.Log(logLevel, 0, null, message, args);
		}

		public static void Log(this ILogger logger, LogLevel logLevel, EventId eventId, string message, params object[] args)
		{
			logger.Log(logLevel, eventId, null, message, args);
		}

		public static void Log(this ILogger logger, LogLevel logLevel, Exception exception, string message, params object[] args)
		{
			logger.Log(logLevel, 0, exception, message, args);
		}

		public static void Log(this ILogger logger, LogLevel logLevel, EventId eventId, Exception exception, string message, params object[] args)
		{
			if (logger == null)
			{
				throw new ArgumentNullException("logger");
			}
			logger.Log(logLevel, eventId, new FormattedLogValues(message, args), exception, _messageFormatter);
		}

		public static IDisposable BeginScope(this ILogger logger, string messageFormat, params object[] args)
		{
			if (logger == null)
			{
				throw new ArgumentNullException("logger");
			}
			return logger.BeginScope(new FormattedLogValues(messageFormat, args));
		}

		private static string MessageFormatter(object state, Exception error)
		{
			return state.ToString();
		}
	}
	public class LoggerExternalScopeProvider : IExternalScopeProvider
	{
		private class Scope : IDisposable
		{
			private readonly LoggerExternalScopeProvider _provider;

			private bool _isDisposed;

			public Scope Parent { get; }

			public object State { get; }

			internal Scope(LoggerExternalScopeProvider provider, object state, Scope parent)
			{
				_provider = provider;
				State = state;
				Parent = parent;
			}

			public override string ToString()
			{
				return State?.ToString();
			}

			public void Dispose()
			{
				if (!_isDisposed)
				{
					_provider._currentScope.Value = Parent;
					_isDisposed = true;
				}
			}
		}

		private readonly AsyncLocal<Scope> _currentScope = new AsyncLocal<Scope>();

		public void ForEachScope<TState>(Action<object, TState> callback, TState state)
		{
			Report(_currentScope.Value);
			void Report(Scope current)
			{
				if (current != null)
				{
					Report(current.Parent);
					callback(current.State, state);
				}
			}
		}

		public IDisposable Push(object state)
		{
			Scope value = _currentScope.Value;
			Scope scope = new Scope(this, state, value);
			_currentScope.Value = scope;
			return scope;
		}
	}
	public static class LoggerFactoryExtensions
	{
		public static ILogger<T> CreateLogger<T>(this ILoggerFactory factory)
		{
			if (factory == null)
			{
				throw new ArgumentNullException("factory");
			}
			return new Logger<T>(factory);
		}

		public static ILogger CreateLogger(this ILoggerFactory factory, Type type)
		{
			if (factory == null)
			{
				throw new ArgumentNullException("factory");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			return factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(type));
		}
	}
	public static class LoggerMessage
	{
		private class LogValues : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues)state)._formatter.Format(((LogValues)state).ToArray());

			private static object[] _valueArray = new object[0];

			private readonly LogValuesFormatter _formatter;

			public KeyValuePair<string, object> this[int index]
			{
				get
				{
					if (index == 0)
					{
						return new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat);
					}
					throw new IndexOutOfRangeException("index");
				}
			}

			public int Count => 1;

			public LogValues(LogValuesFormatter formatter)
			{
				_formatter = formatter;
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				yield return this[0];
			}

			public object[] ToArray()
			{
				return _valueArray;
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

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

		private class LogValues<T0> : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues<T0>)state)._formatter.Format(((LogValues<T0>)state).ToArray());

			private readonly LogValuesFormatter _formatter;

			private readonly T0 _value0;

			public KeyValuePair<string, object> this[int index] => index switch
			{
				0 => new KeyValuePair<string, object>(_formatter.ValueNames[0], _value0), 
				1 => new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat), 
				_ => throw new IndexOutOfRangeException("index"), 
			};

			public int Count => 2;

			public LogValues(LogValuesFormatter formatter, T0 value0)
			{
				_formatter = formatter;
				_value0 = value0;
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				int i = 0;
				while (i < Count)
				{
					yield return this[i];
					int num = i + 1;
					i = num;
				}
			}

			public object[] ToArray()
			{
				return new object[1] { _value0 };
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

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

		private class LogValues<T0, T1> : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues<T0, T1>)state)._formatter.Format(((LogValues<T0, T1>)state).ToArray());

			private readonly LogValuesFormatter _formatter;

			private readonly T0 _value0;

			private readonly T1 _value1;

			public KeyValuePair<string, object> this[int index] => index switch
			{
				0 => new KeyValuePair<string, object>(_formatter.ValueNames[0], _value0), 
				1 => new KeyValuePair<string, object>(_formatter.ValueNames[1], _value1), 
				2 => new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat), 
				_ => throw new IndexOutOfRangeException("index"), 
			};

			public int Count => 3;

			public LogValues(LogValuesFormatter formatter, T0 value0, T1 value1)
			{
				_formatter = formatter;
				_value0 = value0;
				_value1 = value1;
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				int i = 0;
				while (i < Count)
				{
					yield return this[i];
					int num = i + 1;
					i = num;
				}
			}

			public object[] ToArray()
			{
				return new object[2] { _value0, _value1 };
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

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

		private class LogValues<T0, T1, T2> : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues<T0, T1, T2>)state)._formatter.Format(((LogValues<T0, T1, T2>)state).ToArray());

			private readonly LogValuesFormatter _formatter;

			public T0 _value0;

			public T1 _value1;

			public T2 _value2;

			public int Count => 4;

			public KeyValuePair<string, object> this[int index] => index switch
			{
				0 => new KeyValuePair<string, object>(_formatter.ValueNames[0], _value0), 
				1 => new KeyValuePair<string, object>(_formatter.ValueNames[1], _value1), 
				2 => new KeyValuePair<string, object>(_formatter.ValueNames[2], _value2), 
				3 => new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat), 
				_ => throw new IndexOutOfRangeException("index"), 
			};

			public LogValues(LogValuesFormatter formatter, T0 value0, T1 value1, T2 value2)
			{
				_formatter = formatter;
				_value0 = value0;
				_value1 = value1;
				_value2 = value2;
			}

			public object[] ToArray()
			{
				return new object[3] { _value0, _value1, _value2 };
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				int i = 0;
				while (i < Count)
				{
					yield return this[i];
					int num = i + 1;
					i = num;
				}
			}

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

		private class LogValues<T0, T1, T2, T3> : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues<T0, T1, T2, T3>)state)._formatter.Format(((LogValues<T0, T1, T2, T3>)state).ToArray());

			private readonly LogValuesFormatter _formatter;

			public T0 _value0;

			public T1 _value1;

			public T2 _value2;

			public T3 _value3;

			public int Count => 5;

			public KeyValuePair<string, object> this[int index] => index switch
			{
				0 => new KeyValuePair<string, object>(_formatter.ValueNames[0], _value0), 
				1 => new KeyValuePair<string, object>(_formatter.ValueNames[1], _value1), 
				2 => new KeyValuePair<string, object>(_formatter.ValueNames[2], _value2), 
				3 => new KeyValuePair<string, object>(_formatter.ValueNames[3], _value3), 
				4 => new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat), 
				_ => throw new IndexOutOfRangeException("index"), 
			};

			public LogValues(LogValuesFormatter formatter, T0 value0, T1 value1, T2 value2, T3 value3)
			{
				_formatter = formatter;
				_value0 = value0;
				_value1 = value1;
				_value2 = value2;
				_value3 = value3;
			}

			public object[] ToArray()
			{
				return new object[4] { _value0, _value1, _value2, _value3 };
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				int i = 0;
				while (i < Count)
				{
					yield return this[i];
					int num = i + 1;
					i = num;
				}
			}

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

		private class LogValues<T0, T1, T2, T3, T4> : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues<T0, T1, T2, T3, T4>)state)._formatter.Format(((LogValues<T0, T1, T2, T3, T4>)state).ToArray());

			private readonly LogValuesFormatter _formatter;

			public T0 _value0;

			public T1 _value1;

			public T2 _value2;

			public T3 _value3;

			public T4 _value4;

			public int Count => 6;

			public KeyValuePair<string, object> this[int index] => index switch
			{
				0 => new KeyValuePair<string, object>(_formatter.ValueNames[0], _value0), 
				1 => new KeyValuePair<string, object>(_formatter.ValueNames[1], _value1), 
				2 => new KeyValuePair<string, object>(_formatter.ValueNames[2], _value2), 
				3 => new KeyValuePair<string, object>(_formatter.ValueNames[3], _value3), 
				4 => new KeyValuePair<string, object>(_formatter.ValueNames[4], _value4), 
				5 => new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat), 
				_ => throw new IndexOutOfRangeException("index"), 
			};

			public LogValues(LogValuesFormatter formatter, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4)
			{
				_formatter = formatter;
				_value0 = value0;
				_value1 = value1;
				_value2 = value2;
				_value3 = value3;
				_value4 = value4;
			}

			public object[] ToArray()
			{
				return new object[5] { _value0, _value1, _value2, _value3, _value4 };
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				int i = 0;
				while (i < Count)
				{
					yield return this[i];
					int num = i + 1;
					i = num;
				}
			}

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

		private class LogValues<T0, T1, T2, T3, T4, T5> : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues<T0, T1, T2, T3, T4, T5>)state)._formatter.Format(((LogValues<T0, T1, T2, T3, T4, T5>)state).ToArray());

			private readonly LogValuesFormatter _formatter;

			public T0 _value0;

			public T1 _value1;

			public T2 _value2;

			public T3 _value3;

			public T4 _value4;

			public T5 _value5;

			public int Count => 7;

			public KeyValuePair<string, object> this[int index] => index switch
			{
				0 => new KeyValuePair<string, object>(_formatter.ValueNames[0], _value0), 
				1 => new KeyValuePair<string, object>(_formatter.ValueNames[1], _value1), 
				2 => new KeyValuePair<string, object>(_formatter.ValueNames[2], _value2), 
				3 => new KeyValuePair<string, object>(_formatter.ValueNames[3], _value3), 
				4 => new KeyValuePair<string, object>(_formatter.ValueNames[4], _value4), 
				5 => new KeyValuePair<string, object>(_formatter.ValueNames[5], _value5), 
				6 => new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat), 
				_ => throw new IndexOutOfRangeException("index"), 
			};

			public LogValues(LogValuesFormatter formatter, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5)
			{
				_formatter = formatter;
				_value0 = value0;
				_value1 = value1;
				_value2 = value2;
				_value3 = value3;
				_value4 = value4;
				_value5 = value5;
			}

			public object[] ToArray()
			{
				return new object[6] { _value0, _value1, _value2, _value3, _value4, _value5 };
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				int i = 0;
				while (i < Count)
				{
					yield return this[i];
					int num = i + 1;
					i = num;
				}
			}

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

		private class LogValues<T0, T1, T2, T3, T4, T5, T6> : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
		{
			public static Func<object, Exception, string> Callback = (object state, Exception exception) => ((LogValues<T0, T1, T2, T3, T4, T5, T6>)state)._formatter.Format(((LogValues<T0, T1, T2, T3, T4, T5, T6>)state).ToArray());

			private readonly LogValuesFormatter _formatter;

			public T0 _value0;

			public T1 _value1;

			public T2 _value2;

			public T3 _value3;

			public T4 _value4;

			public T5 _value5;

			public T6 _value6;

			public int Count => 8;

			public KeyValuePair<string, object> this[int index] => index switch
			{
				0 => new KeyValuePair<string, object>(_formatter.ValueNames[0], _value0), 
				1 => new KeyValuePair<string, object>(_formatter.ValueNames[1], _value1), 
				2 => new KeyValuePair<string, object>(_formatter.ValueNames[2], _value2), 
				3 => new KeyValuePair<string, object>(_formatter.ValueNames[3], _value3), 
				4 => new KeyValuePair<string, object>(_formatter.ValueNames[4], _value4), 
				5 => new KeyValuePair<string, object>(_formatter.ValueNames[5], _value5), 
				6 => new KeyValuePair<string, object>(_formatter.ValueNames[6], _value6), 
				7 => new KeyValuePair<string, object>("{OriginalFormat}", _formatter.OriginalFormat), 
				_ => throw new IndexOutOfRangeException("index"), 
			};

			public LogValues(LogValuesFormatter formatter, T0 value0, T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6)
			{
				_formatter = formatter;
				_value0 = value0;
				_value1 = value1;
				_value2 = value2;
				_value3 = value3;
				_value4 = value4;
				_value5 = value5;
				_value6 = value6;
			}

			public object[] ToArray()
			{
				return new object[7] { _value0, _value1, _value2, _value3, _value4, _value5, _value6 };
			}

			public override string ToString()
			{
				return _formatter.Format(ToArray());
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				int i = 0;
				while (i < Count)
				{
					yield return this[i];
					int num = i + 1;
					i = num;
				}
			}

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

		public static Func<ILogger, IDisposable> DefineScope(string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 0);
			LogValues logValues = new LogValues(formatter);
			return (ILogger logger) => logger.BeginScope(logValues);
		}

		public static Func<ILogger, T1, IDisposable> DefineScope<T1>(string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 1);
			return (ILogger logger, T1 arg1) => logger.BeginScope(new LogValues<T1>(formatter, arg1));
		}

		public static Func<ILogger, T1, T2, IDisposable> DefineScope<T1, T2>(string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 2);
			return (ILogger logger, T1 arg1, T2 arg2) => logger.BeginScope(new LogValues<T1, T2>(formatter, arg1, arg2));
		}

		public static Func<ILogger, T1, T2, T3, IDisposable> DefineScope<T1, T2, T3>(string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 3);
			return (ILogger logger, T1 arg1, T2 arg2, T3 arg3) => logger.BeginScope(new LogValues<T1, T2, T3>(formatter, arg1, arg2, arg3));
		}

		public static Action<ILogger, Exception> Define(LogLevel logLevel, EventId eventId, string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 0);
			return delegate(ILogger logger, Exception exception)
			{
				if (logger.IsEnabled(logLevel))
				{
					logger.Log(logLevel, eventId, new LogValues(formatter), exception, LogValues.Callback);
				}
			};
		}

		public static Action<ILogger, T1, Exception> Define<T1>(LogLevel logLevel, EventId eventId, string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 1);
			return delegate(ILogger logger, T1 arg1, Exception exception)
			{
				if (logger.IsEnabled(logLevel))
				{
					logger.Log(logLevel, eventId, new LogValues<T1>(formatter, arg1), exception, LogValues<T1>.Callback);
				}
			};
		}

		public static Action<ILogger, T1, T2, Exception> Define<T1, T2>(LogLevel logLevel, EventId eventId, string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 2);
			return delegate(ILogger logger, T1 arg1, T2 arg2, Exception exception)
			{
				if (logger.IsEnabled(logLevel))
				{
					logger.Log(logLevel, eventId, new LogValues<T1, T2>(formatter, arg1, arg2), exception, LogValues<T1, T2>.Callback);
				}
			};
		}

		public static Action<ILogger, T1, T2, T3, Exception> Define<T1, T2, T3>(LogLevel logLevel, EventId eventId, string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 3);
			return delegate(ILogger logger, T1 arg1, T2 arg2, T3 arg3, Exception exception)
			{
				if (logger.IsEnabled(logLevel))
				{
					logger.Log(logLevel, eventId, new LogValues<T1, T2, T3>(formatter, arg1, arg2, arg3), exception, LogValues<T1, T2, T3>.Callback);
				}
			};
		}

		public static Action<ILogger, T1, T2, T3, T4, Exception> Define<T1, T2, T3, T4>(LogLevel logLevel, EventId eventId, string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 4);
			return delegate(ILogger logger, T1 arg1, T2 arg2, T3 arg3, T4 arg4, Exception exception)
			{
				if (logger.IsEnabled(logLevel))
				{
					logger.Log(logLevel, eventId, new LogValues<T1, T2, T3, T4>(formatter, arg1, arg2, arg3, arg4), exception, LogValues<T1, T2, T3, T4>.Callback);
				}
			};
		}

		public static Action<ILogger, T1, T2, T3, T4, T5, Exception> Define<T1, T2, T3, T4, T5>(LogLevel logLevel, EventId eventId, string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 5);
			return delegate(ILogger logger, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, Exception exception)
			{
				if (logger.IsEnabled(logLevel))
				{
					logger.Log(logLevel, eventId, new LogValues<T1, T2, T3, T4, T5>(formatter, arg1, arg2, arg3, arg4, arg5), exception, LogValues<T1, T2, T3, T4, T5>.Callback);
				}
			};
		}

		public static Action<ILogger, T1, T2, T3, T4, T5, T6, Exception> Define<T1, T2, T3, T4, T5, T6>(LogLevel logLevel, EventId eventId, string formatString)
		{
			LogValuesFormatter formatter = CreateLogValuesFormatter(formatString, 6);
			return delegate(ILogger logger, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, Exception exception)
			{
				if (logger.IsEnabled(logLevel))
				{
					logger.Log(logLevel, eventId, new LogValues<T1, T2, T3, T4, T5, T6>(formatter, arg1, arg2, arg3, arg4, arg5, arg6), exception, LogValues<T1, T2, T3, T4, T5, T6>.Callback);
				}
			};
		}

		private static LogValuesFormatter CreateLogValuesFormatter(string formatString, int expectedNamedParameterCount)
		{
			LogValuesFormatter logValuesFormatter = new LogValuesFormatter(formatString);
			int count = logValuesFormatter.ValueNames.Count;
			if (count != expectedNamedParameterCount)
			{
				throw new ArgumentException(Resource.FormatUnexpectedNumberOfNamedParameters(formatString, expectedNamedParameterCount, count));
			}
			return logValuesFormatter;
		}
	}
	public class Logger<T> : ILogger<T>, ILogger
	{
		private readonly ILogger _logger;

		public Logger(ILoggerFactory factory)
		{
			if (factory == null)
			{
				throw new ArgumentNullException("factory");
			}
			_logger = factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(typeof(T)));
		}

		IDisposable ILogger.BeginScope<TState>(TState state)
		{
			return _logger.BeginScope(state);
		}

		bool ILogger.IsEnabled(LogLevel logLevel)
		{
			return _logger.IsEnabled(logLevel);
		}

		void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
		{
			_logger.Log(logLevel, eventId, state, exception, formatter);
		}
	}
	public enum LogLevel
	{
		Trace,
		Debug,
		Information,
		Warning,
		Error,
		Critical,
		None
	}
}
namespace Microsoft.Extensions.Logging.Abstractions
{
	public class NullLogger : ILogger
	{
		public static NullLogger Instance { get; } = new NullLogger();


		private NullLogger()
		{
		}

		public IDisposable BeginScope<TState>(TState state)
		{
			return NullScope.Instance;
		}

		public bool IsEnabled(LogLevel logLevel)
		{
			return false;
		}

		public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
		{
		}
	}
	public class NullLoggerFactory : ILoggerFactory, IDisposable
	{
		public static readonly NullLoggerFactory Instance = new NullLoggerFactory();

		public ILogger CreateLogger(string name)
		{
			return NullLogger.Instance;
		}

		public void AddProvider(ILoggerProvider provider)
		{
		}

		public void Dispose()
		{
		}
	}
	public class NullLogger<T> : ILogger<T>, ILogger
	{
		private class NullDisposable : IDisposable
		{
			public static readonly NullDisposable Instance = new NullDisposable();

			public void Dispose()
			{
			}
		}

		public static readonly NullLogger<T> Instance = new NullLogger<T>();

		public IDisposable BeginScope<TState>(TState state)
		{
			return NullDisposable.Instance;
		}

		public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
		{
		}

		public bool IsEnabled(LogLevel logLevel)
		{
			return false;
		}
	}
	public class NullLoggerProvider : ILoggerProvider, IDisposable
	{
		public static NullLoggerProvider Instance { get; } = new NullLoggerProvider();


		private NullLoggerProvider()
		{
		}

		public ILogger CreateLogger(string categoryName)
		{
			return NullLogger.Instance;
		}

		public void Dispose()
		{
		}
	}
	internal static class Resource
	{
		private static readonly ResourceManager _resourceManager = new ResourceManager("Microsoft.Extensions.Logging.Abstractions.Resource", typeof(Resource).GetTypeInfo().Assembly);

		internal static string UnexpectedNumberOfNamedParameters => GetString("UnexpectedNumberOfNamedParameters");

		internal static string FormatUnexpectedNumberOfNamedParameters(object p0, object p1, object p2)
		{
			return string.Format(CultureInfo.CurrentCulture, GetString("UnexpectedNumberOfNamedParameters"), p0, p1, p2);
		}

		private static string GetString(string name, params string[] formatterNames)
		{
			string text = _resourceManager.GetString(name);
			if (formatterNames != null)
			{
				for (int i = 0; i < formatterNames.Length; i++)
				{
					text = text.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
				}
			}
			return text;
		}
	}
}
namespace Microsoft.Extensions.Logging.Abstractions.Internal
{
	public class NullScope : IDisposable
	{
		public static NullScope Instance { get; } = new NullScope();


		private NullScope()
		{
		}

		public void Dispose()
		{
		}
	}
	public class TypeNameHelper
	{
		private static readonly Dictionary<Type, string> _builtInTypeNames = new Dictionary<Type, string>
		{
			{
				typeof(bool),
				"bool"
			},
			{
				typeof(byte),
				"byte"
			},
			{
				typeof(char),
				"char"
			},
			{
				typeof(decimal),
				"decimal"
			},
			{
				typeof(double),
				"double"
			},
			{
				typeof(float),
				"float"
			},
			{
				typeof(int),
				"int"
			},
			{
				typeof(long),
				"long"
			},
			{
				typeof(object),
				"object"
			},
			{
				typeof(sbyte),
				"sbyte"
			},
			{
				typeof(short),
				"short"
			},
			{
				typeof(string),
				"string"
			},
			{
				typeof(uint),
				"uint"
			},
			{
				typeof(ulong),
				"ulong"
			},
			{
				typeof(ushort),
				"ushort"
			}
		};

		public static string GetTypeDisplayName(Type type)
		{
			if (type.GetTypeInfo().IsGenericType)
			{
				string[] array = type.GetGenericTypeDefinition().FullName.Split(new char[1] { '+' });
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i];
					int num = text.IndexOf('`');
					if (num >= 0)
					{
						text = text.Substring(0, num);
					}
					array[i] = text;
				}
				return string.Join(".", array);
			}
			if (_builtInTypeNames.ContainsKey(type))
			{
				return _builtInTypeNames[type];
			}
			string text2 = type.FullName;
			if (type.IsNested)
			{
				text2 = text2.Replace('+', '.');
			}
			return text2;
		}
	}
}
namespace Microsoft.Extensions.Logging.Internal
{
	public class FormattedLogValues : IReadOnlyList<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, object>>
	{
		internal const int MaxCachedFormatters = 1024;

		private const string NullFormat = "[null]";

		private static int _count;

		private static ConcurrentDictionary<string, LogValuesFormatter> _formatters = new ConcurrentDictionary<string, LogValuesFormatter>();

		private readonly LogValuesFormatter _formatter;

		private readonly object[] _values;

		private readonly string _originalMessage;

		internal LogValuesFormatter Formatter => _formatter;

		public KeyValuePair<string, object> this[int index]
		{
			get
			{
				if (index < 0 || index >= Count)
				{
					throw new IndexOutOfRangeException("index");
				}
				if (index == Count - 1)
				{
					return new KeyValuePair<string, object>("{OriginalFormat}", _originalMessage);
				}
				return _formatter.GetValue(_values, index);
			}
		}

		public int Count
		{
			get
			{
				if (_formatter == null)
				{
					return 1;
				}
				return _formatter.ValueNames.Count + 1;
			}
		}

		public FormattedLogValues(string format, params object[] values)
		{
			if ((values == null || values.Length != 0) && format != null)
			{
				if (_count >= 1024)
				{
					if (!_formatters.TryGetValue(format, out _formatter))
					{
						_formatter = new LogValuesFormatter(format);
					}
				}
				else
				{
					_formatter = _formatters.GetOrAdd(format, delegate(string f)
					{
						Interlocked.Increment(ref _count);
						return new LogValuesFormatter(f);
					});
				}
			}
			_originalMessage = format ?? "[null]";
			_values = values;
		}

		public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
		{
			int i = 0;
			while (i < Count)
			{
				yield return this[i];
				int num = i + 1;
				i = num;
			}
		}

		public override string ToString()
		{
			if (_formatter == null)
			{
				return _originalMessage;
			}
			return _formatter.Format(_values);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	public class LogValuesFormatter
	{
		private const string NullValue = "(null)";

		private static readonly object[] EmptyArray = new object[0];

		private static readonly char[] FormatDelimiters = new char[2] { ',', ':' };

		private readonly string _format;

		private readonly List<string> _valueNames = new List<string>();

		public string OriginalFormat { get; private set; }

		public List<string> ValueNames => _valueNames;

		public LogValuesFormatter(string format)
		{
			OriginalFormat = format;
			StringBuilder stringBuilder = new StringBuilder();
			int num = 0;
			int length = format.Length;
			while (num < length)
			{
				int num2 = FindBraceIndex(format, '{', num, length);
				int num3 = FindBraceIndex(format, '}', num2, length);
				int num4 = FindIndexOfAny(format, FormatDelimiters, num2, num3);
				if (num3 == length)
				{
					stringBuilder.Append(format, num, length - num);
					num = length;
					continue;
				}
				stringBuilder.Append(format, num, num2 - num + 1);
				stringBuilder.Append(_valueNames.Count.ToString(CultureInfo.InvariantCulture));
				_valueNames.Add(format.Substring(num2 + 1, num4 - num2 - 1));
				stringBuilder.Append(format, num4, num3 - num4 + 1);
				num = num3 + 1;
			}
			_format = stringBuilder.ToString();
		}

		private static int FindBraceIndex(string format, char brace, int startIndex, int endIndex)
		{
			int result = endIndex;
			int i = startIndex;
			int num = 0;
			for (; i < endIndex; i++)
			{
				if (num > 0 && format[i] != brace)
				{
					if (num % 2 != 0)
					{
						break;
					}
					num = 0;
					result = endIndex;
				}
				else
				{
					if (format[i] != brace)
					{
						continue;
					}
					if (brace == '}')
					{
						if (num == 0)
						{
							result = i;
						}
					}
					else
					{
						result = i;
					}
					num++;
				}
			}
			return result;
		}

		private static int FindIndexOfAny(string format, char[] chars, int startIndex, int endIndex)
		{
			int num = format.IndexOfAny(chars, startIndex, endIndex - startIndex);
			if (num != -1)
			{
				return num;
			}
			return endIndex;
		}

		public string Format(object[] values)
		{
			if (values != null)
			{
				for (int i = 0; i < values.Length; i++)
				{
					object obj = values[i];
					if (obj == null)
					{
						values[i] = "(null)";
					}
					else if (!(obj is string) && obj is IEnumerable source)
					{
						values[i] = string.Join(", ", from object o in source
							select o ?? "(null)");
					}
				}
			}
			return string.Format(CultureInfo.InvariantCulture, _format, values ?? EmptyArray);
		}

		public KeyValuePair<string, object> GetValue(object[] values, int index)
		{
			if (index < 0 || index > _valueNames.Count)
			{
				throw new IndexOutOfRangeException("index");
			}
			if (_valueNames.Count > index)
			{
				return new KeyValuePair<string, object>(_valueNames[index], values[index]);
			}
			return new KeyValuePair<string, object>("{OriginalFormat}", OriginalFormat);
		}

		public IEnumerable<KeyValuePair<string, object>> GetValues(object[] values)
		{
			KeyValuePair<string, object>[] array = new KeyValuePair<string, object>[values.Length + 1];
			for (int i = 0; i != _valueNames.Count; i++)
			{
				array[i] = new KeyValuePair<string, object>(_valueNames[i], values[i]);
			}
			array[^1] = new KeyValuePair<string, object>("{OriginalFormat}", OriginalFormat);
			return array;
		}
	}
}

lib/Newtonsoft.Json.dll

Decompiled 5 months 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.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.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: AssemblyDelaySign(true)]
[assembly: AssemblyKeyFile("../IdentityPublicKey.snk")]
[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(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[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("12.0.301")]
[assembly: AssemblyInformationalVersion("12.0.301")]
[assembly: AssemblyProduct("Json.NET")]
[assembly: AssemblyTitle("Json.NET for Unity AOT (IL2CPP)")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("12.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.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
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 = num & _mask;
			for (Entry entry = _entries[num3]; 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;
			_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) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1 || text.IndexOf('e') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		private static string EnsureDecimalPlace(string text)
		{
			if (text.IndexOf('.') != -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]
		[return: MaybeNull]
		public static T DeserializeObject<T>(string value, params JsonConverter[] converters)
		{
			return (T)DeserializeObject(value, typeof(T), converters);
		}

		[DebuggerStepThrough]
		[return: MaybeNull]
		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)
		{
			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, [AllowNull] 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, [AllowNull] 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;
			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]
		[return: MaybeNull]
		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;
		}

		private 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 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.GetValueOrDefault();
			}
			set
			{
				_preserveReferencesHandling = value;
			}
		}

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

		public MetadataPropertyHandling MetadataPropertyHandling
		{
		

lib/Tiltify-Client.dll

Decompiled 5 months ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Tiltify.Events;
using Tiltify.Exceptions;
using Tiltify.Models;
using Tiltify.RateLimiter;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Tiltify-Client")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Tiltify-Client")]
[assembly: AssemblyTitle("Tiltify-Client")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Tiltify
{
	public class ApiBase
	{
		internal const string BaseTiltifyAPI = "https://tiltify.com/api";

		private readonly ApiSettings settings;

		private readonly IRateLimiter rateLimiter;

		private readonly IHttpCallHandler http;

		private readonly JsonSerializerSettings jsonDeserializer = new JsonSerializerSettings
		{
			NullValueHandling = (NullValueHandling)1,
			MissingMemberHandling = (MissingMemberHandling)0
		};

		public ApiBase(ApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			this.settings = settings;
			this.rateLimiter = rateLimiter;
			this.http = http;
		}

		protected async Task<string> TiltifyGetAsync(string resource, ApiVersion api, List<KeyValuePair<string, string>> getParams = null, string customBase = null)
		{
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			string accessToken = settings.OAuthToken;
			return await rateLimiter.Perform(async () => (await http.GeneralRequestAsync(url, "GET", null, api, accessToken).ConfigureAwait(continueOnCapturedContext: false)).Value).ConfigureAwait(continueOnCapturedContext: false);
		}

		protected async Task<T> TiltifyGetGenericAsync<T>(string resource, ApiVersion api, List<KeyValuePair<string, string>> getParams = null, string customBase = null)
		{
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			string accessToken = settings.OAuthToken;
			return await rateLimiter.Perform(async () => JsonConvert.DeserializeObject<T>((await http.GeneralRequestAsync(url, "GET", null, api, accessToken).ConfigureAwait(continueOnCapturedContext: false)).Value, jsonDeserializer)).ConfigureAwait(continueOnCapturedContext: false);
		}

		private string ConstructResourceUrl(string resource = null, List<KeyValuePair<string, string>> getParams = null, ApiVersion api = ApiVersion.V3, string overrideUrl = null)
		{
			string text = "";
			if (overrideUrl == null)
			{
				if (resource == null)
				{
					throw new Exception("Cannot pass null resource with null override url");
				}
				if (api == ApiVersion.V3)
				{
					text = "https://tiltify.com/api/v3" + resource;
				}
			}
			else
			{
				text = ((resource == null) ? overrideUrl : (overrideUrl + resource));
			}
			if (getParams != null)
			{
				for (int i = 0; i < getParams.Count; i++)
				{
					text = ((i != 0) ? (text + "&" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)) : (text + "?" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)));
				}
			}
			return text;
		}
	}
	public class ApiSettings
	{
		public string OAuthToken { get; set; }
	}
	public enum ApiVersion
	{
		V3 = 3
	}
	public class Campaigns : ApiBase
	{
		public Campaigns(ApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
			: base(settings, rateLimiter, http)
		{
		}

		public Task<GetCampaignDonationsResponse> GetCampaignDonations(int campaignId)
		{
			return TiltifyGetGenericAsync<GetCampaignDonationsResponse>($"/campaigns/{campaignId}/donations", ApiVersion.V3);
		}
	}
	public interface IHttpCallHandler
	{
		Task<KeyValuePair<int, string>> GeneralRequestAsync(string url, string method, string payload = null, ApiVersion api = ApiVersion.V3, string accessToken = null);

		Task PutBytesAsync(string url, byte[] payload);

		Task<int> RequestReturnResponseCodeAsync(string url, string method, List<KeyValuePair<string, string>> getParams = null);
	}
	public interface IRateLimiter
	{
		Task Perform(Func<Task> perform, CancellationToken cancellationToken);

		Task Perform(Func<Task> perform);

		Task<T> Perform<T>(Func<Task<T>> perform);

		Task<T> Perform<T>(Func<Task<T>> perform, CancellationToken cancellationToken);

		Task Perform(Action perform, CancellationToken cancellationToken);

		Task Perform(Action perform);

		Task<T> Perform<T>(Func<T> perform);

		Task<T> Perform<T>(Func<T> perform, CancellationToken cancellationToken);
	}
	internal class Throttlers
	{
		public readonly BlockingCollection<Tuple<DateTime, string>> SendQueue = new BlockingCollection<Tuple<DateTime, string>>();

		public bool ResetThrottlerRunning;

		public int SentCount = 0;

		public Task ResetThrottler;

		private readonly TimeSpan _throttlingPeriod;

		private readonly WebSocketClient _client;

		public bool Reconnecting { get; set; } = false;


		public bool ShouldDispose { get; set; } = false;


		public CancellationTokenSource TokenSource { get; set; }

		public Throttlers(WebSocketClient client, TimeSpan throttlingPeriod)
		{
			_throttlingPeriod = throttlingPeriod;
			_client = client;
		}

		public void StartThrottlingWindowReset()
		{
			ResetThrottler = Task.Run(async delegate
			{
				ResetThrottlerRunning = true;
				while (!ShouldDispose && !Reconnecting)
				{
					Interlocked.Exchange(ref SentCount, 0);
					await Task.Delay(_throttlingPeriod, TokenSource.Token);
				}
				ResetThrottlerRunning = false;
				return Task.CompletedTask;
			});
		}

		public void IncrementSentCount()
		{
			Interlocked.Increment(ref SentCount);
		}

		public Task StartSenderTask()
		{
			StartThrottlingWindowReset();
			return Task.Run(async delegate
			{
				try
				{
					while (!ShouldDispose)
					{
						await Task.Delay(_client.Options.SendDelay);
						if (SentCount == _client.Options.MessagesAllowedInPeriod)
						{
							_client.MessageThrottled(new OnMessageThrottledEventArgs
							{
								Message = "Message Throttle Occured. Too Many Messages within the period specified in WebsocketClientOptions.",
								AllowedInPeriod = _client.Options.MessagesAllowedInPeriod,
								Period = _client.Options.ThrottlingPeriod,
								SentMessageCount = Interlocked.CompareExchange(ref SentCount, 0, 0)
							});
						}
						else if (_client.IsConnected && !ShouldDispose)
						{
							Tuple<DateTime, string> msg = SendQueue.Take(TokenSource.Token);
							if (!(msg.Item1.Add(_client.Options.SendCacheItemTimeout) < DateTime.UtcNow))
							{
								try
								{
									await _client.SendAsync(Encoding.UTF8.GetBytes(msg.Item2));
									IncrementSentCount();
								}
								catch (Exception ex3)
								{
									Exception ex2 = ex3;
									_client.SendFailed(new OnSendFailedEventArgs
									{
										Data = msg.Item2,
										Exception = ex2
									});
									break;
								}
							}
						}
					}
				}
				catch (OperationCanceledException)
				{
				}
				catch (Exception ex3)
				{
					Exception ex = ex3;
					_client.SendFailed(new OnSendFailedEventArgs
					{
						Data = "",
						Exception = ex
					});
					_client.Error(new OnErrorEventArgs
					{
						Exception = ex
					});
				}
			});
		}
	}
	public class Tiltify
	{
		private readonly ILogger<Tiltify> logger;

		public ApiSettings Settings { get; }

		public Campaigns Campaigns { get; }

		public Users Users { get; }

		public Tiltify(ILoggerFactory loggerFactory = null, IRateLimiter rateLimiter = null, ApiSettings settings = null, IHttpCallHandler http = null)
		{
			logger = loggerFactory?.CreateLogger<Tiltify>();
			rateLimiter = rateLimiter ?? BypassLimiter.CreateLimiterBypassInstance();
			http = http ?? new TiltifyhHttpClient(loggerFactory?.CreateLogger<TiltifyhHttpClient>());
			Settings = settings ?? new ApiSettings();
			Campaigns = new Campaigns(settings, rateLimiter, http);
			Users = new Users(settings, rateLimiter, http);
		}
	}
	public class TiltifyhHttpClient : IHttpCallHandler
	{
		private readonly ILogger<TiltifyhHttpClient> _logger;

		private readonly HttpClient _http;

		public TiltifyhHttpClient(ILogger<TiltifyhHttpClient> logger = null)
		{
			_logger = logger;
			_http = new HttpClient(new TiltifyHttpClientHandler(_logger));
		}

		public async Task PutBytesAsync(string url, byte[] payload)
		{
			HttpResponseMessage response = await _http.PutAsync(new Uri(url), new ByteArrayContent(payload)).ConfigureAwait(continueOnCapturedContext: false);
			if (!response.IsSuccessStatusCode)
			{
				HandleWebException(response);
			}
		}

		public async Task<KeyValuePair<int, string>> GeneralRequestAsync(string url, string method, string payload = null, ApiVersion api = ApiVersion.V3, string accessToken = null)
		{
			HttpRequestMessage request = new HttpRequestMessage
			{
				RequestUri = new Uri(url),
				Method = new HttpMethod(method)
			};
			if (string.IsNullOrWhiteSpace(accessToken))
			{
				throw new InvalidCredentialException("A Client-Id and OAuth token is required to use the Tiltify API.");
			}
			request.Headers.Add(HttpRequestHeader.Accept.ToString(), "application/json");
			request.Headers.Add(HttpRequestHeader.Authorization.ToString(), "Bearer " + FormatOAuth(accessToken));
			if (payload != null)
			{
				request.Content = new StringContent(payload, Encoding.UTF8, "application/json");
			}
			HttpResponseMessage response = await _http.SendAsync(request).ConfigureAwait(continueOnCapturedContext: false);
			if (response.IsSuccessStatusCode)
			{
				return new KeyValuePair<int, string>(value: await response.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false), key: (int)response.StatusCode);
			}
			HandleWebException(response);
			return new KeyValuePair<int, string>(0, null);
		}

		public async Task<int> RequestReturnResponseCodeAsync(string url, string method, List<KeyValuePair<string, string>> getParams = null)
		{
			if (getParams != null)
			{
				for (int i = 0; i < getParams.Count; i++)
				{
					url = ((i != 0) ? (url + "&" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)) : (url + "?" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)));
				}
			}
			HttpRequestMessage request = new HttpRequestMessage
			{
				RequestUri = new Uri(url),
				Method = new HttpMethod(method)
			};
			return (int)(await _http.SendAsync(request).ConfigureAwait(continueOnCapturedContext: false)).StatusCode;
		}

		private static string FormatOAuth(string token)
		{
			return token.Contains(" ") ? token.Split(new char[1] { ' ' })[1] : token;
		}

		private void HandleWebException(HttpResponseMessage errorResp)
		{
			switch (errorResp.StatusCode)
			{
			case HttpStatusCode.BadRequest:
				throw new BadRequestException("Your request failed because either: \n 1. Your ClientID was invalid/not set. \n 2. Your refresh token was invalid. \n 3. You requested a username when the server was expecting a user ID.");
			case HttpStatusCode.Unauthorized:
			{
				HttpHeaderValueCollection<AuthenticationHeaderValue> wwwAuthenticate = errorResp.Headers.WwwAuthenticate;
				if (wwwAuthenticate == null || wwwAuthenticate.Count <= 0)
				{
					throw new BadScopeException("Your request was blocked due to bad credentials (Do you have the right scope for your access token?).");
				}
				throw new TokenExpiredException("Your request was blocked due to an expired Token. Please refresh your token and update your API instance settings.");
			}
			case HttpStatusCode.Forbidden:
				throw new BadTokenException("The token provided in the request did not match the associated user. Make sure the token you're using is from the resource owner.");
			case HttpStatusCode.NotFound:
				throw new BadResourceException("The resource you tried to access was not valid.");
			case HttpStatusCode.TooManyRequests:
			{
				errorResp.Headers.TryGetValues("Ratelimit-Reset", out IEnumerable<string> values);
				throw new TooManyRequestsException("You have reached your rate limit. Too many requests were made", values.FirstOrDefault());
			}
			case HttpStatusCode.BadGateway:
				throw new BadGatewayException("The API answered with a 502 Bad Gateway. Please retry your request");
			case HttpStatusCode.GatewayTimeout:
				throw new GatewayTimeoutException("The API answered with a 504 Gateway Timeout. Please retry your request");
			case HttpStatusCode.InternalServerError:
				throw new InternalServerErrorException("The API answered with a 500 Internal Server Error. Please retry your request");
			default:
				throw new HttpRequestException($"Something went wrong during the request! Please try again later. Status code: {errorResp.StatusCode}");
			}
		}
	}
	public class TiltifyHttpClientHandler : DelegatingHandler
	{
		private readonly ILogger<IHttpCallHandler> _logger;

		public TiltifyHttpClientHandler(ILogger<IHttpCallHandler> logger)
			: base(new HttpClientHandler())
		{
			_logger = logger;
		}

		protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
		{
			if (request.Content != null)
			{
				ILogger<IHttpCallHandler> logger = _logger;
				if (logger != null)
				{
					ILogger logger2 = logger;
					object obj = DateTime.Now;
					object obj2 = "Request";
					object obj3 = request.Method.ToString();
					object obj4 = request.RequestUri.ToString();
					string text = await request.Content.ReadAsStringAsync();
					logger2.LogInformation("Timestamp: {timestamp} Type: {type} Method: {method} Resource: {url} Content: {content}", obj, obj2, obj3, obj4, text);
				}
			}
			else
			{
				_logger?.LogInformation("Timestamp: {timestamp} Type: {type} Method: {method} Resource: {url}", DateTime.Now, "Request", request.Method.ToString(), request.RequestUri.ToString());
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			HttpResponseMessage response = await base.SendAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			stopwatch.Stop();
			if (response.IsSuccessStatusCode)
			{
				if (response.Content != null)
				{
					ILogger<IHttpCallHandler> logger3 = _logger;
					if (logger3 != null)
					{
						ILogger logger4 = logger3;
						object obj5 = DateTime.Now;
						object obj6 = "Response";
						object requestUri = response.RequestMessage.RequestUri;
						object obj7 = (int)response.StatusCode;
						object obj8 = stopwatch.ElapsedMilliseconds;
						string text2 = await response.Content.ReadAsStringAsync();
						logger4.LogInformation("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms Content: {content}", obj5, obj6, requestUri, obj7, obj8, text2);
					}
				}
				else
				{
					_logger?.LogInformation("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms", DateTime.Now, "Response", response.RequestMessage.RequestUri, (int)response.StatusCode, stopwatch.ElapsedMilliseconds);
				}
			}
			else if (response.Content != null)
			{
				ILogger<IHttpCallHandler> logger5 = _logger;
				if (logger5 != null)
				{
					ILogger logger6 = logger5;
					object obj9 = DateTime.Now;
					object obj10 = "Response";
					object requestUri2 = response.RequestMessage.RequestUri;
					object obj11 = (int)response.StatusCode;
					object obj12 = stopwatch.ElapsedMilliseconds;
					string text3 = await response.Content.ReadAsStringAsync();
					logger6.LogError("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms Content: {content}", obj9, obj10, requestUri2, obj11, obj12, text3);
				}
			}
			else
			{
				_logger?.LogError("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms", DateTime.Now, "Response", response.RequestMessage.RequestUri, (int)response.StatusCode, stopwatch.ElapsedMilliseconds);
			}
			return response;
		}
	}
	public class TiltifyWebSocket
	{
		private readonly WebSocketClient _socket;

		private readonly List<PreviousRequest> _previousRequests = new List<PreviousRequest>();

		private readonly Semaphore _previousRequestsSemaphore = new Semaphore(1, 1);

		private readonly ILogger<TiltifyWebSocket> _logger;

		private readonly System.Timers.Timer _pingTimer = new System.Timers.Timer();

		private readonly System.Timers.Timer _pongTimer = new System.Timers.Timer();

		private bool _pongReceived = false;

		private readonly List<string> _topicList = new List<string>();

		private readonly Dictionary<string, string> _topicToChannelId = new Dictionary<string, string>();

		private int websocketMessageId = 16;

		private static readonly Random Random = new Random();

		public bool IsConnected => _socket.IsConnected;

		public event EventHandler<OnLogArgs> OnLog;

		public event EventHandler OnTiltifyServiceConnected;

		public event EventHandler OnTiltifyServiceClosed;

		private event EventHandler<OnTiltifyServiceErrorArgs> OnTiltifyServiceError;

		public event EventHandler<OnListenResponseArgs> OnListenResponse;

		public event EventHandler<OnCampaignDonationArgs> OnCampaignDonation;

		public TiltifyWebSocket(ILogger<TiltifyWebSocket> logger = null, WebSocketClientOptions options = null)
		{
			_logger = logger;
			_socket = new WebSocketClient(options);
			_socket.OnConnected += Socket_OnConnected;
			_socket.OnError += OnError;
			_socket.OnMessage += OnMessage;
			_socket.OnDisconnected += Socket_OnDisconnected;
			_pongTimer.Interval = 10000.0;
			_pongTimer.Elapsed += PongTimerTick;
		}

		private void OnError(object sender, OnErrorEventArgs e)
		{
			_logger?.LogError($"OnError in Tiltify Websocket connection occured! Exception: {e.Exception}");
			this.OnTiltifyServiceError?.Invoke(this, new OnTiltifyServiceErrorArgs
			{
				Exception = e.Exception
			});
		}

		private void OnMessage(object sender, OnMessageEventArgs e)
		{
			_logger?.LogDebug("Received Websocket OnMessage: " + e.Message);
			this.OnLog?.Invoke(this, new OnLogArgs
			{
				Data = e.Message
			});
			ParseMessage(e.Message);
		}

		private void Socket_OnDisconnected(object sender, EventArgs e)
		{
			_logger?.LogWarning("Tiltify Websocket connection closed");
			_pingTimer.Stop();
			_pongTimer.Stop();
			this.OnTiltifyServiceClosed?.Invoke(this, null);
		}

		private void Socket_OnConnected(object sender, EventArgs e)
		{
			_logger?.LogInformation("Tiltify Websocket connection established");
			_pingTimer.Interval = 30000.0;
			_pingTimer.Elapsed += PingTimerTick;
			_pingTimer.Start();
			this.OnTiltifyServiceConnected?.Invoke(this, null);
		}

		private void PingTimerTick(object sender, ElapsedEventArgs e)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			_pongReceived = false;
			string text = GenerateMessageId();
			JArray val = new JArray(new object[5]
			{
				null,
				text,
				"phoenix",
				"heartbeat",
				(object)new JObject()
			});
			_socket.Send(((object)val).ToString());
			_pongTimer.Start();
		}

		private void PongTimerTick(object sender, ElapsedEventArgs e)
		{
			_pongTimer.Stop();
			if (_pongReceived)
			{
				_pongReceived = false;
			}
			else
			{
				_socket.Close();
			}
		}

		private void ParseMessage(string message)
		{
			WebSocketResponse webSocketResponse = new WebSocketResponse(message);
			if (webSocketResponse.Topic == null)
			{
				return;
			}
			if (int.TryParse(webSocketResponse.JoinId, out var result))
			{
				int value = Math.Max(websocketMessageId, result);
				Interlocked.Exchange(ref websocketMessageId, value);
			}
			string[] array = webSocketResponse.Topic.Split(new char[1] { '.' });
			switch (webSocketResponse.Event?.ToLower())
			{
			case "phx_close":
				_socket.Close();
				return;
			case "phx_reply":
			{
				if ("phoenix".Equals(webSocketResponse.Topic))
				{
					_pongReceived = true;
					return;
				}
				if (_previousRequests.Count == 0)
				{
					break;
				}
				bool flag = false;
				_previousRequestsSemaphore.WaitOne();
				try
				{
					int num = 0;
					while (num < _previousRequests.Count)
					{
						PreviousRequest previousRequest = _previousRequests[num];
						if (string.Equals(previousRequest.MessageId, webSocketResponse.MessageId, StringComparison.CurrentCulture))
						{
							_previousRequests.RemoveAt(num);
							_topicToChannelId.TryGetValue(previousRequest.Topic, out var value2);
							this.OnListenResponse?.Invoke(this, new OnListenResponseArgs
							{
								Response = webSocketResponse,
								Topic = previousRequest.Topic,
								Successful = true,
								ChannelId = value2
							});
							flag = true;
						}
						else
						{
							num++;
						}
					}
				}
				finally
				{
					_previousRequestsSemaphore.Release();
				}
				if (flag)
				{
					return;
				}
				break;
			}
			case "donation":
			{
				if (array.Length < 3 || !"campaign".Equals(array[0]) || !"donation".Equals(array[2]))
				{
					break;
				}
				DonationInformation donation = webSocketResponse.Data.ToObject<DonationInformation>();
				this.OnCampaignDonation?.Invoke(this, new OnCampaignDonationArgs
				{
					Donation = donation
				});
				return;
			}
			case "reconnect":
				_socket.Close();
				break;
			}
			UnaccountedFor(message);
		}

		private string GenerateMessageId()
		{
			return Interlocked.Increment(ref websocketMessageId).ToString();
		}

		private void ListenToTopic(string topic)
		{
			_topicList.Add(topic);
		}

		private void ListenToTopics(params string[] topics)
		{
			foreach (string item in topics)
			{
				_topicList.Add(item);
			}
		}

		public void SendTopics(bool unlisten = false)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			string text = GenerateMessageId();
			List<string> list = new List<string>();
			_previousRequestsSemaphore.WaitOne();
			try
			{
				foreach (string topic in _topicList)
				{
					_previousRequests.Add(new PreviousRequest(text, topic));
					list.Add(topic);
				}
			}
			finally
			{
				_previousRequestsSemaphore.Release();
			}
			foreach (string item in list)
			{
				JArray val = new JArray(new object[5]
				{
					text,
					text,
					item,
					(!unlisten) ? "phx_join" : "phx_leave",
					(object)new JObject()
				});
				_socket.Send(((object)val).ToString());
			}
			_topicList.Clear();
		}

		private void UnaccountedFor(string message)
		{
			_logger?.LogInformation("[Tiltify] [Unaccounted] " + message);
		}

		public void ListenToCampaignDonations(string campaignId)
		{
			string text = "campaign." + campaignId + ".donation";
			_topicToChannelId[text] = campaignId;
			ListenToTopic(text);
		}

		public void Connect()
		{
			_socket.Open();
		}

		public void Disconnect()
		{
			_socket.Close();
		}
	}
	public class Users : ApiBase
	{
		public Users(ApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
			: base(settings, rateLimiter, http)
		{
		}

		public Task<GetUserResponse> GetUser()
		{
			return TiltifyGetGenericAsync<GetUserResponse>("/user", ApiVersion.V3);
		}
	}
	public class WebSocketClient
	{
		private int NotConnectedCounter;

		private readonly Throttlers _throttlers;

		private CancellationTokenSource _tokenSource = new CancellationTokenSource();

		private bool _stopServices;

		private bool _networkServicesRunning;

		private Task[] _networkTasks;

		private Task _monitorTask;

		public TimeSpan DefaultKeepAliveInterval { get; set; }

		public int SendQueueLength => _throttlers.SendQueue.Count;

		public bool IsConnected
		{
			get
			{
				ClientWebSocket client = Client;
				return client != null && client.State == WebSocketState.Open;
			}
		}

		public WebSocketClientOptions Options { get; }

		public ClientWebSocket Client { get; private set; }

		private string Url { get; }

		public event EventHandler<OnConnectedEventArgs> OnConnected;

		public event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

		public event EventHandler<OnErrorEventArgs> OnError;

		public event EventHandler<OnFatalErrorEventArgs> OnFatality;

		public event EventHandler<OnMessageEventArgs> OnMessage;

		public event EventHandler<OnMessageThrottledEventArgs> OnMessageThrottled;

		public event EventHandler<OnSendFailedEventArgs> OnSendFailed;

		public event EventHandler<OnStateChangedEventArgs> OnStateChanged;

		public event EventHandler<OnReconnectedEventArgs> OnReconnected;

		public WebSocketClient(WebSocketClientOptions options = null)
		{
			Options = options ?? new WebSocketClientOptions();
			Url = "wss://websockets.tiltify.com:443/socket/websocket?vsn=2.0.0";
			_throttlers = new Throttlers(this, Options.ThrottlingPeriod)
			{
				TokenSource = _tokenSource
			};
		}

		private void InitializeClient()
		{
			Client?.Abort();
			Client = new ClientWebSocket();
			if (_monitorTask == null)
			{
				_monitorTask = StartMonitorTask();
			}
			else if (_monitorTask.IsCompleted)
			{
				_monitorTask = StartMonitorTask();
			}
		}

		public bool Open()
		{
			try
			{
				if (IsConnected)
				{
					return true;
				}
				InitializeClient();
				Client.ConnectAsync(new Uri(Url), _tokenSource.Token).Wait(10000);
				if (!IsConnected)
				{
					return Open();
				}
				StartNetworkServices();
				return true;
			}
			catch (WebSocketException)
			{
				InitializeClient();
				return false;
			}
		}

		public void Close(bool callDisconnect = true)
		{
			Client?.Abort();
			_stopServices = callDisconnect;
			CleanupServices();
			InitializeClient();
			this.OnDisconnected?.Invoke(this, new OnDisconnectedEventArgs());
		}

		public void Reconnect()
		{
			Task.Run(delegate
			{
				Task.Delay(20).Wait();
				Close();
				if (Open())
				{
					this.OnReconnected?.Invoke(this, new OnReconnectedEventArgs());
				}
			});
		}

		public bool Send(string message)
		{
			try
			{
				if (!IsConnected || SendQueueLength >= Options.SendQueueCapacity)
				{
					return false;
				}
				_throttlers.SendQueue.Add(new Tuple<DateTime, string>(DateTime.UtcNow, message));
				return true;
			}
			catch (Exception exception)
			{
				this.OnError?.Invoke(this, new OnErrorEventArgs
				{
					Exception = exception
				});
				throw;
			}
		}

		private void StartNetworkServices()
		{
			_networkServicesRunning = true;
			_networkTasks = new Task[2]
			{
				StartListenerTask(),
				_throttlers.StartSenderTask()
			}.ToArray();
			if (_networkTasks.Any((Task c) => c.IsFaulted))
			{
				_networkServicesRunning = false;
				CleanupServices();
			}
		}

		public Task SendAsync(byte[] message)
		{
			return Client.SendAsync(new ArraySegment<byte>(message), WebSocketMessageType.Text, endOfMessage: true, _tokenSource.Token);
		}

		private Task StartListenerTask()
		{
			return Task.Run(async delegate
			{
				string message = "";
				while (IsConnected && _networkServicesRunning)
				{
					byte[] buffer = new byte[1024];
					WebSocketReceiveResult result;
					try
					{
						result = await Client.ReceiveAsync(new ArraySegment<byte>(buffer), _tokenSource.Token);
					}
					catch
					{
						InitializeClient();
						break;
					}
					if (result != null)
					{
						switch (result.MessageType)
						{
						case WebSocketMessageType.Close:
							Close();
							break;
						case WebSocketMessageType.Text:
							if (!result.EndOfMessage)
							{
								message += Encoding.UTF8.GetString(buffer).TrimEnd(new char[1]);
								continue;
							}
							message += Encoding.UTF8.GetString(buffer).TrimEnd(new char[1]);
							this.OnMessage?.Invoke(this, new OnMessageEventArgs
							{
								Message = message
							});
							break;
						default:
							throw new ArgumentOutOfRangeException();
						case WebSocketMessageType.Binary:
							break;
						}
						message = "";
					}
				}
			});
		}

		private Task StartMonitorTask()
		{
			return Task.Run(delegate
			{
				bool flag = false;
				int num = 0;
				try
				{
					bool isConnected = IsConnected;
					while (!_tokenSource.IsCancellationRequested)
					{
						if (isConnected == IsConnected)
						{
							Thread.Sleep(200);
							if (!IsConnected)
							{
								NotConnectedCounter++;
							}
							else
							{
								num++;
							}
							if (num >= 300)
							{
								num = 0;
							}
							switch (NotConnectedCounter)
							{
							case 25:
							case 75:
							case 150:
							case 300:
							case 600:
								Reconnect();
								break;
							default:
								if (NotConnectedCounter >= 1200 && NotConnectedCounter % 600 == 0)
								{
									Reconnect();
								}
								break;
							}
							if (NotConnectedCounter != 0 && IsConnected)
							{
								NotConnectedCounter = 0;
							}
						}
						else
						{
							this.OnStateChanged?.Invoke(this, new OnStateChangedEventArgs
							{
								IsConnected = (Client.State == WebSocketState.Open),
								WasConnected = isConnected
							});
							if (IsConnected)
							{
								this.OnConnected?.Invoke(this, new OnConnectedEventArgs());
							}
							if (!IsConnected && !_stopServices)
							{
								if (isConnected && Options.ReconnectionPolicy != null && !Options.ReconnectionPolicy.AreAttemptsComplete())
								{
									flag = true;
									break;
								}
								this.OnDisconnected?.Invoke(this, new OnDisconnectedEventArgs());
								if (Client.CloseStatus.HasValue && Client.CloseStatus != WebSocketCloseStatus.NormalClosure)
								{
									this.OnError?.Invoke(this, new OnErrorEventArgs
									{
										Exception = new Exception(Client.CloseStatus.ToString() + " " + Client.CloseStatusDescription)
									});
								}
							}
							isConnected = IsConnected;
						}
					}
				}
				catch (Exception exception)
				{
					this.OnError?.Invoke(this, new OnErrorEventArgs
					{
						Exception = exception
					});
				}
				if (flag && !_stopServices)
				{
					Reconnect();
				}
			}, _tokenSource.Token);
		}

		private void CleanupServices()
		{
			_tokenSource.Cancel();
			_tokenSource = new CancellationTokenSource();
			_throttlers.TokenSource = _tokenSource;
			if (_stopServices)
			{
				Task[] networkTasks = _networkTasks;
				if (networkTasks != null && networkTasks.Length != 0 && !Task.WaitAll(_networkTasks, 15000))
				{
					this.OnFatality?.Invoke(this, new OnFatalErrorEventArgs
					{
						Reason = "Fatal network error. Network services fail to shut down."
					});
					_stopServices = false;
					_throttlers.Reconnecting = false;
					_networkServicesRunning = false;
				}
			}
		}

		public void MessageThrottled(OnMessageThrottledEventArgs eventArgs)
		{
			this.OnMessageThrottled?.Invoke(this, eventArgs);
		}

		public void SendFailed(OnSendFailedEventArgs eventArgs)
		{
			this.OnSendFailed?.Invoke(this, eventArgs);
		}

		public void Error(OnErrorEventArgs eventArgs)
		{
			this.OnError?.Invoke(this, eventArgs);
		}

		public void Dispose()
		{
			Close();
			_throttlers.ShouldDispose = true;
			_tokenSource.Cancel();
			Thread.Sleep(500);
			_tokenSource.Dispose();
			Client?.Dispose();
			GC.Collect();
		}
	}
	public class WebSocketClientOptions
	{
		public int SendQueueCapacity { get; set; } = 10000;


		public TimeSpan SendCacheItemTimeout { get; set; } = TimeSpan.FromMinutes(30.0);


		public ushort SendDelay { get; set; } = 50;


		public ReconnectionPolicy ReconnectionPolicy { get; set; } = new ReconnectionPolicy(3000, (int?)10);


		public int DisconnectWait { get; set; } = 20000;


		public TimeSpan ThrottlingPeriod { get; set; } = TimeSpan.FromSeconds(30.0);


		public int MessagesAllowedInPeriod { get; set; } = 100;

	}
}
namespace Tiltify.RateLimiter
{
	public class BypassLimiter : IRateLimiter
	{
		public static BypassLimiter CreateLimiterBypassInstance()
		{
			return new BypassLimiter();
		}

		public Task Perform(Func<Task> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public Task<T> Perform<T>(Func<Task<T>> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public Task Perform(Func<Task> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			return perform();
		}

		public Task<T> Perform<T>(Func<Task<T>> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			return perform();
		}

		private static Func<Task> Transform(Action act)
		{
			return delegate
			{
				act();
				return Task.FromResult(0);
			};
		}

		private static Func<Task<T>> Transform<T>(Func<T> compute)
		{
			return () => Task.FromResult(compute());
		}

		public Task Perform(Action perform, CancellationToken cancellationToken)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}

		public Task Perform(Action perform)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform, CancellationToken cancellationToken)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}
	}
	public class ComposedAwaitableConstraint : IAwaitableConstraint
	{
		private readonly IAwaitableConstraint _ac1;

		private readonly IAwaitableConstraint _ac2;

		private readonly SemaphoreSlim _semafore = new SemaphoreSlim(1, 1);

		internal ComposedAwaitableConstraint(IAwaitableConstraint ac1, IAwaitableConstraint ac2)
		{
			_ac1 = ac1;
			_ac2 = ac2;
		}

		public async Task<IDisposable> WaitForReadiness(CancellationToken cancellationToken)
		{
			await _semafore.WaitAsync(cancellationToken);
			IDisposable[] diposables;
			try
			{
				diposables = await Task.WhenAll<IDisposable>(_ac1.WaitForReadiness(cancellationToken), _ac2.WaitForReadiness(cancellationToken));
			}
			catch (Exception)
			{
				_semafore.Release();
				throw;
			}
			return new DisposeAction(delegate
			{
				IDisposable[] array = diposables;
				foreach (IDisposable disposable in array)
				{
					disposable.Dispose();
				}
				_semafore.Release();
			});
		}
	}
	public class CountByIntervalAwaitableConstraint : IAwaitableConstraint
	{
		public IReadOnlyList<DateTime> TimeStamps => _timeStamps.ToList();

		protected LimitedSizeStack<DateTime> _timeStamps { get; }

		private int _count { get; }

		private TimeSpan _timeSpan { get; }

		private SemaphoreSlim _semafore { get; } = new SemaphoreSlim(1, 1);


		private ITime _time { get; }

		public CountByIntervalAwaitableConstraint(int count, TimeSpan timeSpan, ITime time = null)
		{
			if (count <= 0)
			{
				throw new ArgumentException("count should be strictly positive", "count");
			}
			if (timeSpan.TotalMilliseconds <= 0.0)
			{
				throw new ArgumentException("timeSpan should be strictly positive", "timeSpan");
			}
			_count = count;
			_timeSpan = timeSpan;
			_timeStamps = new LimitedSizeStack<DateTime>(_count);
			_time = time ?? TimeSystem.StandardTime;
		}

		public async Task<IDisposable> WaitForReadiness(CancellationToken cancellationToken)
		{
			await _semafore.WaitAsync(cancellationToken);
			int count = 0;
			DateTime now = _time.GetTimeNow();
			DateTime target = now - _timeSpan;
			LinkedListNode<DateTime> element = _timeStamps.First;
			LinkedListNode<DateTime> last = null;
			while (element != null && element.Value > target)
			{
				last = element;
				element = element.Next;
				count++;
			}
			if (count < _count)
			{
				return new DisposeAction(OnEnded);
			}
			TimeSpan timetoWait = last.Value.Add(_timeSpan) - now;
			try
			{
				await _time.GetDelay(timetoWait, cancellationToken);
			}
			catch (Exception)
			{
				_semafore.Release();
				throw;
			}
			return new DisposeAction(OnEnded);
		}

		private void OnEnded()
		{
			DateTime timeNow = _time.GetTimeNow();
			_timeStamps.Push(timeNow);
			OnEnded(timeNow);
			_semafore.Release();
		}

		protected virtual void OnEnded(DateTime now)
		{
		}
	}
	public class DisposeAction : IDisposable
	{
		private Action _act;

		public DisposeAction(Action act)
		{
			_act = act;
		}

		public void Dispose()
		{
			_act?.Invoke();
			_act = null;
		}
	}
	public interface IAwaitableConstraint
	{
		Task<IDisposable> WaitForReadiness(CancellationToken cancellationToken);
	}
	public static class IAwaitableConstraintExtension
	{
		public static IAwaitableConstraint Compose(this IAwaitableConstraint ac1, IAwaitableConstraint ac2)
		{
			IAwaitableConstraint result;
			if (ac1 != ac2)
			{
				IAwaitableConstraint awaitableConstraint = new ComposedAwaitableConstraint(ac1, ac2);
				result = awaitableConstraint;
			}
			else
			{
				result = ac1;
			}
			return result;
		}
	}
	public interface ITime
	{
		DateTime GetTimeNow();

		Task GetDelay(TimeSpan timespan, CancellationToken cancellationToken);
	}
	public class LimitedSizeStack<T> : LinkedList<T>
	{
		private readonly int _maxSize;

		public LimitedSizeStack(int maxSize)
		{
			_maxSize = maxSize;
		}

		public void Push(T item)
		{
			AddFirst(item);
			if (base.Count > _maxSize)
			{
				RemoveLast();
			}
		}
	}
	public class PersistentCountByIntervalAwaitableConstraint : CountByIntervalAwaitableConstraint
	{
		private readonly Action<DateTime> _saveStateAction;

		public PersistentCountByIntervalAwaitableConstraint(int count, TimeSpan timeSpan, Action<DateTime> saveStateAction, IEnumerable<DateTime> initialTimeStamps, ITime time = null)
			: base(count, timeSpan, time)
		{
			_saveStateAction = saveStateAction;
			if (initialTimeStamps == null)
			{
				return;
			}
			foreach (DateTime initialTimeStamp in initialTimeStamps)
			{
				base._timeStamps.Push(initialTimeStamp);
			}
		}

		protected override void OnEnded(DateTime now)
		{
			_saveStateAction(now);
		}
	}
	public class TimeLimiter : IRateLimiter
	{
		private readonly IAwaitableConstraint _ac;

		public static TimeLimiter GetFromMaxCountByInterval(int maxCount, TimeSpan timeSpan)
		{
			return new TimeLimiter(new CountByIntervalAwaitableConstraint(maxCount, timeSpan));
		}

		public static TimeLimiter GetPersistentTimeLimiter(int maxCount, TimeSpan timeSpan, Action<DateTime> saveStateAction)
		{
			return GetPersistentTimeLimiter(maxCount, timeSpan, saveStateAction, null);
		}

		public static TimeLimiter GetPersistentTimeLimiter(int maxCount, TimeSpan timeSpan, Action<DateTime> saveStateAction, IEnumerable<DateTime> initialTimeStamps)
		{
			return new TimeLimiter(new PersistentCountByIntervalAwaitableConstraint(maxCount, timeSpan, saveStateAction, initialTimeStamps));
		}

		public static TimeLimiter Compose(params IAwaitableConstraint[] constraints)
		{
			IAwaitableConstraint awaitableConstraint = null;
			foreach (IAwaitableConstraint awaitableConstraint2 in constraints)
			{
				awaitableConstraint = ((awaitableConstraint == null) ? awaitableConstraint2 : awaitableConstraint.Compose(awaitableConstraint2));
			}
			return new TimeLimiter(awaitableConstraint);
		}

		internal TimeLimiter(IAwaitableConstraint ac)
		{
			_ac = ac;
		}

		public Task Perform(Func<Task> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public Task<T> Perform<T>(Func<Task<T>> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public async Task Perform(Func<Task> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			using (await _ac.WaitForReadiness(cancellationToken))
			{
				await perform();
			}
		}

		public async Task<T> Perform<T>(Func<Task<T>> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			using (await _ac.WaitForReadiness(cancellationToken))
			{
				return await perform();
			}
		}

		private static Func<Task> Transform(Action act)
		{
			return delegate
			{
				act();
				return Task.FromResult(0);
			};
		}

		private static Func<Task<T>> Transform<T>(Func<T> compute)
		{
			return () => Task.FromResult(compute());
		}

		public Task Perform(Action perform, CancellationToken cancellationToken)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}

		public Task Perform(Action perform)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform, CancellationToken cancellationToken)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}
	}
	public class TimeSystem : ITime
	{
		public static ITime StandardTime { get; }

		static TimeSystem()
		{
			StandardTime = new TimeSystem();
		}

		private TimeSystem()
		{
		}

		DateTime ITime.GetTimeNow()
		{
			return DateTime.Now;
		}

		Task ITime.GetDelay(TimeSpan timespan, CancellationToken cancellationToken)
		{
			return Task.Delay(timespan, cancellationToken);
		}
	}
}
namespace Tiltify.Models
{
	public class DonationInformation
	{
		[JsonProperty(PropertyName = "id")]
		public int Id { get; protected set; }

		[JsonProperty(PropertyName = "event_id")]
		public int? CampaignId { get; protected set; }

		[JsonProperty(PropertyName = "challenge_id")]
		public int? ChallengeId { get; protected set; }

		[JsonProperty(PropertyName = "poll_option_id")]
		public int? PollOptionId { get; protected set; }

		[JsonProperty(PropertyName = "amount")]
		public double Amount { get; protected set; }

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

		[JsonProperty(PropertyName = "comment")]
		public string Comment { get; protected set; }

		[JsonProperty(PropertyName = "completedAt")]
		public long CompletedAt { get; protected set; }

		[JsonProperty(PropertyName = "reward_id")]
		public int? RewardId { get; protected set; }

		[JsonProperty(PropertyName = "rewardId")]
		private int? RewardIdAltKey
		{
			set
			{
				RewardId = value;
			}
		}
	}
	public class GetCampaignDonationsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public DonationInformation[] Data { get; protected set; }
	}
	public class GetUserResponse
	{
		[JsonProperty(PropertyName = "data")]
		public UserInformation Data { get; protected set; }
	}
	internal class PreviousRequest
	{
		public string MessageId { get; }

		public string Topic { get; }

		public PreviousRequest(string messageId, string topic = "none set")
		{
			MessageId = messageId;
			Topic = topic;
		}
	}
	public class ReconnectionPolicy
	{
		private readonly int _reconnectStepInterval;

		private readonly int? _initMaxAttempts;

		private int _minReconnectInterval;

		private readonly int _maxReconnectInterval;

		private int? _maxAttempts;

		private int _attemptsMade;

		public ReconnectionPolicy()
		{
			_reconnectStepInterval = 3000;
			_minReconnectInterval = 3000;
			_maxReconnectInterval = 30000;
			_maxAttempts = null;
			_initMaxAttempts = null;
			_attemptsMade = 0;
		}

		public void SetMaxAttempts(int attempts)
		{
			_maxAttempts = attempts;
		}

		public void Reset()
		{
			_attemptsMade = 0;
			_minReconnectInterval = _reconnectStepInterval;
			_maxAttempts = _initMaxAttempts;
		}

		public void SetAttemptsMade(int count)
		{
			_attemptsMade = count;
		}

		public ReconnectionPolicy(int minReconnectInterval, int maxReconnectInterval, int? maxAttempts)
		{
			_reconnectStepInterval = minReconnectInterval;
			_minReconnectInterval = ((minReconnectInterval > maxReconnectInterval) ? maxReconnectInterval : minReconnectInterval);
			_maxReconnectInterval = maxReconnectInterval;
			_maxAttempts = maxAttempts;
			_initMaxAttempts = maxAttempts;
			_attemptsMade = 0;
		}

		public ReconnectionPolicy(int minReconnectInterval, int maxReconnectInterval)
		{
			_reconnectStepInterval = minReconnectInterval;
			_minReconnectInterval = ((minReconnectInterval > maxReconnectInterval) ? maxReconnectInterval : minReconnectInterval);
			_maxReconnectInterval = maxReconnectInterval;
			_maxAttempts = null;
			_initMaxAttempts = null;
			_attemptsMade = 0;
		}

		public ReconnectionPolicy(int reconnectInterval)
		{
			_reconnectStepInterval = reconnectInterval;
			_minReconnectInterval = reconnectInterval;
			_maxReconnectInterval = reconnectInterval;
			_maxAttempts = null;
			_initMaxAttempts = null;
			_attemptsMade = 0;
		}

		public ReconnectionPolicy(int reconnectInterval, int? maxAttempts)
		{
			_reconnectStepInterval = reconnectInterval;
			_minReconnectInterval = reconnectInterval;
			_maxReconnectInterval = reconnectInterval;
			_maxAttempts = maxAttempts;
			_initMaxAttempts = maxAttempts;
			_attemptsMade = 0;
		}

		internal void ProcessValues()
		{
			_attemptsMade++;
			if (_minReconnectInterval < _maxReconnectInterval)
			{
				_minReconnectInterval += _reconnectStepInterval;
			}
			if (_minReconnectInterval > _maxReconnectInterval)
			{
				_minReconnectInterval = _maxReconnectInterval;
			}
		}

		public int GetReconnectInterval()
		{
			return _minReconnectInterval;
		}

		public bool AreAttemptsComplete()
		{
			return _attemptsMade == _maxAttempts;
		}
	}
	public class UserInformation
	{
		[JsonProperty(PropertyName = "id")]
		public int Id { get; protected set; }

		[JsonProperty(PropertyName = "username")]
		public string Username { get; protected set; }

		[JsonProperty(PropertyName = "slug")]
		public string Slug { get; protected set; }

		[JsonProperty(PropertyName = "thumbnail")]
		public ThumbnailInformation Comment { get; protected set; }

		[JsonProperty(PropertyName = "status")]
		public string Status { get; protected set; }
	}
	public class ThumbnailInformation
	{
		[JsonProperty(PropertyName = "src")]
		public string Src { get; protected set; }

		[JsonProperty(PropertyName = "alt")]
		public string Alt { get; protected set; }

		[JsonProperty(PropertyName = "width")]
		public int Width { get; protected set; }

		[JsonProperty(PropertyName = "height")]
		public int Height { get; protected set; }
	}
	public class WebSocketResponse
	{
		public string JoinId { get; }

		public string MessageId { get; }

		public string Topic { get; }

		public string Event { get; }

		public JToken Data { get; }

		public WebSocketResponse(string json)
		{
			JArray val = JArray.Parse(json);
			JoinId = ((object)val[0])?.ToString();
			MessageId = ((object)val[1]).ToString();
			Topic = ((object)val[2]).ToString();
			Event = ((object)val[3]).ToString();
			Data = val[4];
		}
	}
}
namespace Tiltify.Exceptions
{
	public class BadGatewayException : Exception
	{
		public BadGatewayException(string data)
			: base(data)
		{
		}
	}
	public class BadParameterException : Exception
	{
		public BadParameterException(string badParamData)
			: base(badParamData)
		{
		}
	}
	public class BadRequestException : Exception
	{
		public BadRequestException(string apiData)
			: base(apiData)
		{
		}
	}
	public class BadResourceException : Exception
	{
		public BadResourceException(string apiData)
			: base(apiData)
		{
		}
	}
	public class BadScopeException : Exception
	{
		public BadScopeException(string data)
			: base(data)
		{
		}
	}
	public class BadTokenException : Exception
	{
		public BadTokenException(string data)
			: base(data)
		{
		}
	}
	public class ClientIdAndOAuthTokenRequired : Exception
	{
		public ClientIdAndOAuthTokenRequired(string explanation)
			: base(explanation)
		{
		}
	}
	public class GatewayTimeoutException : Exception
	{
		public GatewayTimeoutException(string data)
			: base(data)
		{
		}
	}
	public class InternalServerErrorException : Exception
	{
		public InternalServerErrorException(string data)
			: base(data)
		{
		}
	}
	public class InvalidCredentialException : Exception
	{
		public InvalidCredentialException(string data)
			: base(data)
		{
		}
	}
	public class TokenExpiredException : Exception
	{
		public TokenExpiredException(string data)
			: base(data)
		{
		}
	}
	public sealed class TooManyRequestsException : Exception
	{
		public TooManyRequestsException(string data, string resetTime)
			: base(data)
		{
			if (double.TryParse(resetTime, out var result))
			{
				Data.Add("Ratelimit-Reset", result);
			}
		}
	}
	public class UnexpectedResponseException : Exception
	{
		public UnexpectedResponseException(string data)
			: base(data)
		{
		}
	}
}
namespace Tiltify.Events
{
	public class OnCampaignDonationArgs : EventArgs
	{
		public DonationInformation Donation;
	}
	public class OnConnectedEventArgs : EventArgs
	{
	}
	public class OnDisconnectedEventArgs : EventArgs
	{
	}
	public class OnErrorEventArgs : EventArgs
	{
		public Exception Exception { get; set; }
	}
	public class OnFatalErrorEventArgs : EventArgs
	{
		public string Reason;
	}
	public class OnListenResponseArgs : EventArgs
	{
		public string Topic;

		public WebSocketResponse Response;

		public bool Successful;

		public string ChannelId;
	}
	public class OnLogArgs : EventArgs
	{
		public string Data { get; set; }
	}
	public class OnMessageEventArgs : EventArgs
	{
		public string Message;
	}
	public class OnMessageThrottledEventArgs : EventArgs
	{
		public string Message { get; set; }

		public int SentMessageCount { get; set; }

		public TimeSpan Period { get; set; }

		public int AllowedInPeriod { get; set; }
	}
	public class OnReconnectedEventArgs : EventArgs
	{
	}
	public class OnSendFailedEventArgs : EventArgs
	{
		public string Data;

		public Exception Exception;
	}
	public class OnStateChangedEventArgs : EventArgs
	{
		public bool IsConnected;

		public bool WasConnected;
	}
	public class OnTiltifyServiceErrorArgs : EventArgs
	{
		public Exception Exception { get; set; }
	}
}

lib/TwitchLib.Api.Core.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using TwitchLib.Api.Core.Common;
using TwitchLib.Api.Core.Enums;
using TwitchLib.Api.Core.Exceptions;
using TwitchLib.Api.Core.Extensions.RateLimiter;
using TwitchLib.Api.Core.Interfaces;
using TwitchLib.Api.Core.Interfaces.Clips;
using TwitchLib.Api.Core.Internal;
using TwitchLib.Api.Core.Models;
using TwitchLib.Api.Core.Models.Root;
using TwitchLib.Api.Core.Models.Undocumented.CSMaps;
using TwitchLib.Api.Core.Models.Undocumented.CSStreams;
using TwitchLib.Api.Core.Models.Undocumented.ChannelExtensionData;
using TwitchLib.Api.Core.Models.Undocumented.ChannelPanels;
using TwitchLib.Api.Core.Models.Undocumented.ChatProperties;
using TwitchLib.Api.Core.Models.Undocumented.ChatUser;
using TwitchLib.Api.Core.Models.Undocumented.Chatters;
using TwitchLib.Api.Core.Models.Undocumented.ClipChat;
using TwitchLib.Api.Core.Models.Undocumented.Comments;
using TwitchLib.Api.Core.Models.Undocumented.Hosting;
using TwitchLib.Api.Core.Models.Undocumented.RecentEvents;
using TwitchLib.Api.Core.Models.Undocumented.RecentMessages;
using TwitchLib.Api.Core.Models.Undocumented.TwitchPrimeOffers;
using TwitchLib.Api.Core.RateLimiter;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing the core of TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.3")]
[assembly: AssemblyInformationalVersion("3.1.3")]
[assembly: AssemblyProduct("TwitchLib.Api.Core")]
[assembly: AssemblyTitle("TwitchLib.Api.Core")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.3.0")]
namespace TwitchLib.Api.Core
{
	public class ApiBase
	{
		private class TwitchLibJsonSerializer
		{
			private class LowercaseContractResolver : DefaultContractResolver
			{
				protected override string ResolvePropertyName(string propertyName)
				{
					return propertyName.ToLower();
				}
			}

			private readonly JsonSerializerSettings _settings = new JsonSerializerSettings
			{
				ContractResolver = (IContractResolver)(object)new LowercaseContractResolver(),
				NullValueHandling = (NullValueHandling)1
			};

			public string SerializeObject(object o)
			{
				return JsonConvert.SerializeObject(o, (Formatting)1, _settings);
			}
		}

		private readonly TwitchLibJsonSerializer _jsonSerializer;

		protected readonly IApiSettings Settings;

		private readonly IRateLimiter _rateLimiter;

		private readonly IHttpCallHandler _http;

		internal const string BaseV5 = "https://api.twitch.tv/kraken";

		internal const string BaseHelix = "https://api.twitch.tv/helix";

		internal const string BaseOauthToken = "https://id.twitch.tv/oauth2/token";

		private readonly JsonSerializerSettings _twitchLibJsonDeserializer = new JsonSerializerSettings
		{
			NullValueHandling = (NullValueHandling)1,
			MissingMemberHandling = (MissingMemberHandling)0
		};

		public ApiBase(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Settings = settings;
			_rateLimiter = rateLimiter;
			_http = http;
			_jsonSerializer = new TwitchLibJsonSerializer();
		}

		public Task<CredentialCheckResponseModel> CheckCredentialsAsync()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			string text = "Check successful";
			string text2 = "";
			bool flag = true;
			if (!string.IsNullOrWhiteSpace(Settings.ClientId) && !ValidClientId(Settings.ClientId))
			{
				flag = false;
				text2 = "The passed Client Id was not valid. To get a valid Client Id, register an application here: https://www.twitch.tv/kraken/oauth2/clients/new";
			}
			if (!string.IsNullOrWhiteSpace(Settings.AccessToken) && ValidAccessToken(Settings.AccessToken) == null)
			{
				flag = false;
				text2 += "The passed Access Token was not valid. To get an access token, go here:  https://twitchtokengenerator.com/";
			}
			return Task.FromResult<CredentialCheckResponseModel>(new CredentialCheckResponseModel
			{
				Result = flag,
				ResultMessage = (flag ? text : text2)
			});
		}

		public void DynamicScopeValidation(AuthScopes requiredScope, string accessToken = null)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (!Settings.SkipDynamicScopeValidation && !string.IsNullOrWhiteSpace(accessToken))
			{
				Settings.Scopes = ValidAccessToken(accessToken);
				if (Settings.Scopes == null)
				{
					throw new InvalidCredentialException("The current access token does not support this call. Missing required scope: " + ((object)(AuthScopes)(ref requiredScope)).ToString().ToLower() + ". You can skip this check by using: IApiSettings.SkipDynamicScopeValidation = true . You can also generate a new token with this scope here: https://twitchtokengenerator.com");
				}
				if ((!Settings.Scopes.Contains(requiredScope) && (int)requiredScope != 0) || ((int)requiredScope == 0 && Settings.Scopes.Any((AuthScopes x) => (int)x == 30)))
				{
					throw new InvalidCredentialException("The current access token (" + string.Join(",", Settings.Scopes) + ") does not support this call. Missing required scope: " + ((object)(AuthScopes)(ref requiredScope)).ToString().ToLower() + ". You can skip this check by using: IApiSettings.SkipDynamicScopeValidation = true . You can also generate a new token with this scope here: https://twitchtokengenerator.com");
				}
			}
		}

		internal virtual Task<Root> GetRootAsync(string authToken = null, string clientId = null)
		{
			return TwitchGetGenericAsync<Root>("", (ApiVersion)5, null, authToken, clientId);
		}

		public string GetAccessToken(string accessToken = null)
		{
			if (!string.IsNullOrEmpty(accessToken))
			{
				return accessToken;
			}
			if (!string.IsNullOrEmpty(Settings.AccessToken))
			{
				return Settings.AccessToken;
			}
			if (!string.IsNullOrEmpty(Settings.Secret) && !string.IsNullOrEmpty(Settings.ClientId) && !Settings.SkipAutoServerTokenGeneration)
			{
				return GenerateServerBasedAccessToken();
			}
			return null;
		}

		internal string GenerateServerBasedAccessToken()
		{
			KeyValuePair<int, string> keyValuePair = _http.GeneralRequest("https://id.twitch.tv/oauth2/token?client_id=" + Settings.ClientId + "&client_secret=" + Settings.Secret + "&grant_type=client_credentials", "POST", (string)null, (ApiVersion)6, Settings.ClientId, (string)null);
			if (keyValuePair.Key == 200)
			{
				dynamic val = JsonConvert.DeserializeObject<object>(keyValuePair.Value);
				int num = (int)val.expires_in;
				return (string)val.access_token;
			}
			return null;
		}

		internal void ForceAccessTokenAndClientIdForHelix(string clientId, string accessToken, ApiVersion api)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)api != 6 || (!string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(accessToken)))
			{
				return;
			}
			throw new ClientIdAndOAuthTokenRequired("As of May 1, all calls to Twitch's Helix API require Client-ID and OAuth access token be set. Example: api.Settings.AccessToken = \"twitch-oauth-access-token-here\"; api.Settings.ClientId = \"twitch-client-id-here\";");
		}

		protected Task<T> TwitchGetGenericAsync<T>(string resource, ApiVersion api, List<KeyValuePair<string, string>> getParams = null, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<T>((Func<Task<T>>)(async () => await Task.Run(() => JsonConvert.DeserializeObject<T>(_http.GeneralRequest(url, "GET", (string)null, api, clientId, accessToken).Value, _twitchLibJsonDeserializer)).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected Task<string> TwitchDeleteAsync(string resource, ApiVersion api, List<KeyValuePair<string, string>> getParams = null, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<string>((Func<Task<string>>)(async () => await Task.Run(() => _http.GeneralRequest(url, "DELETE", (string)null, api, clientId, accessToken).Value).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected Task<T> TwitchPostGenericAsync<T>(string resource, ApiVersion api, string payload, List<KeyValuePair<string, string>> getParams = null, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<T>((Func<Task<T>>)(async () => await Task.Run(() => JsonConvert.DeserializeObject<T>(_http.GeneralRequest(url, "POST", payload, api, clientId, accessToken).Value, _twitchLibJsonDeserializer)).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected Task<T> TwitchPostGenericModelAsync<T>(string resource, ApiVersion api, RequestModel model, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			string url = ConstructResourceUrl(resource, null, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<T>((Func<Task<T>>)(async () => await Task.Run(() => JsonConvert.DeserializeObject<T>(_http.GeneralRequest(url, "POST", (model != null) ? _jsonSerializer.SerializeObject(model) : "", api, clientId, accessToken).Value, _twitchLibJsonDeserializer)).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected Task<T> TwitchDeleteGenericAsync<T>(string resource, ApiVersion api, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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)
			string url = ConstructResourceUrl(resource, null, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<T>((Func<Task<T>>)(async () => await Task.Run(() => JsonConvert.DeserializeObject<T>(_http.GeneralRequest(url, "DELETE", (string)null, api, clientId, accessToken).Value, _twitchLibJsonDeserializer)).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected Task<T> TwitchPutGenericAsync<T>(string resource, ApiVersion api, string payload, List<KeyValuePair<string, string>> getParams = null, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<T>((Func<Task<T>>)(async () => await Task.Run(() => JsonConvert.DeserializeObject<T>(_http.GeneralRequest(url, "PUT", payload, api, clientId, accessToken).Value, _twitchLibJsonDeserializer)).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected Task<string> TwitchPutAsync(string resource, ApiVersion api, string payload, List<KeyValuePair<string, string>> getParams = null, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<string>((Func<Task<string>>)(async () => await Task.Run(() => _http.GeneralRequest(url, "PUT", payload, api, clientId, accessToken).Value).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected Task<KeyValuePair<int, string>> TwitchPostAsync(string resource, ApiVersion api, string payload, List<KeyValuePair<string, string>> getParams = null, string accessToken = null, string clientId = null, string customBase = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			string url = ConstructResourceUrl(resource, getParams, api, customBase);
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<KeyValuePair<int, string>>((Func<Task<KeyValuePair<int, string>>>)(async () => await Task.Run(() => _http.GeneralRequest(url, "POST", payload, api, clientId, accessToken)).ConfigureAwait(continueOnCapturedContext: false)));
		}

		protected void PutBytes(string url, byte[] payload)
		{
			_http.PutBytes(url, payload);
		}

		internal int RequestReturnResponseCode(string url, string method, List<KeyValuePair<string, string>> getParams = null)
		{
			return _http.RequestReturnResponseCode(url, method, getParams);
		}

		protected Task<T> GetGenericAsync<T>(string url, List<KeyValuePair<string, string>> getParams = null, string accessToken = null, ApiVersion api = 5, string clientId = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			if (getParams != null)
			{
				for (int i = 0; i < getParams.Count; i++)
				{
					if (i == 0)
					{
						url = url + "?" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value);
					}
					else
					{
						url = url + "&" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value);
					}
				}
			}
			if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(Settings.ClientId))
			{
				clientId = Settings.ClientId;
			}
			accessToken = GetAccessToken(accessToken);
			ForceAccessTokenAndClientIdForHelix(clientId, accessToken, api);
			return _rateLimiter.Perform<T>((Func<Task<T>>)(async () => await Task.Run(() => JsonConvert.DeserializeObject<T>(_http.GeneralRequest(url, "GET", (string)null, api, clientId, accessToken).Value, _twitchLibJsonDeserializer)).ConfigureAwait(continueOnCapturedContext: false)));
		}

		internal Task<T> GetSimpleGenericAsync<T>(string url, List<KeyValuePair<string, string>> getParams = null)
		{
			if (getParams != null)
			{
				for (int i = 0; i < getParams.Count; i++)
				{
					if (i == 0)
					{
						url = url + "?" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value);
					}
					else
					{
						url = url + "&" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value);
					}
				}
			}
			return _rateLimiter.Perform<T>((Func<Task<T>>)(async () => JsonConvert.DeserializeObject<T>(await SimpleRequestAsync(url), _twitchLibJsonDeserializer)));
		}

		private Task<string> SimpleRequestAsync(string url)
		{
			TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
			WebClient client = new WebClient();
			client.DownloadStringCompleted += DownloadStringCompletedEventHandler;
			client.DownloadString(new Uri(url));
			return tcs.Task;
			void DownloadStringCompletedEventHandler(object sender, DownloadStringCompletedEventArgs args)
			{
				if (args.Cancelled)
				{
					tcs.SetCanceled();
				}
				else if (args.Error != null)
				{
					tcs.SetException(args.Error);
				}
				else
				{
					tcs.SetResult(args.Result);
				}
				client.DownloadStringCompleted -= DownloadStringCompletedEventHandler;
			}
		}

		private bool ValidClientId(string clientId)
		{
			try
			{
				Root result = GetRootAsync(null, clientId).GetAwaiter().GetResult();
				return result.Token != null;
			}
			catch (BadRequestException)
			{
				return false;
			}
		}

		private List<AuthScopes> ValidAccessToken(string accessToken)
		{
			try
			{
				Root result = GetRootAsync(accessToken).GetAwaiter().GetResult();
				if (result.Token == null)
				{
					return null;
				}
				return BuildScopesList(result.Token);
			}
			catch
			{
				return null;
			}
		}

		private static List<AuthScopes> BuildScopesList(RootToken token)
		{
			List<AuthScopes> list = new List<AuthScopes>();
			string[] scopes = token.Auth.Scopes;
			for (int i = 0; i < scopes.Length; i++)
			{
				switch (scopes[i])
				{
				case "channel_check_subscription":
					list.Add((AuthScopes)1);
					break;
				case "channel_commercial":
					list.Add((AuthScopes)2);
					break;
				case "channel_editor":
					list.Add((AuthScopes)3);
					break;
				case "channel_feed_edit":
					list.Add((AuthScopes)4);
					break;
				case "channel_feed_read":
					list.Add((AuthScopes)5);
					break;
				case "channel_read":
					list.Add((AuthScopes)6);
					break;
				case "channel_stream":
					list.Add((AuthScopes)7);
					break;
				case "channel_subscriptions":
					list.Add((AuthScopes)8);
					break;
				case "chat_login":
					list.Add((AuthScopes)9);
					break;
				case "collections_edit":
					list.Add((AuthScopes)10);
					break;
				case "communities_edit":
					list.Add((AuthScopes)11);
					break;
				case "communities_moderate":
					list.Add((AuthScopes)12);
					break;
				case "user_blocks_edit":
					list.Add((AuthScopes)13);
					break;
				case "user_blocks_read":
					list.Add((AuthScopes)14);
					break;
				case "user_follows_edit":
					list.Add((AuthScopes)15);
					break;
				case "user_read":
					list.Add((AuthScopes)16);
					break;
				case "user_subscriptions":
					list.Add((AuthScopes)17);
					break;
				case "openid":
					list.Add((AuthScopes)19);
					break;
				case "viewing_activity_read":
					list.Add((AuthScopes)18);
					break;
				case "user:edit":
					list.Add((AuthScopes)20);
					break;
				case "user:edit:broadcast":
					list.Add((AuthScopes)26);
					break;
				case "user:read:broadcast":
					list.Add((AuthScopes)27);
					break;
				case "user:read:email":
					list.Add((AuthScopes)21);
					break;
				case "clips:edit":
					list.Add((AuthScopes)22);
					break;
				case "bits:read":
					list.Add((AuthScopes)23);
					break;
				case "analytics:read:games":
					list.Add((AuthScopes)24);
					break;
				case "analytics:read:extensions":
					list.Add((AuthScopes)25);
					break;
				case "channel:read:subscriptions":
					list.Add((AuthScopes)28);
					break;
				case "moderation:read":
					list.Add((AuthScopes)29);
					break;
				}
			}
			if (list.Count == 0)
			{
				list.Add((AuthScopes)30);
			}
			return list;
		}

		private string ConstructResourceUrl(string resource = null, List<KeyValuePair<string, string>> getParams = null, ApiVersion api = 5, string overrideUrl = null)
		{
			//IL_0024: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			string text = "";
			if (overrideUrl == null)
			{
				if (resource == null)
				{
					throw new Exception("Cannot pass null resource with null override url");
				}
				if ((int)api != 5)
				{
					if ((int)api == 6)
					{
						text = "https://api.twitch.tv/helix" + resource;
					}
				}
				else
				{
					text = "https://api.twitch.tv/kraken" + resource;
				}
			}
			else
			{
				text = ((resource == null) ? overrideUrl : (overrideUrl + resource));
			}
			if (getParams != null)
			{
				for (int i = 0; i < getParams.Count; i++)
				{
					text = ((i != 0) ? (text + "&" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)) : (text + "?" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)));
				}
			}
			return text;
		}
	}
	public class ApiSettings : IApiSettings, INotifyPropertyChanged
	{
		private string _clientId;

		private string _secret;

		private string _accessToken;

		private bool _skipDynamicScopeValidation;

		private bool _skipAutoServerTokenGeneration;

		private List<AuthScopes> _scopes;

		public string ClientId
		{
			get
			{
				return _clientId;
			}
			set
			{
				if (value != _clientId)
				{
					_clientId = value;
					NotifyPropertyChanged("ClientId");
				}
			}
		}

		public string Secret
		{
			get
			{
				return _secret;
			}
			set
			{
				if (value != _secret)
				{
					_secret = value;
					NotifyPropertyChanged("Secret");
				}
			}
		}

		public string AccessToken
		{
			get
			{
				return _accessToken;
			}
			set
			{
				if (value != _accessToken)
				{
					_accessToken = value;
					NotifyPropertyChanged("AccessToken");
				}
			}
		}

		public bool SkipDynamicScopeValidation
		{
			get
			{
				return _skipDynamicScopeValidation;
			}
			set
			{
				if (value != _skipDynamicScopeValidation)
				{
					_skipDynamicScopeValidation = value;
					NotifyPropertyChanged("SkipDynamicScopeValidation");
				}
			}
		}

		public bool SkipAutoServerTokenGeneration
		{
			get
			{
				return _skipAutoServerTokenGeneration;
			}
			set
			{
				if (value != _skipAutoServerTokenGeneration)
				{
					_skipAutoServerTokenGeneration = value;
					NotifyPropertyChanged("SkipAutoServerTokenGeneration");
				}
			}
		}

		public List<AuthScopes> Scopes
		{
			get
			{
				return _scopes;
			}
			set
			{
				if (value != _scopes)
				{
					_scopes = value;
					NotifyPropertyChanged("Scopes");
				}
			}
		}

		public event PropertyChangedEventHandler PropertyChanged;

		private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
		{
			this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
		}
	}
}
namespace TwitchLib.Api.Core.Undocumented
{
	public class Undocumented : ApiBase
	{
		public Undocumented(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
			: base(settings, rateLimiter, http)
		{
		}

		public async Task<GetClipChatResponse> GetClipChatAsync(IClip clip)
		{
			if (clip == null)
			{
				return null;
			}
			string vodId = "v" + clip.VOD.Id;
			string offsetTime = clip.VOD.Url.Split(new char[1] { '=' })[1];
			long offsetSeconds = 2L;
			if (offsetTime.Contains("h"))
			{
				offsetSeconds += int.Parse(offsetTime.Split(new char[1] { 'h' })[0]) * 60 * 60;
				offsetTime = offsetTime.Replace(offsetTime.Split(new char[1] { 'h' })[0] + "h", "");
			}
			if (offsetTime.Contains("m"))
			{
				offsetSeconds += int.Parse(offsetTime.Split(new char[1] { 'm' })[0]) * 60;
				offsetTime = offsetTime.Replace(offsetTime.Split(new char[1] { 'm' })[0] + "m", "");
			}
			if (offsetTime.Contains("s"))
			{
				offsetSeconds += int.Parse(offsetTime.Split(new char[1] { 's' })[0]);
			}
			List<KeyValuePair<string, string>> getParams = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("video_id", vodId),
				new KeyValuePair<string, string>("offset_seconds", offsetSeconds.ToString())
			};
			return await GetGenericAsync<GetClipChatResponse>("https://rechat.twitch.tv/rechat-messages", getParams, null, (ApiVersion)5).ConfigureAwait(continueOnCapturedContext: false);
		}

		public Task<TwitchPrimeOffers> GetTwitchPrimeOffersAsync()
		{
			List<KeyValuePair<string, string>> getParams = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("on_site", "1")
			};
			return GetGenericAsync<TwitchPrimeOffers>("https://api.twitch.tv/api/premium/offers", getParams, null, (ApiVersion)5);
		}

		public Task<ChannelHostsResponse> GetChannelHostsAsync(string channelId)
		{
			List<KeyValuePair<string, string>> getParams = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("include_logins", "1"),
				new KeyValuePair<string, string>("target", channelId)
			};
			return TwitchGetGenericAsync<ChannelHostsResponse>("hosts", (ApiVersion)5, getParams, null, null, "https://tmi.twitch.tv/");
		}

		public Task<ChatProperties> GetChatPropertiesAsync(string channelName)
		{
			return GetGenericAsync<ChatProperties>("https://api.twitch.tv/api/channels/" + channelName + "/chat_properties", null, null, (ApiVersion)5);
		}

		public Task<Panel[]> GetChannelPanelsAsync(string channelName)
		{
			return GetGenericAsync<Panel[]>("https://api.twitch.tv/api/channels/" + channelName + "/panels", null, null, (ApiVersion)5);
		}

		public Task<CSMapsResponse> GetCSMapsAsync()
		{
			return GetGenericAsync<CSMapsResponse>("https://api.twitch.tv/api/cs/maps", null, null, (ApiVersion)5);
		}

		public Task<CSStreams> GetCSStreamsAsync(int limit = 25, int offset = 0)
		{
			List<KeyValuePair<string, string>> getParams = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("limit", limit.ToString()),
				new KeyValuePair<string, string>("offset", offset.ToString())
			};
			return GetGenericAsync<CSStreams>("https://api.twitch.tv/api/cs", getParams, null, (ApiVersion)5);
		}

		public Task<RecentMessagesResponse> GetRecentMessagesAsync(string channelId)
		{
			return GetGenericAsync<RecentMessagesResponse>("https://tmi.twitch.tv/api/rooms/" + channelId + "/recent_messages", null, null, (ApiVersion)5);
		}

		public async Task<List<ChatterFormatted>> GetChattersAsync(string channelName)
		{
			ChattersResponse resp = await GetGenericAsync<ChattersResponse>("https://tmi.twitch.tv/group/user/" + channelName.ToLower() + "/chatters", null, null, (ApiVersion)5);
			List<ChatterFormatted> chatters = ((IEnumerable<string>)resp.Chatters.Staff).Select((Func<string, ChatterFormatted>)((string chatter) => new ChatterFormatted(chatter, (UserType)6))).ToList();
			chatters.AddRange(((IEnumerable<string>)resp.Chatters.Admins).Select((Func<string, ChatterFormatted>)((string chatter) => new ChatterFormatted(chatter, (UserType)5))));
			chatters.AddRange(((IEnumerable<string>)resp.Chatters.GlobalMods).Select((Func<string, ChatterFormatted>)((string chatter) => new ChatterFormatted(chatter, (UserType)3))));
			chatters.AddRange(((IEnumerable<string>)resp.Chatters.Moderators).Select((Func<string, ChatterFormatted>)((string chatter) => new ChatterFormatted(chatter, (UserType)2))));
			chatters.AddRange(((IEnumerable<string>)resp.Chatters.Viewers).Select((Func<string, ChatterFormatted>)((string chatter) => new ChatterFormatted(chatter, (UserType)0))));
			chatters.AddRange(((IEnumerable<string>)resp.Chatters.VIP).Select((Func<string, ChatterFormatted>)((string chatter) => new ChatterFormatted(chatter, (UserType)1))));
			foreach (ChatterFormatted chatter2 in chatters)
			{
				if (string.Equals(chatter2.Username, channelName, StringComparison.CurrentCultureIgnoreCase))
				{
					chatter2.UserType = (UserType)4;
				}
			}
			return chatters;
		}

		public Task<RecentEvents> GetRecentChannelEventsAsync(string channelId)
		{
			return GetGenericAsync<RecentEvents>("https://api.twitch.tv/bits/channels/" + channelId + "/events/recent", null, null, (ApiVersion)5);
		}

		public Task<ChatUserResponse> GetChatUserAsync(string userId, string channelId = null)
		{
			return GetGenericAsync<ChatUserResponse>((channelId != null) ? ("https://api.twitch.tv/kraken/users/" + userId + "/chat/channels/" + channelId) : ("https://api.twitch.tv/kraken/users/" + userId + "/chat/"), null, null, (ApiVersion)5);
		}

		public Task<bool> IsUsernameAvailableAsync(string username)
		{
			List<KeyValuePair<string, string>> getParams = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("users_service", "true")
			};
			int num = RequestReturnResponseCode("https://passport.twitch.tv/usernames/" + username, "HEAD", getParams);
			return num switch
			{
				200 => Task.FromResult(result: false), 
				204 => Task.FromResult(result: true), 
				_ => throw new BadResourceException("Unexpected response from resource. Expecting response code 200 or 204, received: " + num), 
			};
		}

		public Task<GetChannelExtensionDataResponse> GetChannelExtensionDataAsync(string channelId)
		{
			return TwitchGetGenericAsync<GetChannelExtensionDataResponse>("/channels/" + channelId + "/extensions", (ApiVersion)5, null, null, null, "https://api.twitch.tv/v5");
		}

		public Task<CommentsPage> GetCommentsPageAsync(string videoId, int? contentOffsetSeconds = null, string cursor = null)
		{
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
			if (string.IsNullOrWhiteSpace(videoId))
			{
				throw new BadParameterException("The video id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
			}
			if (contentOffsetSeconds.HasValue)
			{
				list.Add(new KeyValuePair<string, string>("content_offset_seconds", contentOffsetSeconds.Value.ToString()));
			}
			if (cursor != null)
			{
				list.Add(new KeyValuePair<string, string>("cursor", cursor));
			}
			return GetGenericAsync<CommentsPage>("https://api.twitch.tv/kraken/videos/" + videoId + "/comments", list, null, (ApiVersion)5);
		}

		public async Task<List<CommentsPage>> GetAllCommentsAsync(string videoId)
		{
			List<CommentsPage> list = new List<CommentsPage>();
			List<CommentsPage> list2 = list;
			list2.Add(await GetCommentsPageAsync(videoId));
			List<CommentsPage> pages = list;
			while (pages.Last().Next != null)
			{
				List<CommentsPage> list3 = pages;
				list3.Add(await GetCommentsPageAsync(videoId, null, pages.Last().Next));
			}
			return pages;
		}
	}
}
namespace TwitchLib.Api.Core.RateLimiter
{
	public class BypassLimiter : IRateLimiter
	{
		public Task Perform(Func<Task> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public Task<T> Perform<T>(Func<Task<T>> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public Task Perform(Func<Task> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			return perform();
		}

		public Task<T> Perform<T>(Func<Task<T>> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			return perform();
		}

		private static Func<Task> Transform(Action act)
		{
			return delegate
			{
				act();
				return Task.FromResult(0);
			};
		}

		private static Func<Task<T>> Transform<T>(Func<T> compute)
		{
			return () => Task.FromResult(compute());
		}

		public Task Perform(Action perform, CancellationToken cancellationToken)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}

		public Task Perform(Action perform)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform, CancellationToken cancellationToken)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}

		public static BypassLimiter CreateLimiterBypassInstance()
		{
			return new BypassLimiter();
		}
	}
	public class ComposedAwaitableConstraint : IAwaitableConstraint
	{
		private IAwaitableConstraint _ac1;

		private IAwaitableConstraint _ac2;

		private readonly SemaphoreSlim _semafore = new SemaphoreSlim(1, 1);

		internal ComposedAwaitableConstraint(IAwaitableConstraint ac1, IAwaitableConstraint ac2)
		{
			_ac1 = ac1;
			_ac2 = ac2;
		}

		public async Task<IDisposable> WaitForReadiness(CancellationToken cancellationToken)
		{
			await _semafore.WaitAsync(cancellationToken);
			IDisposable[] diposables;
			try
			{
				diposables = await Task.WhenAll<IDisposable>(_ac1.WaitForReadiness(cancellationToken), _ac2.WaitForReadiness(cancellationToken));
			}
			catch (Exception)
			{
				_semafore.Release();
				throw;
			}
			return new DisposeAction(delegate
			{
				IDisposable[] array = diposables;
				foreach (IDisposable disposable in array)
				{
					disposable.Dispose();
				}
				_semafore.Release();
			});
		}
	}
	public class CountByIntervalAwaitableConstraint : IAwaitableConstraint
	{
		public IReadOnlyList<DateTime> TimeStamps => _timeStamps.ToList();

		protected LimitedSizeStack<DateTime> _timeStamps { get; }

		private int _count { get; }

		private TimeSpan _timeSpan { get; }

		private SemaphoreSlim _semafore { get; } = new SemaphoreSlim(1, 1);


		private ITime _time { get; }

		public CountByIntervalAwaitableConstraint(int count, TimeSpan timeSpan, ITime time = null)
		{
			if (count <= 0)
			{
				throw new ArgumentException("count should be strictly positive", "count");
			}
			if (timeSpan.TotalMilliseconds <= 0.0)
			{
				throw new ArgumentException("timeSpan should be strictly positive", "timeSpan");
			}
			_count = count;
			_timeSpan = timeSpan;
			_timeStamps = new LimitedSizeStack<DateTime>(_count);
			_time = time ?? TimeSystem.StandardTime;
		}

		public async Task<IDisposable> WaitForReadiness(CancellationToken cancellationToken)
		{
			await _semafore.WaitAsync(cancellationToken);
			int count = 0;
			DateTime now = _time.GetTimeNow();
			DateTime target = now - _timeSpan;
			LinkedListNode<DateTime> element = _timeStamps.First;
			LinkedListNode<DateTime> last = null;
			while (element != null && element.Value > target)
			{
				last = element;
				element = element.Next;
				count++;
			}
			if (count < _count)
			{
				return new DisposeAction(OnEnded);
			}
			TimeSpan timetoWait = last.Value.Add(_timeSpan) - now;
			try
			{
				await _time.GetDelay(timetoWait, cancellationToken);
			}
			catch (Exception)
			{
				_semafore.Release();
				throw;
			}
			return new DisposeAction(OnEnded);
		}

		private void OnEnded()
		{
			DateTime timeNow = _time.GetTimeNow();
			_timeStamps.Push(timeNow);
			OnEnded(timeNow);
			_semafore.Release();
		}

		protected virtual void OnEnded(DateTime now)
		{
		}
	}
	public class DisposeAction : IDisposable
	{
		private Action _act;

		public DisposeAction(Action act)
		{
			_act = act;
		}

		public void Dispose()
		{
			_act?.Invoke();
			_act = null;
		}
	}
	public class LimitedSizeStack<T> : LinkedList<T>
	{
		private readonly int _maxSize;

		public LimitedSizeStack(int maxSize)
		{
			_maxSize = maxSize;
		}

		public void Push(T item)
		{
			AddFirst(item);
			if (base.Count > _maxSize)
			{
				RemoveLast();
			}
		}
	}
	public class PersistentCountByIntervalAwaitableConstraint : CountByIntervalAwaitableConstraint
	{
		private readonly Action<DateTime> _saveStateAction;

		public PersistentCountByIntervalAwaitableConstraint(int count, TimeSpan timeSpan, Action<DateTime> saveStateAction, IEnumerable<DateTime> initialTimeStamps, ITime time = null)
			: base(count, timeSpan, time)
		{
			_saveStateAction = saveStateAction;
			if (initialTimeStamps == null)
			{
				return;
			}
			foreach (DateTime initialTimeStamp in initialTimeStamps)
			{
				base._timeStamps.Push(initialTimeStamp);
			}
		}

		protected override void OnEnded(DateTime now)
		{
			_saveStateAction(now);
		}
	}
	public class TimeLimiter : IRateLimiter
	{
		private readonly IAwaitableConstraint _ac;

		internal TimeLimiter(IAwaitableConstraint ac)
		{
			_ac = ac;
		}

		public Task Perform(Func<Task> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public Task<T> Perform<T>(Func<Task<T>> perform)
		{
			return Perform(perform, CancellationToken.None);
		}

		public async Task Perform(Func<Task> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			using (await _ac.WaitForReadiness(cancellationToken))
			{
				await perform();
			}
		}

		public async Task<T> Perform<T>(Func<Task<T>> perform, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			using (await _ac.WaitForReadiness(cancellationToken))
			{
				return await perform();
			}
		}

		private static Func<Task> Transform(Action act)
		{
			return delegate
			{
				act();
				return Task.FromResult(0);
			};
		}

		private static Func<Task<T>> Transform<T>(Func<T> compute)
		{
			return () => Task.FromResult(compute());
		}

		public Task Perform(Action perform, CancellationToken cancellationToken)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}

		public Task Perform(Action perform)
		{
			Func<Task> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2);
		}

		public Task<T> Perform<T>(Func<T> perform, CancellationToken cancellationToken)
		{
			Func<Task<T>> perform2 = Transform(perform);
			return Perform(perform2, cancellationToken);
		}

		public static TimeLimiter GetFromMaxCountByInterval(int maxCount, TimeSpan timeSpan)
		{
			return new TimeLimiter((IAwaitableConstraint)(object)new CountByIntervalAwaitableConstraint(maxCount, timeSpan));
		}

		public static TimeLimiter GetPersistentTimeLimiter(int maxCount, TimeSpan timeSpan, Action<DateTime> saveStateAction)
		{
			return GetPersistentTimeLimiter(maxCount, timeSpan, saveStateAction, null);
		}

		public static TimeLimiter GetPersistentTimeLimiter(int maxCount, TimeSpan timeSpan, Action<DateTime> saveStateAction, IEnumerable<DateTime> initialTimeStamps)
		{
			return new TimeLimiter((IAwaitableConstraint)(object)new PersistentCountByIntervalAwaitableConstraint(maxCount, timeSpan, saveStateAction, initialTimeStamps));
		}

		public static TimeLimiter Compose(params IAwaitableConstraint[] constraints)
		{
			IAwaitableConstraint val = null;
			foreach (IAwaitableConstraint val2 in constraints)
			{
				val = ((val == null) ? val2 : val.Compose(val2));
			}
			return new TimeLimiter(val);
		}
	}
	public class TimeSystem : ITime
	{
		public static ITime StandardTime { get; }

		static TimeSystem()
		{
			StandardTime = (ITime)(object)new TimeSystem();
		}

		private TimeSystem()
		{
		}

		DateTime ITime.GetTimeNow()
		{
			return DateTime.Now;
		}

		Task ITime.GetDelay(TimeSpan timespan, CancellationToken cancellationToken)
		{
			return Task.Delay(timespan, cancellationToken);
		}
	}
}
namespace TwitchLib.Api.Core.Internal
{
	public class TwitchHttpClientHandler : DelegatingHandler
	{
		private readonly ILogger<IHttpCallHandler> _logger;

		public TwitchHttpClientHandler(ILogger<IHttpCallHandler> logger)
			: base(new HttpClientHandler())
		{
			_logger = logger;
		}

		protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
		{
			if (request.Content != null)
			{
				ILogger<IHttpCallHandler> logger = _logger;
				if (logger != null)
				{
					ILogger logger2 = logger;
					object obj = DateTime.Now;
					object obj2 = "Request";
					object obj3 = request.Method.ToString();
					object obj4 = request.RequestUri.ToString();
					string text = await request.Content.ReadAsStringAsync();
					logger2.LogInformation("Timestamp: {timestamp} Type: {type} Method: {method} Resource: {url} Content: {content}", obj, obj2, obj3, obj4, text);
				}
			}
			else
			{
				_logger?.LogInformation("Timestamp: {timestamp} Type: {type} Method: {method} Resource: {url}", DateTime.Now, "Request", request.Method.ToString(), request.RequestUri.ToString());
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
			stopwatch.Stop();
			if (response.IsSuccessStatusCode)
			{
				if (response.Content != null)
				{
					ILogger<IHttpCallHandler> logger3 = _logger;
					if (logger3 != null)
					{
						ILogger logger4 = logger3;
						object obj5 = DateTime.Now;
						object obj6 = "Response";
						object requestUri = response.RequestMessage.RequestUri;
						object obj7 = (int)response.StatusCode;
						object obj8 = stopwatch.ElapsedMilliseconds;
						string text2 = await response.Content.ReadAsStringAsync();
						logger4.LogInformation("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms Content: {content}", obj5, obj6, requestUri, obj7, obj8, text2);
					}
				}
				else
				{
					_logger?.LogInformation("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms", DateTime.Now, "Response", response.RequestMessage.RequestUri, (int)response.StatusCode, stopwatch.ElapsedMilliseconds);
				}
			}
			else if (response.Content != null)
			{
				ILogger<IHttpCallHandler> logger5 = _logger;
				if (logger5 != null)
				{
					ILogger logger6 = logger5;
					object obj9 = DateTime.Now;
					object obj10 = "Response";
					object requestUri2 = response.RequestMessage.RequestUri;
					object obj11 = (int)response.StatusCode;
					object obj12 = stopwatch.ElapsedMilliseconds;
					string text3 = await response.Content.ReadAsStringAsync();
					logger6.LogError("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms Content: {content}", obj9, obj10, requestUri2, obj11, obj12, text3);
				}
			}
			else
			{
				_logger?.LogError("Timestamp: {timestamp} Type: {type} Resource: {url} Statuscode: {statuscode} Elapsed: {elapsed} ms", DateTime.Now, "Response", response.RequestMessage.RequestUri, (int)response.StatusCode, stopwatch.ElapsedMilliseconds);
			}
			return response;
		}
	}
}
namespace TwitchLib.Api.Core.HttpCallHandlers
{
	public class TwitchHttpClient : IHttpCallHandler
	{
		private readonly ILogger<TwitchHttpClient> _logger;

		private readonly HttpClient _http;

		public TwitchHttpClient(ILogger<TwitchHttpClient> logger = null)
		{
			_logger = logger;
			_http = new HttpClient(new TwitchHttpClientHandler((ILogger<IHttpCallHandler>)_logger));
		}

		public void PutBytes(string url, byte[] payload)
		{
			HttpResponseMessage result = _http.PutAsync(new Uri(url), new ByteArrayContent(payload)).GetAwaiter().GetResult();
			if (!result.IsSuccessStatusCode)
			{
				HandleWebException(result);
			}
		}

		public KeyValuePair<int, string> GeneralRequest(string url, string method, string payload = null, ApiVersion api = 5, string clientId = null, string accessToken = null)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Invalid comparison between Unknown and I4
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected I4, but got Unknown
			HttpRequestMessage httpRequestMessage = new HttpRequestMessage
			{
				RequestUri = new Uri(url),
				Method = new HttpMethod(method)
			};
			if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(accessToken))
			{
				throw new InvalidCredentialException("A Client-Id or OAuth token is required to use the Twitch API. If you previously set them in InitializeAsync, please be sure to await the method.");
			}
			if (!string.IsNullOrEmpty(clientId))
			{
				httpRequestMessage.Headers.Add("Client-ID", clientId);
			}
			string text = "OAuth";
			if ((int)api == 6)
			{
				httpRequestMessage.Headers.Add(HttpRequestHeader.Accept.ToString(), "application/json");
				text = "Bearer";
			}
			else if ((int)api > 0)
			{
				httpRequestMessage.Headers.Add(HttpRequestHeader.Accept.ToString(), $"application/vnd.twitchtv.v{(int)api}+json");
			}
			if (!string.IsNullOrEmpty(accessToken))
			{
				httpRequestMessage.Headers.Add(HttpRequestHeader.Authorization.ToString(), text + " " + Helpers.FormatOAuth(accessToken));
			}
			if (payload != null)
			{
				httpRequestMessage.Content = new StringContent(payload, Encoding.UTF8, "application/json");
			}
			HttpResponseMessage result = _http.SendAsync(httpRequestMessage).GetAwaiter().GetResult();
			if (result.IsSuccessStatusCode)
			{
				string result2 = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
				return new KeyValuePair<int, string>((int)result.StatusCode, result2);
			}
			HandleWebException(result);
			return new KeyValuePair<int, string>(0, null);
		}

		public int RequestReturnResponseCode(string url, string method, List<KeyValuePair<string, string>> getParams = null)
		{
			if (getParams != null)
			{
				for (int i = 0; i < getParams.Count; i++)
				{
					url = ((i != 0) ? (url + "&" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)) : (url + "?" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)));
				}
			}
			HttpRequestMessage request = new HttpRequestMessage
			{
				RequestUri = new Uri(url),
				Method = new HttpMethod(method)
			};
			HttpResponseMessage result = _http.SendAsync(request).GetAwaiter().GetResult();
			return (int)result.StatusCode;
		}

		private void HandleWebException(HttpResponseMessage errorResp)
		{
			switch (errorResp.StatusCode)
			{
			case HttpStatusCode.BadRequest:
				throw new BadRequestException("Your request failed because either: \n 1. Your ClientID was invalid/not set. \n 2. Your refresh token was invalid. \n 3. You requested a username when the server was expecting a user ID.");
			case HttpStatusCode.Unauthorized:
			{
				HttpHeaderValueCollection<AuthenticationHeaderValue> wwwAuthenticate = errorResp.Headers.WwwAuthenticate;
				if (wwwAuthenticate == null || wwwAuthenticate.Count <= 0)
				{
					throw new BadScopeException("Your request was blocked due to bad credentials (Do you have the right scope for your access token?).");
				}
				throw new TokenExpiredException("Your request was blocked due to an expired Token. Please refresh your token and update your API instance settings.");
			}
			case HttpStatusCode.NotFound:
				throw new BadResourceException("The resource you tried to access was not valid.");
			case HttpStatusCode.UnprocessableEntity:
				throw new NotPartneredException("The resource you requested is only available to channels that have been partnered by Twitch.");
			case HttpStatusCode.TooManyRequests:
			{
				errorResp.Headers.TryGetValues("Ratelimit-Reset", out IEnumerable<string> values);
				throw new TooManyRequestsException("You have reached your rate limit. Too many requests were made", values.FirstOrDefault());
			}
			case HttpStatusCode.BadGateway:
				throw new BadGatewayException("The API answered with a 502 Bad Gateway. Please retry your request");
			case HttpStatusCode.GatewayTimeout:
				throw new GatewayTimeoutException("The API answered with a 504 Gateway Timeout. Please retry your request");
			case HttpStatusCode.InternalServerError:
				throw new InternalServerErrorException("The API answered with a 500 Internal Server Error. Please retry your request");
			case HttpStatusCode.Forbidden:
				throw new BadTokenException("The token provided in the request did not match the associated user. Make sure the token you're using is from the resource owner (streamer? viewer?)");
			default:
				throw new HttpRequestException("Something went wrong during the request! Please try again later");
			}
		}
	}
	public class TwitchWebRequest : IHttpCallHandler
	{
		private readonly ILogger<TwitchWebRequest> _logger;

		public TwitchWebRequest(ILogger<TwitchWebRequest> logger = null)
		{
			_logger = logger;
		}

		public void PutBytes(string url, byte[] payload)
		{
			try
			{
				using WebClient webClient = new WebClient();
				webClient.UploadData(new Uri(url), "PUT", payload);
			}
			catch (WebException e)
			{
				HandleWebException(e);
			}
		}

		public KeyValuePair<int, string> GeneralRequest(string url, string method, string payload = null, ApiVersion api = 5, string clientId = null, string accessToken = null)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Invalid comparison between Unknown and I4
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Invalid comparison between Unknown and I4
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected I4, but got Unknown
			HttpWebRequest httpWebRequest = WebRequest.CreateHttp(url);
			if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(accessToken))
			{
				throw new InvalidCredentialException("A Client-Id or OAuth token is required to use the Twitch API. If you previously set them in InitializeAsync, please be sure to await the method.");
			}
			if (!string.IsNullOrEmpty(clientId))
			{
				httpWebRequest.Headers["Client-ID"] = clientId;
			}
			httpWebRequest.Method = method;
			httpWebRequest.ContentType = "application/json";
			string text = "OAuth";
			if ((int)api == 6)
			{
				httpWebRequest.Accept = "application/json";
				text = "Bearer";
			}
			else if ((int)api > 0)
			{
				httpWebRequest.Accept = $"application/vnd.twitchtv.v{(int)api}+json";
			}
			if (!string.IsNullOrEmpty(accessToken))
			{
				httpWebRequest.Headers["Authorization"] = text + " " + Helpers.FormatOAuth(accessToken);
			}
			if (payload != null)
			{
				using StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStreamAsync().GetAwaiter().GetResult());
				streamWriter.Write(payload);
			}
			try
			{
				HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
				using StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream() ?? throw new InvalidOperationException());
				string value = streamReader.ReadToEnd();
				return new KeyValuePair<int, string>((int)httpWebResponse.StatusCode, value);
			}
			catch (WebException e)
			{
				HandleWebException(e);
			}
			return new KeyValuePair<int, string>(0, null);
		}

		public int RequestReturnResponseCode(string url, string method, List<KeyValuePair<string, string>> getParams = null)
		{
			if (getParams != null)
			{
				for (int i = 0; i < getParams.Count; i++)
				{
					url = ((i != 0) ? (url + "&" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)) : (url + "?" + getParams[i].Key + "=" + Uri.EscapeDataString(getParams[i].Value)));
				}
			}
			HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
			httpWebRequest.Method = method;
			HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
			return (int)httpWebResponse.StatusCode;
		}

		private void HandleWebException(WebException e)
		{
			if (!(e.Response is HttpWebResponse httpWebResponse))
			{
				throw e;
			}
			switch (httpWebResponse.StatusCode)
			{
			case HttpStatusCode.BadRequest:
				throw new BadRequestException("Your request failed because either: \n 1. Your ClientID was invalid/not set. \n 2. Your refresh token was invalid. \n 3. You requested a username when the server was expecting a user ID.");
			case HttpStatusCode.Unauthorized:
			{
				string[] values = httpWebResponse.Headers.GetValues("WWW-Authenticate");
				if ((values != null && values.Length == 0) || string.IsNullOrEmpty((values != null) ? values[0] : null))
				{
					throw new BadScopeException("Your request was blocked due to bad credentials (do you have the right scope for your access token?).");
				}
				if (values[0].Contains("error='invalid_token'"))
				{
					throw new TokenExpiredException("Your request was blocked du to an expired Token. Please refresh your token and update your API instance settings.");
				}
				break;
			}
			case HttpStatusCode.NotFound:
				throw new BadResourceException("The resource you tried to access was not valid.");
			case HttpStatusCode.TooManyRequests:
			{
				string resetTime = httpWebResponse.Headers.Get("Ratelimit-Reset");
				throw new TooManyRequestsException("You have reached your rate limit. Too many requests were made", resetTime);
			}
			case HttpStatusCode.UnprocessableEntity:
				throw new NotPartneredException("The resource you requested is only available to channels that have been partnered by Twitch.");
			default:
				throw e;
			}
		}
	}
}
namespace TwitchLib.Api.Core.Extensions.System
{
	public static class DateTimeExtensions
	{
		public static string ToRfc3339String(this DateTime dateTime)
		{
			return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
		}
	}
	public static class IEnumerableExtensions
	{
		public static void AddTo<T>(this IEnumerable<T> source, List<T> destination)
		{
			if (source != null)
			{
				destination.AddRange(source);
			}
		}
	}
}
namespace TwitchLib.Api.Core.Extensions.RateLimiter
{
	public static class IAwaitableConstraintExtension
	{
		public static IAwaitableConstraint Compose(this IAwaitableConstraint ac1, IAwaitableConstraint ac2)
		{
			IAwaitableConstraint result;
			if (ac1 != ac2)
			{
				IAwaitableConstraint val = (IAwaitableConstraint)(object)new ComposedAwaitableConstraint(ac1, ac2);
				result = val;
			}
			else
			{
				result = ac1;
			}
			return result;
		}
	}
}
namespace TwitchLib.Api.Core.Exceptions
{
	public class BadGatewayException : Exception
	{
		public BadGatewayException(string data)
			: base(data)
		{
		}
	}
	public class BadParameterException : Exception
	{
		public BadParameterException(string badParamData)
			: base(badParamData)
		{
		}
	}
	public class BadRequestException : Exception
	{
		public BadRequestException(string apiData)
			: base(apiData)
		{
		}
	}
	public class BadResourceException : Exception
	{
		public BadResourceException(string apiData)
			: base(apiData)
		{
		}
	}
	public class BadScopeException : Exception
	{
		public BadScopeException(string data)
			: base(data)
		{
		}
	}
	public class BadTokenException : Exception
	{
		public BadTokenException(string data)
			: base(data)
		{
		}
	}
	public class ClientIdAndOAuthTokenRequired : Exception
	{
		public ClientIdAndOAuthTokenRequired(string explanation)
			: base(explanation)
		{
		}
	}
	public class GatewayTimeoutException : Exception
	{
		public GatewayTimeoutException(string data)
			: base(data)
		{
		}
	}
	public class InternalServerErrorException : Exception
	{
		public InternalServerErrorException(string data)
			: base(data)
		{
		}
	}
	public class InvalidCredentialException : Exception
	{
		public InvalidCredentialException(string data)
			: base(data)
		{
		}
	}
	public class NotPartneredException : Exception
	{
		public NotPartneredException(string apiData)
			: base(apiData)
		{
		}
	}
	public class StreamOfflineException : Exception
	{
		public StreamOfflineException(string apiData)
			: base(apiData)
		{
		}
	}
	public class TokenExpiredException : Exception
	{
		public TokenExpiredException(string data)
			: base(data)
		{
		}
	}
	public sealed class TooManyRequestsException : Exception
	{
		public TooManyRequestsException(string data, string resetTime)
			: base(data)
		{
			if (double.TryParse(resetTime, out var result))
			{
				Data.Add("Ratelimit-Reset", result);
			}
		}
	}
	public class UnexpectedResponseException : Exception
	{
		public UnexpectedResponseException(string data)
			: base(data)
		{
		}
	}
}
namespace TwitchLib.Api.Core.Exceptions.UploadVideo
{
	public class InternalServerErrorException : Exception
	{
		public InternalServerErrorException(string apiData)
			: base(apiData)
		{
		}
	}
	public class InvalidUploadTokenException : Exception
	{
		public InvalidUploadTokenException(string apiData)
			: base(apiData)
		{
		}
	}
	public class InvalidVideoIdException : Exception
	{
		public InvalidVideoIdException(string apiData)
			: base(apiData)
		{
		}
	}
}
namespace TwitchLib.Api.Core.Exceptions.UploadVideo.UploadVideoPart
{
	public class BadPartException : Exception
	{
		public BadPartException(string apiData)
			: base(apiData)
		{
		}
	}
	public class ContentLengthRequiredException : Exception
	{
		public ContentLengthRequiredException(string apiData)
			: base(apiData)
		{
		}
	}
	public class UploadFailedException : Exception
	{
		public UploadFailedException(string apiData)
			: base(apiData)
		{
		}
	}
}
namespace TwitchLib.Api.Core.Exceptions.UploadVideo.CreateVideo
{
	public class InvalidChannelException : Exception
	{
		public InvalidChannelException(string apiData)
			: base(apiData)
		{
		}
	}
	public class UnauthorizedException : Exception
	{
		public UnauthorizedException(string apiData)
			: base(apiData)
		{
		}
	}
}
namespace TwitchLib.Api.Core.Exceptions.UploadVideo.CompleteUpload
{
	public class MissingPartsException : Exception
	{
		public MissingPartsException(string apiData)
			: base(apiData)
		{
		}
	}
}
namespace TwitchLib.Api.Core.Common
{
	public static class Helpers
	{
		public static string FormatOAuth(string token)
		{
			return token.Contains(" ") ? token.Split(new char[1] { ' ' })[1] : token;
		}

		public static string AuthScopesToString(AuthScopes scope)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected I4, but got Unknown
			return (scope - 1) switch
			{
				0 => "channel_check_subscription", 
				1 => "channel_commercial", 
				2 => "channel_editor", 
				3 => "channel_feed_edit", 
				4 => "channel_feed_read", 
				5 => "channel_read", 
				6 => "channel_stream", 
				7 => "channel_subscriptions", 
				8 => "chat_login", 
				9 => "collections_edit", 
				10 => "communities_edit", 
				11 => "communities_moderate", 
				12 => "user_blocks_edit", 
				13 => "user_blocks_read", 
				14 => "user_follows_edit", 
				15 => "user_read", 
				16 => "user_subscriptions", 
				17 => "viewing_activity_read", 
				18 => "openid", 
				19 => "user:edit", 
				20 => "user:read:email", 
				21 => "clips:edit", 
				23 => "analytics:read:games", 
				24 => "analytics:read:extensions", 
				22 => "bits:read", 
				25 => "user:edit:broadcast", 
				26 => "user:read:broadcast", 
				27 => "channel:read:subscriptions", 
				_ => "", 
			};
		}

		public static string Base64Encode(string plainText)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(plainText);
			return Convert.ToBase64String(bytes);
		}
	}
}

lib/TwitchLib.Api.Core.Enums.dll

Decompiled 5 months ago
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing the enums of TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.2")]
[assembly: AssemblyInformationalVersion("3.1.2")]
[assembly: AssemblyProduct("TwitchLib.Api.Core.Enums")]
[assembly: AssemblyTitle("TwitchLib.Api.Core.Enums")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.2.0")]
namespace TwitchLib.Api.Core.Enums;

public enum ApiVersion
{
	V5 = 5,
	Helix = 6,
	Void = 0
}
public enum AuthScopes
{
	Any,
	Channel_Check_Subscription,
	Channel_Commercial,
	Channel_Editor,
	Channel_Feed_Edit,
	Channel_Feed_Read,
	Channel_Read,
	Channel_Stream,
	Channel_Subscriptions,
	Chat_Login,
	Collections_Edit,
	Communities_Edit,
	Communities_Moderate,
	User_Blocks_Edit,
	User_Blocks_Read,
	User_Follows_Edit,
	User_Read,
	User_Subscriptions,
	Viewing_Activity_Read,
	OpenId,
	Helix_User_Edit,
	Helix_User_Read_Email,
	Helix_Clips_Edit,
	Helix_Bits_Read,
	Helix_Analytics_Read_Games,
	Helix_Analytics_Read_Extensions,
	Helix_User_Edit_Broadcast,
	Helix_User_Read_Broadcast,
	Helix_Channel_Read_Subscriptions,
	Helix_Moderation_Read,
	None
}
public enum BadgeColor
{
	Red = 10000,
	Blue = 5000,
	Green = 1000,
	Purple = 100,
	Gray = 1
}
public enum BitsLeaderboardPeriodEnum
{
	Day,
	Week,
	Month,
	Year,
	All
}
public enum BroadcastType
{
	All,
	Archive,
	Highlight
}
public enum ChatColorPresets
{
	Blue,
	Coral,
	DodgerBlue,
	SpringGreen,
	YellowGreen,
	Green,
	OrangeRed,
	Red,
	GoldenRod,
	HotPink,
	CadetBlue,
	SeaGreen,
	Chocolate,
	BlueViolet,
	Firebrick
}
public enum CodeStatusEnum
{
	SUCCESSFULLY_REDEEMED,
	ALREADY_CLAIMED,
	EXPIRED,
	USER_NOT_ELIGIBLE,
	NOT_FOUND,
	INACTIVE,
	UNUSED,
	INCORRECT_FORMAT,
	INTERNAL_ERROR
}
public enum CommercialLength
{
	Seconds30 = 30,
	Seconds60 = 60,
	Seconds90 = 90,
	Seconds120 = 120,
	Seconds150 = 150,
	Seconds180 = 180
}
public enum Direction
{
	Ascending,
	Descending
}
public enum EntitleGrantType
{
	BulkDropsGrant
}
public enum ExtensionType
{
	Panel,
	Overlay,
	Component
}
public enum GameSearchType
{
	Suggest
}
public enum LogType
{
	Normal,
	Failure,
	Success
}
public enum Noisy
{
	NotSet,
	True,
	False
}
public enum Period
{
	Day,
	Week,
	Month,
	All
}
public enum PubSubRequestType
{
	ListenToTopic
}
public enum SendReceiveDirection
{
	Sent,
	Received
}
public enum SortBy
{
	CreatedAt,
	LastBroadcast,
	Login
}
public enum SortDirection
{
	Descending,
	Ascending
}
public enum SortKey
{
	CreatedAt,
	LastBroadcaster,
	Login
}
public enum StreamIdentifierType : byte
{
	Usernames,
	UserIds
}
public enum StreamType
{
	Live,
	Playlist,
	All
}
public abstract class StringEnum
{
	public string Value { get; }

	protected StringEnum(string value)
	{
		Value = value;
	}

	public override string ToString()
	{
		return Value;
	}
}
public enum SubscriptionPlan
{
	NotSet,
	Prime,
	Tier1,
	Tier2,
	Tier3
}
public enum ThrottleType
{
	MessageTooShort,
	MessageTooLong
}
public enum UserType : byte
{
	Viewer,
	VIP,
	Moderator,
	GlobalModerator,
	Broadcaster,
	Admin,
	Staff
}
public enum VideoPlaybackType
{
	StreamUp,
	StreamDown,
	ViewCount
}
public enum VideoSort
{
	Time,
	Trending,
	Views
}
public enum VideoType
{
	All,
	Upload,
	Archive,
	Highlight
}
public enum Viewable
{
	Public,
	Private
}
public enum WebhookCallMode
{
	Subscribe,
	Unsubscribe
}

lib/TwitchLib.Api.Core.Interfaces.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using TwitchLib.Api.Core.Enums;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing all of the interfaces used in TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.2")]
[assembly: AssemblyInformationalVersion("3.1.2")]
[assembly: AssemblyProduct("TwitchLib.Api.Core.Interfaces")]
[assembly: AssemblyTitle("TwitchLib.Api.Core.Interfaces")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.2.0")]
namespace TwitchLib.Api.Core.Interfaces
{
	public interface IApiSettings
	{
		string AccessToken { get; set; }

		string Secret { get; set; }

		string ClientId { get; set; }

		bool SkipDynamicScopeValidation { get; set; }

		bool SkipAutoServerTokenGeneration { get; set; }

		List<AuthScopes> Scopes { get; set; }

		event PropertyChangedEventHandler PropertyChanged;
	}
	public interface IAwaitableConstraint
	{
		Task<IDisposable> WaitForReadiness(CancellationToken cancellationToken);
	}
	public interface IFollow
	{
		DateTime CreatedAt { get; }

		bool Notifications { get; }

		IUser User { get; }
	}
	public interface IFollows
	{
		int Total { get; }

		string Cursor { get; }

		IFollow[] Follows { get; }
	}
	public interface IHttpCallHandler
	{
		KeyValuePair<int, string> GeneralRequest(string url, string method, string payload = null, ApiVersion api = 5, string clientId = null, string accessToken = null);

		void PutBytes(string url, byte[] payload);

		int RequestReturnResponseCode(string url, string method, List<KeyValuePair<string, string>> getParams = null);
	}
	public interface IRateLimiter
	{
		Task Perform(Func<Task> perform, CancellationToken cancellationToken);

		Task Perform(Func<Task> perform);

		Task<T> Perform<T>(Func<Task<T>> perform);

		Task<T> Perform<T>(Func<Task<T>> perform, CancellationToken cancellationToken);

		Task Perform(Action perform, CancellationToken cancellationToken);

		Task Perform(Action perform);

		Task<T> Perform<T>(Func<T> perform);

		Task<T> Perform<T>(Func<T> perform, CancellationToken cancellationToken);
	}
	public interface ITime
	{
		DateTime GetTimeNow();

		Task GetDelay(TimeSpan timespan, CancellationToken cancellationToken);
	}
	public interface IUser
	{
		string Id { get; }

		string Bio { get; }

		DateTime CreatedAt { get; }

		string DisplayName { get; }

		string Logo { get; }

		string Name { get; }

		string Type { get; }

		DateTime UpdatedAt { get; }
	}
}
namespace TwitchLib.Api.Core.Interfaces.Clips
{
	public interface IClip
	{
		IVOD VOD { get; }
	}
	public interface IVOD
	{
		string Id { get; }

		string Url { get; }

		int Offset { get; }

		string PreviewImageUrl { get; }
	}
}

lib/TwitchLib.Api.Core.Models.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Newtonsoft.Json;
using TwitchLib.Api.Core.Enums;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing the core models used in TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.3")]
[assembly: AssemblyInformationalVersion("3.1.3")]
[assembly: AssemblyProduct("TwitchLib.Api.Core.Models")]
[assembly: AssemblyTitle("TwitchLib.Api.Core.Models")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.3.0")]
namespace TwitchLib.Api.Core.Models
{
	public class CredentialCheckResponseModel
	{
		public bool Result { get; set; }

		public string ResultMessage { get; set; }
	}
	public abstract class RequestModel
	{
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.TwitchPrimeOffers
{
	public class Asset
	{
		[JsonProperty(PropertyName = "assetType")]
		public string AssetType { get; protected set; }

		[JsonProperty(PropertyName = "location")]
		public string Location { get; protected set; }

		[JsonProperty(PropertyName = "location2x")]
		public string Location2x { get; protected set; }

		[JsonProperty(PropertyName = "mediaType")]
		public string MediaType { get; protected set; }
	}
	public class Offer
	{
		[JsonProperty(PropertyName = "applicableGame")]
		public string ApplicableGame { get; protected set; }

		[JsonProperty(PropertyName = "assets")]
		public Asset[] Assets { get; protected set; }

		[JsonProperty(PropertyName = "contentCategories")]
		public string[] ContentCategories { get; protected set; }

		[JsonProperty(PropertyName = "contentClaimInstructions")]
		public string ContentClaimInstruction { get; protected set; }

		[JsonProperty(PropertyName = "contentDeliveryMethod")]
		public string ContentDeliveryMethod { get; protected set; }

		[JsonProperty(PropertyName = "endTime")]
		public DateTime EndTime { get; protected set; }

		[JsonProperty(PropertyName = "offerDescription")]
		public string OfferDescription { get; protected set; }

		[JsonProperty(PropertyName = "offerId")]
		public string OfferId { get; protected set; }

		[JsonProperty(PropertyName = "offerTitle")]
		public string OfferTitle { get; protected set; }

		[JsonProperty(PropertyName = "priority")]
		public int Priority { get; protected set; }

		[JsonProperty(PropertyName = "publisherName")]
		public string PublisherName { get; protected set; }

		[JsonProperty(PropertyName = "startTime")]
		public DateTime StartTime { get; protected set; }
	}
	public class TwitchPrimeOffers
	{
		[JsonProperty(PropertyName = "offers")]
		public Offer[] Offers { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.RecentMessages
{
	public class RecentMessagesResponse
	{
		[JsonProperty(PropertyName = "messages")]
		public string[] Messages { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.RecentEvents
{
	public class Recent
	{
		[JsonProperty(PropertyName = "has_recent_events")]
		public bool HasRecentEvents { get; protected set; }

		[JsonProperty(PropertyName = "message_id")]
		public string MessageId { get; protected set; }

		[JsonProperty(PropertyName = "timestamp")]
		public string Timestamp { get; protected set; }

		[JsonProperty(PropertyName = "channel_id")]
		public string ChannelId { get; protected set; }

		[JsonProperty(PropertyName = "allotted_time_ms")]
		public long AllottedTimeMs { get; protected set; }

		[JsonProperty(PropertyName = "time_remaining_ms")]
		public long TimeRemainingMs { get; protected set; }

		[JsonProperty(PropertyName = "amount")]
		public int Amount { get; protected set; }

		[JsonProperty(PropertyName = "bits_used")]
		public int? BitsUsed { get; protected set; }

		[JsonProperty(PropertyName = "message")]
		public string Message { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "username")]
		public string Username { get; protected set; }
	}
	public class RecentEvents
	{
		[JsonProperty(PropertyName = "recent")]
		public Recent Recent { get; protected set; }

		[JsonProperty(PropertyName = "top")]
		public Top Top { get; protected set; }

		[JsonProperty(PropertyName = "has_recent_event")]
		public bool HasRecentEvent { get; protected set; }

		[JsonProperty(PropertyName = "message_id")]
		public string MessageId { get; protected set; }

		[JsonProperty(PropertyName = "timestamp")]
		public string Timestamp { get; protected set; }

		[JsonProperty(PropertyName = "channel_id")]
		public string ChannelId { get; protected set; }

		[JsonProperty(PropertyName = "allotted_time_ms")]
		public string AllottedTimeMs { get; protected set; }

		[JsonProperty(PropertyName = "time_remaining_ms")]
		public string TimeRemainingMs { get; protected set; }

		[JsonProperty(PropertyName = "amount")]
		public int Amount { get; protected set; }

		[JsonProperty(PropertyName = "bits_used")]
		public int? BitsUsed { get; protected set; }

		[JsonProperty(PropertyName = "message")]
		public string Message { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "username")]
		public string Username { get; protected set; }
	}
	public class Top
	{
		[JsonProperty(PropertyName = "has_top_event")]
		public bool HasTopEvent { get; protected set; }

		[JsonProperty(PropertyName = "message_id")]
		public string MessageId { get; protected set; }

		[JsonProperty(PropertyName = "amount")]
		public int Amount { get; protected set; }

		[JsonProperty(PropertyName = "bits_used")]
		public int? BitsUsed { get; protected set; }

		[JsonProperty(PropertyName = "message")]
		public string Message { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "username")]
		public string Username { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.Hosting
{
	public class ChannelHostsResponse
	{
		[JsonProperty(PropertyName = "hosts")]
		public HostListing[] Hosts { get; protected set; }
	}
	public class HostListing
	{
		[JsonProperty(PropertyName = "host_id")]
		public string HostId { get; protected set; }

		[JsonProperty(PropertyName = "target_id")]
		public string TargetId { get; protected set; }

		[JsonProperty(PropertyName = "host_login")]
		public string HostLogin { get; protected set; }

		[JsonProperty(PropertyName = "target_login")]
		public string TargetLogin { get; protected set; }

		[JsonProperty(PropertyName = "host_display_name")]
		public string HostDisplayName { get; protected set; }

		[JsonProperty(PropertyName = "target_display_name")]
		public string TargetDisplayName { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.CSStreams
{
	public class Box
	{
		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class CSStream
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "viewers")]
		public int Viewers { get; protected set; }

		[JsonProperty(PropertyName = "map")]
		public string Map { get; protected set; }

		[JsonProperty(PropertyName = "map_name")]
		public string MapName { get; protected set; }

		[JsonProperty(PropertyName = "map_img")]
		public string MapImg { get; protected set; }

		[JsonProperty(PropertyName = "skill")]
		public int Skill { get; protected set; }

		[JsonProperty(PropertyName = "preview")]
		public Preview Preview { get; protected set; }

		[JsonProperty(PropertyName = "is_playlist")]
		public bool IsPlaylist { get; protected set; }

		[JsonProperty(PropertyName = "user")]
		public User User { get; protected set; }
	}
	public class CSStreams
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "streams")]
		public CSStream[] Streams { get; protected set; }
	}
	public class LocalizedGame
	{
		[JsonProperty(PropertyName = "name")]
		public string Name { get; protected set; }

		[JsonProperty(PropertyName = "popularity")]
		public int Popularity { get; protected set; }

		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "giantbomb_id")]
		public string GiantbombId { get; protected set; }

		[JsonProperty(PropertyName = "box")]
		public Box Box { get; protected set; }

		[JsonProperty(PropertyName = "logo")]
		public Logo Logo { get; protected set; }

		[JsonProperty(PropertyName = "localized_name")]
		public string LocalizedName { get; protected set; }

		[JsonProperty(PropertyName = "locale")]
		public string Locale { get; protected set; }
	}
	public class Logo
	{
		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class Preview
	{
		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class User
	{
		[JsonProperty(PropertyName = "mature")]
		public bool Mature { get; protected set; }

		[JsonProperty(PropertyName = "status")]
		public string Status { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_language")]
		public string BroadcasterLanguage { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "localized_game")]
		public LocalizedGame LocalizedGame { get; protected set; }

		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

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

		[JsonProperty(PropertyName = "bio")]
		public string Bio { get; protected set; }

		[JsonProperty(PropertyName = "partner")]
		public bool Partner { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }

		[JsonProperty(PropertyName = "delay")]
		public string Delay { get; protected set; }

		[JsonProperty(PropertyName = "prerolls")]
		public bool Prerolls { get; protected set; }

		[JsonProperty(PropertyName = "postrolls")]
		public bool Postrolls { get; protected set; }

		[JsonProperty(PropertyName = "primary_team_name")]
		public string PrimaryTeamName { get; protected set; }

		[JsonProperty(PropertyName = "primary_team_display_name")]
		public string PrimaryTeamDisplayName { get; protected set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; protected set; }

		[JsonProperty(PropertyName = "banner")]
		public string Banner { get; protected set; }

		[JsonProperty(PropertyName = "video_banner")]
		public string VideoBanner { get; protected set; }

		[JsonProperty(PropertyName = "background")]
		public string Background { get; protected set; }

		[JsonProperty(PropertyName = "profile_banner")]
		public string ProfileBanner { get; protected set; }

		[JsonProperty(PropertyName = "profile_banner_background_color")]
		public string ProfileBannerBackgroundColor { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }

		[JsonProperty(PropertyName = "followers")]
		public int Followers { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.CSMaps
{
	public class CSMapsResponse
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "maps")]
		public Map[] Maps { get; protected set; }
	}
	public class Map
	{
		[JsonProperty(PropertyName = "map")]
		public string MapCode { get; protected set; }

		[JsonProperty(PropertyName = "map_name")]
		public string MapName { get; protected set; }

		[JsonProperty(PropertyName = "map_image")]
		public string MapImage { get; protected set; }

		[JsonProperty(PropertyName = "viewers")]
		public int Viewers { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.Comments
{
	public class Comment
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; set; }

		[JsonProperty(PropertyName = "created_at")]
		public object CreatedAt { get; set; }

		[JsonProperty(PropertyName = "updated_at")]
		public object UpdatedAt { get; set; }

		[JsonProperty(PropertyName = "channel_id")]
		public string ChannelId { get; set; }

		[JsonProperty(PropertyName = "content_type")]
		public string ContentType { get; set; }

		[JsonProperty(PropertyName = "content_id")]
		public string ContentId { get; set; }

		[JsonProperty(PropertyName = "content_offset_seconds")]
		public float ContentOffsetSeconds { get; set; }

		[JsonProperty(PropertyName = "commenter")]
		public Commenter Commenter { get; set; }

		[JsonProperty(PropertyName = "source")]
		public string Source { get; set; }

		[JsonProperty(PropertyName = "state")]
		public string State { get; set; }

		[JsonProperty(PropertyName = "message")]
		public Message Message { get; set; }

		[JsonProperty(PropertyName = "more_replies")]
		public bool MoreReplies { get; set; }
	}
	public class Commenter
	{
		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; set; }

		[JsonProperty(PropertyName = "_id")]
		public string Id { get; set; }

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

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

		[JsonProperty(PropertyName = "bio")]
		public string Bio { get; set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; set; }
	}
	public class CommentsPage
	{
		[JsonProperty(PropertyName = "comments")]
		public Comment[] Comments { get; set; }

		[JsonProperty(PropertyName = "_prev")]
		public string Prev { get; set; }

		[JsonProperty(PropertyName = "_next")]
		public string Next { get; set; }
	}
	public class Emoticon
	{
		[JsonProperty(PropertyName = "emoticon_id")]
		public string EmoticonId { get; set; }

		[JsonProperty(PropertyName = "emoticon_set_id")]
		public string EmoticonSetId { get; set; }
	}
	public class Emoticons
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; set; }

		[JsonProperty(PropertyName = "begin")]
		public int Begin { get; set; }

		[JsonProperty(PropertyName = "end")]
		public int End { get; set; }
	}
	public class Fragment
	{
		[JsonProperty(PropertyName = "text")]
		public string Text { get; set; }

		[JsonProperty(PropertyName = "emoticon")]
		public Emoticon Emoticon { get; set; }
	}
	public class Message
	{
		[JsonProperty(PropertyName = "body")]
		public string Body { get; set; }

		[JsonProperty(PropertyName = "emoticons")]
		public Emoticons[] Emoticons { get; set; }

		[JsonProperty(PropertyName = "fragments")]
		public Fragment[] Fragments { get; set; }

		[JsonProperty(PropertyName = "is_action")]
		public bool IsAction { get; set; }

		[JsonProperty(PropertyName = "user_color")]
		public string UserColor { get; set; }

		[JsonProperty(PropertyName = "user_badges")]
		public UserBadges[] UserBadges { get; set; }
	}
	public class UserBadges
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; set; }

		[JsonProperty(PropertyName = "version")]
		public string Version { get; set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.ClipChat
{
	public class GetClipChatResponse
	{
		[JsonProperty(PropertyName = "data")]
		public ReChatMessage[] Messages { get; protected set; }
	}
	public class ReChatMessage
	{
		[JsonProperty(PropertyName = "type")]
		public string Type { get; protected set; }

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

		[JsonProperty(PropertyName = "attributes")]
		public ReChatMessageAttributes Attributes { get; protected set; }
	}
	public class ReChatMessageAttributes
	{
		[JsonProperty(PropertyName = "command")]
		public string Command { get; protected set; }

		[JsonProperty(PropertyName = "room")]
		public string Room { get; protected set; }

		[JsonProperty(PropertyName = "timestamp")]
		public string Timestamp { get; protected set; }

		[JsonProperty(PropertyName = "video-offset")]
		public long VideoOffset { get; protected set; }

		[JsonProperty(PropertyName = "deleted")]
		public bool Deleted { get; protected set; }

		[JsonProperty(PropertyName = "message")]
		public string Message { get; protected set; }

		[JsonProperty(PropertyName = "from")]
		public string From { get; protected set; }

		[JsonProperty(PropertyName = "tags")]
		public ReChatMessageAttributesTags Tags { get; protected set; }

		[JsonProperty(PropertyName = "color")]
		public string Color { get; protected set; }
	}
	public class ReChatMessageAttributesTags
	{
		[JsonProperty(PropertyName = "badges")]
		public string Badges { get; protected set; }

		[JsonProperty(PropertyName = "color")]
		public string Color { get; protected set; }

		[JsonProperty(PropertyName = "display-name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "emotes")]
		public Dictionary<string, int[][]> Emotes { get; protected set; }

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

		[JsonProperty(PropertyName = "mod")]
		public bool Mod { get; protected set; }

		[JsonProperty(PropertyName = "room-id")]
		public string RoomId { get; protected set; }

		[JsonProperty(PropertyName = "sent-ts")]
		public string SentTs { get; protected set; }

		[JsonProperty(PropertyName = "subscriber")]
		public bool Subscriber { get; protected set; }

		[JsonProperty(PropertyName = "tmi-sent-ts")]
		public string TmiSentTs { get; protected set; }

		[JsonProperty(PropertyName = "turbo")]
		public bool Turbo { get; protected set; }

		[JsonProperty(PropertyName = "user-id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user-type")]
		public string UserType { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.ChatUser
{
	public class ChatUser
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "version")]
		public string Version { get; protected set; }
	}
	public class ChatUserResponse
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "login")]
		public string Login { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "color")]
		public string Color { get; protected set; }

		[JsonProperty(PropertyName = "is_verified_bot")]
		public bool IsVerifiedBot { get; protected set; }

		[JsonProperty(PropertyName = "badges")]
		public List<ChatUser> Badges { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.Chatters
{
	public class ChatterFormatted
	{
		public string Username { get; protected set; }

		public UserType UserType { get; set; }

		public ChatterFormatted(string username, UserType userType)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Username = username;
			UserType = userType;
		}
	}
	public class Chatters
	{
		[JsonProperty(PropertyName = "moderators")]
		public string[] Moderators { get; protected set; }

		[JsonProperty(PropertyName = "staff")]
		public string[] Staff { get; protected set; }

		[JsonProperty(PropertyName = "admins")]
		public string[] Admins { get; protected set; }

		[JsonProperty(PropertyName = "global_mods")]
		public string[] GlobalMods { get; protected set; }

		[JsonProperty(PropertyName = "vips")]
		public string[] VIP { get; protected set; }

		[JsonProperty(PropertyName = "viewers")]
		public string[] Viewers { get; protected set; }
	}
	public class ChattersResponse
	{
		[JsonProperty(PropertyName = "chatter_count")]
		public int ChatterCount { get; protected set; }

		[JsonProperty(PropertyName = "chatters")]
		public Chatters Chatters { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.ChatProperties
{
	public class ChatProperties
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "hide_chat_links")]
		public bool HideChatLinks { get; protected set; }

		[JsonProperty(PropertyName = "chat_delay_duration")]
		public int ChatDelayDuration { get; protected set; }

		[JsonProperty(PropertyName = "chat_rules")]
		public string[] ChatRules { get; protected set; }

		[JsonProperty(PropertyName = "twitchbot_rule_id")]
		public int TwitchbotRuleId { get; protected set; }

		[JsonProperty(PropertyName = "devchat")]
		public bool DevChat { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "subsonly")]
		public bool SubsOnly { get; protected set; }

		[JsonProperty(PropertyName = "chat_servers")]
		public string[] ChatServers { get; protected set; }

		[JsonProperty(PropertyName = "web_socket_servers")]
		public string[] WebSocketServers { get; protected set; }

		[JsonProperty(PropertyName = "web_socket_pct")]
		public double WebSocketPct { get; protected set; }

		[JsonProperty(PropertyName = "darklaunch_pct")]
		public double DarkLaunchPct { get; protected set; }

		[JsonProperty(PropertyName = "available_chat_notification_tokens")]
		public string[] AvailableChatNotificationTokens { get; protected set; }

		[JsonProperty(PropertyName = "sce_title_preset_text_1")]
		public string SceTitlePresetText1 { get; protected set; }

		[JsonProperty(PropertyName = "sce_title_preset_text_2")]
		public string SceTitlePresetText2 { get; protected set; }

		[JsonProperty(PropertyName = "sce_title_preset_text_3")]
		public string SceTitlePresetText3 { get; protected set; }

		[JsonProperty(PropertyName = "sce_title_preset_text_4")]
		public string SceTitlePresetText4 { get; protected set; }

		[JsonProperty(PropertyName = "sce_title_preset_text_5")]
		public string SceTitlePresetText5 { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.ChannelPanels
{
	public class Data
	{
		[JsonProperty(PropertyName = "link")]
		public string Link { get; protected set; }

		[JsonProperty(PropertyName = "image")]
		public string Image { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }
	}
	public class Panel
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "display_order")]
		public int DisplayOrder { get; protected set; }

		[JsonProperty(PropertyName = "default")]
		public string Kind { get; protected set; }

		[JsonProperty(PropertyName = "html_description")]
		public string HtmlDescription { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "data")]
		public Data Data { get; protected set; }

		[JsonProperty(PropertyName = "channel")]
		public string Channel { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Undocumented.ChannelExtensionData
{
	public class ActivationConfig
	{
		[JsonProperty(PropertyName = "slot")]
		public string Slot { get; protected set; }

		[JsonProperty(PropertyName = "anchor")]
		public string Anchor { get; protected set; }
	}
	public class Extension
	{
		[JsonProperty(PropertyName = "ud")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "state")]
		public string State { get; protected set; }

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

		[JsonProperty(PropertyName = "anchor")]
		public string Anchor { get; protected set; }

		[JsonProperty(PropertyName = "panel_height")]
		public int PanelHeight { get; protected set; }

		[JsonProperty(PropertyName = "author_name")]
		public string AuthorName { get; protected set; }

		[JsonProperty(PropertyName = "support_email")]
		public string SupportEmail { get; protected set; }

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

		[JsonProperty(PropertyName = "description")]
		public string Description { get; protected set; }

		[JsonProperty(PropertyName = "summary")]
		public string Summary { get; protected set; }

		[JsonProperty(PropertyName = "viewer_url")]
		public string ViewerUrl { get; protected set; }

		[JsonProperty(PropertyName = "viewer_urls")]
		public ViewerUrls ViewerUrls { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public Views Views { get; protected set; }

		[JsonProperty(PropertyName = "config_url")]
		public string ConfigUrl { get; protected set; }

		[JsonProperty(PropertyName = "live_config_url")]
		public string LiveConfigUrl { get; protected set; }

		[JsonProperty(PropertyName = "icon_url")]
		public string IconUrl { get; protected set; }

		[JsonProperty(PropertyName = "icon_urls")]
		public IconUrls IconUrls { get; protected set; }

		[JsonProperty(PropertyName = "screenshot_urls")]
		public string[] ScreenshotUrls { get; protected set; }

		[JsonProperty(PropertyName = "installation_count")]
		public int InstallationCount { get; protected set; }

		[JsonProperty(PropertyName = "can_install")]
		public bool CanInstall { get; protected set; }

		[JsonProperty(PropertyName = "whitelisted_panel_urls")]
		public string[] WhitelistedPanelUrls { get; protected set; }

		[JsonProperty(PropertyName = "whitelisted_config_urls")]
		public string[] WhitelistedConfigUrls { get; protected set; }

		[JsonProperty(PropertyName = "eula_tos_url")]
		public string EulaTosUrl { get; protected set; }

		[JsonProperty(PropertyName = "privacy_policy_url")]
		public string PrivacyPolicyUrl { get; protected set; }

		[JsonProperty(PropertyName = "request_identity_link")]
		public bool RequestIdentityLink { get; protected set; }

		[JsonProperty(PropertyName = "vendor_code")]
		public string VendorCode { get; protected set; }

		[JsonProperty(PropertyName = "sku")]
		public string SKU { get; protected set; }

		[JsonProperty(PropertyName = "bits_enabled")]
		public bool BitsEnabled { get; protected set; }
	}
	public class ExtToken
	{
		[JsonProperty(PropertyName = "extension_id")]
		public string ExtensionId { get; protected set; }

		[JsonProperty(PropertyName = "token")]
		public string Token { get; protected set; }
	}
	public class GetChannelExtensionDataResponse
	{
		[JsonProperty(PropertyName = "issued_at")]
		public string IssuedAt { get; protected set; }

		[JsonProperty(PropertyName = "tokens")]
		public ExtToken[] Tokens { get; protected set; }

		[JsonProperty(PropertyName = "installed_extensions")]
		public InstalledExtension[] InstalledExtensions { get; protected set; }
	}
	public class IconUrls
	{
		[JsonProperty(PropertyName = "100x100")]
		public string Url100x100 { get; protected set; }
	}
	public class InstallationStatus
	{
		[JsonProperty(PropertyName = "extension_id")]
		public string ExtensionId { get; protected set; }

		[JsonProperty(PropertyName = "activation_config")]
		public ActivationConfig ActivationConfig { get; protected set; }

		[JsonProperty(PropertyName = "activation_state")]
		public string ActivationState { get; protected set; }

		[JsonProperty(PropertyName = "can_activate")]
		public bool CanActivate { get; protected set; }
	}
	public class InstalledExtension
	{
		[JsonProperty(PropertyName = "extension")]
		public Extension Extension { get; protected set; }

		[JsonProperty(PropertyName = "installation_status")]
		public InstallationStatus InstallationStatus { get; protected set; }
	}
	public class View
	{
		[JsonProperty(PropertyName = "viewer_url")]
		public string ViewerUrl { get; protected set; }
	}
	public class ViewerUrls
	{
		[JsonProperty(PropertyName = "video_overlay")]
		public string VideoOverlay { get; protected set; }
	}
	public class Views
	{
		[JsonProperty(PropertyName = "video_overlay")]
		public View VideoOverlay { get; protected set; }

		[JsonProperty(PropertyName = "config")]
		public View Config { get; protected set; }
	}
}
namespace TwitchLib.Api.Core.Models.Root
{
	public class Root
	{
		[JsonProperty(PropertyName = "token")]
		public RootToken Token { get; protected set; }
	}
	public class RootAuthorization
	{
		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "scopes")]
		public string[] Scopes { get; protected set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }
	}
	public class RootToken
	{
		[JsonProperty(PropertyName = "authorization")]
		public RootAuthorization Auth { get; protected set; }

		[JsonProperty(PropertyName = "client_id")]
		public string ClientId { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string Username { get; protected set; }

		[JsonProperty(PropertyName = "valid")]
		public bool Valid { get; protected set; }
	}
}

lib/TwitchLib.Api.dll

Decompiled 5 months ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
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.Versioning;
using System.Threading.Tasks;
using System.Timers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TwitchLib.Api.Core;
using TwitchLib.Api.Core.Common;
using TwitchLib.Api.Core.Enums;
using TwitchLib.Api.Core.HttpCallHandlers;
using TwitchLib.Api.Core.Interfaces;
using TwitchLib.Api.Core.RateLimiter;
using TwitchLib.Api.Core.Undocumented;
using TwitchLib.Api.Events;
using TwitchLib.Api.Helix;
using TwitchLib.Api.Helix.Models.Helpers;
using TwitchLib.Api.Helix.Models.Streams;
using TwitchLib.Api.Helix.Models.Users;
using TwitchLib.Api.Interfaces;
using TwitchLib.Api.Services.Core;
using TwitchLib.Api.Services.Core.FollowerService;
using TwitchLib.Api.Services.Core.LiveStreamMonitor;
using TwitchLib.Api.Services.Events;
using TwitchLib.Api.Services.Events.FollowerService;
using TwitchLib.Api.Services.Events.LiveStreamMonitor;
using TwitchLib.Api.ThirdParty;
using TwitchLib.Api.ThirdParty.AuthorizationFlow;
using TwitchLib.Api.ThirdParty.ModLookup;
using TwitchLib.Api.ThirdParty.UsernameChange;
using TwitchLib.Api.V5;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Api component of TwitchLib. This component allows you to access the Twitch API using both authenticated and unauthenticated calls, as well as undocumented and third party APIs.")]
[assembly: AssemblyFileVersion("3.1.2")]
[assembly: AssemblyInformationalVersion("3.1.2")]
[assembly: AssemblyProduct("TwitchLib.Api")]
[assembly: AssemblyTitle("TwitchLib.Api")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.2.0")]
namespace TwitchLib.Api
{
	public class TwitchAPI : ITwitchAPI
	{
		private readonly ILogger<TwitchAPI> _logger;

		public IApiSettings Settings { get; }

		public V5 V5 { get; }

		public Helix Helix { get; }

		public TwitchLib.Api.ThirdParty.ThirdParty ThirdParty { get; }

		public Undocumented Undocumented { get; }

		public TwitchAPI(ILoggerFactory loggerFactory = null, IRateLimiter rateLimiter = null, IApiSettings settings = null, IHttpCallHandler http = null)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_0045: 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)
			_logger = loggerFactory?.CreateLogger<TwitchAPI>();
			rateLimiter = (IRateLimiter)(((object)rateLimiter) ?? ((object)BypassLimiter.CreateLimiterBypassInstance()));
			http = (IHttpCallHandler)(((object)http) ?? ((object)new TwitchHttpClient(loggerFactory?.CreateLogger<TwitchHttpClient>())));
			Settings = (IApiSettings)(((object)settings) ?? ((object)new ApiSettings()));
			Helix = new Helix(loggerFactory, rateLimiter, Settings, http);
			V5 = new V5(loggerFactory, rateLimiter, Settings, http);
			ThirdParty = new TwitchLib.Api.ThirdParty.ThirdParty(Settings, rateLimiter, http);
			Undocumented = new Undocumented(Settings, rateLimiter, http);
			Settings.PropertyChanged += SettingsPropertyChanged;
		}

		private void SettingsPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			switch (e.PropertyName)
			{
			case "AccessToken":
				V5.Settings.AccessToken = Settings.AccessToken;
				Helix.Settings.AccessToken = Settings.AccessToken;
				break;
			case "Secret":
				V5.Settings.Secret = Settings.Secret;
				Helix.Settings.Secret = Settings.Secret;
				break;
			case "ClientId":
				V5.Settings.ClientId = Settings.ClientId;
				Helix.Settings.ClientId = Settings.ClientId;
				break;
			case "SkipDynamicScopeValidation":
				V5.Settings.SkipDynamicScopeValidation = Settings.SkipDynamicScopeValidation;
				Helix.Settings.SkipDynamicScopeValidation = Settings.SkipDynamicScopeValidation;
				break;
			case "SkipAutoServerTokenGeneration":
				V5.Settings.SkipAutoServerTokenGeneration = Settings.SkipAutoServerTokenGeneration;
				Helix.Settings.SkipAutoServerTokenGeneration = Settings.SkipAutoServerTokenGeneration;
				break;
			case "Scopes":
				V5.Settings.Scopes = Settings.Scopes;
				Helix.Settings.Scopes = Settings.Scopes;
				break;
			}
		}
	}
}
namespace TwitchLib.Api.ThirdParty
{
	public class ThirdParty
	{
		public class UsernameChangeApi : ApiBase
		{
			public UsernameChangeApi(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
				: base(settings, rateLimiter, http)
			{
			}

			public Task<List<UsernameChangeListing>> GetUsernameChangesAsync(string username)
			{
				List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
				{
					new KeyValuePair<string, string>("q", username),
					new KeyValuePair<string, string>("format", "json")
				};
				return ((ApiBase)this).GetGenericAsync<List<UsernameChangeListing>>("https://twitch-tools.rootonline.de/username_changelogs_search.php", list, (string)null, (ApiVersion)0, (string)null);
			}
		}

		public class ModLookupApi : ApiBase
		{
			public ModLookupApi(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
				: base(settings, rateLimiter, http)
			{
			}

			public Task<ModLookupResponse> GetChannelsModdedForByNameAsync(string username, int offset = 0, int limit = 100, bool useTls12 = true)
			{
				if (useTls12)
				{
					ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
				}
				List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
				{
					new KeyValuePair<string, string>("offset", offset.ToString()),
					new KeyValuePair<string, string>("limit", limit.ToString())
				};
				return ((ApiBase)this).GetGenericAsync<ModLookupResponse>("https://twitchstuff.3v.fi/modlookup/api/user/" + username, list, (string)null, (ApiVersion)0, (string)null);
			}

			public Task<TopResponse> GetChannelsModdedForByTopAsync(bool useTls12 = true)
			{
				if (useTls12)
				{
					ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
				}
				return ((ApiBase)this).GetGenericAsync<TopResponse>("https://twitchstuff.3v.fi/modlookup/api/top", (List<KeyValuePair<string, string>>)null, (string)null, (ApiVersion)5, (string)null);
			}

			public Task<StatsResponse> GetChannelsModdedForStatsAsync(bool useTls12 = true)
			{
				if (useTls12)
				{
					ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
				}
				return ((ApiBase)this).GetGenericAsync<StatsResponse>("https://twitchstuff.3v.fi/modlookup/api/stats", (List<KeyValuePair<string, string>>)null, (string)null, (ApiVersion)5, (string)null);
			}
		}

		public class AuthorizationFlowApi : ApiBase
		{
			private const string BaseUrl = "https://twitchtokengenerator.com/api";

			private string _apiId;

			private Timer _pingTimer;

			public event EventHandler<OnUserAuthorizationDetectedArgs> OnUserAuthorizationDetected;

			public event EventHandler<OnAuthorizationFlowErrorArgs> OnError;

			public AuthorizationFlowApi(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
				: base(settings, rateLimiter, http)
			{
			}

			public CreatedFlow CreateFlow(string applicationTitle, IEnumerable<AuthScopes> scopes)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: 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_001f: Unknown result type (might be due to invalid IL or missing references)
				string text = null;
				foreach (AuthScopes scope in scopes)
				{
					text = ((text != null) ? (text + "+" + Helpers.AuthScopesToString(scope)) : Helpers.AuthScopesToString(scope));
				}
				string address = "https://twitchtokengenerator.com/api/create/" + Helpers.Base64Encode(applicationTitle) + "/" + text;
				string text2 = new WebClient().DownloadString(address);
				return JsonConvert.DeserializeObject<CreatedFlow>(text2);
			}

			public RefreshTokenResponse RefreshToken(string refreshToken)
			{
				string address = "https://twitchtokengenerator.com/api/refresh/" + refreshToken;
				string text = new WebClient().DownloadString(address);
				return JsonConvert.DeserializeObject<RefreshTokenResponse>(text);
			}

			public void BeginPingingStatus(string id, int intervalMs = 5000)
			{
				_apiId = id;
				_pingTimer = new Timer(intervalMs);
				_pingTimer.Elapsed += OnPingTimerElapsed;
				_pingTimer.Start();
			}

			public PingResponse PingStatus(string id = null)
			{
				if (id != null)
				{
					_apiId = id;
				}
				string jsonStr = new WebClient().DownloadString("https://twitchtokengenerator.com/api/status/" + _apiId);
				return new PingResponse(jsonStr);
			}

			private void OnPingTimerElapsed(object sender, ElapsedEventArgs e)
			{
				PingResponse pingResponse = PingStatus();
				if (pingResponse.Success)
				{
					_pingTimer.Stop();
					this.OnUserAuthorizationDetected?.Invoke(null, new OnUserAuthorizationDetectedArgs
					{
						Id = pingResponse.Id,
						Scopes = pingResponse.Scopes,
						Token = pingResponse.Token,
						Username = pingResponse.Username,
						Refresh = pingResponse.Refresh
					});
				}
				else if (pingResponse.Error != 3)
				{
					_pingTimer.Stop();
					this.OnError?.Invoke(null, new OnAuthorizationFlowErrorArgs
					{
						Error = pingResponse.Error,
						Message = pingResponse.Message
					});
				}
			}
		}

		public UsernameChangeApi UsernameChange { get; }

		public ModLookupApi ModLookup { get; }

		public AuthorizationFlowApi AuthorizationFlow { get; }

		public ThirdParty(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		{
			UsernameChange = new UsernameChangeApi(settings, rateLimiter, http);
			ModLookup = new ModLookupApi(settings, rateLimiter, http);
			AuthorizationFlow = new AuthorizationFlowApi(settings, rateLimiter, http);
		}
	}
}
namespace TwitchLib.Api.ThirdParty.UsernameChange
{
	public class UsernameChangeListing
	{
		[JsonProperty(PropertyName = "userid")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "username_old")]
		public string UsernameOld { get; protected set; }

		[JsonProperty(PropertyName = "username_new")]
		public string UsernameNew { get; protected set; }

		[JsonProperty(PropertyName = "found_at")]
		public DateTime FoundAt { get; protected set; }
	}
	public class UsernameChangeResponse
	{
		public UsernameChangeListing[] UsernameChangeListings { get; protected set; }
	}
}
namespace TwitchLib.Api.ThirdParty.ModLookup
{
	public class ModLookupListing
	{
		[JsonProperty(PropertyName = "name")]
		public string Name { get; protected set; }

		[JsonProperty(PropertyName = "followers")]
		public int Followers { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }

		[JsonProperty(PropertyName = "partnered")]
		public bool Partnered { get; protected set; }
	}
	public class ModLookupResponse
	{
		[JsonProperty(PropertyName = "status")]
		public int Status { get; protected set; }

		[JsonProperty(PropertyName = "user")]
		public string User { get; protected set; }

		[JsonProperty(PropertyName = "count")]
		public int Count { get; protected set; }

		[JsonProperty(PropertyName = "channels")]
		public ModLookupListing[] Channels { get; protected set; }
	}
	public class Stats
	{
		[JsonProperty(PropertyName = "relations")]
		public int Relations { get; protected set; }

		[JsonProperty(PropertyName = "channels_total")]
		public int ChannelsTotal { get; protected set; }

		[JsonProperty(PropertyName = "users")]
		public int Users { get; protected set; }

		[JsonProperty(PropertyName = "channels_no_mods")]
		public int ChannelsNoMods { get; protected set; }

		[JsonProperty(PropertyName = "channels_only_broadcaster")]
		public int ChannelsOnlyBroadcaster { get; protected set; }
	}
	public class StatsResponse
	{
		[JsonProperty(PropertyName = "status")]
		public int Status { get; protected set; }

		[JsonProperty(PropertyName = "stats")]
		public Stats Stats { get; protected set; }
	}
	public class Top
	{
		[JsonProperty(PropertyName = "modcount")]
		public ModLookupListing[] ModCount { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public ModLookupListing[] Views { get; protected set; }

		[JsonProperty(PropertyName = "followers")]
		public ModLookupListing[] Followers { get; protected set; }
	}
	public class TopResponse
	{
		[JsonProperty(PropertyName = "status")]
		public int Status { get; protected set; }

		[JsonProperty(PropertyName = "top")]
		public Top Top { get; protected set; }
	}
}
namespace TwitchLib.Api.ThirdParty.AuthorizationFlow
{
	public class CreatedFlow
	{
		[JsonProperty(PropertyName = "message")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }
	}
	public class PingResponse
	{
		public bool Success { get; protected set; }

		public string Id { get; protected set; }

		public int Error { get; protected set; }

		public string Message { get; protected set; }

		public List<AuthScopes> Scopes { get; protected set; }

		public string Token { get; protected set; }

		public string Refresh { get; protected set; }

		public string Username { get; protected set; }

		public PingResponse(string jsonStr)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			JObject val = JObject.Parse(jsonStr);
			Success = bool.Parse(((object)((JToken)val).SelectToken("success")).ToString());
			if (!Success)
			{
				Error = int.Parse(((object)((JToken)val).SelectToken("error")).ToString());
				Message = ((object)((JToken)val).SelectToken("message")).ToString();
				return;
			}
			Scopes = new List<AuthScopes>();
			foreach (JToken item in (IEnumerable<JToken>)((JToken)val).SelectToken("scopes"))
			{
				Scopes.Add(StringToScope(((object)item).ToString()));
			}
			Token = ((object)((JToken)val).SelectToken("token")).ToString();
			Refresh = ((object)((JToken)val).SelectToken("refresh")).ToString();
			Username = ((object)((JToken)val).SelectToken("username")).ToString();
		}

		private AuthScopes StringToScope(string scope)
		{
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			return (AuthScopes)(scope switch
			{
				"user_read" => 16, 
				"user_blocks_edit" => 13, 
				"user_blocks_read" => 14, 
				"user_follows_edit" => 15, 
				"channel_read" => 6, 
				"channel_commercial" => 2, 
				"channel_stream" => 8, 
				"channel_subscriptions" => 8, 
				"user_subscriptions" => 17, 
				"channel_check_subscription" => 1, 
				"chat_login" => 9, 
				"channel_editor" => 3, 
				"channel_feed_read" => 5, 
				"channel_feed_edit" => 4, 
				"collections_edit" => 10, 
				"communities_edit" => 11, 
				"communities_moderate" => 12, 
				"viewing_activity_read" => 18, 
				"user:edit" => 20, 
				"user:read:email" => 21, 
				"clips:edit" => 22, 
				"analytics:read:games" => 24, 
				"bits:read" => 23, 
				"channel:read:subscriptions" => 28, 
				_ => throw new Exception("Unknown scope"), 
			});
		}
	}
	public class RefreshTokenResponse
	{
		[JsonProperty(PropertyName = "token")]
		public string Token { get; protected set; }

		[JsonProperty(PropertyName = "refresh")]
		public string Refresh { get; protected set; }
	}
}
namespace TwitchLib.Api.Services
{
	public class ApiService
	{
		protected readonly ITwitchAPI _api;

		private readonly ServiceTimer _serviceTimer;

		public List<string> ChannelsToMonitor { get; private set; }

		public int IntervalInSeconds => _serviceTimer.IntervalInSeconds;

		public bool Enabled => _serviceTimer.Enabled;

		public event EventHandler<OnServiceStartedArgs> OnServiceStarted;

		public event EventHandler<OnServiceStoppedArgs> OnServiceStopped;

		public event EventHandler<OnServiceTickArgs> OnServiceTick;

		public event EventHandler<OnChannelsSetArgs> OnChannelsSet;

		protected ApiService(ITwitchAPI api, int checkIntervalInSeconds)
		{
			if (api == null)
			{
				throw new ArgumentNullException("api");
			}
			if (checkIntervalInSeconds < 1)
			{
				throw new ArgumentException("The interval must be 1 second or more.", "checkIntervalInSeconds");
			}
			_api = api;
			_serviceTimer = new ServiceTimer(OnServiceTimerTick, checkIntervalInSeconds);
		}

		public virtual void Start()
		{
			if (ChannelsToMonitor == null)
			{
				throw new InvalidOperationException("You must atleast add 1 channel to service before starting it.");
			}
			if (_serviceTimer.Enabled)
			{
				throw new InvalidOperationException("The service has already been started.");
			}
			_serviceTimer.Start();
			this.OnServiceStarted?.Invoke(this, new OnServiceStartedArgs());
		}

		public virtual void Stop()
		{
			if (!_serviceTimer.Enabled)
			{
				throw new InvalidOperationException("The service hasn't started yet, or has already been stopped.");
			}
			_serviceTimer.Stop();
			this.OnServiceStopped?.Invoke(this, new OnServiceStoppedArgs());
		}

		protected virtual void SetChannels(List<string> channelsToMonitor)
		{
			if (channelsToMonitor == null)
			{
				throw new ArgumentNullException("channelsToMonitor");
			}
			if (channelsToMonitor.Count == 0)
			{
				throw new ArgumentException("The provided list is empty.", "channelsToMonitor");
			}
			ChannelsToMonitor = channelsToMonitor;
			this.OnChannelsSet?.Invoke(this, new OnChannelsSetArgs
			{
				Channels = channelsToMonitor
			});
		}

		protected virtual Task OnServiceTimerTick()
		{
			this.OnServiceTick?.Invoke(this, new OnServiceTickArgs());
			return Task.CompletedTask;
		}
	}
	public class FollowerService : ApiService
	{
		private readonly Dictionary<string, DateTime> _lastFollowerDates = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);

		private TwitchLib.Api.Services.Core.FollowerService.CoreMonitor _monitor;

		private TwitchLib.Api.Services.Core.FollowerService.IdBasedMonitor _idBasedMonitor;

		private TwitchLib.Api.Services.Core.FollowerService.NameBasedMonitor _nameBasedMonitor;

		public Dictionary<string, List<Follow>> KnownFollowers { get; } = new Dictionary<string, List<Follow>>(StringComparer.OrdinalIgnoreCase);


		public int QueryCountPerRequest { get; }

		public int CacheSize { get; }

		private TwitchLib.Api.Services.Core.FollowerService.IdBasedMonitor IdBasedMonitor => _idBasedMonitor ?? (_idBasedMonitor = new TwitchLib.Api.Services.Core.FollowerService.IdBasedMonitor(_api));

		private TwitchLib.Api.Services.Core.FollowerService.NameBasedMonitor NameBasedMonitor => _nameBasedMonitor ?? (_nameBasedMonitor = new TwitchLib.Api.Services.Core.FollowerService.NameBasedMonitor(_api));

		public event EventHandler<OnNewFollowersDetectedArgs> OnNewFollowersDetected;

		public FollowerService(ITwitchAPI api, int checkIntervalInSeconds = 60, int queryCountPerRequest = 100, int cacheSize = 1000)
			: base(api, checkIntervalInSeconds)
		{
			if (queryCountPerRequest < 1 || queryCountPerRequest > 100)
			{
				throw new ArgumentException("Twitch doesn't support less than 1 or more than 100 followers per request.", "queryCountPerRequest");
			}
			if (cacheSize < queryCountPerRequest)
			{
				throw new ArgumentException("The cache size must be at least the size of the queryCountPerRequest parameter.", "cacheSize");
			}
			QueryCountPerRequest = queryCountPerRequest;
			CacheSize = cacheSize;
		}

		public void ClearCache()
		{
			KnownFollowers.Clear();
			_lastFollowerDates.Clear();
			_nameBasedMonitor?.ClearCache();
			_nameBasedMonitor = null;
			_idBasedMonitor = null;
		}

		public void SetChannelsById(List<string> channelsToMonitor)
		{
			SetChannels(channelsToMonitor);
			_monitor = IdBasedMonitor;
		}

		public void SetChannelsByName(List<string> channelsToMonitor)
		{
			SetChannels(channelsToMonitor);
			_monitor = NameBasedMonitor;
		}

		public async Task UpdateLatestFollowersAsync(bool callEvents = true)
		{
			if (base.ChannelsToMonitor == null)
			{
				return;
			}
			foreach (string channel in base.ChannelsToMonitor)
			{
				List<Follow> latestFollowers = await GetLatestFollowersAsync(channel);
				if (latestFollowers.Count == 0)
				{
					return;
				}
				List<Follow> newFollowers;
				if (!KnownFollowers.TryGetValue(channel, out var knownFollowers))
				{
					newFollowers = latestFollowers;
					KnownFollowers[channel] = latestFollowers.Take(CacheSize).ToList();
					_lastFollowerDates[channel] = latestFollowers.Last().FollowedAt;
				}
				else
				{
					HashSet<string> existingFollowerIds = new HashSet<string>(knownFollowers.Select((Follow f) => f.FromUserId));
					DateTime latestKnownFollowerDate = _lastFollowerDates[channel];
					newFollowers = new List<Follow>();
					foreach (Follow follower in latestFollowers)
					{
						if (existingFollowerIds.Add(follower.FromUserId) && !(follower.FollowedAt < latestKnownFollowerDate))
						{
							newFollowers.Add(follower);
							latestKnownFollowerDate = follower.FollowedAt;
							knownFollowers.Add(follower);
						}
					}
					existingFollowerIds.Clear();
					existingFollowerIds.TrimExcess();
					if (knownFollowers.Count > CacheSize)
					{
						knownFollowers.RemoveRange(0, knownFollowers.Count - CacheSize);
					}
					if (newFollowers.Count <= 0)
					{
						return;
					}
					_lastFollowerDates[channel] = latestKnownFollowerDate;
				}
				if (!callEvents)
				{
					return;
				}
				this.OnNewFollowersDetected?.Invoke(this, new OnNewFollowersDetectedArgs
				{
					Channel = channel,
					NewFollowers = newFollowers
				});
				knownFollowers = null;
			}
		}

		protected override async Task OnServiceTimerTick()
		{
			await base.OnServiceTimerTick();
			await UpdateLatestFollowersAsync();
		}

		private async Task<List<Follow>> GetLatestFollowersAsync(string channel)
		{
			return (await _monitor.GetUsersFollowsAsync(channel, QueryCountPerRequest)).Follows.Reverse().ToList();
		}
	}
	public class LiveStreamMonitorService : ApiService
	{
		private TwitchLib.Api.Services.Core.LiveStreamMonitor.CoreMonitor _monitor;

		private TwitchLib.Api.Services.Core.LiveStreamMonitor.IdBasedMonitor _idBasedMonitor;

		private TwitchLib.Api.Services.Core.LiveStreamMonitor.NameBasedMonitor _nameBasedMonitor;

		public Dictionary<string, Stream> LiveStreams { get; } = new Dictionary<string, Stream>(StringComparer.OrdinalIgnoreCase);


		public int MaxStreamRequestCountPerRequest { get; }

		private TwitchLib.Api.Services.Core.LiveStreamMonitor.IdBasedMonitor IdBasedMonitor => _idBasedMonitor ?? (_idBasedMonitor = new TwitchLib.Api.Services.Core.LiveStreamMonitor.IdBasedMonitor(_api));

		private TwitchLib.Api.Services.Core.LiveStreamMonitor.NameBasedMonitor NameBasedMonitor => _nameBasedMonitor ?? (_nameBasedMonitor = new TwitchLib.Api.Services.Core.LiveStreamMonitor.NameBasedMonitor(_api));

		public event EventHandler<OnStreamOnlineArgs> OnStreamOnline;

		public event EventHandler<OnStreamOfflineArgs> OnStreamOffline;

		public event EventHandler<OnStreamUpdateArgs> OnStreamUpdate;

		public LiveStreamMonitorService(ITwitchAPI api, int checkIntervalInSeconds = 60, int maxStreamRequestCountPerRequest = 100)
			: base(api, checkIntervalInSeconds)
		{
			if (maxStreamRequestCountPerRequest < 1 || maxStreamRequestCountPerRequest > 100)
			{
				throw new ArgumentException("Twitch doesn't support less than 1 or more than 100 streams per request.", "maxStreamRequestCountPerRequest");
			}
			MaxStreamRequestCountPerRequest = maxStreamRequestCountPerRequest;
		}

		public void ClearCache()
		{
			LiveStreams.Clear();
			_nameBasedMonitor?.ClearCache();
			_nameBasedMonitor = null;
			_idBasedMonitor = null;
		}

		public void SetChannelsById(List<string> channelsToMonitor)
		{
			SetChannels(channelsToMonitor);
			_monitor = IdBasedMonitor;
		}

		public void SetChannelsByName(List<string> channelsToMonitor)
		{
			SetChannels(channelsToMonitor);
			_monitor = NameBasedMonitor;
		}

		public async Task UpdateLiveStreamersAsync(bool callEvents = true)
		{
			List<Stream> result = await GetLiveStreamersAsync();
			foreach (string channel in base.ChannelsToMonitor)
			{
				IEnumerable<Stream> source = result;
				Stream liveStream = source.FirstOrDefault(await _monitor.CompareStream(channel));
				if (liveStream != null)
				{
					HandleLiveStreamUpdate(channel, liveStream, callEvents);
				}
				else
				{
					HandleOfflineStreamUpdate(channel, callEvents);
				}
			}
		}

		protected override async Task OnServiceTimerTick()
		{
			await base.OnServiceTimerTick();
			await UpdateLiveStreamersAsync();
		}

		private void HandleLiveStreamUpdate(string channel, Stream liveStream, bool callEvents)
		{
			bool flag = LiveStreams.ContainsKey(channel);
			LiveStreams[channel] = liveStream;
			if (callEvents)
			{
				if (!flag)
				{
					this.OnStreamOnline?.Invoke(this, new OnStreamOnlineArgs
					{
						Channel = channel,
						Stream = liveStream
					});
				}
				else
				{
					this.OnStreamUpdate?.Invoke(this, new OnStreamUpdateArgs
					{
						Channel = channel,
						Stream = liveStream
					});
				}
			}
		}

		private void HandleOfflineStreamUpdate(string channel, bool callEvents)
		{
			if (LiveStreams.TryGetValue(channel, out var value))
			{
				LiveStreams.Remove(channel);
				if (callEvents)
				{
					this.OnStreamOffline?.Invoke(this, new OnStreamOfflineArgs
					{
						Channel = channel,
						Stream = value
					});
				}
			}
		}

		private async Task<List<Stream>> GetLiveStreamersAsync()
		{
			List<Stream> livestreamers = new List<Stream>();
			double pages = Math.Ceiling((double)base.ChannelsToMonitor.Count / (double)MaxStreamRequestCountPerRequest);
			for (int i = 0; (double)i < pages; i++)
			{
				List<string> selectedSet = base.ChannelsToMonitor.Skip(i * MaxStreamRequestCountPerRequest).Take(MaxStreamRequestCountPerRequest).ToList();
				GetStreamsResponse resultset = await _monitor.GetStreamsAsync(selectedSet);
				if (resultset.Streams != null)
				{
					livestreamers.AddRange(resultset.Streams);
				}
			}
			return livestreamers;
		}
	}
}
namespace TwitchLib.Api.Services.Events
{
	public class OnChannelsSetArgs : EventArgs
	{
		public List<string> Channels;
	}
	public class OnServiceStartedArgs : EventArgs
	{
	}
	public class OnServiceStoppedArgs : EventArgs
	{
	}
	public class OnServiceTickArgs : EventArgs
	{
	}
}
namespace TwitchLib.Api.Services.Events.LiveStreamMonitor
{
	public class OnStreamOfflineArgs : EventArgs
	{
		public string Channel;

		public Stream Stream;
	}
	public class OnStreamOnlineArgs : EventArgs
	{
		public string Channel;

		public Stream Stream;
	}
	public class OnStreamUpdateArgs : EventArgs
	{
		public string Channel;

		public Stream Stream;
	}
}
namespace TwitchLib.Api.Services.Events.FollowerService
{
	public class OnNewFollowersDetectedArgs : EventArgs
	{
		public string Channel;

		public List<Follow> NewFollowers;
	}
}
namespace TwitchLib.Api.Services.Core
{
	internal class ServiceTimer : Timer
	{
		public delegate Task ServiceTimerTick();

		private readonly ServiceTimerTick _serviceTimerTickAsyncCallback;

		public int IntervalInSeconds { get; }

		public ServiceTimer(ServiceTimerTick serviceTimerTickAsyncCallback, int intervalInSeconds = 60)
		{
			_serviceTimerTickAsyncCallback = serviceTimerTickAsyncCallback;
			base.Interval = intervalInSeconds * 1000;
			IntervalInSeconds = intervalInSeconds;
			base.Elapsed += TimerElapsedAsync;
		}

		private async void TimerElapsedAsync(object sender, ElapsedEventArgs e)
		{
			await _serviceTimerTickAsyncCallback();
		}
	}
}
namespace TwitchLib.Api.Services.Core.LiveStreamMonitor
{
	internal abstract class CoreMonitor
	{
		protected readonly ITwitchAPI _api;

		public abstract Task<GetStreamsResponse> GetStreamsAsync(List<string> channels);

		public abstract Task<Func<Stream, bool>> CompareStream(string channel);

		protected CoreMonitor(ITwitchAPI api)
		{
			_api = api;
		}
	}
	internal class IdBasedMonitor : CoreMonitor
	{
		public IdBasedMonitor(ITwitchAPI api)
			: base(api)
		{
		}

		public override Task<Func<Stream, bool>> CompareStream(string channel)
		{
			return Task.FromResult<Func<Stream, bool>>((Stream stream) => stream.UserId == channel);
		}

		public override Task<GetStreamsResponse> GetStreamsAsync(List<string> channels)
		{
			return _api.Helix.Streams.GetStreamsAsync((string)null, (List<string>)null, channels.Count, (List<string>)null, (List<string>)null, "all", channels, (List<string>)null);
		}
	}
	internal class NameBasedMonitor : CoreMonitor
	{
		private readonly ConcurrentDictionary<string, string> _channelToId = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		public NameBasedMonitor(ITwitchAPI api)
			: base(api)
		{
		}

		public override async Task<Func<Stream, bool>> CompareStream(string channel)
		{
			if (!_channelToId.TryGetValue(channel, out var channelId))
			{
				User? obj = (await _api.Helix.Users.GetUsersAsync((List<string>)null, new List<string> { channel }, (string)null)).Users.FirstOrDefault();
				channelId = ((obj != null) ? obj.Id : null);
				_channelToId[channel] = channelId ?? throw new InvalidOperationException("No channel with the name \"" + channel + "\" could be found.");
			}
			return (Stream stream) => stream.UserId == channelId;
		}

		public override Task<GetStreamsResponse> GetStreamsAsync(List<string> channels)
		{
			return _api.Helix.Streams.GetStreamsAsync((string)null, (List<string>)null, channels.Count, (List<string>)null, (List<string>)null, "all", (List<string>)null, channels);
		}

		public void ClearCache()
		{
			_channelToId.Clear();
		}
	}
}
namespace TwitchLib.Api.Services.Core.FollowerService
{
	internal abstract class CoreMonitor
	{
		protected readonly ITwitchAPI _api;

		public abstract Task<GetUsersFollowsResponse> GetUsersFollowsAsync(string channel, int queryCount);

		protected CoreMonitor(ITwitchAPI api)
		{
			_api = api;
		}
	}
	internal class IdBasedMonitor : CoreMonitor
	{
		public IdBasedMonitor(ITwitchAPI api)
			: base(api)
		{
		}

		public override Task<GetUsersFollowsResponse> GetUsersFollowsAsync(string channel, int queryCount)
		{
			return _api.Helix.Users.GetUsersFollowsAsync((string)null, (string)null, queryCount, (string)null, channel);
		}
	}
	internal class NameBasedMonitor : CoreMonitor
	{
		private readonly ConcurrentDictionary<string, string> _channelToId = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		public NameBasedMonitor(ITwitchAPI api)
			: base(api)
		{
		}

		public override async Task<GetUsersFollowsResponse> GetUsersFollowsAsync(string channel, int queryCount)
		{
			if (!_channelToId.TryGetValue(channel, out var channelId))
			{
				User? obj = (await _api.Helix.Users.GetUsersAsync((List<string>)null, new List<string> { channel }, (string)null)).Users.FirstOrDefault();
				channelId = ((obj != null) ? obj.Id : null);
				_channelToId[channel] = channelId ?? throw new InvalidOperationException("No channel with the name \"" + channel + "\" could be found.");
			}
			return await _api.Helix.Users.GetUsersFollowsAsync((string)null, (string)null, queryCount, (string)null, channelId);
		}

		public void ClearCache()
		{
			_channelToId.Clear();
		}
	}
}
namespace TwitchLib.Api.Interfaces
{
	public interface ITwitchAPI
	{
		IApiSettings Settings { get; }

		V5 V5 { get; }

		Helix Helix { get; }

		TwitchLib.Api.ThirdParty.ThirdParty ThirdParty { get; }

		Undocumented Undocumented { get; }
	}
}
namespace TwitchLib.Api.Helpers
{
	public static class ExtensionAnalyticsHelper
	{
		public static async Task<List<ExtensionAnalytics>> HandleUrlAsync(string url)
		{
			IEnumerable<string> data = ExtractData(await GetContentsAsync(url));
			return data.Select((Func<string, ExtensionAnalytics>)((string line) => new ExtensionAnalytics(line))).ToList();
		}

		private static IEnumerable<string> ExtractData(IEnumerable<string> cnts)
		{
			return cnts.Where((string line) => line.Any(char.IsDigit)).ToList();
		}

		private static async Task<string[]> GetContentsAsync(string url)
		{
			HttpClient client = new HttpClient();
			return (await client.GetStringAsync(url)).Split(new string[1] { Environment.NewLine }, StringSplitOptions.None);
		}
	}
}
namespace TwitchLib.Api.Events
{
	public class OnAuthorizationFlowErrorArgs
	{
		public int Error { get; set; }

		public string Message { get; set; }
	}
	public class OnUserAuthorizationDetectedArgs
	{
		public string Id { get; set; }

		public List<AuthScopes> Scopes { get; set; }

		public string Username { get; set; }

		public string Token { get; set; }

		public string Refresh { get; set; }
	}
}

lib/TwitchLib.Api.Helix.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TwitchLib.Api.Core;
using TwitchLib.Api.Core.Enums;
using TwitchLib.Api.Core.Exceptions;
using TwitchLib.Api.Core.Extensions.System;
using TwitchLib.Api.Core.HttpCallHandlers;
using TwitchLib.Api.Core.Interfaces;
using TwitchLib.Api.Core.RateLimiter;
using TwitchLib.Api.Helix.Models.Analytics;
using TwitchLib.Api.Helix.Models.Bits;
using TwitchLib.Api.Helix.Models.Clips.CreateClip;
using TwitchLib.Api.Helix.Models.Clips.GetClip;
using TwitchLib.Api.Helix.Models.Entitlements.CreateEntitlementGrantsUploadURL;
using TwitchLib.Api.Helix.Models.Entitlements.GetCodeStatus;
using TwitchLib.Api.Helix.Models.Entitlements.RedeemCode;
using TwitchLib.Api.Helix.Models.Extensions.Transactions;
using TwitchLib.Api.Helix.Models.Games;
using TwitchLib.Api.Helix.Models.Moderation.CheckAutoModStatus;
using TwitchLib.Api.Helix.Models.Moderation.CheckAutoModStatus.Request;
using TwitchLib.Api.Helix.Models.Moderation.GetBannedEvents;
using TwitchLib.Api.Helix.Models.Moderation.GetBannedUsers;
using TwitchLib.Api.Helix.Models.Moderation.GetModeratorEvents;
using TwitchLib.Api.Helix.Models.Moderation.GetModerators;
using TwitchLib.Api.Helix.Models.Streams;
using TwitchLib.Api.Helix.Models.StreamsMetadata;
using TwitchLib.Api.Helix.Models.Subscriptions;
using TwitchLib.Api.Helix.Models.Tags;
using TwitchLib.Api.Helix.Models.Users;
using TwitchLib.Api.Helix.Models.Users.Internal;
using TwitchLib.Api.Helix.Models.Videos;
using TwitchLib.Api.Helix.Models.Webhooks;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing the Helix section of TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.2")]
[assembly: AssemblyInformationalVersion("3.1.2")]
[assembly: AssemblyProduct("TwitchLib.Api.Helix")]
[assembly: AssemblyTitle("TwitchLib.Api.Helix")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.2.0")]
namespace TwitchLib.Api.Helix;

public class Analytics : ApiBase
{
	public Analytics(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetGameAnalyticsResponse> GetGameAnalyticsAsync(string gameId = null, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)24, authToken);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (gameId != null)
		{
			list.Add(new KeyValuePair<string, string>("game_id", gameId));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetGameAnalyticsResponse>("/analytics/games", (ApiVersion)6, list, authToken, (string)null, (string)null);
	}

	public Task<GetExtensionAnalyticsResponse> GetExtensionAnalyticsAsync(string extensionId, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)25, authToken);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (extensionId != null)
		{
			list.Add(new KeyValuePair<string, string>("extension_id", extensionId));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetExtensionAnalyticsResponse>("/analytics/extensions", (ApiVersion)6, list, authToken, (string)null, (string)null);
	}
}
public class Bits : ApiBase
{
	public Bits(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetBitsLeaderboardResponse> GetBitsLeaderboardAsync(int count = 10, BitsLeaderboardPeriodEnum period = 4, DateTime? startedAt = null, string userid = null, string accessToken = null)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: 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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Expected I4, but got Unknown
		((ApiBase)this).DynamicScopeValidation((AuthScopes)23, accessToken);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("count", count.ToString())
		};
		switch ((int)period)
		{
		case 0:
			list.Add(new KeyValuePair<string, string>("period", "day"));
			break;
		case 1:
			list.Add(new KeyValuePair<string, string>("period", "week"));
			break;
		case 2:
			list.Add(new KeyValuePair<string, string>("period", "month"));
			break;
		case 3:
			list.Add(new KeyValuePair<string, string>("period", "year"));
			break;
		case 4:
			list.Add(new KeyValuePair<string, string>("period", "all"));
			break;
		}
		if (startedAt.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("started_at", DateTimeExtensions.ToRfc3339String(startedAt.Value)));
		}
		if (userid != null)
		{
			list.Add(new KeyValuePair<string, string>("user_id", userid));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetBitsLeaderboardResponse>("/bits/leaderboard", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}
}
public class Clips : ApiBase
{
	public Clips(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetClipResponse> GetClipAsync(string clipId = null, string gameId = null, string broadcasterId = null, string before = null, string after = null, DateTime? startedAt = null, DateTime? endedAt = null, int first = 20)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		if (first < 0 || first > 100)
		{
			throw new BadParameterException("'first' must between 0 (inclusive) and 100 (inclusive).");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (clipId != null)
		{
			list.Add(new KeyValuePair<string, string>("id", clipId));
		}
		if (gameId != null)
		{
			list.Add(new KeyValuePair<string, string>("game_id", gameId));
		}
		if (broadcasterId != null)
		{
			list.Add(new KeyValuePair<string, string>("broadcaster_id", broadcasterId));
		}
		if (list.Count != 1)
		{
			throw new BadParameterException("One of the following parameters must be set: clipId, gameId, broadcasterId. Only one is allowed to be set.");
		}
		if (!startedAt.HasValue && endedAt.HasValue)
		{
			throw new BadParameterException("The ended_at parameter cannot be used without the started_at parameter. Please include both parameters!");
		}
		if (startedAt.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("started_at", DateTimeExtensions.ToRfc3339String(startedAt.Value)));
		}
		if (endedAt.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("ended_at", DateTimeExtensions.ToRfc3339String(endedAt.Value)));
		}
		if (before != null)
		{
			list.Add(new KeyValuePair<string, string>("before", before));
		}
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		list.Add(new KeyValuePair<string, string>("first", first.ToString()));
		return ((ApiBase)this).TwitchGetGenericAsync<GetClipResponse>("/clips", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}

	public Task<CreatedClipResponse> CreateClipAsync(string broadcasterId, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)22, (string)null);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("broadcaster_id", broadcasterId)
		};
		return ((ApiBase)this).TwitchPostGenericAsync<CreatedClipResponse>("/clips", (ApiVersion)6, (string)null, list, authToken, (string)null, (string)null);
	}
}
public class Entitlements : ApiBase
{
	public Entitlements(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<CreateEntitlementGrantsUploadUrlResponse> CreateEntitlementGrantsUploadUrlAsync(string manifestId, EntitleGrantType type, string url = null, string applicationAccessToken = null)
	{
		//IL_002c: 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_002e: 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_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		if (manifestId == null)
		{
			throw new BadParameterException("manifestId cannot be null");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("manifest_id", manifestId)
		};
		if ((int)type == 0)
		{
			list.Add(new KeyValuePair<string, string>("type", "bulk_drops_grant"));
			return ((ApiBase)this).TwitchGetGenericAsync<CreateEntitlementGrantsUploadUrlResponse>("/entitlements/upload", (ApiVersion)6, list, applicationAccessToken, (string)null, (string)null);
		}
		throw new BadParameterException("Unknown entitlement grant type");
	}

	public Task<GetCodeStatusResponse> GetCodeStatusAsync(List<string> codes, string userId, string accessToken = null)
	{
		//IL_0022: 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)
		if (codes == null || codes.Count == 0 || codes.Count > 20)
		{
			throw new BadParameterException("codes cannot be null and must ahve between 1 and 20 items");
		}
		if (userId == null)
		{
			throw new BadParameterException("userId cannot be null");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("user_id", userId)
		};
		foreach (string code in codes)
		{
			list.Add(new KeyValuePair<string, string>("code", code));
		}
		return ((ApiBase)this).TwitchPostGenericAsync<GetCodeStatusResponse>("/entitlements/codes", (ApiVersion)6, (string)null, list, accessToken, (string)null, (string)null);
	}

	public Task<RedeemCodeResponse> RedeemCodeAsync(List<string> codes, string accessToken = null)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		if (codes == null || codes.Count == 0 || codes.Count > 20)
		{
			throw new BadParameterException("codes cannot be null and must ahve between 1 and 20 items");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		foreach (string code in codes)
		{
			list.Add(new KeyValuePair<string, string>("code", code));
		}
		return ((ApiBase)this).TwitchPostGenericAsync<RedeemCodeResponse>("/entitlements/codes", (ApiVersion)6, (string)null, list, accessToken, (string)null, (string)null);
	}
}
public class Extensions : ApiBase
{
	public Extensions(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetExtensionTransactionsResponse> GetExtensionTransactionsAsync(string extensionId, List<string> ids = null, string after = null, int first = 20, string applicationAccessToken = null)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		if (extensionId == null)
		{
			throw new BadParameterException("extensionId cannot be null");
		}
		if (first < 1 || first > 100)
		{
			throw new BadParameterException("'first' must between 1 (inclusive) and 100 (inclusive).");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		list.Add(new KeyValuePair<string, string>("extension_id", extensionId));
		if (ids != null)
		{
			foreach (string id in ids)
			{
				list.Add(new KeyValuePair<string, string>("id", id));
			}
		}
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		list.Add(new KeyValuePair<string, string>("first", first.ToString()));
		return ((ApiBase)this).TwitchGetGenericAsync<GetExtensionTransactionsResponse>("/extensions/transactions", (ApiVersion)6, list, applicationAccessToken, (string)null, (string)null);
	}
}
public class Games : ApiBase
{
	public Games(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetGamesResponse> GetGamesAsync(List<string> gameIds = null, List<string> gameNames = null)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		if ((gameIds == null && gameNames == null) || (gameIds != null && gameIds.Count == 0 && gameNames == null) || (gameNames != null && gameNames.Count == 0 && gameIds == null))
		{
			throw new BadParameterException("Either gameIds or gameNames must have at least one value");
		}
		if (gameIds != null && gameIds.Count > 100)
		{
			throw new BadParameterException("gameIds list cannot exceed 100 items");
		}
		if (gameNames != null && gameNames.Count > 100)
		{
			throw new BadParameterException("gameNames list cannot exceed 100 items");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (gameIds != null && gameIds.Count > 0)
		{
			foreach (string gameId in gameIds)
			{
				list.Add(new KeyValuePair<string, string>("id", gameId));
			}
		}
		if (gameNames != null && gameNames.Count > 0)
		{
			foreach (string gameName in gameNames)
			{
				list.Add(new KeyValuePair<string, string>("name", gameName));
			}
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetGamesResponse>("/games", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}

	public Task<GetTopGamesResponse> GetTopGamesAsync(string before = null, string after = null, int first = 20)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		if (first < 0 || first > 100)
		{
			throw new BadParameterException("'first' parameter must be between 1 (inclusive) and 100 (inclusive).");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("first", first.ToString())
		};
		if (before != null)
		{
			list.Add(new KeyValuePair<string, string>("before", before));
		}
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetTopGamesResponse>("/games/top", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}
}
public class Helix
{
	private readonly ILogger<Helix> _logger;

	public Extensions Extensions;

	public IApiSettings Settings { get; }

	public Analytics Analytics { get; }

	public Bits Bits { get; }

	public Clips Clips { get; }

	public Entitlements Entitlements { get; }

	public Games Games { get; }

	public Moderation Moderation { get; }

	public Subscriptions Subscriptions { get; }

	public Streams Streams { get; }

	public Tags Tags { get; }

	public Videos Videos { get; }

	public Users Users { get; }

	public Webhooks Webhooks { get; }

	public Helix(ILoggerFactory loggerFactory = null, IRateLimiter rateLimiter = null, IApiSettings settings = null, IHttpCallHandler http = null)
	{
		//IL_0045: 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)
		_logger = loggerFactory?.CreateLogger<Helix>();
		rateLimiter = (IRateLimiter)(((object)rateLimiter) ?? ((object)BypassLimiter.CreateLimiterBypassInstance()));
		http = (IHttpCallHandler)(((object)http) ?? ((object)new TwitchHttpClient(loggerFactory?.CreateLogger<TwitchHttpClient>())));
		Settings = (IApiSettings)(((object)settings) ?? ((object)new ApiSettings()));
		Analytics = new Analytics(Settings, rateLimiter, http);
		Bits = new Bits(Settings, rateLimiter, http);
		Clips = new Clips(Settings, rateLimiter, http);
		Entitlements = new Entitlements(Settings, rateLimiter, http);
		Extensions = new Extensions(Settings, rateLimiter, http);
		Games = new Games(Settings, rateLimiter, http);
		Moderation = new Moderation(Settings, rateLimiter, http);
		Streams = new Streams(Settings, rateLimiter, http);
		Subscriptions = new Subscriptions(Settings, rateLimiter, http);
		Tags = new Tags(Settings, rateLimiter, http);
		Users = new Users(Settings, rateLimiter, http);
		Videos = new Videos(Settings, rateLimiter, http);
		Webhooks = new Webhooks(Settings, rateLimiter, http);
	}
}
public class Moderation : ApiBase
{
	public Moderation(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<CheckAutoModStatusResponse> CheckAutoModStatusAsync(List<Message> messages, string broadcasterId, string accessToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		if (messages == null || messages.Count == 0)
		{
			throw new BadParameterException("messages cannot be null and must be greater than 0 length");
		}
		if (broadcasterId == null || broadcasterId.Length == 0)
		{
			throw new BadParameterException("broadcasterId cannot be null and must be greater than 0 length");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("broacaster_id", broadcasterId)
		};
		MessageRequest val = new MessageRequest
		{
			Messages = messages.ToArray()
		};
		return ((ApiBase)this).TwitchPostGenericAsync<CheckAutoModStatusResponse>("/moderation/enforcements/status", (ApiVersion)6, JsonConvert.SerializeObject((object)val), list, accessToken, (string)null, (string)null);
	}

	public Task<GetBannedEventsResponse> GetBannedEventsAsync(string broadcasterId, List<string> userIds = null, string after = null, string first = null, string accessToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (broadcasterId == null || broadcasterId.Length == 0)
		{
			throw new BadParameterException("broadcasterId cannot be null and must be greater than 0 length");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("broadcaster_id", broadcasterId)
		};
		if (userIds != null && userIds.Count > 0)
		{
			foreach (string userId in userIds)
			{
				list.Add(new KeyValuePair<string, string>("user_id", userId));
			}
		}
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		if (first != null)
		{
			list.Add(new KeyValuePair<string, string>("first", first));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetBannedEventsResponse>("/moderation/banned/events", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}

	public Task<GetBannedUsersResponse> GetBannedUsersAsync(string broadcasterId, List<string> userIds = null, string after = null, string before = null, string accessToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (broadcasterId == null || broadcasterId.Length == 0)
		{
			throw new BadParameterException("broadcasterId cannot be null and must be greater than 0 length");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("broadcaster_id", broadcasterId)
		};
		if (userIds != null && userIds.Count > 0)
		{
			foreach (string userId in userIds)
			{
				list.Add(new KeyValuePair<string, string>("user_id", userId));
			}
		}
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		if (before != null)
		{
			list.Add(new KeyValuePair<string, string>("before", before));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetBannedUsersResponse>("/moderation/banned", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}

	public Task<GetModeratorsResponse> GetModeratorsAsync(string broadcasterId, List<string> userIds = null, string after = null, string accessToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (broadcasterId == null || broadcasterId.Length == 0)
		{
			throw new BadParameterException("broadcasterId cannot be null and must be greater than 0 length");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("broadcaster_id", broadcasterId)
		};
		if (userIds != null && userIds.Count > 0)
		{
			foreach (string userId in userIds)
			{
				list.Add(new KeyValuePair<string, string>("user_id", userId));
			}
		}
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetModeratorsResponse>("/moderation/moderators", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}

	public Task<GetModeratorEventsResponse> GetModeratorEventsAsync(string broadcasterId, List<string> userIds = null, string accessToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (broadcasterId == null || broadcasterId.Length == 0)
		{
			throw new BadParameterException("broadcasterId cannot be null and must be greater than 0 length");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("broadcaster_id", broadcasterId)
		};
		if (userIds != null && userIds.Count > 0)
		{
			foreach (string userId in userIds)
			{
				list.Add(new KeyValuePair<string, string>("user_id", userId));
			}
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetModeratorEventsResponse>("/moderation/moderators/events", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}
}
public class Streams : ApiBase
{
	public Streams(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetStreamsResponse> GetStreamsAsync(string after = null, List<string> communityIds = null, int first = 20, List<string> gameIds = null, List<string> languages = null, string type = "all", List<string> userIds = null, List<string> userLogins = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("first", first.ToString()),
			new KeyValuePair<string, string>("type", type)
		};
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		if (communityIds != null && communityIds.Count > 0)
		{
			foreach (string communityId in communityIds)
			{
				list.Add(new KeyValuePair<string, string>("community_id", communityId));
			}
		}
		if (gameIds != null && gameIds.Count > 0)
		{
			foreach (string gameId in gameIds)
			{
				list.Add(new KeyValuePair<string, string>("game_id", gameId));
			}
		}
		if (languages != null && languages.Count > 0)
		{
			foreach (string language in languages)
			{
				list.Add(new KeyValuePair<string, string>("language", language));
			}
		}
		if (userIds != null && userIds.Count > 0)
		{
			foreach (string userId in userIds)
			{
				list.Add(new KeyValuePair<string, string>("user_id", userId));
			}
		}
		if (userLogins != null && userLogins.Count > 0)
		{
			foreach (string userLogin in userLogins)
			{
				list.Add(new KeyValuePair<string, string>("user_login", userLogin));
			}
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetStreamsResponse>("/streams", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}

	public Task<GetStreamsMetadataResponse> GetStreamsMetadataAsync(string after = null, List<string> communityIds = null, int first = 20, List<string> gameIds = null, List<string> languages = null, string type = "all", List<string> userIds = null, List<string> userLogins = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("first", first.ToString()),
			new KeyValuePair<string, string>("type", type)
		};
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		if (communityIds != null && communityIds.Count > 0)
		{
			foreach (string communityId in communityIds)
			{
				list.Add(new KeyValuePair<string, string>("community_id", communityId));
			}
		}
		if (gameIds != null && gameIds.Count > 0)
		{
			foreach (string gameId in gameIds)
			{
				list.Add(new KeyValuePair<string, string>("game_id", gameId));
			}
		}
		if (languages != null && languages.Count > 0)
		{
			foreach (string language in languages)
			{
				list.Add(new KeyValuePair<string, string>("language", language));
			}
		}
		if (userIds != null && userIds.Count > 0)
		{
			foreach (string userId in userIds)
			{
				list.Add(new KeyValuePair<string, string>("user_id", userId));
			}
		}
		if (userLogins != null && userLogins.Count > 0)
		{
			foreach (string userLogin in userLogins)
			{
				list.Add(new KeyValuePair<string, string>("user_login", userLogin));
			}
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetStreamsMetadataResponse>("/streams/metadata", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}

	public Task<GetStreamTagsResponse> GetStreamTagsAsync(string broadcasterId, string accessToken = null)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(broadcasterId))
		{
			throw new BadParameterException("BroadcasterId must be set");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		list.Add(new KeyValuePair<string, string>("broadcaster_id", broadcasterId));
		return ((ApiBase)this).TwitchGetGenericAsync<GetStreamTagsResponse>("/streams/tags", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}

	public Task ReplaceStreamTags(string broadcasterId, List<string> tagIds = null, string accessToken = null)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Expected O, but got Unknown
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Expected O, but got Unknown
		((ApiBase)this).DynamicScopeValidation((AuthScopes)26, accessToken);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		list.Add(new KeyValuePair<string, string>("broadcaster_id", broadcasterId));
		string text = null;
		if (tagIds != null && tagIds.Count > 0)
		{
			dynamic val = (dynamic)new JObject();
			val.tag_ids = (dynamic)new JArray((object)tagIds);
			text = val.ToString();
		}
		return ((ApiBase)this).TwitchPutAsync("/streams/tags", (ApiVersion)6, text, list, accessToken, (string)null, (string)null);
	}
}
public class Subscriptions : ApiBase
{
	public Subscriptions(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetUserSubscriptionsResponse> GetUserSubscriptionsAsync(string broadcasterId, List<string> userIds, string accessToken = null)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(broadcasterId))
		{
			throw new BadParameterException("BroadcasterId must be set");
		}
		if (userIds == null || userIds.Count == 0)
		{
			throw new BadParameterException("UserIds must be set contain at least one user id");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		list.Add(new KeyValuePair<string, string>("broadcaster_id", broadcasterId));
		foreach (string userId in userIds)
		{
			list.Add(new KeyValuePair<string, string>("user_id", userId));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetUserSubscriptionsResponse>("/subscriptions", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}

	public Task<GetBroadcasterSubscriptionsResponse> GetBroadcasterSubscriptions(string broadcasterId, string accessToken = null)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(broadcasterId))
		{
			throw new BadParameterException("BroadcasterId must be set");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		list.Add(new KeyValuePair<string, string>("broadcaster_id", broadcasterId));
		return ((ApiBase)this).TwitchGetGenericAsync<GetBroadcasterSubscriptionsResponse>("/subscriptions", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}
}
public class Tags : ApiBase
{
	public Tags(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetAllStreamTagsResponse> GetAllStreamTagsAsync(string after = null, int first = 20, List<string> tagIds = null, string accessToken = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		if (first >= 0 && first <= 100)
		{
			list.Add(new KeyValuePair<string, string>("first", first.ToString()));
			if (tagIds != null && tagIds.Count > 0)
			{
				foreach (string tagId in tagIds)
				{
					list.Add(new KeyValuePair<string, string>("tag_id", tagId));
				}
			}
			return ((ApiBase)this).TwitchGetGenericAsync<GetAllStreamTagsResponse>("/tags/streams", (ApiVersion)6, list, accessToken, (string)null, (string)null);
		}
		throw new ArgumentOutOfRangeException("first", "first value cannot exceed 100 and cannot be less than 1");
	}
}
public class Users : ApiBase
{
	public Users(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetUsersResponse> GetUsersAsync(List<string> ids = null, List<string> logins = null, string accessToken = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (ids != null && ids.Count > 0)
		{
			foreach (string id in ids)
			{
				list.Add(new KeyValuePair<string, string>("id", id));
			}
		}
		if (logins != null && logins.Count > 0)
		{
			foreach (string login in logins)
			{
				list.Add(new KeyValuePair<string, string>("login", login));
			}
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetUsersResponse>("/users", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}

	public Task<GetUsersFollowsResponse> GetUsersFollowsAsync(string after = null, string before = null, int first = 20, string fromId = null, string toId = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("first", first.ToString())
		};
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		if (before != null)
		{
			list.Add(new KeyValuePair<string, string>("before", before));
		}
		if (fromId != null)
		{
			list.Add(new KeyValuePair<string, string>("from_id", fromId));
		}
		if (toId != null)
		{
			list.Add(new KeyValuePair<string, string>("to_id", toId));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetUsersFollowsResponse>("/users/follows", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}

	public Task PutUsersAsync(string description, string accessToken = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("description", description)
		};
		return ((ApiBase)this).TwitchPutAsync("/users", (ApiVersion)6, (string)null, list, accessToken, (string)null, (string)null);
	}

	public Task<GetUserExtensionsResponse> GetUserExtensionsAsync(string authToken = null)
	{
		return ((ApiBase)this).TwitchGetGenericAsync<GetUserExtensionsResponse>("/users/extensions/list", (ApiVersion)6, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<GetUserActiveExtensionsResponse> GetUserActiveExtensionsAsync(string userid = null, string authToken = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (userid != null)
		{
			list.Add(new KeyValuePair<string, string>("user_id", userid));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetUserActiveExtensionsResponse>("/users/extensions", (ApiVersion)6, list, authToken, (string)null, (string)null);
	}

	public Task<GetUserActiveExtensionsResponse> UpdateUserExtensionsAsync(IEnumerable<ExtensionSlot> userExtensionStates, string authToken = null)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected I4, but got Unknown
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Expected O, but got Unknown
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Expected O, but got Unknown
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Expected O, but got Unknown
		((ApiBase)this).DynamicScopeValidation((AuthScopes)3, authToken);
		Dictionary<string, UserExtensionState> dictionary = new Dictionary<string, UserExtensionState>();
		Dictionary<string, UserExtensionState> dictionary2 = new Dictionary<string, UserExtensionState>();
		Dictionary<string, UserExtensionState> dictionary3 = new Dictionary<string, UserExtensionState>();
		foreach (ExtensionSlot userExtensionState in userExtensionStates)
		{
			ExtensionType type = userExtensionState.Type;
			ExtensionType val = type;
			switch ((int)val)
			{
			case 2:
				dictionary3.Add(userExtensionState.Slot, userExtensionState.UserExtensionState);
				break;
			case 1:
				dictionary2.Add(userExtensionState.Slot, userExtensionState.UserExtensionState);
				break;
			case 0:
				dictionary.Add(userExtensionState.Slot, userExtensionState.UserExtensionState);
				break;
			default:
				throw new ArgumentOutOfRangeException("ExtensionType");
			}
		}
		JObject val2 = new JObject();
		UpdateUserExtensionsRequest val3 = new UpdateUserExtensionsRequest();
		if (dictionary.Count > 0)
		{
			val3.Panel = dictionary;
		}
		if (dictionary2.Count > 0)
		{
			val3.Overlay = dictionary2;
		}
		if (dictionary3.Count > 0)
		{
			val3.Component = dictionary3;
		}
		((JContainer)val2).Add((object)new JProperty("data", (object)JObject.FromObject((object)val3)));
		string text = ((object)val2).ToString();
		return ((ApiBase)this).TwitchPutGenericAsync<GetUserActiveExtensionsResponse>("/users/extensions", (ApiVersion)6, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}
}
public class Videos : ApiBase
{
	public Videos(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetVideosResponse> GetVideoAsync(List<string> videoIds = null, string userId = null, string gameId = null, string after = null, string before = null, int first = 20, string language = null, Period period = 3, VideoSort sort = 0, VideoType type = 0)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Expected I4, but got Unknown
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Expected I4, but got Unknown
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_0287: Unknown result type (might be due to invalid IL or missing references)
		//IL_0289: Unknown result type (might be due to invalid IL or missing references)
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a4: Expected I4, but got Unknown
		//IL_0277: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		if ((videoIds == null || videoIds.Count == 0) && userId == null && gameId == null)
		{
			throw new BadParameterException("VideoIds, userId, and gameId cannot all be null/empty.");
		}
		if ((videoIds != null && videoIds.Count > 0 && userId != null) || (videoIds != null && videoIds.Count > 0 && gameId != null) || (userId != null && gameId != null))
		{
			throw new BadParameterException("If videoIds are present, you may not use userid or gameid. If gameid is present, you may not use videoIds or userid. If userid is present, you may not use videoids or gameids.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (videoIds != null && videoIds.Count > 0)
		{
			foreach (string videoId in videoIds)
			{
				list.Add(new KeyValuePair<string, string>("id", videoId));
			}
		}
		if (userId != null)
		{
			list.Add(new KeyValuePair<string, string>("user_id", userId));
		}
		if (gameId != null)
		{
			list.Add(new KeyValuePair<string, string>("game_id", gameId));
		}
		if (userId != null || gameId != null)
		{
			if (after != null)
			{
				list.Add(new KeyValuePair<string, string>("after", after));
			}
			if (before != null)
			{
				list.Add(new KeyValuePair<string, string>("before", before));
			}
			list.Add(new KeyValuePair<string, string>("first", first.ToString()));
			if (language != null)
			{
				list.Add(new KeyValuePair<string, string>("language", language));
			}
			switch ((int)period)
			{
			case 3:
				list.Add(new KeyValuePair<string, string>("period", "all"));
				break;
			case 0:
				list.Add(new KeyValuePair<string, string>("period", "day"));
				break;
			case 2:
				list.Add(new KeyValuePair<string, string>("period", "month"));
				break;
			case 1:
				list.Add(new KeyValuePair<string, string>("period", "week"));
				break;
			default:
				throw new ArgumentOutOfRangeException("period", period, null);
			}
			switch ((int)sort)
			{
			case 0:
				list.Add(new KeyValuePair<string, string>("sort", "time"));
				break;
			case 1:
				list.Add(new KeyValuePair<string, string>("sort", "trending"));
				break;
			case 2:
				list.Add(new KeyValuePair<string, string>("sort", "views"));
				break;
			default:
				throw new ArgumentOutOfRangeException("sort", sort, null);
			}
			switch ((int)type)
			{
			case 0:
				list.Add(new KeyValuePair<string, string>("type", "all"));
				break;
			case 3:
				list.Add(new KeyValuePair<string, string>("type", "highlight"));
				break;
			case 2:
				list.Add(new KeyValuePair<string, string>("type", "archive"));
				break;
			case 1:
				list.Add(new KeyValuePair<string, string>("type", "upload"));
				break;
			default:
				throw new ArgumentOutOfRangeException("type", type, null);
			}
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetVideosResponse>("/videos", (ApiVersion)6, list, (string)null, (string)null, (string)null);
	}
}
public class Webhooks : ApiBase
{
	public Webhooks(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<GetWebhookSubscriptionsResponse> GetWebhookSubscriptionsAsync(string after = null, int first = 20, string accessToken = null)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		if (first < 1 || first > 100)
		{
			throw new BadParameterException("'first' must between 1 (inclusive) and 100 (inclusive).");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("first", first.ToString())
		};
		if (after != null)
		{
			list.Add(new KeyValuePair<string, string>("after", after));
		}
		accessToken = ((ApiBase)this).GetAccessToken(accessToken);
		if (string.IsNullOrEmpty(accessToken))
		{
			throw new BadParameterException("'accessToken' be supplied, set AccessToken in settings or ClientId and Secret in settings");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<GetWebhookSubscriptionsResponse>("/webhooks/subscriptions", (ApiVersion)6, list, accessToken, (string)null, (string)null);
	}

	public Task<bool> UserFollowsSomeoneAsync(string callbackUrl, WebhookCallMode mode, string userInitiatorId, TimeSpan? duration = null, string signingSecret = null, string accessToken = null)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		int leaseSeconds = (int)ValidateTimespan(duration).TotalSeconds;
		return PerformWebhookRequestAsync(mode, "https://api.twitch.tv/helix/users/follows?first=1&from_id=" + userInitiatorId, callbackUrl, leaseSeconds, signingSecret, accessToken);
	}

	public Task<bool> UserReceivesFollowerAsync(string callbackUrl, WebhookCallMode mode, string userReceiverId, TimeSpan? duration = null, string signingSecret = null, string accessToken = null)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		int leaseSeconds = (int)ValidateTimespan(duration).TotalSeconds;
		return PerformWebhookRequestAsync(mode, "https://api.twitch.tv/helix/users/follows?first=1&to_id=" + userReceiverId, callbackUrl, leaseSeconds, signingSecret, accessToken);
	}

	public Task<bool> UserFollowsUserAsync(string callbackUrl, WebhookCallMode mode, string userInitiator, string userReceiverId, TimeSpan? duration = null, string signingSecret = null, string accessToken = null)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		int leaseSeconds = (int)ValidateTimespan(duration).TotalSeconds;
		return PerformWebhookRequestAsync(mode, "https://api.twitch.tv/helix/users/follows?first=1&from_id=" + userInitiator + "&to_id=" + userReceiverId, callbackUrl, leaseSeconds, signingSecret);
	}

	public Task<bool> StreamUpDownAsync(string callbackUrl, WebhookCallMode mode, string userId, TimeSpan? duration = null, string signingSecret = null, string accessToken = null)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		int leaseSeconds = (int)ValidateTimespan(duration).TotalSeconds;
		return PerformWebhookRequestAsync(mode, "https://api.twitch.tv/helix/streams?user_id=" + userId, callbackUrl, leaseSeconds, signingSecret, accessToken);
	}

	public Task<bool> UserChangedAsync(string callbackUrl, WebhookCallMode mode, int id, TimeSpan? duration = null, string signingSecret = null)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		int leaseSeconds = (int)ValidateTimespan(duration).TotalSeconds;
		return PerformWebhookRequestAsync(mode, $"https://api.twitch.tv/helix/users?id={id}", callbackUrl, leaseSeconds, signingSecret);
	}

	public Task<bool> GameAnalyticsAsync(string callbackUrl, WebhookCallMode mode, string gameId, TimeSpan? duration = null, string signingSecret = null, string authToken = null)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)24, authToken);
		int leaseSeconds = (int)ValidateTimespan(duration).TotalSeconds;
		return PerformWebhookRequestAsync(mode, "https://api.twitch.tv/helix/analytics/games?game_id=" + gameId, callbackUrl, leaseSeconds, signingSecret);
	}

	private TimeSpan ValidateTimespan(TimeSpan? duration)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if (duration.HasValue && duration.Value > TimeSpan.FromDays(10.0))
		{
			throw new BadParameterException("Maximum timespan allowed for webhook subscription duration is 10 days.");
		}
		return duration ?? TimeSpan.FromDays(10.0);
	}

	private async Task<bool> PerformWebhookRequestAsync(WebhookCallMode mode, string topicUrl, string callbackUrl, int leaseSeconds, string signingSecret = null, string accessToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		List<KeyValuePair<string, string>> getParams = new List<KeyValuePair<string, string>>
		{
			((int)mode == 0) ? new KeyValuePair<string, string>("hub.mode", "subscribe") : new KeyValuePair<string, string>("hub.mode", "unsubscribe"),
			new KeyValuePair<string, string>("hub.topic", topicUrl),
			new KeyValuePair<string, string>("hub.callback", callbackUrl),
			new KeyValuePair<string, string>("hub.lease_seconds", leaseSeconds.ToString())
		};
		if (signingSecret != null)
		{
			getParams.Add(new KeyValuePair<string, string>("hub.secret", signingSecret));
		}
		return (await ((ApiBase)this).TwitchPostAsync("/webhooks/hub", (ApiVersion)6, (string)null, getParams, accessToken, (string)null, (string)null).ConfigureAwait(continueOnCapturedContext: false)).Key == 202;
	}
}

lib/TwitchLib.Api.Helix.Models.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Newtonsoft.Json;
using TwitchLib.Api.Core.Enums;
using TwitchLib.Api.Helix.Models.Common;
using TwitchLib.Api.Helix.Models.Users.Internal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing the Helix models used in TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.3")]
[assembly: AssemblyInformationalVersion("3.1.3")]
[assembly: AssemblyProduct("TwitchLib.Api.Helix.Models")]
[assembly: AssemblyTitle("TwitchLib.Api.Helix.Models")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.3.0")]
namespace TwitchLib.Api.Helix.Models.Webhooks
{
	public class GetWebhookSubscriptionsResponse
	{
		[JsonProperty(PropertyName = "total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "data")]
		public Subscription[] Subscriptions { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
	public class Subscription
	{
		[JsonProperty(PropertyName = "topic")]
		public string Topic { get; protected set; }

		[JsonProperty(PropertyName = "callback")]
		public string Callback { get; protected set; }

		[JsonProperty(PropertyName = "expires_at")]
		public DateTime ExpiresAt { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Videos
{
	public class GetVideosResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Video[] Videos { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
	public class Video
	{
		[JsonProperty(PropertyName = "created_at")]
		public string CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "description")]
		public string Description { get; protected set; }

		[JsonProperty(PropertyName = "duration")]
		public string Duration { get; protected set; }

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

		[JsonProperty(PropertyName = "language")]
		public string Language { get; protected set; }

		[JsonProperty(PropertyName = "published_at")]
		public string PublishedAt { get; protected set; }

		[JsonProperty(PropertyName = "thumbnail_url")]
		public string ThumbnailUrl { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "view_count")]
		public int ViewCount { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Users
{
	public class Follow
	{
		[JsonProperty(PropertyName = "from_id")]
		public string FromUserId { get; protected set; }

		[JsonProperty(PropertyName = "from_name")]
		public string FromUserName { get; protected set; }

		[JsonProperty(PropertyName = "to_id")]
		public string ToUserId { get; protected set; }

		[JsonProperty(PropertyName = "to_name")]
		public string ToUserName { get; protected set; }

		[JsonProperty(PropertyName = "followed_at")]
		public DateTime FollowedAt { get; protected set; }
	}
	public class GetUserActiveExtensionsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public ActiveExtensions Data { get; protected set; }
	}
	public class GetUserExtensionsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public UserExtension[] Users { get; protected set; }
	}
	public class GetUsersFollowsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Follow[] Follows { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }

		[JsonProperty(PropertyName = "total")]
		public long TotalFollows { get; protected set; }
	}
	public class GetUsersResponse
	{
		[JsonProperty(PropertyName = "data")]
		public User[] Users { get; protected set; }
	}
	public class UpdateUserExtensionsRequest
	{
		[JsonProperty(PropertyName = "panel")]
		public Dictionary<string, UserExtensionState> Panel { get; set; }

		[JsonProperty(PropertyName = "component")]
		public Dictionary<string, UserExtensionState> Component { get; set; }

		[JsonProperty(PropertyName = "overlay")]
		public Dictionary<string, UserExtensionState> Overlay { get; set; }
	}
	public class User
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "login")]
		public string Login { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

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

		[JsonProperty(PropertyName = "broadcaster_type")]
		public string BroadcasterType { get; protected set; }

		[JsonProperty(PropertyName = "description")]
		public string Description { get; protected set; }

		[JsonProperty(PropertyName = "profile_image_url")]
		public string ProfileImageUrl { get; protected set; }

		[JsonProperty(PropertyName = "offline_image_url")]
		public string OfflineImageUrl { get; protected set; }

		[JsonProperty(PropertyName = "view_count")]
		public long ViewCount { get; protected set; }

		[JsonProperty(PropertyName = "email")]
		public string Email { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Users.Internal
{
	public class ActiveExtensions
	{
		[JsonProperty(PropertyName = "panel")]
		public Dictionary<string, UserActiveExtension> Panel { get; protected set; }

		[JsonProperty(PropertyName = "overlay")]
		public Dictionary<string, UserActiveExtension> Overlay { get; protected set; }

		[JsonProperty(PropertyName = "component")]
		public Dictionary<string, UserActiveExtension> Component { get; protected set; }
	}
	public class ExtensionSlot
	{
		public ExtensionType Type;

		public string Slot;

		public UserExtensionState UserExtensionState;

		public ExtensionSlot(ExtensionType type, string slot, UserExtensionState userExtensionState)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Type = type;
			Slot = slot;
			UserExtensionState = userExtensionState;
		}
	}
	public class UserActiveExtension
	{
		[JsonProperty(PropertyName = "active")]
		public bool Active { get; protected set; }

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

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

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

		[JsonProperty(PropertyName = "x")]
		public int X { get; protected set; }

		[JsonProperty(PropertyName = "y")]
		public int Y { get; protected set; }
	}
	public class UserExtension
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

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

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

		[JsonProperty(PropertyName = "can_activate")]
		public bool CanActivate { get; protected set; }

		[JsonProperty(PropertyName = "type")]
		public string[] Type { get; protected set; }
	}
	public class UserExtensionState
	{
		[JsonProperty(PropertyName = "active")]
		public bool Active { get; protected set; }

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

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

		public UserExtensionState(bool active, string id, string version)
		{
			Active = active;
			Id = id;
			Version = version;
		}
	}
}
namespace TwitchLib.Api.Helix.Models.Tags
{
	public class GetAllStreamTagsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Tag[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Subscriptions
{
	public class GetBroadcasterSubscriptionsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Subscription[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
	public class GetUserSubscriptionsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Subscription[] Data { get; protected set; }
	}
	public class Subscription
	{
		[JsonProperty(PropertyName = "broadcaster_id")]
		public string BroadcasterId { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_name")]
		public string BroadcasterName { get; protected set; }

		[JsonProperty(PropertyName = "is_gift")]
		public bool IsGift { get; protected set; }

		[JsonProperty(PropertyName = "tier")]
		public string Tier { get; protected set; }

		[JsonProperty(PropertyName = "plan_name")]
		public string PlanName { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string UserName { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Streams
{
	public class GetStreamsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Stream[] Streams { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
	public class GetStreamTagsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Tag[] Data { get; protected set; }
	}
	public class LiveStreams
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "streams")]
		public Stream[] Streams { get; protected set; }
	}
	public class Stream
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string UserName { get; protected set; }

		[JsonProperty(PropertyName = "game_id")]
		public string GameId { get; protected set; }

		[JsonProperty(PropertyName = "community_ids")]
		public string[] CommunityIds { get; protected set; }

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

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "viewer_count")]
		public int ViewerCount { get; protected set; }

		[JsonProperty(PropertyName = "started_at")]
		public DateTime StartedAt { get; protected set; }

		[JsonProperty(PropertyName = "language")]
		public string Language { get; protected set; }

		[JsonProperty(PropertyName = "thumbnail_url")]
		public string ThumbnailUrl { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.StreamsMetadata
{
	public class GetStreamsMetadataResponse
	{
		[JsonProperty(PropertyName = "data")]
		public StreamMetadata[] StreamsMetadatas { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
	public class Hearthstone
	{
		[JsonProperty(PropertyName = "broadcaster")]
		public PlayerHearthstone Broadcaster { get; protected set; }

		[JsonProperty(PropertyName = "opponent")]
		public PlayerHearthstone Opponent { get; protected set; }
	}
	public class HeroHearthstone
	{
		[JsonProperty(PropertyName = "class")]
		public string Class { get; protected set; }

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

		[JsonProperty(PropertyName = "type")]
		public string Type { get; protected set; }
	}
	public class HeroOverwatch
	{
		[JsonProperty(PropertyName = "ability")]
		public string Ability { get; protected set; }

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

		[JsonProperty(PropertyName = "role")]
		public string Role { get; protected set; }
	}
	public class Overwatch
	{
		public PlayerOverwatch Broadcaster { get; protected set; }
	}
	public class PlayerHearthstone
	{
		[JsonProperty(PropertyName = "hero")]
		public HeroHearthstone Hero { get; protected set; }
	}
	public class PlayerOverwatch
	{
		[JsonProperty(PropertyName = "hero")]
		public HeroOverwatch Hero { get; protected set; }
	}
	public class StreamMetadata
	{
		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "game_id")]
		public string GameId { get; protected set; }

		[JsonProperty(PropertyName = "hearthstone")]
		public Hearthstone Hearthstone { get; protected set; }

		[JsonProperty(PropertyName = "overwatch")]
		public Overwatch Overwatch { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Moderation.GetModerators
{
	public class GetModeratorsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Moderator[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
	public class Moderator
	{
		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string UserName { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Moderation.GetModeratorEvents
{
	public class EventData
	{
		[JsonProperty(PropertyName = "broadcaster_id")]
		public string BroadcasterId { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_name")]
		public string BroadcasterName { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string UserName { get; protected set; }
	}
	public class GetModeratorEventsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public ModeratorEvent[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
	public class ModeratorEvent
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "event_type")]
		public string EventType { get; protected set; }

		[JsonProperty(PropertyName = "event_timestamp")]
		public DateTime EventTimestamp { get; protected set; }

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

		[JsonProperty(PropertyName = "event_data")]
		public EventData EventData { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Moderation.GetBannedUsers
{
	public class BannedUserEvent
	{
		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string UserName { get; protected set; }

		[JsonProperty(PropertyName = "expires_at")]
		public DateTime? ExpiresAt { get; protected set; }
	}
	public class GetBannedUsersResponse
	{
		[JsonProperty(PropertyName = "data")]
		public BannedUserEvent[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Moderation.GetBannedEvents
{
	public class BannedEvent
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "event_type")]
		public string EventType { get; protected set; }

		[JsonProperty(PropertyName = "event_timestamp")]
		public DateTime EventTimestamp { get; protected set; }

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

		[JsonProperty(PropertyName = "event_data")]
		public EventData EventData { get; protected set; }
	}
	public class EventData
	{
		[JsonProperty(PropertyName = "broadcaster_id")]
		public string BroadcasterId { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_name")]
		public string BroadcasterName { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string UserName { get; protected set; }

		[JsonProperty(PropertyName = "expires_at")]
		public DateTime? ExpiresAt { get; protected set; }
	}
	public class GetBannedEventsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public BannedEvent[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Moderation.CheckAutoModStatus
{
	public class AutoModResult
	{
		[JsonProperty(PropertyName = "msg_id")]
		public string MsgId { get; protected set; }

		[JsonProperty(PropertyName = "is_permitted")]
		public bool IsPermitted { get; protected set; }
	}
	public class CheckAutoModStatusResponse
	{
		[JsonProperty(PropertyName = "data")]
		public AutoModResult[] Data { get; protected set; }
	}
	public class Message
	{
		[JsonProperty(PropertyName = "msg_id")]
		public string MsgId { get; set; }

		[JsonProperty(PropertyName = "msg_text")]
		public bool MsgText { get; set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Moderation.CheckAutoModStatus.Request
{
	public class MessageRequest
	{
		[JsonProperty(PropertyName = "data")]
		public Message[] Messages { get; set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Helpers
{
	public class ExtensionAnalytics
	{
		public string Date { get; protected set; }

		public string ExtensionName { get; protected set; }

		public string ExtensionClientId { get; protected set; }

		public int Installs { get; protected set; }

		public int Uninstalls { get; protected set; }

		public int Activations { get; protected set; }

		public int UniqueActiveChannels { get; protected set; }

		public int Renders { get; protected set; }

		public int UniqueRenders { get; protected set; }

		public int Views { get; protected set; }

		public int UniqueViewers { get; protected set; }

		public int UniqueInteractors { get; protected set; }

		public int Clicks { get; protected set; }

		public double ClicksPerInteractor { get; protected set; }

		public double InteractionRate { get; protected set; }

		public ExtensionAnalytics(string row)
		{
			string[] array = row.Split(new char[1] { ',' });
			Date = array[0];
			ExtensionName = array[1];
			ExtensionClientId = array[2];
			Installs = int.Parse(array[3]);
			Uninstalls = int.Parse(array[4]);
			Activations = int.Parse(array[5]);
			UniqueActiveChannels = int.Parse(array[6]);
			Renders = int.Parse(array[7]);
			UniqueRenders = int.Parse(array[8]);
			Views = int.Parse(array[9]);
			UniqueViewers = int.Parse(array[10]);
			UniqueInteractors = int.Parse(array[11]);
			Clicks = int.Parse(array[12]);
			ClicksPerInteractor = double.Parse(array[13]);
			InteractionRate = double.Parse(array[14]);
		}
	}
}
namespace TwitchLib.Api.Helix.Models.Games
{
	public class Game
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

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

		[JsonProperty(PropertyName = "box_art_url")]
		public string BoxArtUrl { get; protected set; }
	}
	public class GetGamesResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Game[] Games { get; protected set; }
	}
	public class GetTopGamesResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Game[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Extensions.Transactions
{
	public class GetExtensionTransactionsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Transaction[] CreatedClips { get; protected set; }
	}
	public class ProductData
	{
		[JsonProperty(PropertyName = "sku")]
		public string SKU { get; protected set; }

		[JsonProperty(PropertyName = "cost")]
		public Cost Cost { get; protected set; }

		[JsonProperty(PropertyName = "displayName")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "inDevelopment")]
		public bool InDevelopment { get; protected set; }
	}
	public class Cost
	{
		[JsonProperty(PropertyName = "amount")]
		public int Amount { get; protected set; }

		[JsonProperty(PropertyName = "type")]
		public string Type { get; protected set; }
	}
	public class Transaction
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "timestamp")]
		public DateTime Timestamp { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_id")]
		public string BroadcasterId { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_name")]
		public string BroadcasterName { get; protected set; }

		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "user_name")]
		public string UserName { get; protected set; }

		[JsonProperty(PropertyName = "product_type")]
		public string ProductType { get; protected set; }

		[JsonProperty(PropertyName = "product_data")]
		public ProductData ProductData { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Entitlements
{
	public class Status
	{
		[JsonProperty(PropertyName = "code")]
		public string Code { get; protected set; }

		[JsonProperty(PropertyName = "status")]
		public CodeStatusEnum StatusEnum { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Entitlements.RedeemCode
{
	public class RedeemCodeResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Status[] Data { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Entitlements.GetCodeStatus
{
	public class GetCodeStatusResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Status[] Data { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Entitlements.CreateEntitlementGrantsUploadURL
{
	public class CreateEntitlementGrantsUploadUrlResponse
	{
		[JsonProperty(PropertyName = "data")]
		public UploadUrl[] Data { get; protected set; }
	}
	public class UploadUrl
	{
		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Common
{
	public class DateRange
	{
		[JsonProperty(PropertyName = "started_at")]
		public DateTime StartedAt { get; protected set; }

		[JsonProperty(PropertyName = "ended_at")]
		public DateTime EndedAt { get; protected set; }
	}
	public class Pagination
	{
		[JsonProperty(PropertyName = "cursor")]
		public string Cursor { get; protected set; }
	}
	public class Tag
	{
		[JsonProperty(PropertyName = "tag_id")]
		public string TagId { get; protected set; }

		[JsonProperty(PropertyName = "is_auto")]
		public bool IsAuto { get; protected set; }

		[JsonProperty(PropertyName = "localization_names")]
		public Dictionary<string, string> LocalizationNames { get; protected set; }

		[JsonProperty(PropertyName = "localization_descriptions")]
		public Dictionary<string, string> LocalizationDescriptions { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Clips.GetClip
{
	public class Clip
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "embed_url")]
		public string EmbedUrl { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_id")]
		public string BroadcasterId { get; protected set; }

		[JsonProperty(PropertyName = "creator_id")]
		public string CreatorId { get; protected set; }

		[JsonProperty(PropertyName = "video_id")]
		public string VideoId { get; protected set; }

		[JsonProperty(PropertyName = "game_id")]
		public string GameId { get; protected set; }

		[JsonProperty(PropertyName = "language")]
		public string Language { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "view_count")]
		public int ViewCount { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public string CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "thumbnail_url")]
		public string ThumbnailUrl { get; protected set; }
	}
	public class GetClipResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Clip[] Clips { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Clips.CreateClip
{
	public class CreatedClip
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "edit_url")]
		public string EditUrl { get; protected set; }
	}
	public class CreatedClipResponse
	{
		[JsonProperty(PropertyName = "data")]
		public CreatedClip[] CreatedClips { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Bits
{
	public class DateRange
	{
		[JsonProperty(PropertyName = "started_at")]
		public DateTime StartedAt { get; protected set; }

		[JsonProperty(PropertyName = "ended_at")]
		public DateTime EndedAt { get; protected set; }
	}
	public class GetBitsLeaderboardResponse
	{
		[JsonProperty(PropertyName = "data")]
		public Listing[] Listings { get; protected set; }

		[JsonProperty(PropertyName = "date_range")]
		public DateRange DateRange { get; protected set; }

		[JsonProperty(PropertyName = "total")]
		public int Total { get; protected set; }
	}
	public class Listing
	{
		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "rank")]
		public int Rank { get; protected set; }

		[JsonProperty(PropertyName = "score")]
		public int Score { get; protected set; }
	}
}
namespace TwitchLib.Api.Helix.Models.Analytics
{
	public class ExtensionAnalytics
	{
		[JsonProperty(PropertyName = "extension_id")]
		public string ExtensionId { get; protected set; }

		[JsonProperty(PropertyName = "URL")]
		public string Url { get; protected set; }
	}
	public class GameAnalytics
	{
		[JsonProperty(PropertyName = "game_id")]
		public string GameId { get; protected set; }

		[JsonProperty(PropertyName = "URL")]
		public string Url { get; protected set; }

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

		[JsonProperty(PropertyName = "date_range")]
		public DateRange DateRange { get; protected set; }
	}
	public class GetExtensionAnalyticsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public ExtensionAnalytics[] Data { get; protected set; }
	}
	public class GetGameAnalyticsResponse
	{
		[JsonProperty(PropertyName = "data")]
		public GameAnalytics[] Data { get; protected set; }

		[JsonProperty(PropertyName = "pagination")]
		public Pagination Pagination { get; protected set; }
	}
}

lib/TwitchLib.Api.V5.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using TwitchLib.Api.Core;
using TwitchLib.Api.Core.Enums;
using TwitchLib.Api.Core.Exceptions;
using TwitchLib.Api.Core.Extensions.System;
using TwitchLib.Api.Core.HttpCallHandlers;
using TwitchLib.Api.Core.Interfaces;
using TwitchLib.Api.Core.Models.Root;
using TwitchLib.Api.Core.RateLimiter;
using TwitchLib.Api.V5.Models.Auth;
using TwitchLib.Api.V5.Models.Badges;
using TwitchLib.Api.V5.Models.Bits;
using TwitchLib.Api.V5.Models.Channels;
using TwitchLib.Api.V5.Models.Chat;
using TwitchLib.Api.V5.Models.Clips;
using TwitchLib.Api.V5.Models.Collections;
using TwitchLib.Api.V5.Models.Communities;
using TwitchLib.Api.V5.Models.Games;
using TwitchLib.Api.V5.Models.Ingests;
using TwitchLib.Api.V5.Models.Search;
using TwitchLib.Api.V5.Models.Streams;
using TwitchLib.Api.V5.Models.Subscriptions;
using TwitchLib.Api.V5.Models.Teams;
using TwitchLib.Api.V5.Models.UploadVideo;
using TwitchLib.Api.V5.Models.Users;
using TwitchLib.Api.V5.Models.Videos;
using TwitchLib.Api.V5.Models.ViewerHeartbeatService;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing the V5 section of TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.2")]
[assembly: AssemblyInformationalVersion("3.1.2")]
[assembly: AssemblyProduct("TwitchLib.Api.V5")]
[assembly: AssemblyTitle("TwitchLib.Api.V5")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.2.0")]
namespace TwitchLib.Api.V5;

public class Auth : ApiBase
{
	public Auth(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<RefreshResponse> RefreshAuthTokenAsync(string refreshToken, string clientSecret, string clientId = null)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		string value = clientId ?? base.Settings.ClientId;
		if (string.IsNullOrWhiteSpace(refreshToken))
		{
			throw new BadParameterException("The refresh token is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(clientSecret))
		{
			throw new BadParameterException("The client secret is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(value))
		{
			throw new BadParameterException("The clientId is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("grant_type", "refresh_token"),
			new KeyValuePair<string, string>("refresh_token", refreshToken),
			new KeyValuePair<string, string>("client_id", value),
			new KeyValuePair<string, string>("client_secret", clientSecret)
		};
		return ((ApiBase)this).TwitchPostGenericAsync<RefreshResponse>("/oauth2/token", (ApiVersion)5, (string)null, list, (string)null, (string)null, "https://id.twitch.tv");
	}
}
public class Badges : ApiBase
{
	public Badges(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<ChannelDisplayBadges> GetSubscriberBadgesForChannelAsync(string channelId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelDisplayBadges>("/v1/badges/channels/" + channelId + "/display", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, "https://badges.twitch.tv");
	}

	public Task<GlobalBadgesResponse> GetGlobalBadgesAsync()
	{
		return ((ApiBase)this).TwitchGetGenericAsync<GlobalBadgesResponse>("/v1/badges/global/display", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, "https://badges.twitch.tv");
	}
}
public class Bits : ApiBase
{
	public Bits(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<Cheermotes> GetCheermotesAsync(string channelId = null)
	{
		List<KeyValuePair<string, string>> list = null;
		if (channelId != null)
		{
			list = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("channel_id", channelId)
			};
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Cheermotes>("/bits/actions", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}
}
public class Channels : ApiBase
{
	public Channels(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<ChannelAuthed> GetChannelAsync(string authToken = null)
	{
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelAuthed>("/channel", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<Channel> GetChannelByIDAsync(string channelId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Channel>("/channels/" + channelId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<Channel> UpdateChannelAsync(string channelId, string status = null, string game = null, string delay = null, bool? channelFeedEnabled = null, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)26, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (!string.IsNullOrEmpty(status))
		{
			list.Add(new KeyValuePair<string, string>("status", "\"" + status + "\""));
		}
		if (!string.IsNullOrEmpty(game))
		{
			list.Add(new KeyValuePair<string, string>("game", "\"" + game + "\""));
		}
		if (!string.IsNullOrEmpty(delay))
		{
			list.Add(new KeyValuePair<string, string>("delay", "\"" + delay + "\""));
		}
		if (channelFeedEnabled.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("channel_feed_enabled", (channelFeedEnabled == true) ? "true" : "false"));
		}
		string text = "";
		switch (list.Count)
		{
		case 0:
			throw new BadParameterException("At least one parameter must be specified: status, game, delay, channel_feed_enabled.");
		case 1:
			text = "\"" + list[0].Key + "\": " + list[0].Value;
			break;
		default:
		{
			for (int i = 0; i < list.Count; i++)
			{
				text = ((list.Count - i > 1) ? (text + "\"" + list[i].Key + "\": " + list[i].Value + ",") : (text + "\"" + list[i].Key + "\": " + list[i].Value));
			}
			break;
		}
		}
		text = "{ \"channel\": {" + text + "} }";
		return ((ApiBase)this).TwitchPutGenericAsync<Channel>("/channels/" + channelId, (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<ChannelEditors> GetChannelEditorsAsync(string channelId, string authToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)6, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelEditors>("/channels/" + channelId + "/editors", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<ChannelFollowers> GetChannelFollowersAsync(string channelId, int? limit = null, int? offset = null, string cursor = null, string direction = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
		}
		if (!string.IsNullOrEmpty(cursor))
		{
			list.Add(new KeyValuePair<string, string>("cursor", cursor));
		}
		if (!string.IsNullOrEmpty(direction) && (direction == "asc" || direction == "desc"))
		{
			list.Add(new KeyValuePair<string, string>("direction", direction));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelFollowers>("/channels/" + channelId + "/follows", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public async Task<List<ChannelFollow>> GetAllFollowersAsync(string channelId)
	{
		List<ChannelFollow> followers = new List<ChannelFollow>();
		ChannelFollowers firstBatch = await GetChannelFollowersAsync(channelId, 100).ConfigureAwait(continueOnCapturedContext: false);
		int totalFollowers = firstBatch.Total;
		string cursor = firstBatch.Cursor;
		followers.AddRange(firstBatch.Follows.OfType<ChannelFollow>().ToList());
		int amount = firstBatch.Follows.Length;
		int leftOverFollowers = (totalFollowers - amount) % 100;
		int requiredRequests = (totalFollowers - amount - leftOverFollowers) / 100;
		await Task.Delay(1000);
		for (int i = 0; i < requiredRequests; i++)
		{
			ChannelFollowers requestedFollowers = await GetChannelFollowersAsync(channelId, 100, null, cursor).ConfigureAwait(continueOnCapturedContext: false);
			cursor = requestedFollowers.Cursor;
			followers.AddRange(requestedFollowers.Follows.OfType<ChannelFollow>().ToList());
			await Task.Delay(1000);
		}
		if (leftOverFollowers > 0)
		{
			followers.AddRange((await GetChannelFollowersAsync(channelId, leftOverFollowers, null, cursor).ConfigureAwait(continueOnCapturedContext: false)).Follows.OfType<ChannelFollow>().ToList());
		}
		return followers;
	}

	public Task<ChannelTeams> GetChannelTeamsAsync(string channelId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelTeams>("/channels/" + channelId + "/teams", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<ChannelSubscribers> GetChannelSubscribersAsync(string channelId, int? limit = null, int? offset = null, string direction = null, string authToken = null)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)8, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
		}
		if (!string.IsNullOrEmpty(direction) && (direction == "asc" || direction == "desc"))
		{
			list.Add(new KeyValuePair<string, string>("direction", direction));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelSubscribers>("/channels/" + channelId + "/subscriptions", (ApiVersion)5, list, authToken, (string)null, (string)null);
	}

	public async Task<List<Subscription>> GetAllSubscribersAsync(string channelId, string accessToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)8, accessToken);
		List<Subscription> allSubs = new List<Subscription>();
		ChannelSubscribers firstBatch = await GetChannelSubscribersAsync(channelId, 100, 0, "asc", accessToken);
		int totalSubs = firstBatch.Total;
		allSubs.AddRange(firstBatch.Subscriptions);
		int amount = firstBatch.Subscriptions.Length;
		int leftOverSubs = (totalSubs - amount) % 100;
		int requiredRequests = (totalSubs - amount - leftOverSubs) / 100;
		int currentOffset = amount;
		await Task.Delay(1000);
		for (int i = 0; i < requiredRequests; i++)
		{
			ChannelSubscribers requestedSubs = await GetChannelSubscribersAsync(channelId, 100, currentOffset, "asc", accessToken).ConfigureAwait(continueOnCapturedContext: false);
			allSubs.AddRange(requestedSubs.Subscriptions);
			currentOffset += requestedSubs.Subscriptions.Length;
			await Task.Delay(1000);
		}
		if (leftOverSubs > 0)
		{
			allSubs.AddRange((await GetChannelSubscribersAsync(channelId, leftOverSubs, currentOffset, "asc", accessToken).ConfigureAwait(continueOnCapturedContext: false)).Subscriptions);
		}
		return allSubs;
	}

	public Task<Subscription> CheckChannelSubscriptionByUserAsync(string channelId, string userId, string authToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)1, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Subscription>("/channels/" + channelId + "/subscriptions/" + userId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<ChannelVideos> GetChannelVideosAsync(string channelId, int? limit = null, int? offset = null, List<string> broadcastType = null, List<string> language = null, string sort = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
		}
		if (broadcastType != null && broadcastType.Count > 0)
		{
			bool flag = false;
			foreach (string item in broadcastType)
			{
				if (item == "archive" || item == "highlight" || item == "upload")
				{
					flag = true;
					continue;
				}
				flag = false;
				break;
			}
			if (flag)
			{
				list.Add(new KeyValuePair<string, string>("broadcast_type", string.Join(",", broadcastType)));
			}
		}
		if (language != null && language.Count > 0)
		{
			list.Add(new KeyValuePair<string, string>("language", string.Join(",", language)));
		}
		if (!string.IsNullOrWhiteSpace(sort) && (sort == "views" || sort == "time"))
		{
			list.Add(new KeyValuePair<string, string>("sort", sort));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelVideos>("/channels/" + channelId + "/videos", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<ChannelCommercial> StartChannelCommercialAsync(string channelId, CommercialLength duration, string authToken = null)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected I4, but got Unknown
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)2, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "{\"duration\": " + (int)duration + "}";
		return ((ApiBase)this).TwitchPostGenericAsync<ChannelCommercial>("/channels/" + channelId + "/commercial", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<ChannelAuthed> ResetChannelStreamKeyAsync(string channelId, string authToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)7, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteGenericAsync<ChannelAuthed>("/channels/" + channelId + "/stream_key", (ApiVersion)5, authToken, (string)null, (string)null);
	}

	public Task<Community> GetChannelCommunityAsync(string channelId, string authToken = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Community>("/channels/" + channelId + "/community", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<CommunitiesResponse> GetChannelCommunitiesAsync(string channelId, string authToken = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is now allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<CommunitiesResponse>("/channels/" + channelId + "/communities", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task SetChannelCommunitiesAsync(string channelId, List<string> communityIds, string authToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)3, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (communityIds == null || communityIds.Count == 0)
		{
			throw new BadParameterException("The no community ids where specified");
		}
		if (communityIds != null && communityIds.Count > 3)
		{
			throw new BadParameterException("You can only set up to 3 communities");
		}
		if (communityIds.Any(string.IsNullOrWhiteSpace))
		{
			throw new BadParameterException("One or more of the community ids is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "";
		foreach (string communityId in communityIds)
		{
			text = ((!(text == "")) ? (text + ", \"" + communityId + "\"") : ("\"" + communityId + "\""));
		}
		text = "{\"community_ids\": [" + text + "]}";
		return ((ApiBase)this).TwitchPutAsync("/channels/" + channelId + "/communities", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task DeleteChannelFromCommunityAsync(string channelId, string authToken = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/channels/" + channelId + "/community", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}
}
public class Chat : ApiBase
{
	public Chat(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<ChannelBadges> GetChatBadgesByChannelAsync(string channelId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid for catching the channel badges. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<ChannelBadges>("/chat/" + channelId + "/badges", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<EmoteSet> GetChatEmoticonsBySetAsync(List<int> emotesets = null)
	{
		List<KeyValuePair<string, string>> list = null;
		if (emotesets != null && emotesets.Count > 0)
		{
			list = new List<KeyValuePair<string, string>>
			{
				new KeyValuePair<string, string>("emotesets", string.Join(",", emotesets))
			};
		}
		return ((ApiBase)this).TwitchGetGenericAsync<EmoteSet>("/chat/emoticon_images", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<AllChatEmotes> GetAllChatEmoticonsAsync()
	{
		return ((ApiBase)this).TwitchGetGenericAsync<AllChatEmotes>("/chat/emoticons", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<ChatRoomsByChannelResponse> GetChatRoomsByChannelAsync(string channelId, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)0, authToken);
		return ((ApiBase)this).TwitchGetGenericAsync<ChatRoomsByChannelResponse>("/chat/" + channelId + "/rooms", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}
}
public class Clips : ApiBase
{
	public Clips(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<Clip> GetClipAsync(string slug)
	{
		return ((ApiBase)this).TwitchGetGenericAsync<Clip>("/clips/" + slug, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<TopClipsResponse> GetTopClipsAsync(string channel = null, string cursor = null, string game = null, long limit = 10L, Period period = 1, bool trending = false)
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Expected I4, but got Unknown
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("limit", limit.ToString())
		};
		if (channel != null)
		{
			list.Add(new KeyValuePair<string, string>("channel", channel));
		}
		if (cursor != null)
		{
			list.Add(new KeyValuePair<string, string>("cursor", cursor));
		}
		if (game != null)
		{
			list.Add(new KeyValuePair<string, string>("game", game));
		}
		list.Add(trending ? new KeyValuePair<string, string>("trending", "true") : new KeyValuePair<string, string>("trending", "false"));
		switch ((int)period)
		{
		case 3:
			list.Add(new KeyValuePair<string, string>("period", "all"));
			break;
		case 2:
			list.Add(new KeyValuePair<string, string>("period", "month"));
			break;
		case 1:
			list.Add(new KeyValuePair<string, string>("period", "week"));
			break;
		case 0:
			list.Add(new KeyValuePair<string, string>("period", "day"));
			break;
		default:
			throw new ArgumentOutOfRangeException("period", period, null);
		}
		return ((ApiBase)this).TwitchGetGenericAsync<TopClipsResponse>("/clips/top", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<FollowClipsResponse> GetFollowedClipsAsync(long limit = 10L, string cursor = null, bool trending = false, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)16, authToken);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("limit", limit.ToString())
		};
		if (cursor != null)
		{
			list.Add(new KeyValuePair<string, string>("cursor", cursor));
		}
		list.Add(trending ? new KeyValuePair<string, string>("trending", "true") : new KeyValuePair<string, string>("trending", "false"));
		return ((ApiBase)this).TwitchGetGenericAsync<FollowClipsResponse>("/clips/followed", (ApiVersion)5, list, authToken, (string)null, (string)null);
	}
}
public class Collections : ApiBase
{
	public Collections(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<CollectionMetadata> GetCollectionMetadataAsync(string collectionId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<CollectionMetadata>("/collections/" + collectionId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<Collection> GetCollectionAsync(string collectionId, bool? includeAllItems = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (includeAllItems.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("include_all_items", includeAllItems.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Collection>("/collections/" + collectionId + "/items", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<CollectionsByChannel> GetCollectionsByChannelAsync(string channelId, long? limit = null, string cursor = null, string containingItem = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid for catching a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (!string.IsNullOrWhiteSpace(cursor))
		{
			list.Add(new KeyValuePair<string, string>("cursor", cursor));
		}
		if (!string.IsNullOrWhiteSpace(containingItem))
		{
			list.Add(new KeyValuePair<string, string>("containing_item", containingItem.StartsWith("video:") ? containingItem : ("video:" + containingItem)));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<CollectionsByChannel>("/channels/" + channelId + "/collections", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<CollectionMetadata> CreateCollectionAsync(string channelId, string collectionTitle, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)10, authToken);
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid for a collection creation. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(collectionTitle))
		{
			throw new BadParameterException("The collection title is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "{\"title\": \"" + collectionTitle + "\"}";
		return ((ApiBase)this).TwitchPostGenericAsync<CollectionMetadata>("/channels/" + channelId + "/collections", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task UpdateCollectionAsync(string collectionId, string newCollectionTitle, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)10, authToken);
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(newCollectionTitle))
		{
			throw new BadParameterException("The new collection title is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "{\"title\": \"" + newCollectionTitle + "\"}";
		return ((ApiBase)this).TwitchPutAsync("/collections/" + collectionId, (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task CreateCollectionThumbnailAsync(string collectionId, string itemId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)10, authToken);
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(itemId))
		{
			throw new BadParameterException("The item id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "{\"item_id\": \"" + itemId + "\"}";
		return ((ApiBase)this).TwitchPutAsync("/collections/" + collectionId + "/thumbnail", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task DeleteCollectionAsync(string collectionId, string authToken = null)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)10, authToken);
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/collections/" + collectionId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<CollectionItem> AddItemToCollectionAsync(string collectionId, string itemId, string itemType, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)10, authToken);
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(itemId))
		{
			throw new BadParameterException("The item id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (itemType != "video")
		{
			throw new BadParameterException("The item_type " + itemType + " is not valid for a collection. Item type MUST be \"video\".");
		}
		string text = "{\"id\": \"" + itemId + "\", \"type\": \"" + itemType + "\"}";
		return ((ApiBase)this).TwitchPostGenericAsync<CollectionItem>("/collections/" + collectionId + "/items", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task DeleteItemFromCollectionAsync(string collectionId, string itemId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)10, authToken);
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(itemId))
		{
			throw new BadParameterException("The item id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/collections/" + collectionId + "/items/" + itemId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task MoveItemWithinCollectionAsync(string collectionId, string itemId, int position, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)10, authToken);
		if (string.IsNullOrWhiteSpace(collectionId))
		{
			throw new BadParameterException("The collection id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(itemId))
		{
			throw new BadParameterException("The item id is not valid for a collection. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (position < 1)
		{
			throw new BadParameterException("The position is not valid for a collection. It is not allowed to be less than 1.");
		}
		string text = "{\"position\": \"" + position + "\"}";
		return ((ApiBase)this).TwitchPutAsync("/collections/" + collectionId + "/items/" + itemId, (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}
}
public class Communities : ApiBase
{
	public Communities(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<Community> GetCommunityByNameAsync(string communityName)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(communityName))
		{
			throw new BadParameterException("The community name is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("name", communityName)
		};
		return ((ApiBase)this).TwitchGetGenericAsync<Community>("/communities", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<Community> GetCommunityByIDAsync(string communityId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Community>("/communities/" + communityId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task UpdateCommunityAsync(string communityId, string summary = null, string description = null, string rules = null, string email = null, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (!string.IsNullOrEmpty(summary))
		{
			list.Add(new KeyValuePair<string, string>("status", "\"" + summary + "\""));
		}
		if (!string.IsNullOrEmpty(description))
		{
			list.Add(new KeyValuePair<string, string>("description", "\"" + description + "\""));
		}
		if (!string.IsNullOrEmpty(rules))
		{
			list.Add(new KeyValuePair<string, string>("rules", "\"" + rules + "\""));
		}
		if (!string.IsNullOrEmpty(email))
		{
			list.Add(new KeyValuePair<string, string>("email", "\"" + email + "\""));
		}
		string text = "";
		switch (list.Count)
		{
		case 0:
			throw new BadParameterException("At least one parameter must be specified: summary, description, rules, email.");
		case 1:
			text = "\"" + list[0].Key + "\": " + list[0].Value;
			break;
		default:
		{
			for (int i = 0; i < list.Count; i++)
			{
				text = ((list.Count - i > 1) ? (text + "\"" + list[i].Key + "\": " + list[i].Value + ",") : (text + "\"" + list[i].Key + "\": " + list[i].Value));
			}
			break;
		}
		}
		text = "{" + text + "}";
		return ((ApiBase)this).TwitchPutAsync("/communities/" + communityId, (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<TopCommunities> GetTopCommunitiesAsync(long? limit = null, string cursor = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (!string.IsNullOrEmpty(cursor))
		{
			list.Add(new KeyValuePair<string, string>("cursor", cursor));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<TopCommunities>("/communities/top", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<BannedUsers> GetCommunityBannedUsersAsync(string communityId, long? limit = null, string cursor = null, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)12, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (!string.IsNullOrEmpty(cursor))
		{
			list.Add(new KeyValuePair<string, string>("cursor", cursor));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<BannedUsers>("/communities/" + communityId + "/bans", (ApiVersion)5, list, authToken, (string)null, (string)null);
	}

	public Task BanCommunityUserAsync(string communityId, string userId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)12, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchPutAsync("/communities/" + communityId + "/bans/" + userId, (ApiVersion)5, (string)null, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task UnBanCommunityUserAsync(string communityId, string userId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)12, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/communities/" + communityId + "/bans/" + userId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task CreateCommunityAvatarImageAsync(string communityId, string avatarImage, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(avatarImage))
		{
			throw new BadParameterException("The avatar image is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "{\"avatar_image\": \"" + avatarImage + "\"}";
		return ((ApiBase)this).TwitchPostAsync("/communities/" + communityId + "/images/avatar", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task DeleteCommunityAvatarImageAsync(string communityId, string authToken = null)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/communities/" + communityId + "/images/avatar", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task CreateCommunityCoverImageAsync(string communityId, string coverImage, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(coverImage))
		{
			throw new BadParameterException("The cover image is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "{\"cover_image\": \"" + coverImage + "\"}";
		return ((ApiBase)this).TwitchPostAsync("/communities/" + communityId + "/images/cover", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public async Task DeleteCommunityCoverImageAsync(string communityId, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		await ((ApiBase)this).TwitchDeleteAsync("/communities/" + communityId + "/images/cover", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null).ConfigureAwait(continueOnCapturedContext: false);
	}

	public Task<Moderators> GetCommunityModeratorsAsync(string communityId, string authToken)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Moderators>("/communities/" + communityId + "/moderators", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public async Task AddCommunityModeratorAsync(string communityId, string userId, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		await ((ApiBase)this).TwitchPutAsync("/communities/" + communityId + "/moderators/" + userId, (ApiVersion)5, (string)null, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null).ConfigureAwait(continueOnCapturedContext: false);
	}

	public async Task DeleteCommunityModeratorAsync(string communityId, string userId, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)11, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		await ((ApiBase)this).TwitchDeleteAsync("/communities/" + communityId + "/moderators/" + userId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null).ConfigureAwait(continueOnCapturedContext: false);
	}

	public Task<Dictionary<string, bool>> GetCommunityPermissionsAsync(string communityId, string authToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)0, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Dictionary<string, bool>>("/communities/" + communityId + "/permissions", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public async Task ReportCommunityViolationAsync(string communityId, string channelId)
	{
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string payload = "{\"channel_id\": \"" + channelId + "\"}";
		await ((ApiBase)this).TwitchPostAsync("/communities/" + communityId + "/report_channel", (ApiVersion)5, payload, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null).ConfigureAwait(continueOnCapturedContext: false);
	}

	public Task<TimedOutUsers> GetCommunityTimedOutUsersAsync(string communityId, long? limit = null, string cursor = null, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)12, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (!string.IsNullOrEmpty(cursor))
		{
			list.Add(new KeyValuePair<string, string>("cursor", cursor));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<TimedOutUsers>("/communities/" + communityId + "/timeouts", (ApiVersion)5, list, authToken, (string)null, (string)null);
	}

	public async Task AddCommunityTimedOutUserAsync(string communityId, string userId, int duration, string reason = null, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)12, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string payload = "{\"duration\": \"" + duration + "\"" + ((!string.IsNullOrWhiteSpace(reason)) ? (", \"reason\": \"" + reason + "\"}") : "}");
		await ((ApiBase)this).TwitchPutAsync("/communities/" + communityId + "/timeouts/" + userId, (ApiVersion)5, payload, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null).ConfigureAwait(continueOnCapturedContext: false);
	}

	public async Task DeleteCommunityTimedOutUserAsync(string communityId, string userId, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)12, authToken);
		if (string.IsNullOrWhiteSpace(communityId))
		{
			throw new BadParameterException("The community id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		await ((ApiBase)this).TwitchDeleteAsync("/communities/" + communityId + "/timeouts/" + userId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null).ConfigureAwait(continueOnCapturedContext: false);
	}
}
public class Games : ApiBase
{
	public Games(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<TopGames> GetTopGamesAsync(int? limit = null, int? offset = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<TopGames>("/games/top", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}
}
public class Ingests : ApiBase
{
	public Ingests(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<Ingests> GetIngestServerListAsync()
	{
		return ((ApiBase)this).TwitchGetGenericAsync<Ingests>("/ingests", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}
}
public class Root : ApiBase
{
	public Root(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<Root> GetRootAsync(string authToken = null, string clientId = null)
	{
		return ((ApiBase)this).TwitchGetGenericAsync<Root>("", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, clientId, (string)null);
	}
}
public class Search : ApiBase
{
	public Search(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<SearchChannels> SearchChannelsAsync(string encodedSearchQuery, int? limit = null, int? offset = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("query", encodedSearchQuery)
		};
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<SearchChannels>("/search/channels", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<SearchGames> SearchGamesAsync(string encodedSearchQuery, bool? live = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("query", encodedSearchQuery)
		};
		if (live.HasValue)
		{
			list.Add(live.Value ? new KeyValuePair<string, string>("live", "true") : new KeyValuePair<string, string>("live", "false"));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<SearchGames>("/search/games", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<SearchStreams> SearchStreamsAsync(string encodedSearchQuery, int? limit = null, int? offset = null, bool? hls = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("query", encodedSearchQuery)
		};
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		if (hls.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("hls", hls.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<SearchStreams>("/search/streams", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}
}
public class Streams : ApiBase
{
	public Streams(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<StreamByUser> GetStreamByUserAsync(string channelId, string streamType = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid for fetching streams. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (!string.IsNullOrWhiteSpace(streamType))
		{
			switch (streamType)
			{
			default:
				if (!(streamType == "watch_party"))
				{
					break;
				}
				goto case "live";
			case "live":
			case "playlist":
			case "all":
				list.Add(new KeyValuePair<string, string>("stream_type", streamType));
				break;
			}
		}
		return ((ApiBase)this).TwitchGetGenericAsync<StreamByUser>("/streams/" + channelId, (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<LiveStreams> GetLiveStreamsAsync(List<string> channelList = null, string game = null, string language = null, string streamType = null, int? limit = null, int? offset = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (channelList != null && channelList.Count > 0)
		{
			list.Add(new KeyValuePair<string, string>("channel", string.Join(",", channelList)));
		}
		if (!string.IsNullOrWhiteSpace(game))
		{
			list.Add(new KeyValuePair<string, string>("game", game));
		}
		if (!string.IsNullOrWhiteSpace(language))
		{
			list.Add(new KeyValuePair<string, string>("language", language));
		}
		if (!string.IsNullOrWhiteSpace(streamType))
		{
			switch (streamType)
			{
			default:
				if (!(streamType == "watch_party"))
				{
					break;
				}
				goto case "live";
			case "live":
			case "playlist":
			case "all":
				list.Add(new KeyValuePair<string, string>("stream_type", streamType));
				break;
			}
		}
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<LiveStreams>("/streams", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<StreamsSummary> GetStreamsSummaryAsync(string game = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (game != null)
		{
			list.Add(new KeyValuePair<string, string>("game", game));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<StreamsSummary>("/streams/summary", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<FeaturedStreams> GetFeaturedStreamAsync(int? limit = null, int? offset = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<FeaturedStreams>("/streams/featured", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<FollowedStreams> GetFollowedStreamsAsync(string streamType = null, int? limit = null, int? offset = null, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)16, authToken);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (!string.IsNullOrWhiteSpace(streamType))
		{
			switch (streamType)
			{
			default:
				if (!(streamType == "watch_party"))
				{
					break;
				}
				goto case "live";
			case "live":
			case "playlist":
			case "all":
				list.Add(new KeyValuePair<string, string>("stream_type", streamType));
				break;
			}
		}
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<FollowedStreams>("/streams/followed", (ApiVersion)5, list, authToken, (string)null, (string)null);
	}

	public async Task<TimeSpan?> GetUptimeAsync(string channelId)
	{
		try
		{
			StreamByUser stream = await GetStreamByUserAsync(channelId).ConfigureAwait(continueOnCapturedContext: false);
			return DateTime.UtcNow - stream.Stream.CreatedAt;
		}
		catch (Exception)
		{
			return null;
		}
	}

	public async Task<bool> BroadcasterOnlineAsync(string channelId)
	{
		return (await GetStreamByUserAsync(channelId).ConfigureAwait(continueOnCapturedContext: false)).Stream != null;
	}
}
public class Teams : ApiBase
{
	public Teams(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<AllTeams> GetAllTeamsAsync(int? limit = null, int? offset = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<AllTeams>("/teams", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<Team> GetTeamAsync(string teamName)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(teamName))
		{
			throw new BadParameterException("The team name is not valid for fetching teams. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Team>("/teams/" + teamName, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}
}
public class Users : ApiBase
{
	public Users(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<Users> GetUsersByNameAsync(List<string> usernames)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (usernames == null || usernames.Count == 0)
		{
			throw new BadParameterException("The username list is not valid. It is not allowed to be null or empty.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("login", string.Join(",", usernames))
		};
		return ((ApiBase)this).TwitchGetGenericAsync<Users>("/users", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<UserAuthed> GetUserAsync(string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)16, authToken);
		return ((ApiBase)this).TwitchGetGenericAsync<UserAuthed>("/user", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<User> GetUserByIDAsync(string userId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<User>("/users/" + userId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<Users> GetUserByNameAsync(string username)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(username))
		{
			throw new BadParameterException("The username is not valid.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("login", username)
		};
		return ((ApiBase)this).TwitchGetGenericAsync<Users>("/users", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<UserEmotes> GetUserEmotesAsync(string userId, string authToken = null)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)17, authToken);
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<UserEmotes>("/users/" + userId + "/emotes", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<Subscription> CheckUserSubscriptionByChannelAsync(string userId, string channelId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)17, authToken);
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Subscription>("/users/" + userId + "/subscriptions/" + channelId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<UserFollows> GetUserFollowsAsync(string userId, int? limit = null, int? offset = null, string direction = null, string sortby = null)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		if (!string.IsNullOrEmpty(direction) && (direction == "asc" || direction == "desc"))
		{
			list.Add(new KeyValuePair<string, string>("direction", direction));
		}
		if (!string.IsNullOrEmpty(sortby) && (sortby == "created_at" || sortby == "last_broadcast" || sortby == "login"))
		{
			list.Add(new KeyValuePair<string, string>("sortby", sortby));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<UserFollows>("/users/" + userId + "/follows/channels", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<UserFollow> CheckUserFollowsByChannelAsync(string userId, string channelId)
	{
		//IL_0010: 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)
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<UserFollow>("/users/" + userId + "/follows/channels/" + channelId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public async Task<bool> UserFollowsChannelAsync(string userId, string channelId)
	{
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		try
		{
			await ((ApiBase)this).TwitchGetGenericAsync<UserFollow>("/users/" + userId + "/follows/channels/" + channelId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
			return true;
		}
		catch (BadResourceException)
		{
			return false;
		}
	}

	public Task<UserFollow> FollowChannelAsync(string userId, string channelId, bool? notifications = null, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)15, authToken);
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = (notifications.HasValue ? ("{\"notifications\": " + notifications.Value.ToString().ToLower() + "}") : null);
		return ((ApiBase)this).TwitchPutGenericAsync<UserFollow>("/users/" + userId + "/follows/channels/" + channelId, (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task UnfollowChannelAsync(string userId, string channelId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)15, authToken);
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(channelId))
		{
			throw new BadParameterException("The channel id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/users/" + userId + "/follows/channels/" + channelId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<UserBlocks> GetUserBlockListAsync(string userId, int? limit = null, int? offset = null, string authToken = null)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)14, authToken);
		if (string.IsNullOrWhiteSpace(userId))
		{
			throw new BadParameterException("The user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<UserBlocks>("/users/" + userId + "/blocks", (ApiVersion)5, list, authToken, (string)null, (string)null);
	}

	public Task<UserBlock> BlockUserAsync(string sourceUserId, string targetUserId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)13, authToken);
		if (string.IsNullOrWhiteSpace(sourceUserId))
		{
			throw new BadParameterException("The source user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(targetUserId))
		{
			throw new BadParameterException("The target user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchPutGenericAsync<UserBlock>("/users/" + sourceUserId + "/blocks/" + targetUserId, (ApiVersion)5, (string)null, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task UnblockUserAsync(string sourceUserId, string targetUserId, string authToken = null)
	{
		//IL_001a: 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)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)13, authToken);
		if (string.IsNullOrWhiteSpace(sourceUserId))
		{
			throw new BadParameterException("The source user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		if (string.IsNullOrWhiteSpace(targetUserId))
		{
			throw new BadParameterException("The target user id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/users/" + sourceUserId + "/blocks/" + targetUserId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task CreateUserConnectionToViewerHeartbeatServiceAsync(string identifier, string authToken = null)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)18, authToken);
		if (string.IsNullOrWhiteSpace(identifier))
		{
			throw new BadParameterException("The identifier is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		string text = "{\"identifier\": \"" + identifier + "\"}";
		return ((ApiBase)this).TwitchPutAsync("/user/vhs", (ApiVersion)5, text, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task<VHSConnectionCheck> CheckUserConnectionToViewerHeartbeatServiceAsync(string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)16, authToken);
		return ((ApiBase)this).TwitchGetGenericAsync<VHSConnectionCheck>("/user/vhs", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	public Task DeleteUserConnectionToViewerHeartbeatServicechStreamsAsync(string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)18, authToken);
		return ((ApiBase)this).TwitchDeleteAsync("/user/vhs", (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}
}
public class V5
{
	private readonly ILogger<V5> _logger;

	public IApiSettings Settings { get; }

	public Auth Auth { get; }

	public Badges Badges { get; }

	public Bits Bits { get; }

	public Channels Channels { get; }

	public Chat Chat { get; }

	public Clips Clips { get; }

	public Collections Collections { get; }

	public Communities Communities { get; }

	public Games Games { get; }

	public Ingests Ingests { get; }

	public Root Root { get; }

	public Search Search { get; }

	public Streams Streams { get; }

	public Teams Teams { get; }

	public Videos Videos { get; }

	public Users Users { get; }

	public V5(ILoggerFactory loggerFactory = null, IRateLimiter rateLimiter = null, IApiSettings settings = null, IHttpCallHandler http = null)
	{
		//IL_0045: 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)
		_logger = loggerFactory?.CreateLogger<V5>();
		rateLimiter = (IRateLimiter)(((object)rateLimiter) ?? ((object)BypassLimiter.CreateLimiterBypassInstance()));
		http = (IHttpCallHandler)(((object)http) ?? ((object)new TwitchHttpClient(loggerFactory?.CreateLogger<TwitchHttpClient>())));
		Settings = (IApiSettings)(((object)settings) ?? ((object)new ApiSettings()));
		Auth = new Auth(Settings, rateLimiter, http);
		Badges = new Badges(Settings, rateLimiter, http);
		Bits = new Bits(Settings, rateLimiter, http);
		Channels = new Channels(Settings, rateLimiter, http);
		Chat = new Chat(Settings, rateLimiter, http);
		Clips = new Clips(Settings, rateLimiter, http);
		Collections = new Collections(Settings, rateLimiter, http);
		Communities = new Communities(Settings, rateLimiter, http);
		Games = new Games(Settings, rateLimiter, http);
		Ingests = new Ingests(Settings, rateLimiter, http);
		Root = new Root(Settings, rateLimiter, http);
		Search = new Search(Settings, rateLimiter, http);
		Streams = new Streams(Settings, rateLimiter, http);
		Teams = new Teams(Settings, rateLimiter, http);
		Users = new Users(Settings, rateLimiter, http);
		Videos = new Videos(Settings, rateLimiter, http);
	}
}
public class Videos : ApiBase
{
	private const long MAX_VIDEO_SIZE = 10737418240L;

	public Videos(IApiSettings settings, IRateLimiter rateLimiter, IHttpCallHandler http)
		: base(settings, rateLimiter, http)
	{
	}

	public Task<Video> GetVideoAsync(string videoId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(videoId))
		{
			throw new BadParameterException("The video id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchGetGenericAsync<Video>("/videos/" + videoId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, (string)null, (string)null, (string)null);
	}

	public Task<TopVideos> GetTopVideosAsync(int? limit = null, int? offset = null, string game = null, string period = null, List<string> broadcastType = null, List<string> language = null, string sort = null)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		if (!string.IsNullOrWhiteSpace(game))
		{
			list.Add(new KeyValuePair<string, string>("game", game));
		}
		if (!string.IsNullOrWhiteSpace(period) && (period == "week" || period == "month" || period == "all"))
		{
			list.Add(new KeyValuePair<string, string>("period", period));
		}
		if (broadcastType != null && broadcastType.Count > 0)
		{
			bool flag = false;
			foreach (string item in broadcastType)
			{
				if (item == "archive" || item == "highlight" || item == "upload")
				{
					flag = true;
					continue;
				}
				flag = false;
				break;
			}
			if (flag)
			{
				list.Add(new KeyValuePair<string, string>("broadcast_type", string.Join(",", broadcastType)));
			}
		}
		if (language != null && language.Count > 0)
		{
			list.Add(new KeyValuePair<string, string>("language", string.Join(",", language)));
		}
		if (!string.IsNullOrWhiteSpace(sort) && (sort == "views" || sort == "time"))
		{
			list.Add(new KeyValuePair<string, string>("sort", sort));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<TopVideos>("/videos/top", (ApiVersion)5, list, (string)null, (string)null, (string)null);
	}

	public Task<FollowedVideos> GetFollowedVideosAsync(int? limit = null, int? offset = null, List<string> broadcastType = null, List<string> language = null, string sort = null, string authToken = null)
	{
		((ApiBase)this).DynamicScopeValidation((AuthScopes)16, authToken);
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (limit.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString()));
		}
		if (offset.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString()));
		}
		if (broadcastType != null && broadcastType.Count > 0)
		{
			bool flag = false;
			foreach (string item in broadcastType)
			{
				if (item == "archive" || item == "highlight" || item == "upload")
				{
					flag = true;
					continue;
				}
				flag = false;
				break;
			}
			if (flag)
			{
				list.Add(new KeyValuePair<string, string>("broadcast_type", string.Join(",", broadcastType)));
			}
		}
		if (language != null && language.Count > 0)
		{
			list.Add(new KeyValuePair<string, string>("language", string.Join(",", language)));
		}
		if (!string.IsNullOrWhiteSpace(sort) && (sort == "views" || sort == "time"))
		{
			list.Add(new KeyValuePair<string, string>("sort", sort));
		}
		return ((ApiBase)this).TwitchGetGenericAsync<FollowedVideos>("/videos/followed", (ApiVersion)5, list, authToken, (string)null, (string)null);
	}

	public async Task<UploadedVideo> UploadVideoAsync(string channelId, string videoPath, string title, string description, string game, string language = "en", string tagList = "", Viewable viewable = 0, DateTime? viewableAt = null, string accessToken = null)
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)3, accessToken);
		UploadVideoListing listing = await CreateVideoAsync(channelId, title, description, game, language, tagList, viewable, viewableAt);
		UploadVideoParts(videoPath, listing.Upload);
		await CompleteVideoUploadAsync(listing.Upload, accessToken);
		return listing.Video;
	}

	public Task<Video> UpdateVideoAsync(string videoId, string description = null, string game = null, string language = null, string tagList = null, string title = null, string authToken = null)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)3, authToken);
		if (string.IsNullOrWhiteSpace(videoId))
		{
			throw new BadParameterException("The video id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		if (!string.IsNullOrWhiteSpace(description))
		{
			list.Add(new KeyValuePair<string, string>("description", description));
		}
		if (!string.IsNullOrWhiteSpace(game))
		{
			list.Add(new KeyValuePair<string, string>("game", game));
		}
		if (!string.IsNullOrWhiteSpace(language))
		{
			list.Add(new KeyValuePair<string, string>("language", language));
		}
		if (!string.IsNullOrWhiteSpace(tagList))
		{
			list.Add(new KeyValuePair<string, string>("tagList", tagList));
		}
		if (!string.IsNullOrWhiteSpace(title))
		{
			list.Add(new KeyValuePair<string, string>("title", title));
		}
		return ((ApiBase)this).TwitchPutGenericAsync<Video>("/videos/" + videoId, (ApiVersion)5, (string)null, list, authToken, (string)null, (string)null);
	}

	public Task DeleteVideoAsync(string videoId, string authToken = null)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		((ApiBase)this).DynamicScopeValidation((AuthScopes)3, authToken);
		if (string.IsNullOrWhiteSpace(videoId))
		{
			throw new BadParameterException("The video id is not valid. It is not allowed to be null, empty or filled with whitespaces.");
		}
		return ((ApiBase)this).TwitchDeleteAsync("/videos/" + videoId, (ApiVersion)5, (List<KeyValuePair<string, string>>)null, authToken, (string)null, (string)null);
	}

	private Task<UploadVideoListing> CreateVideoAsync(string channelId, string title, string description = null, string game = null, string language = "en", string tagList = "", Viewable viewable = 0, DateTime? viewableAt = null, string accessToken = null)
	{
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>
		{
			new KeyValuePair<string, string>("channel_id", channelId),
			new KeyValuePair<string, string>("title", title)
		};
		if (!string.IsNullOrWhiteSpace(description))
		{
			list.Add(new KeyValuePair<string, string>("description", description));
		}
		if (game != null)
		{
			list.Add(new KeyValuePair<string, string>("game", game));
		}
		if (language != null)
		{
			list.Add(new KeyValuePair<string, string>("language", language));
		}
		if (tagList != null)
		{
			list.Add(new KeyValuePair<string, string>("tag_list", tagList));
		}
		list.Add(((int)viewable == 0) ? new KeyValuePair<string, string>("viewable", "public") : new KeyValuePair<string, string>("viewable", "private"));
		if (viewableAt.HasValue)
		{
			list.Add(new KeyValuePair<string, string>("viewable_at", DateTimeExtensions.ToRfc3339String(viewableAt.Value)));
		}
		return ((ApiBase)this).TwitchPostGenericAsync<UploadVideoListing>("/videos", (ApiVersion)5, (string)null, list, accessToken, (string)null, (string)null);
	}

	private void UploadVideoParts(string videoPath, Upload upload)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		if (!File.Exists(videoPath))
		{
			throw new BadParameterException("The provided path for a video upload does not appear to be value: " + videoPath);
		}
		FileInfo fileInfo = new FileInfo(videoPath);
		if (fileInfo.Length >= 10737418240L)
		{
			throw new BadParameterException($"The provided file was too large (larger than 10gb). File size: {fileInfo.Length}");
		}
		long length = fileInfo.Length;
		if (length > 25165824)
		{
			using (FileStream fileStream = new FileStream(videoPath, FileMode.Open, FileAccess.Read, FileShare.Read))
			{
				long num = length % 25165824;
				long num2 = (length - num) / 25165824 + 1;
				for (int i = 1; i <= num2; i++)
				{
					byte[] array;
					if (i == num2)
					{
						array = new byte[num];
						fileStream.Read(array, 0, (int)num);
					}
					else
					{
						array = new byte[25165824];
						fileStream.Read(array, 0, 25165824);
					}
					((ApiBase)this).PutBytes($"{upload.Url}?part={i}&upload_token={upload.Token}", array);
					Thread.Sleep(1000);
				}
				return;
			}
		}
		byte[] array2 = File.ReadAllBytes(videoPath);
		((ApiBase)this).PutBytes(upload.Url + "?part=1&upload_token=" + upload.Token, array2);
	}

	private Task CompleteVideoUploadAsync(Upload upload, string accessToken)
	{
		return ((ApiBase)this).TwitchPostAsync((string)null, (ApiVersion)5, (string)null, (List<KeyValuePair<string, string>>)null, accessToken, (string)null, upload.Url + "/complete?upload_token=" + upload.Token);
	}
}

lib/TwitchLib.Api.V5.Models.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TwitchLib.Api.Core.Interfaces;
using TwitchLib.Api.Core.Interfaces.Clips;
using TwitchLib.Api.V5.Models.Channels;
using TwitchLib.Api.V5.Models.Games;
using TwitchLib.Api.V5.Models.Streams;
using TwitchLib.Api.V5.Models.Subscriptions;
using TwitchLib.Api.V5.Models.Teams;
using TwitchLib.Api.V5.Models.Users;
using TwitchLib.Api.V5.Models.Videos;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing the V5 models used in TwitchLib.Api")]
[assembly: AssemblyFileVersion("3.1.2")]
[assembly: AssemblyInformationalVersion("3.1.2")]
[assembly: AssemblyProduct("TwitchLib.Api.V5.Models")]
[assembly: AssemblyTitle("TwitchLib.Api.V5.Models")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/swiftyspiffy/TwitchLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.2.0")]
namespace TwitchLib.Api.V5.Models.ViewerHeartbeatService
{
	public class VHSConnectionCheck
	{
		[JsonProperty(PropertyName = "identifier")]
		public string Identifier { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Videos
{
	public class FollowedVideos
	{
		[JsonProperty(PropertyName = "videos")]
		public Video[] Videos { get; protected set; }
	}
	public class TopVideos
	{
		[JsonProperty(PropertyName = "vods")]
		public Video[] VODs { get; protected set; }
	}
	public class Video
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "animated_preview_url")]
		public string AnimatedPreviewUrl { get; protected set; }

		[JsonProperty(PropertyName = "broadcast_id")]
		public string BroadcastId { get; protected set; }

		[JsonProperty(PropertyName = "broadcast_type")]
		public string BroadcastType { get; protected set; }

		[JsonProperty(PropertyName = "channel")]
		public VideoChannel Channel { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "description")]
		public string Description { get; protected set; }

		[JsonProperty(PropertyName = "description_html")]
		public string DescriptionHtml { get; protected set; }

		[JsonProperty(PropertyName = "fps")]
		public Dictionary<string, double> Fps { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "language")]
		public string Language { get; protected set; }

		[JsonProperty(PropertyName = "length")]
		public long Length { get; protected set; }

		[JsonProperty(PropertyName = "muted_segments")]
		public VideoMutedSegment[] MutedSegments { get; protected set; }

		[JsonProperty(PropertyName = "preview")]
		public VideoPreview Preview { get; protected set; }

		[JsonProperty(PropertyName = "published_at")]
		public DateTime PublishedAt { get; protected set; }

		[JsonProperty(PropertyName = "recorded_at")]
		public DateTime RecordedAt { get; protected set; }

		[JsonProperty(PropertyName = "resolutions")]
		public Dictionary<string, string> Resolutions { get; protected set; }

		[JsonProperty(PropertyName = "status")]
		public string Status { get; protected set; }

		[JsonProperty(PropertyName = "tag_list")]
		public string TagList { get; protected set; }

		[JsonProperty(PropertyName = "thumbnails")]
		public VideoThumbnails Thumbnails { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "viewable")]
		public string Viewable { get; protected set; }

		[JsonProperty(PropertyName = "viewable_at")]
		public DateTime ViewableAt { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }
	}
	public class VideoChannel
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "name")]
		public string Name { get; protected set; }
	}
	public class VideoCreation
	{
		[JsonProperty(PropertyName = "upload")]
		public VideoUpload Upload { get; protected set; }

		[JsonProperty(PropertyName = "video")]
		public Video Video { get; protected set; }
	}
	public class VideoMutedSegment
	{
		[JsonProperty(PropertyName = "duration")]
		public long Duration { get; internal set; }

		[JsonProperty(PropertyName = "offset")]
		public long Offset { get; internal set; }
	}
	public class VideoPreview
	{
		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class VideoThumbnail
	{
		[JsonProperty(PropertyName = "type")]
		public string Type { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }
	}
	public class VideoThumbnails
	{
		[JsonProperty(PropertyName = "large")]
		public VideoThumbnail[] Large { get; internal set; }

		[JsonProperty(PropertyName = "medium")]
		public VideoThumbnail[] Medium { get; internal set; }

		[JsonProperty(PropertyName = "small")]
		public VideoThumbnail[] Small { get; internal set; }

		[JsonProperty(PropertyName = "template")]
		public VideoThumbnail[] Template { get; internal set; }
	}
	public class VideoUpload
	{
		[JsonProperty(PropertyName = "token")]
		public string Token { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Users
{
	public class User : IUser
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; internal set; }

		[JsonProperty(PropertyName = "bio")]
		public string Bio { get; internal set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; internal set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; internal set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; internal set; }

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

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

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; internal set; }
	}
	public class UserAuthed : IUser
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "bio")]
		public string Bio { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "email")]
		public string Email { get; protected set; }

		[JsonProperty(PropertyName = "email_verified")]
		public bool EmailVerified { get; protected set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; protected set; }

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

		[JsonProperty(PropertyName = "notifications")]
		public UserNotifications Notifications { get; protected set; }

		[JsonProperty(PropertyName = "partnered")]
		public bool Partnered { get; protected set; }

		[JsonProperty(PropertyName = "twitter_connected")]
		public bool TwitterConnected { get; protected set; }

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

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }
	}
	public class UserBlock
	{
		[JsonProperty(PropertyName = "_id")]
		public long Id { get; protected set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }

		[JsonProperty(PropertyName = "user")]
		public User User { get; protected set; }
	}
	public class UserBlocks
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "blocks")]
		public UserBlock[] Blocks { get; protected set; }
	}
	public class UserEmote
	{
		[JsonProperty(PropertyName = "code")]
		public string Code { get; protected set; }

		[JsonProperty(PropertyName = "id")]
		public int Id { get; protected set; }
	}
	public class UserEmotes
	{
		[JsonProperty(PropertyName = "emoticon_sets")]
		public Dictionary<string, UserEmote[]> EmoteSets { get; protected set; }
	}
	public class UserFollow
	{
		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "notifications")]
		public bool Notifications { get; protected set; }

		[JsonProperty(PropertyName = "channel")]
		public Channel Channel { get; protected set; }
	}
	public class UserFollows
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "follows")]
		public UserFollow[] Follows { get; protected set; }
	}
	public class UserNotifications
	{
		[JsonProperty(PropertyName = "email")]
		public bool Email { get; protected set; }

		[JsonProperty(PropertyName = "push")]
		public bool Push { get; protected set; }
	}
	public class Users
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "users")]
		public User[] Matches { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.UploadVideo
{
	public class Channel
	{
		[JsonProperty(PropertyName = "name")]
		public string Name { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }
	}
	public class Preview
	{
		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class Upload
	{
		[JsonProperty(PropertyName = "token")]
		public string Token { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }
	}
	public class UploadedVideo
	{
		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "description")]
		public string Description { get; protected set; }

		[JsonProperty(PropertyName = "broadcast_id")]
		public string BroadcastId { get; protected set; }

		[JsonProperty(PropertyName = "status")]
		public string Status { get; protected set; }

		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "tag_list")]
		public string TagList { get; protected set; }

		[JsonProperty(PropertyName = "recorded_at")]
		public DateTime RecordedAt { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

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

		[JsonProperty(PropertyName = "preview")]
		public Preview Preview { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }

		[JsonProperty(PropertyName = "broadcast_type")]
		public string BroadcastType { get; protected set; }

		[JsonProperty(PropertyName = "channel")]
		public Channel Channel { get; protected set; }
	}
	public class UploadVideoListing
	{
		[JsonProperty(PropertyName = "upload")]
		public Upload Upload { get; protected set; }

		[JsonProperty(PropertyName = "video")]
		public UploadedVideo Video { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Teams
{
	public class AllTeams
	{
		[JsonProperty(PropertyName = "teams")]
		public Team[] Teams { get; protected set; }
	}
	public class Team
	{
		[JsonProperty(PropertyName = "_id")]
		public long Id { get; protected set; }

		[JsonProperty(PropertyName = "background")]
		public string Background { get; protected set; }

		[JsonProperty(PropertyName = "banner")]
		public string Banner { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "info")]
		public string Info { get; protected set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; protected set; }

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

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }

		[JsonProperty(PropertyName = "users")]
		public Channel[] Users { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Subscriptions
{
	public class Subscription
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "sub_plan")]
		public string SubPlan { get; protected set; }

		[JsonProperty(PropertyName = "sub_plan_name")]
		public string SubPlanName { get; protected set; }

		[JsonProperty(PropertyName = "user")]
		public User User { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Streams
{
	public class FeaturedStream
	{
		[JsonProperty(PropertyName = "image")]
		public string Image { get; protected set; }

		[JsonProperty(PropertyName = "priority")]
		public int Priority { get; protected set; }

		[JsonProperty(PropertyName = "scheduled")]
		public bool Scheduled { get; protected set; }

		[JsonProperty(PropertyName = "sponsored")]
		public bool Sponsored { get; protected set; }

		[JsonProperty(PropertyName = "stream")]
		public Stream Stream { get; protected set; }

		[JsonProperty(PropertyName = "text")]
		public string Text { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }
	}
	public class FeaturedStreams
	{
		[JsonProperty(PropertyName = "featured")]
		public FeaturedStream[] Featured { get; protected set; }
	}
	public class FollowedStreams
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "streams")]
		public Stream[] Streams { get; protected set; }
	}
	public class LiveStreams
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "streams")]
		public Stream[] Streams { get; protected set; }
	}
	public class Stream
	{
		[JsonProperty(PropertyName = "_id")]
		public long Id { get; protected set; }

		[JsonProperty(PropertyName = "average_fps")]
		public double AverageFps { get; protected set; }

		[JsonProperty(PropertyName = "channel")]
		public Channel Channel { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "delay")]
		public int Delay { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "is_playlist")]
		public bool IsPlaylist { get; protected set; }

		[JsonProperty(PropertyName = "stream_type")]
		public string StreamType { get; protected set; }

		[JsonProperty(PropertyName = "preview")]
		public StreamPreview Preview { get; protected set; }

		[JsonProperty(PropertyName = "video_height")]
		public int VideoHeight { get; protected set; }

		[JsonProperty(PropertyName = "viewers")]
		public int Viewers { get; protected set; }
	}
	public class StreamByUser
	{
		[JsonProperty(PropertyName = "stream")]
		public Stream Stream { get; protected set; }
	}
	public class StreamPreview
	{
		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class StreamsSummary
	{
		[JsonProperty(PropertyName = "channels")]
		public int Channels { get; protected set; }

		[JsonProperty(PropertyName = "viewers")]
		public int Viewers { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Search
{
	public class SearchChannels
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "channels")]
		public Channel[] Channels { get; protected set; }
	}
	public class SearchGames
	{
		[JsonProperty(PropertyName = "games")]
		public Game[] Games { get; protected set; }
	}
	public class SearchStreams
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "streams")]
		public Stream[] Streams { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Ingests
{
	public class Ingest
	{
		[JsonProperty(PropertyName = "_id")]
		public int Id { get; protected set; }

		[JsonProperty(PropertyName = "availability")]
		public double Availability { get; protected set; }

		[JsonProperty(PropertyName = "default")]
		public bool Default { get; protected set; }

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

		[JsonProperty(PropertyName = "url_template")]
		public string UrlTemplate { get; protected set; }
	}
	public class Ingests
	{
		[JsonProperty(PropertyName = "ingests")]
		public Ingest[] IngestServers { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Games
{
	public class Game
	{
		[JsonProperty(PropertyName = "_id")]
		public int Id { get; protected set; }

		[JsonProperty(PropertyName = "viewers")]
		public int Viewers { get; protected set; }

		[JsonProperty(PropertyName = "box")]
		public GameBox Box { get; protected set; }

		[JsonProperty(PropertyName = "giantbomb_id")]
		public int GiantbombId { get; protected set; }

		[JsonProperty(PropertyName = "logo")]
		public GameLogo Logo { get; protected set; }

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

		[JsonProperty(PropertyName = "popularity")]
		public int Popularity { get; protected set; }
	}
	public class GameBox
	{
		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class GameLogo
	{
		[JsonProperty(PropertyName = "large")]
		public string Large { get; protected set; }

		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "template")]
		public string Template { get; protected set; }
	}
	public class TopGame
	{
		[JsonProperty(PropertyName = "channels")]
		public int Channels { get; protected set; }

		[JsonProperty(PropertyName = "viewers")]
		public int Viewers { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public Game Game { get; protected set; }
	}
	public class TopGames
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "top")]
		public TopGame[] Top { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Communities
{
	public class BannedUser
	{
		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

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

		[JsonProperty(PropertyName = "bio")]
		public string Bio { get; protected set; }

		[JsonProperty(PropertyName = "avatar_image_url")]
		public string AvatarImageUrl { get; protected set; }

		[JsonProperty(PropertyName = "start_timestamp")]
		public long StartTimestamp { get; protected set; }
	}
	public class BannedUsers
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "banned_users")]
		public BannedUser[] Users { get; protected set; }
	}
	public class CommunitiesResponse
	{
		[JsonProperty(PropertyName = "communities")]
		public Community[] Communities { get; protected set; }
	}
	public class Community
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "avatar_image_url")]
		public string AvatarImageUrl { get; protected set; }

		[JsonProperty(PropertyName = "cover_image_url")]
		public string CoverImageUrl { get; protected set; }

		[JsonProperty(PropertyName = "description")]
		public string Description { get; protected set; }

		[JsonProperty(PropertyName = "description_html")]
		public string DescriptionHtml { get; protected set; }

		[JsonProperty(PropertyName = "language")]
		public string Language { get; protected set; }

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

		[JsonProperty(PropertyName = "owner_id")]
		public string OwnerId { get; protected set; }

		[JsonProperty(PropertyName = "rules")]
		public string Rules { get; protected set; }

		[JsonProperty(PropertyName = "rules_html")]
		public string RulesHtml { get; protected set; }

		[JsonProperty(PropertyName = "summary")]
		public string Summary { get; protected set; }
	}
	public class Moderator
	{
		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

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

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

		[JsonProperty(PropertyName = "bio")]
		public string Bio { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; protected set; }
	}
	public class Moderators
	{
		[JsonProperty(PropertyName = "moderators")]
		public Moderator[] Users { get; protected set; }
	}
	public class TimedOutUser
	{
		[JsonProperty(PropertyName = "user_id")]
		public string UserId { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

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

		[JsonProperty(PropertyName = "bio")]
		public string Bio { get; protected set; }

		[JsonProperty(PropertyName = "avatar_image_url")]
		public string AvatarImageUrl { get; protected set; }

		[JsonProperty(PropertyName = "start_timestamp")]
		public long StartTimestamp { get; protected set; }

		[JsonProperty(PropertyName = "end_timestamp")]
		public long EndTimestamp { get; protected set; }
	}
	public class TimedOutUsers
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "timed_out_users")]
		public TimedOutUser[] Users { get; protected set; }
	}
	public class TopCommunities
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "communities")]
		public TopCommunity[] Communities { get; protected set; }
	}
	public class TopCommunity
	{
		[JsonProperty(PropertyName = "avatar_image_url")]
		public string AvatarImageUrl { get; protected set; }

		[JsonProperty(PropertyName = "channels")]
		public int Channels { get; protected set; }

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

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

		[JsonProperty(PropertyName = "viewers")]
		public int Viewers { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Collections
{
	public class Collection
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "items")]
		public CollectionItem[] Items { get; protected set; }
	}
	public class CollectionItem
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "description_html")]
		public string DescriptionHtml { get; protected set; }

		[JsonProperty(PropertyName = "duration")]
		public int Duration { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "item_id")]
		public string ItemId { get; protected set; }

		[JsonProperty(PropertyName = "item_type")]
		public string ItemType { get; protected set; }

		[JsonProperty(PropertyName = "owner")]
		public User Owner { get; protected set; }

		[JsonProperty(PropertyName = "published_at")]
		public DateTime PublishedAt { get; protected set; }

		[JsonProperty(PropertyName = "thumbnails")]
		public Dictionary<string, string> Thumbnails { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }
	}
	public class CollectionMetadata
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "items_count")]
		public int ItemsCount { get; protected set; }

		[JsonProperty(PropertyName = "owner")]
		public User Owner { get; protected set; }

		[JsonProperty(PropertyName = "thumbnails")]
		public Dictionary<string, string> Thumbnails { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "total_duration")]
		public int TotalDuration { get; protected set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }
	}
	public class CollectionsByChannel
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "collections")]
		public CollectionMetadata[] Collections { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Clips
{
	public class Broadcaster
	{
		[JsonProperty(PropertyName = "channel_url")]
		public string ChannelUrl { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

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

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; protected set; }

		[JsonProperty(PropertyName = "name")]
		public string Name { get; protected set; }
	}
	public class Clip
	{
		[JsonProperty(PropertyName = "broadcaster")]
		public Broadcaster Broadcaster { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "curator")]
		public Curator Curator { get; protected set; }

		[JsonProperty(PropertyName = "duration")]
		public double Duration { get; protected set; }

		[JsonProperty(PropertyName = "embed_html")]
		public string EmbedHtml { get; protected set; }

		[JsonProperty(PropertyName = "embed_url")]
		public string EmbedUrl { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "language")]
		public string Language { get; protected set; }

		[JsonProperty(PropertyName = "thumbnails")]
		public Thumbnails Thumbnails { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "tracking_id")]
		public string TrackingId { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }

		[JsonProperty(PropertyName = "vod")]
		public VOD VOD { get; protected set; }
	}
	public class Curator
	{
		[JsonProperty(PropertyName = "channel_url")]
		public string ChannelUrl { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

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

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; protected set; }

		[JsonProperty(PropertyName = "name")]
		public string Name { get; protected set; }
	}
	public class FollowClipsResponse
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "clips")]
		public Clip[] Clips { get; protected set; }
	}
	public enum Period
	{
		Day,
		Week,
		Month,
		All
	}
	public class Thumbnails
	{
		[JsonProperty(PropertyName = "medium")]
		public string Medium { get; protected set; }

		[JsonProperty(PropertyName = "small")]
		public string Small { get; protected set; }

		[JsonProperty(PropertyName = "tiny")]
		public string Tiny { get; protected set; }
	}
	public class TopClipsResponse
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		public List<Clip> Clips { get; protected set; } = new List<Clip>();


		public TopClipsResponse(JToken json)
		{
		}
	}
	public class VOD : IVOD
	{
		[JsonProperty(PropertyName = "id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

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

		[JsonProperty(PropertyName = "preview_image_url")]
		public string PreviewImageUrl { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Chat
{
	public class AllChatEmote
	{
		[JsonProperty(PropertyName = "regex")]
		public string Regex { get; protected set; }

		[JsonProperty(PropertyName = "images")]
		public EmoticonImage[] Images { get; protected set; }
	}
	public class AllChatEmotes
	{
		[JsonProperty(PropertyName = "emoticons")]
		public AllChatEmote[] Emoticons { get; protected set; }
	}
	public class Badge
	{
		[JsonProperty(PropertyName = "alpha")]
		public string Alpha { get; protected set; }

		[JsonProperty(PropertyName = "image")]
		public string Image { get; protected set; }

		[JsonProperty(PropertyName = "svg")]
		public string SVG { get; protected set; }
	}
	public class ChannelBadges
	{
		[JsonProperty(PropertyName = "admin")]
		public Badge Admin { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster")]
		public Badge Broadcaster { get; protected set; }

		[JsonProperty(PropertyName = "global_mod")]
		public Badge GlobalMod { get; protected set; }

		[JsonProperty(PropertyName = "mod")]
		public Badge Mod { get; protected set; }

		[JsonProperty(PropertyName = "staff")]
		public Badge Staff { get; protected set; }

		[JsonProperty(PropertyName = "subscriber")]
		public Badge Subscriber { get; protected set; }

		[JsonProperty(PropertyName = "turbo")]
		public Badge Turbo { get; protected set; }
	}
	public class ChatRoom
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "owner_id")]
		public string OwnerId { get; protected set; }

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

		[JsonProperty(PropertyName = "topic")]
		public string Topic { get; protected set; }

		[JsonProperty(PropertyName = "is_previewable")]
		public bool IsPreviewable { get; protected set; }

		[JsonProperty(PropertyName = "minimum_allowed_role")]
		public string MinimumAllowedRole { get; protected set; }
	}
	public class ChatRoomsByChannelResponse
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "rooms")]
		public ChatRoom[] Rooms { get; protected set; }
	}
	public class Emote
	{
		[JsonProperty(PropertyName = "code")]
		public string Code { get; protected set; }

		[JsonProperty(PropertyName = "emoticon_set")]
		public int EmoticonSet { get; protected set; }

		[JsonProperty(PropertyName = "id")]
		public int Id { get; protected set; }
	}
	public class EmoteSet
	{
		[JsonProperty(PropertyName = "emoticon_sets")]
		public Dictionary<string, Emote[]> EmoticonSets { get; protected set; }

		[JsonProperty(PropertyName = "emoticons")]
		public Emote[] Emoticons { get; protected set; }
	}
	public class EmoticonImage
	{
		[JsonProperty(PropertyName = "width")]
		public int Width { get; protected set; }

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

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "emoticon_set")]
		public int EmoticonSet { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Channels
{
	public class Channel
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; internal set; }

		[JsonProperty(PropertyName = "broadcaster_language")]
		public string BroadcasterLanguage { get; internal set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; internal set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; internal set; }

		[JsonProperty(PropertyName = "followers")]
		public int Followers { get; internal set; }

		[JsonProperty(PropertyName = "broadcaster_type")]
		public string BroadcasterType { get; internal set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; internal set; }

		[JsonProperty(PropertyName = "language")]
		public string Language { get; internal set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; internal set; }

		[JsonProperty(PropertyName = "mature")]
		public bool Mature { get; internal set; }

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

		[JsonProperty(PropertyName = "partner")]
		public bool Partner { get; internal set; }

		[JsonProperty(PropertyName = "profile_banner")]
		public string ProfileBanner { get; internal set; }

		[JsonProperty(PropertyName = "profile_banner_background_color")]
		public string ProfileBannerBackgroundColor { get; internal set; }

		[JsonProperty(PropertyName = "status")]
		public string Status { get; internal set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; internal set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; internal set; }

		[JsonProperty(PropertyName = "video_banner")]
		public string VideoBanner { get; internal set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; internal set; }
	}
	public class ChannelAuthed
	{
		[JsonProperty(PropertyName = "_id")]
		public string Id { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_language")]
		public string BroadcasterLanguage { get; protected set; }

		[JsonProperty(PropertyName = "broadcaster_type")]
		public string BroadcasterType { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "display_name")]
		public string DisplayName { get; protected set; }

		[JsonProperty(PropertyName = "email")]
		public string Email { get; protected set; }

		[JsonProperty(PropertyName = "followers")]
		public int Followers { get; protected set; }

		[JsonProperty(PropertyName = "game")]
		public string Game { get; protected set; }

		[JsonProperty(PropertyName = "language")]
		public string Language { get; protected set; }

		[JsonProperty(PropertyName = "logo")]
		public string Logo { get; protected set; }

		[JsonProperty(PropertyName = "mature")]
		public bool Mature { get; protected set; }

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

		[JsonProperty(PropertyName = "partner")]
		public bool Partner { get; protected set; }

		[JsonProperty(PropertyName = "profile_banner")]
		public string ProfileBanner { get; protected set; }

		[JsonProperty(PropertyName = "profile_banner_background_color")]
		public string ProfileBannerBackgroundColor { get; protected set; }

		[JsonProperty(PropertyName = "status")]
		public string Status { get; protected set; }

		[JsonProperty(PropertyName = "stream_key")]
		public string StreamKey { get; protected set; }

		[JsonProperty(PropertyName = "updated_at")]
		public DateTime UpdatedAt { get; protected set; }

		[JsonProperty(PropertyName = "url")]
		public string Url { get; protected set; }

		[JsonProperty(PropertyName = "video_banner")]
		public string VideoBanner { get; protected set; }

		[JsonProperty(PropertyName = "views")]
		public int Views { get; protected set; }
	}
	public class ChannelCommercial
	{
		[JsonProperty(PropertyName = "duration")]
		public int Duration { get; protected set; }

		[JsonProperty(PropertyName = "message")]
		public string Message { get; protected set; }

		[JsonProperty(PropertyName = "retryafter")]
		public int RetryAfter { get; protected set; }
	}
	public class ChannelEditors
	{
		[JsonProperty(PropertyName = "users")]
		public User[] Editors { get; protected set; }
	}
	public class ChannelFollow : IFollow
	{
		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; protected set; }

		[JsonProperty(PropertyName = "notifications")]
		public bool Notifications { get; protected set; }

		[JsonProperty(PropertyName = "user")]
		public IUser User { get; protected set; }

		public ChannelFollow(User user)
		{
			User = (IUser)(object)user;
		}
	}
	public class ChannelFollowers : IFollows
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "follows")]
		public IFollow[] Follows { get; protected set; }

		public ChannelFollowers(ChannelFollow[] follows)
		{
			Follows = (IFollow[])(object)follows;
		}
	}
	public class ChannelSubscribers
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "subscriptions")]
		public Subscription[] Subscriptions { get; protected set; }
	}
	public class ChannelTeams
	{
		[JsonProperty(PropertyName = "teams")]
		public Team[] Teams { get; protected set; }
	}
	public class ChannelVideos
	{
		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "videos")]
		public Video[] Videos { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.ChannelFeed
{
	public class FeedPost
	{
		[JsonProperty(PropertyName = "body")]
		public string Body { get; protected set; }

		[JsonProperty(PropertyName = "comments")]
		public FeedPostComments Comments { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; internal set; }

		[JsonProperty(PropertyName = "deleted")]
		public bool Deleted { get; internal set; }

		[JsonProperty(PropertyName = "embeds")]
		public object[] Embeds { get; internal set; }

		[JsonProperty(PropertyName = "emotes")]
		public FeedPostEmote[] Emotes { get; internal set; }

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

		[JsonProperty(PropertyName = "permissions")]
		public Dictionary<string, bool> Permissions { get; protected set; }

		[JsonProperty(PropertyName = "reactions")]
		public Dictionary<string, FeedPostReaction> Reactions { get; protected set; }

		[JsonProperty(PropertyName = "user")]
		public User User { get; protected set; }
	}
	public class FeedPostComment
	{
		[JsonProperty(PropertyName = "body")]
		public string Body { get; protected set; }

		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; internal set; }

		[JsonProperty(PropertyName = "deleted")]
		public bool Deleted { get; internal set; }

		[JsonProperty(PropertyName = "emotes")]
		public FeedPostEmote[] Emotes { get; internal set; }

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

		[JsonProperty(PropertyName = "permissions")]
		public Dictionary<string, bool> Permissions { get; protected set; }

		[JsonProperty(PropertyName = "reactions")]
		public Dictionary<string, FeedPostReaction> Reactions { get; protected set; }

		[JsonProperty(PropertyName = "user")]
		public User User { get; protected set; }
	}
	public class FeedPostComments
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "_total")]
		public int Total { get; protected set; }

		[JsonProperty(PropertyName = "comments")]
		public FeedPostComment[] Comments { get; protected set; }
	}
	public class FeedPostCreation
	{
		[JsonProperty(PropertyName = "post")]
		public FeedPost Post { get; internal set; }

		[JsonProperty(PropertyName = "tweet")]
		public string Tweet { get; internal set; }
	}
	public class FeedPostEmote
	{
		[JsonProperty(PropertyName = "end")]
		public int End { get; protected set; }

		[JsonProperty(PropertyName = "id")]
		public int Id { get; protected set; }

		[JsonProperty(PropertyName = "set")]
		public int Set { get; protected set; }

		[JsonProperty(PropertyName = "start")]
		public int Start { get; protected set; }
	}
	public class FeedPostReaction
	{
		[JsonProperty(PropertyName = "count")]
		public int Count { get; protected set; }

		[JsonProperty(PropertyName = "emote")]
		public string Emote { get; protected set; }

		[JsonProperty(PropertyName = "user_ids")]
		public int[] UserIds { get; protected set; }
	}
	public class FeedPostReactionPost
	{
		[JsonProperty(PropertyName = "created_at")]
		public DateTime CreatedAt { get; internal set; }

		[JsonProperty(PropertyName = "emote_id")]
		public string EmoteId { get; internal set; }

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

		[JsonProperty(PropertyName = "user")]
		public User User { get; internal set; }
	}
	public class MultipleFeedPosts
	{
		[JsonProperty(PropertyName = "_cursor")]
		public string Cursor { get; protected set; }

		[JsonProperty(PropertyName = "_topic")]
		public string Topic { get; protected set; }

		[JsonProperty(PropertyName = "_disabled")]
		public bool Disabled { get; protected set; }

		[JsonProperty(PropertyName = "posts")]
		public FeedPost[] Posts { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Bits
{
	public class Action
	{
		[JsonProperty(PropertyName = "prefix")]
		public string Prefix { get; set; }

		[JsonProperty(PropertyName = "scales")]
		public string[] Scales { get; set; }

		[JsonProperty(PropertyName = "tiers")]
		public Tier[] Tiers { get; set; }

		[JsonProperty(PropertyName = "backgrounds")]
		public string[] Backgrounds { get; set; }

		[JsonProperty(PropertyName = "states")]
		public string[] States { get; set; }

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

		[JsonProperty(PropertyName = "updated_at")]
		public string UpdatedAt { get; set; }
	}
	public class Cheermotes
	{
		[JsonProperty(PropertyName = "actions")]
		public Action[] Actions { get; protected set; }
	}
	public class DarkImage
	{
		[JsonProperty(PropertyName = "animated")]
		public ImageLinks Animated { get; set; }

		[JsonProperty(PropertyName = "static")]
		public ImageLinks Static { get; set; }
	}
	public class ImageLinks
	{
		[JsonProperty(PropertyName = "1")]
		public string One { get; set; }

		[JsonProperty(PropertyName = "2")]
		public string Two { get; set; }

		[JsonProperty(PropertyName = "3")]
		public string Three { get; set; }

		[JsonProperty(PropertyName = "4")]
		public string Four { get; set; }

		[JsonProperty(PropertyName = "1.5")]
		public string OnePointFive { get; set; }
	}
	public class Images
	{
		[JsonProperty(PropertyName = "dark")]
		public DarkImage Dark { get; set; }

		[JsonProperty(PropertyName = "light")]
		public LightImage Light { get; set; }
	}
	public class LightImage
	{
		[JsonProperty(PropertyName = "animated")]
		public ImageLinks Animated { get; set; }

		[JsonProperty(PropertyName = "static")]
		public ImageLinks Static { get; set; }
	}
	public class Scales
	{
		[JsonProperty(PropertyName = "0")]
		public string Zero { get; set; }

		[JsonProperty(PropertyName = "1")]
		public string One { get; set; }

		[JsonProperty(PropertyName = "2")]
		public string Two { get; set; }

		[JsonProperty(PropertyName = "3")]
		public string Three { get; set; }

		[JsonProperty(PropertyName = "4")]
		public string Four { get; set; }
	}
	public class Tier
	{
		[JsonProperty(PropertyName = "min_bits")]
		public int MinBits { get; set; }

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

		[JsonProperty(PropertyName = "color")]
		public string Color { get; set; }

		[JsonProperty(PropertyName = "images")]
		public Images Images { get; set; }
	}
}
namespace TwitchLib.Api.V5.Models.Badges
{
	public class Badge
	{
		[JsonProperty(PropertyName = "versions")]
		public Dictionary<string, BadgeContent> Versions { get; protected set; }
	}
	public class BadgeContent
	{
		[JsonProperty(PropertyName = "image_url_1x")]
		public string Image_Url_1x { get; protected set; }

		[JsonProperty(PropertyName = "image_url_2x")]
		public string Image_Url_2x { get; protected set; }

		[JsonProperty(PropertyName = "image_url_4x")]
		public string Image_Url_4x { get; protected set; }

		[JsonProperty(PropertyName = "description")]
		public string Description { get; protected set; }

		[JsonProperty(PropertyName = "title")]
		public string Title { get; protected set; }

		[JsonProperty(PropertyName = "click_action")]
		public string ClickAction { get; protected set; }

		[JsonProperty(PropertyName = "click_url")]
		public string ClickUrl { get; protected set; }
	}
	public class ChannelDisplayBadges
	{
		[JsonProperty(PropertyName = "badge_sets")]
		public BadgeSets Sets { get; protected set; }
	}
	public class BadgeSets
	{
		[JsonProperty(PropertyName = "subscriber")]
		public Badge Subscriber { get; protected set; }

		[JsonProperty(PropertyName = "bits")]
		public Badge Bits { get; protected set; }
	}
	public class GlobalBadgesResponse
	{
		[JsonProperty(PropertyName = "badge_sets")]
		public Dictionary<string, Badge> Sets { get; protected set; }
	}
}
namespace TwitchLib.Api.V5.Models.Auth
{
	public class RefreshResponse
	{
		[JsonProperty(PropertyName = "access_token")]
		public string AccessToken { get; protected set; }

		[JsonProperty(PropertyName = "refresh_token")]
		public string RefreshToken { get; protected set; }

		[JsonProperty(PropertyName = "expires_in")]
		public int ExpiresIn { get; protected set; }

		[JsonProperty(PropertyName = "scope")]
		public string[] Scopes { get; protected set; }
	}
}

lib/TwitchLib.Client.dll

Decompiled 5 months ago
#define DEBUG
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using Microsoft.Extensions.Logging;
using TwitchLib.Client.Enums;
using TwitchLib.Client.Enums.Internal;
using TwitchLib.Client.Events;
using TwitchLib.Client.Exceptions;
using TwitchLib.Client.Interfaces;
using TwitchLib.Client.Internal;
using TwitchLib.Client.Internal.Parsing;
using TwitchLib.Client.Manager;
using TwitchLib.Client.Models;
using TwitchLib.Client.Models.Internal;
using TwitchLib.Communication.Clients;
using TwitchLib.Communication.Events;
using TwitchLib.Communication.Interfaces;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Client component of TwitchLib. This component allows you to access Twitch chat and whispers, as well as the events that are sent over this connection.")]
[assembly: AssemblyFileVersion("3.1.5")]
[assembly: AssemblyInformationalVersion("3.1.5")]
[assembly: AssemblyProduct("TwitchLib.Client")]
[assembly: AssemblyTitle("TwitchLib.Client")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/TwitchLib/TwitchLib.Client")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.5.0")]
namespace TwitchLib.Client
{
	public class TwitchClient : ITwitchClient
	{
		private IClient _client;

		private MessageEmoteCollection _channelEmotes = new MessageEmoteCollection();

		private readonly ICollection<char> _chatCommandIdentifiers = new HashSet<char>();

		private readonly ICollection<char> _whisperCommandIdentifiers = new HashSet<char>();

		private readonly Queue<JoinedChannel> _joinChannelQueue = new Queue<JoinedChannel>();

		private readonly ILogger<TwitchClient> _logger;

		private readonly ClientProtocol _protocol;

		private string _autoJoinChannel;

		private bool _currentlyJoiningChannels;

		private Timer _joinTimer;

		private List<KeyValuePair<string, DateTime>> _awaitingJoins;

		private readonly IrcParser _ircParser;

		private readonly JoinedChannelManager _joinedChannelManager;

		private readonly List<string> _hasSeenJoinedChannels = new List<string>();

		private string _lastMessageSent;

		public Version Version => Assembly.GetEntryAssembly().GetName().Version;

		public bool IsInitialized => _client != null;

		public IReadOnlyList<JoinedChannel> JoinedChannels => _joinedChannelManager.GetJoinedChannels();

		public string TwitchUsername { get; private set; }

		public WhisperMessage PreviousWhisper { get; private set; }

		public bool IsConnected => IsInitialized && _client != null && _client.IsConnected;

		public MessageEmoteCollection ChannelEmotes => _channelEmotes;

		public bool DisableAutoPong { get; set; } = false;


		public bool WillReplaceEmotes { get; set; } = false;


		public bool OverrideBeingHostedCheck { get; set; } = false;


		public ConnectionCredentials ConnectionCredentials { get; private set; }

		public bool AutoReListenOnException { get; set; }

		public event EventHandler<OnVIPsReceivedArgs> OnVIPsReceived;

		public event EventHandler<OnLogArgs> OnLog;

		public event EventHandler<OnConnectedArgs> OnConnected;

		public event EventHandler<OnJoinedChannelArgs> OnJoinedChannel;

		public event EventHandler<OnIncorrectLoginArgs> OnIncorrectLogin;

		public event EventHandler<OnChannelStateChangedArgs> OnChannelStateChanged;

		public event EventHandler<OnUserStateChangedArgs> OnUserStateChanged;

		public event EventHandler<OnMessageReceivedArgs> OnMessageReceived;

		public event EventHandler<OnWhisperReceivedArgs> OnWhisperReceived;

		public event EventHandler<OnMessageSentArgs> OnMessageSent;

		public event EventHandler<OnWhisperSentArgs> OnWhisperSent;

		public event EventHandler<OnChatCommandReceivedArgs> OnChatCommandReceived;

		public event EventHandler<OnWhisperCommandReceivedArgs> OnWhisperCommandReceived;

		public event EventHandler<OnUserJoinedArgs> OnUserJoined;

		public event EventHandler<OnModeratorJoinedArgs> OnModeratorJoined;

		public event EventHandler<OnModeratorLeftArgs> OnModeratorLeft;

		public event EventHandler<OnMessageClearedArgs> OnMessageCleared;

		public event EventHandler<OnNewSubscriberArgs> OnNewSubscriber;

		public event EventHandler<OnReSubscriberArgs> OnReSubscriber;

		public event EventHandler OnHostLeft;

		public event EventHandler<OnExistingUsersDetectedArgs> OnExistingUsersDetected;

		public event EventHandler<OnUserLeftArgs> OnUserLeft;

		public event EventHandler<OnHostingStartedArgs> OnHostingStarted;

		public event EventHandler<OnHostingStoppedArgs> OnHostingStopped;

		public event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

		public event EventHandler<OnConnectionErrorArgs> OnConnectionError;

		public event EventHandler<OnChatClearedArgs> OnChatCleared;

		public event EventHandler<OnUserTimedoutArgs> OnUserTimedout;

		public event EventHandler<OnLeftChannelArgs> OnLeftChannel;

		public event EventHandler<OnUserBannedArgs> OnUserBanned;

		public event EventHandler<OnModeratorsReceivedArgs> OnModeratorsReceived;

		public event EventHandler<OnChatColorChangedArgs> OnChatColorChanged;

		public event EventHandler<OnSendReceiveDataArgs> OnSendReceiveData;

		public event EventHandler<OnNowHostingArgs> OnNowHosting;

		public event EventHandler<OnBeingHostedArgs> OnBeingHosted;

		public event EventHandler<OnRaidNotificationArgs> OnRaidNotification;

		public event EventHandler<OnGiftedSubscriptionArgs> OnGiftedSubscription;

		public event EventHandler<OnCommunitySubscriptionArgs> OnCommunitySubscription;

		public event EventHandler<OnMessageThrottledEventArgs> OnMessageThrottled;

		public event EventHandler<OnWhisperThrottledEventArgs> OnWhisperThrottled;

		public event EventHandler<OnErrorEventArgs> OnError;

		public event EventHandler<OnReconnectedEventArgs> OnReconnected;

		public event EventHandler<OnRitualNewChatterArgs> OnRitualNewChatter;

		public event EventHandler OnSelfRaidError;

		public event EventHandler OnNoPermissionError;

		public event EventHandler OnRaidedChannelIsMatureAudience;

		public event EventHandler<OnFailureToReceiveJoinConfirmationArgs> OnFailureToReceiveJoinConfirmation;

		public event EventHandler<OnUnaccountedForArgs> OnUnaccountedFor;

		public TwitchClient(IClient client = null, ClientProtocol protocol = 1, ILogger<TwitchClient> logger = null)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			_logger = logger;
			_client = client;
			_protocol = protocol;
			_joinedChannelManager = new JoinedChannelManager();
			_ircParser = new IrcParser();
		}

		public void Initialize(ConnectionCredentials credentials, string channel = null, char chatCommandIdentifier = '!', char whisperCommandIdentifier = '!', bool autoReListenOnExceptions = true)
		{
			Log($"TwitchLib-TwitchClient initialized, assembly version: {Assembly.GetExecutingAssembly().GetName().Version}");
			ConnectionCredentials = credentials;
			TwitchUsername = ConnectionCredentials.TwitchUsername;
			_autoJoinChannel = channel?.ToLower();
			if (chatCommandIdentifier != 0)
			{
				_chatCommandIdentifiers.Add(chatCommandIdentifier);
			}
			if (whisperCommandIdentifier != 0)
			{
				_whisperCommandIdentifiers.Add(whisperCommandIdentifier);
			}
			AutoReListenOnException = autoReListenOnExceptions;
			InitializeClient();
		}

		private void InitializeClient()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_002f: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (_client == null)
			{
				ClientProtocol protocol = _protocol;
				ClientProtocol val = protocol;
				if ((int)val != 0)
				{
					if ((int)val == 1)
					{
						_client = (IClient)new WebSocketClient((IClientOptions)null);
					}
				}
				else
				{
					_client = (IClient)new TcpClient((IClientOptions)null);
				}
			}
			Debug.Assert(_client != null, "_client != null");
			_client.OnConnected += _client_OnConnected;
			_client.OnMessage += _client_OnMessage;
			_client.OnDisconnected += _client_OnDisconnected;
			_client.OnFatality += _client_OnFatality;
			_client.OnMessageThrottled += _client_OnMessageThrottled;
			_client.OnWhisperThrottled += _client_OnWhisperThrottled;
			_client.OnReconnected += _client_OnReconnected;
		}

		internal void RaiseEvent(string eventName, object args = null)
		{
			FieldInfo field = GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic);
			MulticastDelegate multicastDelegate = field.GetValue(this) as MulticastDelegate;
			Delegate[] invocationList = multicastDelegate.GetInvocationList();
			foreach (Delegate @delegate in invocationList)
			{
				@delegate.Method.Invoke(@delegate.Target, (args == null) ? new object[2]
				{
					this,
					new EventArgs()
				} : new object[2] { this, args });
			}
		}

		public void SendRaw(string message)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			Log("Writing: " + message);
			_client.Send(message);
			this.OnSendReceiveData?.Invoke(this, new OnSendReceiveDataArgs
			{
				Direction = (SendReceiveDirection)0,
				Data = message
			});
		}

		public void SendMessage(JoinedChannel channel, string message, bool dryRun = false)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			if (!(channel == null || message == null || dryRun))
			{
				if (message.Length > 500)
				{
					LogError("Message length has exceeded the maximum character count. (500)");
					return;
				}
				OutboundChatMessage val = new OutboundChatMessage
				{
					Channel = channel.Channel,
					Username = ConnectionCredentials.TwitchUsername,
					Message = message
				};
				_lastMessageSent = message;
				_client.Send(((object)val).ToString());
			}
		}

		public void SendMessage(string channel, string message, bool dryRun = false)
		{
			SendMessage(GetJoinedChannel(channel), message, dryRun);
		}

		public void SendWhisper(string receiver, string message, bool dryRun = false)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			if (!dryRun)
			{
				OutboundWhisperMessage val = new OutboundWhisperMessage
				{
					Receiver = receiver,
					Username = ConnectionCredentials.TwitchUsername,
					Message = message
				};
				_client.SendWhisper(((object)val).ToString());
				this.OnWhisperSent?.Invoke(this, new OnWhisperSentArgs
				{
					Receiver = receiver,
					Message = message
				});
			}
		}

		public void Connect()
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			Log("Connecting to: " + ConnectionCredentials.TwitchWebsocketURI);
			_joinedChannelManager.Clear();
			_client.Open();
			Log("Should be connected!");
		}

		public void Disconnect()
		{
			Log("Disconnect Twitch Chat Client...");
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			_client.Close(true);
			_joinedChannelManager.Clear();
			PreviousWhisper = null;
		}

		public void Reconnect()
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			Log("Reconnecting to Twitch");
			_joinedChannelManager.Clear();
			_client.Reconnect();
		}

		public void AddChatCommandIdentifier(char identifier)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			_chatCommandIdentifiers.Add(identifier);
		}

		public void RemoveChatCommandIdentifier(char identifier)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			_chatCommandIdentifiers.Remove(identifier);
		}

		public void AddWhisperCommandIdentifier(char identifier)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			_whisperCommandIdentifiers.Add(identifier);
		}

		public void RemoveWhisperCommandIdentifier(char identifier)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			_whisperCommandIdentifiers.Remove(identifier);
		}

		public void SetConnectionCredentials(ConnectionCredentials credentials)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			if (IsConnected)
			{
				throw new IllegalAssignmentException("While the client is connected, you are unable to change the connection credentials. Please disconnect first and then change them.");
			}
			ConnectionCredentials = credentials;
		}

		public void JoinChannel(string channel, bool overrideCheck = false)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			if (!IsConnected)
			{
				HandleNotConnected();
			}
			if (((IEnumerable<JoinedChannel>)JoinedChannels).FirstOrDefault((Func<JoinedChannel, bool>)((JoinedChannel x) => x.Channel.ToLower() == channel && !overrideCheck)) == null)
			{
				_joinChannelQueue.Enqueue(new JoinedChannel(channel));
				if (!_currentlyJoiningChannels)
				{
					QueueingJoinCheck();
				}
			}
		}

		public JoinedChannel GetJoinedChannel(string channel)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			if (JoinedChannels.Count == 0)
			{
				throw new BadStateException("Must be connected to at least one channel.");
			}
			return _joinedChannelManager.GetJoinedChannel(channel);
		}

		public void LeaveChannel(string channel)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			channel = channel.ToLower();
			Log("Leaving channel: " + channel);
			JoinedChannel joinedChannel = _joinedChannelManager.GetJoinedChannel(channel);
			if (joinedChannel != null)
			{
				_client.Send(Rfc2812.Part("#" + channel));
			}
		}

		public void LeaveChannel(JoinedChannel channel)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			LeaveChannel(channel.Channel);
		}

		public void OnReadLineTest(string rawIrc)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			HandleIrcMessage(_ircParser.ParseIrcMessage(rawIrc));
		}

		private void _client_OnWhisperThrottled(object sender, OnWhisperThrottledEventArgs e)
		{
			this.OnWhisperThrottled?.Invoke(sender, e);
		}

		private void _client_OnMessageThrottled(object sender, OnMessageThrottledEventArgs e)
		{
			this.OnMessageThrottled?.Invoke(sender, e);
		}

		private void _client_OnFatality(object sender, OnFatalErrorEventArgs e)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			this.OnConnectionError?.Invoke(this, new OnConnectionErrorArgs
			{
				BotUsername = TwitchUsername,
				Error = new ErrorEvent
				{
					Message = e.Reason
				}
			});
		}

		private void _client_OnDisconnected(object sender, OnDisconnectedEventArgs e)
		{
			this.OnDisconnected?.Invoke(sender, e);
			_joinedChannelManager.Clear();
		}

		private void _client_OnReconnected(object sender, OnReconnectedEventArgs e)
		{
			this.OnReconnected?.Invoke(sender, e);
		}

		private void _client_OnMessage(object sender, OnMessageEventArgs e)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			string[] separator = new string[1] { "\r\n" };
			string[] array = e.Message.Split(separator, StringSplitOptions.None);
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (text.Length > 1)
				{
					Log("Received: " + text);
					this.OnSendReceiveData?.Invoke(this, new OnSendReceiveDataArgs
					{
						Direction = (SendReceiveDirection)1,
						Data = text
					});
					HandleIrcMessage(_ircParser.ParseIrcMessage(text));
				}
			}
		}

		private void _client_OnConnected(object sender, object e)
		{
			_client.Send(Rfc2812.Pass(ConnectionCredentials.TwitchOAuth));
			_client.Send(Rfc2812.Nick(ConnectionCredentials.TwitchUsername));
			_client.Send(Rfc2812.User(ConnectionCredentials.TwitchUsername, 0, ConnectionCredentials.TwitchUsername));
			_client.Send("CAP REQ twitch.tv/membership");
			_client.Send("CAP REQ twitch.tv/commands");
			_client.Send("CAP REQ twitch.tv/tags");
			if (_autoJoinChannel != null)
			{
				JoinChannel(_autoJoinChannel);
			}
		}

		private void QueueingJoinCheck()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			if (_joinChannelQueue.Count > 0)
			{
				_currentlyJoiningChannels = true;
				JoinedChannel val = _joinChannelQueue.Dequeue();
				Log("Joining channel: " + val.Channel);
				_client.Send(Rfc2812.Join("#" + val.Channel.ToLower()));
				_joinedChannelManager.AddJoinedChannel(new JoinedChannel(val.Channel));
				StartJoinedChannelTimer(val.Channel);
			}
			else
			{
				Log("Finished channel joining queue.");
			}
		}

		private void StartJoinedChannelTimer(string channel)
		{
			if (_joinTimer == null)
			{
				_joinTimer = new Timer(1000.0);
				_joinTimer.Elapsed += JoinChannelTimeout;
				_awaitingJoins = new List<KeyValuePair<string, DateTime>>();
			}
			_awaitingJoins.Add(new KeyValuePair<string, DateTime>(channel.ToLower(), DateTime.Now));
			if (!_joinTimer.Enabled)
			{
				_joinTimer.Start();
			}
		}

		private void JoinChannelTimeout(object sender, ElapsedEventArgs e)
		{
			if (_awaitingJoins.Any())
			{
				List<KeyValuePair<string, DateTime>> list = _awaitingJoins.Where((KeyValuePair<string, DateTime> x) => (DateTime.Now - x.Value).TotalSeconds > 5.0).ToList();
				if (!list.Any())
				{
					return;
				}
				_awaitingJoins.RemoveAll((KeyValuePair<string, DateTime> x) => (DateTime.Now - x.Value).TotalSeconds > 5.0);
				{
					foreach (KeyValuePair<string, DateTime> item in list)
					{
						_joinedChannelManager.RemoveJoinedChannel(item.Key.ToLowerInvariant());
						this.OnFailureToReceiveJoinConfirmation?.Invoke(this, new OnFailureToReceiveJoinConfirmationArgs
						{
							Exception = new FailureToReceiveJoinConfirmationException(item.Key)
						});
					}
					return;
				}
			}
			_joinTimer.Stop();
			_currentlyJoiningChannels = false;
			QueueingJoinCheck();
		}

		private void HandleIrcMessage(IrcMessage ircMessage)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected I4, but got Unknown
			if (ircMessage.Message.Contains("Login authentication failed"))
			{
				this.OnIncorrectLogin?.Invoke(this, new OnIncorrectLoginArgs
				{
					Exception = new ErrorLoggingInException(ircMessage.ToString(), TwitchUsername)
				});
			}
			IrcCommand command = ircMessage.Command;
			IrcCommand val = command;
			switch ((int)val)
			{
			case 1:
				HandlePrivMsg(ircMessage);
				break;
			case 2:
				HandleNotice(ircMessage);
				break;
			case 3:
				if (!DisableAutoPong)
				{
					SendRaw("PONG");
				}
				break;
			case 4:
				break;
			case 5:
				HandleJoin(ircMessage);
				break;
			case 6:
				HandlePart(ircMessage);
				break;
			case 7:
				HandleHostTarget(ircMessage);
				break;
			case 8:
				HandleClearChat(ircMessage);
				break;
			case 9:
				HandleClearMsg(ircMessage);
				break;
			case 10:
				HandleUserState(ircMessage);
				break;
			case 11:
				break;
			case 15:
				break;
			case 16:
				break;
			case 17:
				break;
			case 18:
				Handle004();
				break;
			case 19:
				Handle353(ircMessage);
				break;
			case 20:
				Handle366();
				break;
			case 21:
				break;
			case 22:
				break;
			case 23:
				break;
			case 24:
				HandleWhisper(ircMessage);
				break;
			case 25:
				HandleRoomState(ircMessage);
				break;
			case 26:
				Reconnect();
				break;
			case 28:
				HandleUserNotice(ircMessage);
				break;
			case 29:
				HandleMode(ircMessage);
				break;
			case 0:
				this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
				{
					BotUsername = TwitchUsername,
					Channel = null,
					Location = "HandleIrcMessage",
					RawIRC = ircMessage.ToString()
				});
				UnaccountedFor(ircMessage.ToString());
				break;
			default:
				this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
				{
					BotUsername = TwitchUsername,
					Channel = null,
					Location = "HandleIrcMessage",
					RawIRC = ircMessage.ToString()
				});
				UnaccountedFor(ircMessage.ToString());
				break;
			}
		}

		private void HandlePrivMsg(IrcMessage ircMessage)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			if (ircMessage.Hostmask.Equals("[email protected]"))
			{
				BeingHostedNotification beingHostedNotification = new BeingHostedNotification(TwitchUsername, ircMessage);
				this.OnBeingHosted?.Invoke(this, new OnBeingHostedArgs
				{
					BeingHostedNotification = beingHostedNotification
				});
				return;
			}
			ChatMessage val = new ChatMessage(TwitchUsername, ircMessage, ref _channelEmotes, WillReplaceEmotes);
			foreach (JoinedChannel item in JoinedChannels.Where((JoinedChannel x) => string.Equals(x.Channel, ircMessage.Channel, StringComparison.InvariantCultureIgnoreCase)))
			{
				item.HandleMessage(val);
			}
			this.OnMessageReceived?.Invoke(this, new OnMessageReceivedArgs
			{
				ChatMessage = val
			});
			if (_chatCommandIdentifiers != null && _chatCommandIdentifiers.Count != 0 && !string.IsNullOrEmpty(val.Message) && _chatCommandIdentifiers.Contains(val.Message[0]))
			{
				ChatCommand command = new ChatCommand(val);
				this.OnChatCommandReceived?.Invoke(this, new OnChatCommandReceivedArgs
				{
					Command = command
				});
			}
		}

		private void HandleNotice(IrcMessage ircMessage)
		{
			if (ircMessage.Message.Contains("Improperly formatted auth"))
			{
				this.OnIncorrectLogin?.Invoke(this, new OnIncorrectLoginArgs
				{
					Exception = new ErrorLoggingInException(ircMessage.ToString(), TwitchUsername)
				});
				return;
			}
			if (!ircMessage.Tags.TryGetValue("msg-id", out var value))
			{
				this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
				{
					BotUsername = TwitchUsername,
					Channel = ircMessage.Channel,
					Location = "NoticeHandling",
					RawIRC = ircMessage.ToString()
				});
				UnaccountedFor(ircMessage.ToString());
			}
			switch (value)
			{
			case "color_changed":
				this.OnChatColorChanged?.Invoke(this, new OnChatColorChangedArgs
				{
					Channel = ircMessage.Channel
				});
				break;
			case "host_on":
				this.OnNowHosting?.Invoke(this, new OnNowHostingArgs
				{
					Channel = ircMessage.Channel,
					HostedChannel = ircMessage.Message.Split(new char[1] { ' ' })[2].Replace(".", "")
				});
				break;
			case "host_off":
				this.OnHostLeft?.Invoke(this, null);
				break;
			case "room_mods":
				this.OnModeratorsReceived?.Invoke(this, new OnModeratorsReceivedArgs
				{
					Channel = ircMessage.Channel,
					Moderators = ircMessage.Message.Replace(" ", "").Split(new char[1] { ':' })[1].Split(new char[1] { ',' }).ToList()
				});
				break;
			case "no_mods":
				this.OnModeratorsReceived?.Invoke(this, new OnModeratorsReceivedArgs
				{
					Channel = ircMessage.Channel,
					Moderators = new List<string>()
				});
				break;
			case "no_permission":
				this.OnNoPermissionError?.Invoke(this, null);
				break;
			case "raid_error_self":
				this.OnSelfRaidError?.Invoke(this, null);
				break;
			case "raid_notice_mature":
				this.OnRaidedChannelIsMatureAudience?.Invoke(this, null);
				break;
			case "msg_channel_suspended":
				_awaitingJoins.RemoveAll((KeyValuePair<string, DateTime> x) => x.Key.ToLower() == ircMessage.Channel);
				_joinedChannelManager.RemoveJoinedChannel(ircMessage.Channel);
				QueueingJoinCheck();
				this.OnFailureToReceiveJoinConfirmation?.Invoke(this, new OnFailureToReceiveJoinConfirmationArgs
				{
					Exception = new FailureToReceiveJoinConfirmationException(ircMessage.Channel, ircMessage.Message)
				});
				break;
			case "no_vips":
				this.OnVIPsReceived?.Invoke(this, new OnVIPsReceivedArgs
				{
					Channel = ircMessage.Channel,
					VIPs = new List<string>()
				});
				break;
			case "vips_success":
				this.OnVIPsReceived?.Invoke(this, new OnVIPsReceivedArgs
				{
					Channel = ircMessage.Channel,
					VIPs = ircMessage.Message.Replace(" ", "").Replace(".", "").Split(new char[1] { ':' })[1].Split(new char[1] { ',' }).ToList()
				});
				break;
			default:
				this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
				{
					BotUsername = TwitchUsername,
					Channel = ircMessage.Channel,
					Location = "NoticeHandling",
					RawIRC = ircMessage.ToString()
				});
				UnaccountedFor(ircMessage.ToString());
				break;
			}
		}

		private void HandleJoin(IrcMessage ircMessage)
		{
			this.OnUserJoined?.Invoke(this, new OnUserJoinedArgs
			{
				Channel = ircMessage.Channel,
				Username = ircMessage.User
			});
		}

		private void HandlePart(IrcMessage ircMessage)
		{
			if (string.Equals(TwitchUsername, ircMessage.User, StringComparison.InvariantCultureIgnoreCase))
			{
				_joinedChannelManager.RemoveJoinedChannel(ircMessage.Channel);
				_hasSeenJoinedChannels.Remove(ircMessage.Channel);
				this.OnLeftChannel?.Invoke(this, new OnLeftChannelArgs
				{
					BotUsername = TwitchUsername,
					Channel = ircMessage.Channel
				});
			}
			else
			{
				this.OnUserLeft?.Invoke(this, new OnUserLeftArgs
				{
					Channel = ircMessage.Channel,
					Username = ircMessage.User
				});
			}
		}

		private void HandleHostTarget(IrcMessage ircMessage)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (ircMessage.Message.StartsWith("-"))
			{
				HostingStopped hostingStopped = new HostingStopped(ircMessage);
				this.OnHostingStopped?.Invoke(this, new OnHostingStoppedArgs
				{
					HostingStopped = hostingStopped
				});
			}
			else
			{
				HostingStarted hostingStarted = new HostingStarted(ircMessage);
				this.OnHostingStarted?.Invoke(this, new OnHostingStartedArgs
				{
					HostingStarted = hostingStarted
				});
			}
		}

		private void HandleClearChat(IrcMessage ircMessage)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			string value;
			if (string.IsNullOrWhiteSpace(ircMessage.Message))
			{
				this.OnChatCleared?.Invoke(this, new OnChatClearedArgs
				{
					Channel = ircMessage.Channel
				});
			}
			else if (ircMessage.Tags.TryGetValue("ban-duration", out value))
			{
				UserTimeout userTimeout = new UserTimeout(ircMessage);
				this.OnUserTimedout?.Invoke(this, new OnUserTimedoutArgs
				{
					UserTimeout = userTimeout
				});
			}
			else
			{
				UserBan userBan = new UserBan(ircMessage);
				this.OnUserBanned?.Invoke(this, new OnUserBannedArgs
				{
					UserBan = userBan
				});
			}
		}

		private void HandleClearMsg(IrcMessage ircMessage)
		{
			this.OnMessageCleared?.Invoke(this, new OnMessageClearedArgs
			{
				Channel = ircMessage.Channel,
				Message = ircMessage.Message,
				TargetMessageId = ircMessage.ToString().Split(new char[1] { '=' })[3].Split(new char[1] { ';' })[0],
				TmiSentTs = ircMessage.ToString().Split(new char[1] { '=' })[4].Split(new char[1] { ' ' })[0]
			});
		}

		private void HandleUserState(IrcMessage ircMessage)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			UserState val = new UserState(ircMessage);
			if (!_hasSeenJoinedChannels.Contains(val.Channel.ToLowerInvariant()))
			{
				_hasSeenJoinedChannels.Add(val.Channel.ToLowerInvariant());
				this.OnUserStateChanged?.Invoke(this, new OnUserStateChangedArgs
				{
					UserState = val
				});
			}
			else
			{
				this.OnMessageSent?.Invoke(this, new OnMessageSentArgs
				{
					SentMessage = new SentMessage(val, _lastMessageSent)
				});
			}
		}

		private void Handle004()
		{
			this.OnConnected?.Invoke(this, new OnConnectedArgs
			{
				AutoJoinChannel = _autoJoinChannel,
				BotUsername = TwitchUsername
			});
		}

		private void Handle353(IrcMessage ircMessage)
		{
			if (string.Equals(ircMessage.Channel, TwitchUsername, StringComparison.InvariantCultureIgnoreCase))
			{
				this.OnExistingUsersDetected?.Invoke(this, new OnExistingUsersDetectedArgs
				{
					Channel = ircMessage.Channel,
					Users = ircMessage.Message.Split(new char[1] { ' ' }).ToList()
				});
			}
		}

		private void Handle366()
		{
			_currentlyJoiningChannels = false;
			QueueingJoinCheck();
		}

		private void HandleWhisper(IrcMessage ircMessage)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			WhisperMessage val2 = (PreviousWhisper = new WhisperMessage(ircMessage, TwitchUsername));
			this.OnWhisperReceived?.Invoke(this, new OnWhisperReceivedArgs
			{
				WhisperMessage = val2
			});
			if (_whisperCommandIdentifiers != null && _whisperCommandIdentifiers.Count != 0 && !string.IsNullOrEmpty(val2.Message) && _whisperCommandIdentifiers.Contains(val2.Message[0]))
			{
				WhisperCommand command = new WhisperCommand(val2);
				this.OnWhisperCommandReceived?.Invoke(this, new OnWhisperCommandReceivedArgs
				{
					Command = command
				});
				return;
			}
			this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
			{
				BotUsername = TwitchUsername,
				Channel = ircMessage.Channel,
				Location = "WhispergHandling",
				RawIRC = ircMessage.ToString()
			});
			UnaccountedFor(ircMessage.ToString());
		}

		private void HandleRoomState(IrcMessage ircMessage)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			if (ircMessage.Tags.Count > 2)
			{
				KeyValuePair<string, DateTime> item = _awaitingJoins.FirstOrDefault((KeyValuePair<string, DateTime> x) => x.Key == ircMessage.Channel);
				_awaitingJoins.Remove(item);
				this.OnJoinedChannel?.Invoke(this, new OnJoinedChannelArgs
				{
					BotUsername = TwitchUsername,
					Channel = ircMessage.Channel
				});
				if (this.OnBeingHosted != null && ircMessage.Channel.ToLowerInvariant() != TwitchUsername && !OverrideBeingHostedCheck)
				{
					Log("[OnBeingHosted] OnBeingHosted will only be fired while listening to this event as the broadcaster's channel. You do not appear to be connected as the broadcaster. To hide this warning, set TwitchClient property OverrideBeingHostedCheck to true.");
				}
			}
			this.OnChannelStateChanged?.Invoke(this, new OnChannelStateChangedArgs
			{
				ChannelState = new ChannelState(ircMessage),
				Channel = ircMessage.Channel
			});
		}

		private void HandleUserNotice(IrcMessage ircMessage)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Expected O, but got Unknown
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Expected O, but got Unknown
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Expected O, but got Unknown
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Expected O, but got Unknown
			if (!ircMessage.Tags.TryGetValue("msg-id", out var value))
			{
				this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
				{
					BotUsername = TwitchUsername,
					Channel = ircMessage.Channel,
					Location = "UserNoticeHandling",
					RawIRC = ircMessage.ToString()
				});
				UnaccountedFor(ircMessage.ToString());
				return;
			}
			switch (value)
			{
			case "raid":
			{
				RaidNotification raidNotification = new RaidNotification(ircMessage);
				this.OnRaidNotification?.Invoke(this, new OnRaidNotificationArgs
				{
					Channel = ircMessage.Channel,
					RaidNotification = raidNotification
				});
				break;
			}
			case "resub":
			{
				ReSubscriber reSubscriber = new ReSubscriber(ircMessage);
				this.OnReSubscriber?.Invoke(this, new OnReSubscriberArgs
				{
					ReSubscriber = reSubscriber,
					Channel = ircMessage.Channel
				});
				break;
			}
			case "ritual":
			{
				if (!ircMessage.Tags.TryGetValue("msg-param-ritual-name", out var value2))
				{
					this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
					{
						BotUsername = TwitchUsername,
						Channel = ircMessage.Channel,
						Location = "UserNoticeRitualHandling",
						RawIRC = ircMessage.ToString()
					});
					UnaccountedFor(ircMessage.ToString());
					break;
				}
				string text = value2;
				string text2 = text;
				if (text2 == "new_chatter")
				{
					this.OnRitualNewChatter?.Invoke(this, new OnRitualNewChatterArgs
					{
						RitualNewChatter = new RitualNewChatter(ircMessage)
					});
					break;
				}
				this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
				{
					BotUsername = TwitchUsername,
					Channel = ircMessage.Channel,
					Location = "UserNoticeHandling",
					RawIRC = ircMessage.ToString()
				});
				UnaccountedFor(ircMessage.ToString());
				break;
			}
			case "subgift":
			{
				GiftedSubscription giftedSubscription = new GiftedSubscription(ircMessage);
				this.OnGiftedSubscription?.Invoke(this, new OnGiftedSubscriptionArgs
				{
					GiftedSubscription = giftedSubscription,
					Channel = ircMessage.Channel
				});
				break;
			}
			case "submysterygift":
			{
				CommunitySubscription giftedSubscription2 = new CommunitySubscription(ircMessage);
				this.OnCommunitySubscription?.Invoke(this, new OnCommunitySubscriptionArgs
				{
					GiftedSubscription = giftedSubscription2,
					Channel = ircMessage.Channel
				});
				break;
			}
			case "sub":
			{
				Subscriber subscriber = new Subscriber(ircMessage);
				this.OnNewSubscriber?.Invoke(this, new OnNewSubscriberArgs
				{
					Subscriber = subscriber,
					Channel = ircMessage.Channel
				});
				break;
			}
			default:
				this.OnUnaccountedFor?.Invoke(this, new OnUnaccountedForArgs
				{
					BotUsername = TwitchUsername,
					Channel = ircMessage.Channel,
					Location = "UserNoticeHandling",
					RawIRC = ircMessage.ToString()
				});
				UnaccountedFor(ircMessage.ToString());
				break;
			}
		}

		private void HandleMode(IrcMessage ircMessage)
		{
			if (ircMessage.Message.StartsWith("+o"))
			{
				this.OnModeratorJoined?.Invoke(this, new OnModeratorJoinedArgs
				{
					Channel = ircMessage.Channel,
					Username = ircMessage.Message.Split(new char[1] { ' ' })[1]
				});
			}
			else if (ircMessage.Message.StartsWith("-o"))
			{
				this.OnModeratorLeft?.Invoke(this, new OnModeratorLeftArgs
				{
					Channel = ircMessage.Channel,
					Username = ircMessage.Message.Split(new char[1] { ' ' })[1]
				});
			}
		}

		private void UnaccountedFor(string ircString)
		{
			Log("Unaccounted for: " + ircString + " (please create a TwitchLib GitHub issue :P)");
		}

		private void Log(string message, bool includeDate = false, bool includeTime = false)
		{
			string arg = ((includeDate && includeTime) ? $"{DateTime.UtcNow}" : ((!includeDate) ? (DateTime.UtcNow.ToShortTimeString() ?? "") : (DateTime.UtcNow.ToShortDateString() ?? "")));
			if (includeDate || includeTime)
			{
				_logger?.LogInformation($"[TwitchLib, {Assembly.GetExecutingAssembly().GetName().Version} - {arg}] {message}");
			}
			else
			{
				_logger?.LogInformation($"[TwitchLib, {Assembly.GetExecutingAssembly().GetName().Version}] {message}");
			}
			EventHandler<OnLogArgs> onLog = this.OnLog;
			if (onLog != null)
			{
				OnLogArgs onLogArgs = new OnLogArgs();
				ConnectionCredentials connectionCredentials = ConnectionCredentials;
				onLogArgs.BotUsername = ((connectionCredentials != null) ? connectionCredentials.TwitchUsername : null);
				onLogArgs.Data = message;
				onLogArgs.DateTime = DateTime.UtcNow;
				onLog(this, onLogArgs);
			}
		}

		private void LogError(string message, bool includeDate = false, bool includeTime = false)
		{
			string arg = ((includeDate && includeTime) ? $"{DateTime.UtcNow}" : ((!includeDate) ? (DateTime.UtcNow.ToShortTimeString() ?? "") : (DateTime.UtcNow.ToShortDateString() ?? "")));
			if (includeDate || includeTime)
			{
				_logger?.LogError($"[TwitchLib, {Assembly.GetExecutingAssembly().GetName().Version} - {arg}] {message}");
			}
			else
			{
				_logger?.LogError($"[TwitchLib, {Assembly.GetExecutingAssembly().GetName().Version}] {message}");
			}
			EventHandler<OnLogArgs> onLog = this.OnLog;
			if (onLog != null)
			{
				OnLogArgs onLogArgs = new OnLogArgs();
				ConnectionCredentials connectionCredentials = ConnectionCredentials;
				onLogArgs.BotUsername = ((connectionCredentials != null) ? connectionCredentials.TwitchUsername : null);
				onLogArgs.Data = message;
				onLogArgs.DateTime = DateTime.UtcNow;
				onLog(this, onLogArgs);
			}
		}

		public void SendQueuedItem(string message)
		{
			if (!IsInitialized)
			{
				HandleNotInitialized();
			}
			_client.Send(message);
		}

		protected static void HandleNotInitialized()
		{
			throw new ClientNotInitializedException("The twitch client has not been initialized and cannot be used. Please call Initialize();");
		}

		protected static void HandleNotConnected()
		{
			throw new ClientNotConnectedException("In order to perform this action, the client must be connected to Twitch. To confirm connection, try performing this action in or after the OnConnected event has been fired.");
		}
	}
}
namespace TwitchLib.Client.Manager
{
	internal class JoinedChannelManager
	{
		private readonly ConcurrentDictionary<string, JoinedChannel> _joinedChannels;

		public JoinedChannelManager()
		{
			_joinedChannels = new ConcurrentDictionary<string, JoinedChannel>(StringComparer.OrdinalIgnoreCase);
		}

		public void AddJoinedChannel(JoinedChannel joinedChannel)
		{
			_joinedChannels.TryAdd(joinedChannel.Channel, joinedChannel);
		}

		public JoinedChannel GetJoinedChannel(string channel)
		{
			_joinedChannels.TryGetValue(channel, out var value);
			return value;
		}

		public IReadOnlyList<JoinedChannel> GetJoinedChannels()
		{
			return _joinedChannels.Values.ToList().AsReadOnly();
		}

		public void RemoveJoinedChannel(string channel)
		{
			_joinedChannels.TryRemove(channel, out var _);
		}

		public void Clear()
		{
			_joinedChannels.Clear();
		}
	}
}
namespace TwitchLib.Client.Internal
{
	public sealed class Rfc2812
	{
		private static readonly Regex NicknameRegex = new Regex("^[A-Za-z\\[\\]\\\\`_^{|}][A-Za-z0-9\\[\\]\\\\`_\\-^{|}]+$", RegexOptions.Compiled);

		private Rfc2812()
		{
		}

		public static bool IsValidNickname(string nickname)
		{
			return !string.IsNullOrEmpty(nickname) && NicknameRegex.Match(nickname).Success;
		}

		public static string Pass(string password)
		{
			return "PASS " + password;
		}

		public static string Nick(string nickname)
		{
			return "NICK " + nickname;
		}

		public static string User(string username, int usermode, string realname)
		{
			return $"USER {username} {usermode} * :{realname}";
		}

		public static string Oper(string name, string password)
		{
			return "OPER " + name + " " + password;
		}

		public static string Privmsg(string destination, string message)
		{
			return "PRIVMSG " + destination + " :" + message;
		}

		public static string Notice(string destination, string message)
		{
			return "NOTICE " + destination + " :" + message;
		}

		public static string Join(string channel)
		{
			return "JOIN " + channel;
		}

		public static string Join(string[] channels)
		{
			return "JOIN " + string.Join(",", channels);
		}

		public static string Join(string channel, string key)
		{
			return "JOIN " + channel + " " + key;
		}

		public static string Join(string[] channels, string[] keys)
		{
			return "JOIN " + string.Join(",", channels) + " " + string.Join(",", keys);
		}

		public static string Part(string channel)
		{
			return "PART " + channel;
		}

		public static string Part(string[] channels)
		{
			return "PART " + string.Join(",", channels);
		}

		public static string Part(string channel, string partmessage)
		{
			return "PART " + channel + " :" + partmessage;
		}

		public static string Part(string[] channels, string partmessage)
		{
			return "PART " + string.Join(",", channels) + " :" + partmessage;
		}

		public static string Kick(string channel, string nickname)
		{
			return "KICK " + channel + " " + nickname;
		}

		public static string Kick(string channel, string nickname, string comment)
		{
			return "KICK " + channel + " " + nickname + " :" + comment;
		}

		public static string Kick(string[] channels, string nickname)
		{
			return "KICK " + string.Join(",", channels) + " " + nickname;
		}

		public static string Kick(string[] channels, string nickname, string comment)
		{
			return "KICK " + string.Join(",", channels) + " " + nickname + " :" + comment;
		}

		public static string Kick(string channel, string[] nicknames)
		{
			return "KICK " + channel + " " + string.Join(",", nicknames);
		}

		public static string Kick(string channel, string[] nicknames, string comment)
		{
			return "KICK " + channel + " " + string.Join(",", nicknames) + " :" + comment;
		}

		public static string Kick(string[] channels, string[] nicknames)
		{
			return "KICK " + string.Join(",", channels) + " " + string.Join(",", nicknames);
		}

		public static string Kick(string[] channels, string[] nicknames, string comment)
		{
			return "KICK " + string.Join(",", channels) + " " + string.Join(",", nicknames) + " :" + comment;
		}

		public static string Motd()
		{
			return "MOTD";
		}

		public static string Motd(string target)
		{
			return "MOTD " + target;
		}

		public static string Lusers()
		{
			return "LUSERS";
		}

		public static string Lusers(string mask)
		{
			return "LUSER " + mask;
		}

		public static string Lusers(string mask, string target)
		{
			return "LUSER " + mask + " " + target;
		}

		public static string Version()
		{
			return "VERSION";
		}

		public static string Version(string target)
		{
			return "VERSION " + target;
		}

		public static string Stats()
		{
			return "STATS";
		}

		public static string Stats(string query)
		{
			return "STATS " + query;
		}

		public static string Stats(string query, string target)
		{
			return "STATS " + query + " " + target;
		}

		public static string Links()
		{
			return "LINKS";
		}

		public static string Links(string servermask)
		{
			return "LINKS " + servermask;
		}

		public static string Links(string remoteserver, string servermask)
		{
			return "LINKS " + remoteserver + " " + servermask;
		}

		public static string Time()
		{
			return "TIME";
		}

		public static string Time(string target)
		{
			return "TIME " + target;
		}

		public static string Connect(string targetserver, string port)
		{
			return "CONNECT " + targetserver + " " + port;
		}

		public static string Connect(string targetserver, string port, string remoteserver)
		{
			return "CONNECT " + targetserver + " " + port + " " + remoteserver;
		}

		public static string Trace()
		{
			return "TRACE";
		}

		public static string Trace(string target)
		{
			return "TRACE " + target;
		}

		public static string Admin()
		{
			return "ADMIN";
		}

		public static string Admin(string target)
		{
			return "ADMIN " + target;
		}

		public static string Info()
		{
			return "INFO";
		}

		public static string Info(string target)
		{
			return "INFO " + target;
		}

		public static string Servlist()
		{
			return "SERVLIST";
		}

		public static string Servlist(string mask)
		{
			return "SERVLIST " + mask;
		}

		public static string Servlist(string mask, string type)
		{
			return "SERVLIST " + mask + " " + type;
		}

		public static string Squery(string servicename, string servicetext)
		{
			return "SQUERY " + servicename + " :" + servicename;
		}

		public static string List()
		{
			return "LIST";
		}

		public static string List(string channel)
		{
			return "LIST " + channel;
		}

		public static string List(string[] channels)
		{
			return "LIST " + string.Join(",", channels);
		}

		public static string List(string channel, string target)
		{
			return "LIST " + channel + " " + target;
		}

		public static string List(string[] channels, string target)
		{
			return "LIST " + string.Join(",", channels) + " " + target;
		}

		public static string Names()
		{
			return "NAMES";
		}

		public static string Names(string channel)
		{
			return "NAMES " + channel;
		}

		public static string Names(string[] channels)
		{
			return "NAMES " + string.Join(",", channels);
		}

		public static string Names(string channel, string target)
		{
			return "NAMES " + channel + " " + target;
		}

		public static string Names(string[] channels, string target)
		{
			return "NAMES " + string.Join(",", channels) + " " + target;
		}

		public static string Topic(string channel)
		{
			return "TOPIC " + channel;
		}

		public static string Topic(string channel, string newtopic)
		{
			return "TOPIC " + channel + " :" + newtopic;
		}

		public static string Mode(string target)
		{
			return "MODE " + target;
		}

		public static string Mode(string target, string newmode)
		{
			return "MODE " + target + " " + newmode + target + " " + newmode;
		}

		public static string Mode(string target, string[] newModes, string[] newModeParameters)
		{
			if (newModes == null)
			{
				throw new ArgumentNullException("newModes");
			}
			if (newModeParameters == null)
			{
				throw new ArgumentNullException("newModeParameters");
			}
			if (newModes.Length != newModeParameters.Length)
			{
				throw new ArgumentException("newModes and newModeParameters must have the same size.");
			}
			StringBuilder stringBuilder = new StringBuilder(newModes.Length);
			StringBuilder stringBuilder2 = new StringBuilder();
			if (newModes.Length > 3)
			{
				throw new ArgumentOutOfRangeException("Length", newModes.Length, $"Mode change list is too large (> {3}).");
			}
			for (int i = 0; i <= newModes.Length; i += 3)
			{
				for (int j = 0; j < 3 && i + j < newModes.Length; j++)
				{
					stringBuilder.Append(newModes[i + j]);
				}
				for (int k = 0; k < 3 && i + k < newModeParameters.Length; k++)
				{
					stringBuilder2.Append(newModeParameters[i + k]);
					stringBuilder2.Append(" ");
				}
			}
			if (stringBuilder2.Length <= 0)
			{
				return Mode(target, stringBuilder.ToString());
			}
			stringBuilder2.Length--;
			stringBuilder.Append(" ");
			stringBuilder.Append((object?)stringBuilder2);
			return Mode(target, stringBuilder.ToString());
		}

		public static string Service(string nickname, string distribution, string info)
		{
			return "SERVICE " + nickname + " * " + distribution + " * * :" + info;
		}

		public static string Invite(string nickname, string channel)
		{
			return "INVITE " + nickname + " " + channel;
		}

		public static string Who()
		{
			return "WHO";
		}

		public static string Who(string mask)
		{
			return "WHO " + mask;
		}

		public static string Who(string mask, bool ircop)
		{
			return ircop ? ("WHO " + mask + " o") : ("WHO " + mask);
		}

		public static string Whois(string mask)
		{
			return "WHOIS " + mask;
		}

		public static string Whois(string[] masks)
		{
			return "WHOIS " + string.Join(",", masks);
		}

		public static string Whois(string target, string mask)
		{
			return "WHOIS " + target + " " + mask;
		}

		public static string Whois(string target, string[] masks)
		{
			return "WHOIS " + target + " " + string.Join(",", masks);
		}

		public static string Whowas(string nickname)
		{
			return "WHOWAS " + nickname;
		}

		public static string Whowas(string[] nicknames)
		{
			return "WHOWAS " + string.Join(",", nicknames);
		}

		public static string Whowas(string nickname, string count)
		{
			return "WHOWAS " + nickname + " " + count + " ";
		}

		public static string Whowas(string[] nicknames, string count)
		{
			return "WHOWAS " + string.Join(",", nicknames) + " " + count + " ";
		}

		public static string Whowas(string nickname, string count, string target)
		{
			return "WHOWAS " + nickname + " " + count + " " + target;
		}

		public static string Whowas(string[] nicknames, string count, string target)
		{
			return "WHOWAS " + string.Join(",", nicknames) + " " + count + " " + target;
		}

		public static string Kill(string nickname, string comment)
		{
			return "KILL " + nickname + " :" + comment;
		}

		public static string Ping(string server)
		{
			return "PING " + server;
		}

		public static string Ping(string server, string server2)
		{
			return "PING " + server + " " + server2;
		}

		public static string Pong(string server)
		{
			return "PONG " + server;
		}

		public static string Pong(string server, string server2)
		{
			return "PONG " + server + " " + server2;
		}

		public static string Error(string errormessage)
		{
			return "ERROR :" + errormessage;
		}

		public static string Away()
		{
			return "AWAY";
		}

		public static string Away(string awaytext)
		{
			return "AWAY :" + awaytext;
		}

		public static string Rehash()
		{
			return "REHASH";
		}

		public static string Die()
		{
			return "DIE";
		}

		public static string Restart()
		{
			return "RESTART";
		}

		public static string Summon(string user)
		{
			return "SUMMON " + user;
		}

		public static string Summon(string user, string target)
		{
			return "SUMMON " + user + " " + target + user + " " + target;
		}

		public static string Summon(string user, string target, string channel)
		{
			return "SUMMON " + user + " " + target + " " + channel;
		}

		public static string Users()
		{
			return "USERS";
		}

		public static string Users(string target)
		{
			return "USERS " + target;
		}

		public static string Wallops(string wallopstext)
		{
			return "WALLOPS :" + wallopstext;
		}

		public static string Userhost(string nickname)
		{
			return "USERHOST " + nickname;
		}

		public static string Userhost(string[] nicknames)
		{
			return "USERHOST " + string.Join(" ", nicknames);
		}

		public static string Ison(string nickname)
		{
			return "ISON " + nickname;
		}

		public static string Ison(string[] nicknames)
		{
			return "ISON " + string.Join(" ", nicknames);
		}

		public static string Quit()
		{
			return "QUIT";
		}

		public static string Quit(string quitmessage)
		{
			return "QUIT :" + quitmessage;
		}

		public static string Squit(string server, string comment)
		{
			return "SQUIT " + server + " :" + comment;
		}
	}
}
namespace TwitchLib.Client.Internal.Parsing
{
	internal class IrcParser
	{
		private enum ParserState
		{
			STATE_NONE,
			STATE_V3,
			STATE_PREFIX,
			STATE_COMMAND,
			STATE_PARAM,
			STATE_TRAILING
		}

		public IrcMessage ParseIrcMessage(string raw)
		{
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_07cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0747: Unknown result type (might be due to invalid IL or missing references)
			//IL_0737: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0795: Unknown result type (might be due to invalid IL or missing references)
			//IL_079b: Unknown result type (might be due to invalid IL or missing references)
			//IL_07dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_080b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0820: Unknown result type (might be due to invalid IL or missing references)
			//IL_0827: Expected O, but got Unknown
			//IL_0758: Unknown result type (might be due to invalid IL or missing references)
			//IL_074f: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0777: Unknown result type (might be due to invalid IL or missing references)
			//IL_0727: Unknown result type (might be due to invalid IL or missing references)
			//IL_0772: Unknown result type (might be due to invalid IL or missing references)
			//IL_073f: Unknown result type (might be due to invalid IL or missing references)
			//IL_072f: Unknown result type (might be due to invalid IL or missing references)
			//IL_078f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0789: Unknown result type (might be due to invalid IL or missing references)
			//IL_076d: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0761: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0783: Unknown result type (might be due to invalid IL or missing references)
			//IL_0767: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_077d: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			ParserState parserState = ParserState.STATE_NONE;
			int[] array = new int[6];
			int[] array2 = new int[6];
			for (int i = 0; i < raw.Length; i++)
			{
				array2[(int)parserState] = i - array[(int)parserState] - 1;
				if (parserState == ParserState.STATE_NONE && raw[i] == '@')
				{
					parserState = ParserState.STATE_V3;
					i = (array[(int)parserState] = i + 1);
					int num = i;
					string text = null;
					for (; i < raw.Length; i++)
					{
						if (raw[i] == '=')
						{
							text = raw.Substring(num, i - num);
							num = i + 1;
						}
						else if (raw[i] == ';')
						{
							if (text == null)
							{
								dictionary[raw.Substring(num, i - num)] = "1";
							}
							else
							{
								dictionary[text] = raw.Substring(num, i - num);
							}
							num = i + 1;
						}
						else if (raw[i] == ' ')
						{
							if (text == null)
							{
								dictionary[raw.Substring(num, i - num)] = "1";
							}
							else
							{
								dictionary[text] = raw.Substring(num, i - num);
							}
							break;
						}
					}
				}
				else if (parserState < ParserState.STATE_PREFIX && raw[i] == ':')
				{
					parserState = ParserState.STATE_PREFIX;
					i = (array[(int)parserState] = i + 1);
				}
				else if (parserState < ParserState.STATE_COMMAND)
				{
					parserState = ParserState.STATE_COMMAND;
					array[(int)parserState] = i;
				}
				else
				{
					if (parserState < ParserState.STATE_TRAILING && raw[i] == ':')
					{
						parserState = ParserState.STATE_TRAILING;
						i = (array[(int)parserState] = i + 1);
						break;
					}
					if ((parserState < ParserState.STATE_TRAILING && raw[i] == '+') || (parserState < ParserState.STATE_TRAILING && raw[i] == '-'))
					{
						parserState = ParserState.STATE_TRAILING;
						array[(int)parserState] = i;
						break;
					}
					if (parserState == ParserState.STATE_COMMAND)
					{
						parserState = ParserState.STATE_PARAM;
						array[(int)parserState] = i;
					}
				}
				for (; i < raw.Length && raw[i] != ' '; i++)
				{
				}
			}
			array2[(int)parserState] = raw.Length - array[(int)parserState];
			string text2 = raw.Substring(array[3], array2[3]);
			IrcCommand val = (IrcCommand)0;
			switch (text2)
			{
			case "PRIVMSG":
				val = (IrcCommand)1;
				break;
			case "NOTICE":
				val = (IrcCommand)2;
				break;
			case "PING":
				val = (IrcCommand)3;
				break;
			case "PONG":
				val = (IrcCommand)4;
				break;
			case "HOSTTARGET":
				val = (IrcCommand)7;
				break;
			case "CLEARCHAT":
				val = (IrcCommand)8;
				break;
			case "CLEARMSG":
				val = (IrcCommand)9;
				break;
			case "USERSTATE":
				val = (IrcCommand)10;
				break;
			case "GLOBALUSERSTATE":
				val = (IrcCommand)11;
				break;
			case "NICK":
				val = (IrcCommand)12;
				break;
			case "JOIN":
				val = (IrcCommand)5;
				break;
			case "PART":
				val = (IrcCommand)6;
				break;
			case "PASS":
				val = (IrcCommand)13;
				break;
			case "CAP":
				val = (IrcCommand)14;
				break;
			case "001":
				val = (IrcCommand)15;
				break;
			case "002":
				val = (IrcCommand)16;
				break;
			case "003":
				val = (IrcCommand)17;
				break;
			case "004":
				val = (IrcCommand)18;
				break;
			case "353":
				val = (IrcCommand)19;
				break;
			case "366":
				val = (IrcCommand)20;
				break;
			case "372":
				val = (IrcCommand)21;
				break;
			case "375":
				val = (IrcCommand)22;
				break;
			case "376":
				val = (IrcCommand)23;
				break;
			case "WHISPER":
				val = (IrcCommand)24;
				break;
			case "SERVERCHANGE":
				val = (IrcCommand)27;
				break;
			case "RECONNECT":
				val = (IrcCommand)26;
				break;
			case "ROOMSTATE":
				val = (IrcCommand)25;
				break;
			case "USERNOTICE":
				val = (IrcCommand)28;
				break;
			case "MODE":
				val = (IrcCommand)29;
				break;
			}
			string text3 = raw.Substring(array[4], array2[4]);
			string text4 = raw.Substring(array[5], array2[5]);
			string text5 = raw.Substring(array[2], array2[2]);
			return new IrcMessage(val, new string[2] { text3, text4 }, text5, dictionary);
		}
	}
}
namespace TwitchLib.Client.Interfaces
{
	public interface ITwitchClient
	{
		bool AutoReListenOnException { get; set; }

		MessageEmoteCollection ChannelEmotes { get; }

		ConnectionCredentials ConnectionCredentials { get; }

		bool DisableAutoPong { get; set; }

		bool IsConnected { get; }

		bool IsInitialized { get; }

		IReadOnlyList<JoinedChannel> JoinedChannels { get; }

		bool OverrideBeingHostedCheck { get; set; }

		WhisperMessage PreviousWhisper { get; }

		string TwitchUsername { get; }

		bool WillReplaceEmotes { get; set; }

		event EventHandler<OnBeingHostedArgs> OnBeingHosted;

		event EventHandler<OnChannelStateChangedArgs> OnChannelStateChanged;

		event EventHandler<OnChatClearedArgs> OnChatCleared;

		event EventHandler<OnChatColorChangedArgs> OnChatColorChanged;

		event EventHandler<OnChatCommandReceivedArgs> OnChatCommandReceived;

		event EventHandler<OnConnectedArgs> OnConnected;

		event EventHandler<OnConnectionErrorArgs> OnConnectionError;

		event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

		event EventHandler<OnExistingUsersDetectedArgs> OnExistingUsersDetected;

		event EventHandler<OnGiftedSubscriptionArgs> OnGiftedSubscription;

		event EventHandler<OnHostingStartedArgs> OnHostingStarted;

		event EventHandler<OnHostingStoppedArgs> OnHostingStopped;

		event EventHandler OnHostLeft;

		event EventHandler<OnIncorrectLoginArgs> OnIncorrectLogin;

		event EventHandler<OnJoinedChannelArgs> OnJoinedChannel;

		event EventHandler<OnLeftChannelArgs> OnLeftChannel;

		event EventHandler<OnLogArgs> OnLog;

		event EventHandler<OnMessageReceivedArgs> OnMessageReceived;

		event EventHandler<OnMessageSentArgs> OnMessageSent;

		event EventHandler<OnModeratorJoinedArgs> OnModeratorJoined;

		event EventHandler<OnModeratorLeftArgs> OnModeratorLeft;

		event EventHandler<OnModeratorsReceivedArgs> OnModeratorsReceived;

		event EventHandler<OnNewSubscriberArgs> OnNewSubscriber;

		event EventHandler<OnNowHostingArgs> OnNowHosting;

		event EventHandler<OnRaidNotificationArgs> OnRaidNotification;

		event EventHandler<OnReSubscriberArgs> OnReSubscriber;

		event EventHandler<OnSendReceiveDataArgs> OnSendReceiveData;

		event EventHandler<OnUserBannedArgs> OnUserBanned;

		event EventHandler<OnUserJoinedArgs> OnUserJoined;

		event EventHandler<OnUserLeftArgs> OnUserLeft;

		event EventHandler<OnUserStateChangedArgs> OnUserStateChanged;

		event EventHandler<OnUserTimedoutArgs> OnUserTimedout;

		event EventHandler<OnWhisperCommandReceivedArgs> OnWhisperCommandReceived;

		event EventHandler<OnWhisperReceivedArgs> OnWhisperReceived;

		event EventHandler<OnWhisperSentArgs> OnWhisperSent;

		event EventHandler<OnMessageThrottledEventArgs> OnMessageThrottled;

		event EventHandler<OnWhisperThrottledEventArgs> OnWhisperThrottled;

		event EventHandler<OnErrorEventArgs> OnError;

		event EventHandler<OnReconnectedEventArgs> OnReconnected;

		event EventHandler<OnVIPsReceivedArgs> OnVIPsReceived;

		event EventHandler<OnCommunitySubscriptionArgs> OnCommunitySubscription;

		event EventHandler<OnMessageClearedArgs> OnMessageCleared;

		event EventHandler<OnRitualNewChatterArgs> OnRitualNewChatter;

		void Initialize(ConnectionCredentials credentials, string channel = null, char chatCommandIdentifier = '!', char whisperCommandIdentifier = '!', bool autoReListenOnExceptions = true);

		void SetConnectionCredentials(ConnectionCredentials credentials);

		void AddChatCommandIdentifier(char identifier);

		void AddWhisperCommandIdentifier(char identifier);

		void RemoveChatCommandIdentifier(char identifier);

		void RemoveWhisperCommandIdentifier(char identifier);

		void Connect();

		void Disconnect();

		void Reconnect();

		JoinedChannel GetJoinedChannel(string channel);

		void JoinChannel(string channel, bool overrideCheck = false);

		void LeaveChannel(JoinedChannel channel);

		void LeaveChannel(string channel);

		void OnReadLineTest(string rawIrc);

		void SendMessage(JoinedChannel channel, string message, bool dryRun = false);

		void SendMessage(string channel, string message, bool dryRun = false);

		void SendQueuedItem(string message);

		void SendRaw(string message);

		void SendWhisper(string receiver, string message, bool dryRun = false);
	}
}
namespace TwitchLib.Client.Extensions
{
	public static class BanUserExt
	{
		public static void BanUser(this ITwitchClient client, JoinedChannel channel, string viewer, string message = "", bool dryRun = false)
		{
			client.SendMessage(channel, ".ban " + viewer + " " + message);
		}

		public static void BanUser(this ITwitchClient client, string channel, string viewer, string message = "", bool dryRun = false)
		{
			JoinedChannel joinedChannel = client.GetJoinedChannel(channel);
			if (joinedChannel != null)
			{
				client.BanUser(joinedChannel, viewer, message, dryRun);
			}
		}
	}
	public static class ChangeChatColorExt
	{
		public static void ChangeChatColor(this ITwitchClient client, JoinedChannel channel, ChatColorPresets color)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			client.SendMessage(channel, $".color {color}");
		}

		public static void ChangeChatColor(this ITwitchClient client, string channel, ChatColorPresets color)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			client.SendMessage(channel, $".color {color}");
		}
	}
	public static class ClearChatExt
	{
		public static void ClearChat(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".clear");
		}

		public static void ClearChat(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".clear");
		}
	}
	public static class CommercialExt
	{
		public static void StartCommercial(this ITwitchClient client, JoinedChannel channel, CommercialLength length)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)length <= 90)
			{
				if ((int)length == 30)
				{
					client.SendMessage(channel, ".commercial 30");
					return;
				}
				if ((int)length == 60)
				{
					client.SendMessage(channel, ".commercial 60");
					return;
				}
				if ((int)length == 90)
				{
					client.SendMessage(channel, ".commercial 90");
					return;
				}
			}
			else
			{
				if ((int)length == 120)
				{
					client.SendMessage(channel, ".commercial 120");
					return;
				}
				if ((int)length == 150)
				{
					client.SendMessage(channel, ".commercial 150");
					return;
				}
				if ((int)length == 180)
				{
					client.SendMessage(channel, ".commercial 180");
					return;
				}
			}
			throw new ArgumentOutOfRangeException("length", length, null);
		}

		public static void StartCommercial(this ITwitchClient client, string channel, CommercialLength length)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)length <= 90)
			{
				if ((int)length == 30)
				{
					client.SendMessage(channel, ".commercial 30");
					return;
				}
				if ((int)length == 60)
				{
					client.SendMessage(channel, ".commercial 60");
					return;
				}
				if ((int)length == 90)
				{
					client.SendMessage(channel, ".commercial 90");
					return;
				}
			}
			else
			{
				if ((int)length == 120)
				{
					client.SendMessage(channel, ".commercial 120");
					return;
				}
				if ((int)length == 150)
				{
					client.SendMessage(channel, ".commercial 150");
					return;
				}
				if ((int)length == 180)
				{
					client.SendMessage(channel, ".commercial 180");
					return;
				}
			}
			throw new ArgumentOutOfRangeException("length", length, null);
		}
	}
	public static class EmoteOnlyExt
	{
		public static void EmoteOnlyOn(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".emoteonly");
		}

		public static void EmoteOnlyOn(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".emoteonly");
		}

		public static void EmoteOnlyOff(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".emoteonlyoff");
		}

		public static void EmoteOnlyOff(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".emoteonlyoff");
		}
	}
	public static class EventInvocationExt
	{
		public static void InvokeOnBeingHosted(this TwitchClient client, string channel, string botUsername, string hostedByChannel, int viewers, bool isAutoHosted)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			OnBeingHostedArgs args = new OnBeingHostedArgs
			{
				BeingHostedNotification = new BeingHostedNotification(channel, botUsername, hostedByChannel, viewers, isAutoHosted)
			};
			client.RaiseEvent("OnBeingHosted", args);
		}

		public static void InvokeChannelStateChanged(this TwitchClient client, string channel, bool r9k, bool rituals, bool subOnly, int slowMode, bool emoteOnly, string broadcasterLanguage, TimeSpan followersOnly, bool mercury, string roomId)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			ChannelState channelState = new ChannelState(r9k, rituals, subOnly, slowMode, emoteOnly, broadcasterLanguage, channel, followersOnly, mercury, roomId);
			OnChannelStateChangedArgs args = new OnChannelStateChangedArgs
			{
				Channel = channel,
				ChannelState = channelState
			};
			client.RaiseEvent("OnChannelStateChanged", args);
		}

		public static void InvokeChatCleared(this TwitchClient client, string channel)
		{
			OnChatClearedArgs args = new OnChatClearedArgs
			{
				Channel = channel
			};
			client.RaiseEvent("OnChatCleared", args);
		}

		public static void InvokeChatCommandsReceived(this TwitchClient client, string botUsername, string userId, string userName, string displayName, string colorHex, Color color, EmoteSet emoteSet, string message, UserType userType, string channel, string id, bool isSubscriber, int subscribedMonthCount, string roomId, bool isTurbo, bool isModerator, bool isMe, bool isBroadcaster, Noisy noisy, string rawIrcMessage, string emoteReplacedMessage, List<KeyValuePair<string, string>> badges, CheerBadge cheerBadge, int bits, double bitsInDollars, string commandText, string argumentsAsString, List<string> argumentsAsList, char commandIdentifier)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			ChatMessage val = new ChatMessage(botUsername, userId, userName, displayName, colorHex, color, emoteSet, message, userType, channel, id, isSubscriber, subscribedMonthCount, roomId, isTurbo, isModerator, isMe, isBroadcaster, noisy, rawIrcMessage, emoteReplacedMessage, badges, cheerBadge, bits, bitsInDollars);
			OnChatCommandReceivedArgs args = new OnChatCommandReceivedArgs
			{
				Command = new ChatCommand(val, commandText, argumentsAsString, argumentsAsList, commandIdentifier)
			};
			client.RaiseEvent("OnChatCommandReceived", args);
		}

		public static void InvokeConnected(this TwitchClient client, string autoJoinChannel, string botUsername)
		{
			OnConnectedArgs args = new OnConnectedArgs
			{
				AutoJoinChannel = autoJoinChannel,
				BotUsername = botUsername
			};
			client.RaiseEvent("OnConnected", args);
		}

		public static void InvokeConnectionError(this TwitchClient client, string botUsername, ErrorEvent errorEvent)
		{
			OnConnectionErrorArgs args = new OnConnectionErrorArgs
			{
				BotUsername = botUsername,
				Error = errorEvent
			};
			client.RaiseEvent("OnConnectionError", args);
		}

		public static void InvokeDisconnected(this TwitchClient client, string botUsername)
		{
			OnDisconnectedArgs args = new OnDisconnectedArgs
			{
				BotUsername = botUsername
			};
			client.RaiseEvent("OnDisconnected", args);
		}

		public static void InvokeExistingUsersDetected(this TwitchClient client, string channel, List<string> users)
		{
			OnExistingUsersDetectedArgs args = new OnExistingUsersDetectedArgs
			{
				Channel = channel,
				Users = users
			};
			client.RaiseEvent("OnExistingUsersDetected", args);
		}

		public static void InvokeGiftedSubscription(this TwitchClient client, List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string color, string displayName, string emotes, string id, string login, bool isModerator, string msgId, string msgParamMonths, string msgParamRecipientDisplayName, string msgParamRecipientId, string msgParamRecipientUserName, string msgParamSubPlanName, SubscriptionPlan msgParamSubPlan, string roomId, bool isSubscriber, string systemMsg, string systemMsgParsed, string tmiSentTs, bool isTurbo, UserType userType, string userId)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			OnGiftedSubscriptionArgs args = new OnGiftedSubscriptionArgs
			{
				GiftedSubscription = new GiftedSubscription(badges, badgeInfo, color, displayName, emotes, id, login, isModerator, msgId, msgParamMonths, msgParamRecipientDisplayName, msgParamRecipientId, msgParamRecipientUserName, msgParamSubPlanName, msgParamSubPlan, roomId, isSubscriber, systemMsg, systemMsgParsed, tmiSentTs, isTurbo, userType, userId)
			};
			client.RaiseEvent("OnGiftedSubscription", args);
		}

		public static void InvokeOnHostingStarted(this TwitchClient client, string hostingChannel, string targetChannel, int viewers)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			OnHostingStartedArgs args = new OnHostingStartedArgs
			{
				HostingStarted = new HostingStarted(hostingChannel, targetChannel, viewers)
			};
			client.RaiseEvent("OnHostingStarted", args);
		}

		public static void InvokeOnHostingStopped(this TwitchClient client, string hostingChannel, int viewers)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			OnHostingStoppedArgs args = new OnHostingStoppedArgs
			{
				HostingStopped = new HostingStopped(hostingChannel, viewers)
			};
			client.RaiseEvent("OnHostingStopped", args);
		}

		public static void InvokeHostLeft(this TwitchClient client)
		{
			client.RaiseEvent("OnHostLeft");
		}

		public static void InvokeIncorrectLogin(this TwitchClient client, ErrorLoggingInException ex)
		{
			OnIncorrectLoginArgs args = new OnIncorrectLoginArgs
			{
				Exception = ex
			};
			client.RaiseEvent("OnIncorrectLogin", args);
		}

		public static void InvokeJoinedChannel(this TwitchClient client, string botUsername, string channel)
		{
			OnJoinedChannelArgs args = new OnJoinedChannelArgs
			{
				BotUsername = botUsername,
				Channel = channel
			};
			client.RaiseEvent("OnJoinedChannel", args);
		}

		public static void InvokeLeftChannel(this TwitchClient client, string botUsername, string channel)
		{
			OnLeftChannelArgs args = new OnLeftChannelArgs
			{
				BotUsername = botUsername,
				Channel = channel
			};
			client.RaiseEvent("OnLeftChannel", args);
		}

		public static void InvokeLog(this TwitchClient client, string botUsername, string data, DateTime dateTime)
		{
			OnLogArgs args = new OnLogArgs
			{
				BotUsername = botUsername,
				Data = data,
				DateTime = dateTime
			};
			client.RaiseEvent("OnLog", args);
		}

		public static void InvokeMessageReceived(this TwitchClient client, string botUsername, string userId, string userName, string displayName, string colorHex, Color color, EmoteSet emoteSet, string message, UserType userType, string channel, string id, bool isSubscriber, int subscribedMonthCount, string roomId, bool isTurbo, bool isModerator, bool isMe, bool isBroadcaster, Noisy noisy, string rawIrcMessage, string emoteReplacedMessage, List<KeyValuePair<string, string>> badges, CheerBadge cheerBadge, int bits, double bitsInDollars)
		{
			//IL_0014: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			OnMessageReceivedArgs args = new OnMessageReceivedArgs
			{
				ChatMessage = new ChatMessage(botUsername, userId, userName, displayName, colorHex, color, emoteSet, message, userType, channel, id, isSubscriber, subscribedMonthCount, roomId, isTurbo, isModerator, isMe, isBroadcaster, noisy, rawIrcMessage, emoteReplacedMessage, badges, cheerBadge, bits, bitsInDollars)
			};
			client.RaiseEvent("OnMessageReceived", args);
		}

		public static void InvokeMessageSent(this TwitchClient client, List<KeyValuePair<string, string>> badges, string channel, string colorHex, string displayName, string emoteSet, bool isModerator, bool isSubscriber, UserType userType, string message)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			OnMessageSentArgs args = new OnMessageSentArgs
			{
				SentMessage = new SentMessage(badges, channel, colorHex, displayName, emoteSet, isModerator, isSubscriber, userType, message)
			};
			client.RaiseEvent("OnMessageSent", args);
		}

		public static void InvokeModeratorJoined(this TwitchClient client, string channel, string username)
		{
			OnModeratorJoinedArgs args = new OnModeratorJoinedArgs
			{
				Channel = channel,
				Username = username
			};
			client.RaiseEvent("OnModeratorJoined", args);
		}

		public static void InvokeModeratorLeft(this TwitchClient client, string channel, string username)
		{
			OnModeratorLeftArgs args = new OnModeratorLeftArgs
			{
				Channel = channel,
				Username = username
			};
			client.RaiseEvent("OnModeratorLeft", args);
		}

		public static void InvokeModeratorsReceived(this TwitchClient client, string channel, List<string> moderators)
		{
			OnModeratorsReceivedArgs args = new OnModeratorsReceivedArgs
			{
				Channel = channel,
				Moderators = moderators
			};
			client.RaiseEvent("OnModeratorsReceived", args);
		}

		public static void InvokeNewSubscriber(this TwitchClient client, List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string colorHex, Color color, string displayName, string emoteSet, string id, string login, string systemMessage, string msgId, string msgParamCumulativeMonths, string msgParamStreakMonths, bool msgParamShouldShareStreak, string systemMessageParsed, string resubMessage, SubscriptionPlan subscriptionPlan, string subscriptionPlanName, string roomId, string userId, bool isModerator, bool isTurbo, bool isSubscriber, bool isPartner, string tmiSentTs, UserType userType, string rawIrc, string channel)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			OnNewSubscriberArgs args = new OnNewSubscriberArgs
			{
				Subscriber = new Subscriber(badges, badgeInfo, colorHex, color, displayName, emoteSet, id, login, systemMessage, msgId, msgParamCumulativeMonths, msgParamStreakMonths, msgParamShouldShareStreak, systemMessageParsed, resubMessage, subscriptionPlan, subscriptionPlanName, roomId, userId, isModerator, isTurbo, isSubscriber, isPartner, tmiSentTs, userType, rawIrc, channel)
			};
			client.RaiseEvent("OnNewSubscriber", args);
		}

		public static void InvokeNowHosting(this TwitchClient client, string channel, string hostedChannel)
		{
			OnNowHostingArgs args = new OnNowHostingArgs
			{
				Channel = channel,
				HostedChannel = hostedChannel
			};
			client.RaiseEvent("OnNowHosting", args);
		}

		public static void InvokeRaidNotification(this TwitchClient client, string channel, List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string color, string displayName, string emotes, string id, string login, bool moderator, string msgId, string msgParamDisplayName, string msgParamLogin, string msgParamViewerCount, string roomId, bool subscriber, string systemMsg, string systemMsgParsed, string tmiSentTs, bool turbo, UserType userType, string userId)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			OnRaidNotificationArgs args = new OnRaidNotificationArgs
			{
				Channel = channel,
				RaidNotification = new RaidNotification(badges, badgeInfo, color, displayName, emotes, id, login, moderator, msgId, msgParamDisplayName, msgParamLogin, msgParamViewerCount, roomId, subscriber, systemMsg, systemMsgParsed, tmiSentTs, turbo, userType, userId)
			};
			client.RaiseEvent("OnRaidNotification", args);
		}

		public static void InvokeReSubscriber(this TwitchClient client, List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string colorHex, Color color, string displayName, string emoteSet, string id, string login, string systemMessage, string msgId, string msgParamCumulativeMonths, string msgParamStreakMonths, bool msgParamShouldShareStreak, string systemMessageParsed, string resubMessage, SubscriptionPlan subscriptionPlan, string subscriptionPlanName, string roomId, string userId, bool isModerator, bool isTurbo, bool isSubscriber, bool isPartner, string tmiSentTs, UserType userType, string rawIrc, string channel)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			OnReSubscriberArgs args = new OnReSubscriberArgs
			{
				ReSubscriber = new ReSubscriber(badges, badgeInfo, colorHex, color, displayName, emoteSet, id, login, systemMessage, msgId, msgParamCumulativeMonths, msgParamStreakMonths, msgParamShouldShareStreak, systemMessageParsed, resubMessage, subscriptionPlan, subscriptionPlanName, roomId, userId, isModerator, isTurbo, isSubscriber, isPartner, tmiSentTs, userType, rawIrc, channel, 0)
			};
			client.RaiseEvent("OnReSubscriber", args);
		}

		public static void InvokeSendReceiveData(this TwitchClient client, string data, SendReceiveDirection direction)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			OnSendReceiveDataArgs args = new OnSendReceiveDataArgs
			{
				Data = data,
				Direction = direction
			};
			client.RaiseEvent("OnSendReceiveData", args);
		}

		public static void InvokeUserBanned(this TwitchClient client, string channel, string username, string banReason)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			OnUserBannedArgs args = new OnUserBannedArgs
			{
				UserBan = new UserBan(channel, username, banReason)
			};
			client.RaiseEvent("OnUserBanned", args);
		}

		public static void InvokeUserJoined(this TwitchClient client, string channel, string username)
		{
			OnUserJoinedArgs args = new OnUserJoinedArgs
			{
				Channel = channel,
				Username = username
			};
			client.RaiseEvent("OnUserJoined", args);
		}

		public static void InvokeUserLeft(this TwitchClient client, string channel, string username)
		{
			OnUserLeftArgs args = new OnUserLeftArgs
			{
				Channel = channel,
				Username = username
			};
			client.RaiseEvent("OnUserLeft", args);
		}

		public static void InvokeUserStateChanged(this TwitchClient client, List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string colorHex, string displayName, string emoteSet, string channel, bool isSubscriber, bool isModerator, UserType userType)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			OnUserStateChangedArgs args = new OnUserStateChangedArgs
			{
				UserState = new UserState(badges, badgeInfo, colorHex, displayName, emoteSet, channel, isSubscriber, isModerator, userType)
			};
			client.RaiseEvent("OnUserStateChanged", args);
		}

		public static void InvokeUserTimedout(this TwitchClient client, string channel, string username, int timeoutDuration, string timeoutReason)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			OnUserTimedoutArgs args = new OnUserTimedoutArgs
			{
				UserTimeout = new UserTimeout(channel, username, timeoutDuration, timeoutReason)
			};
			client.RaiseEvent("OnUserTimedout", args);
		}

		public static void InvokeWhisperCommandReceived(this TwitchClient client, List<KeyValuePair<string, string>> badges, string colorHex, Color color, string username, string displayName, EmoteSet emoteSet, string threadId, string messageId, string userId, bool isTurbo, string botUsername, string message, UserType userType, string commandText, string argumentsAsString, List<string> argumentsAsList, char commandIdentifier)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			WhisperMessage val = new WhisperMessage(badges, colorHex, color, username, displayName, emoteSet, threadId, messageId, userId, isTurbo, botUsername, message, userType);
			OnWhisperCommandReceivedArgs args = new OnWhisperCommandReceivedArgs
			{
				Command = new WhisperCommand(val, commandText, argumentsAsString, argumentsAsList, commandIdentifier)
			};
			client.RaiseEvent("OnWhisperCommandReceived", args);
		}

		public static void InvokeWhisperReceived(this TwitchClient client, List<KeyValuePair<string, string>> badges, string colorHex, Color color, string username, string displayName, EmoteSet emoteSet, string threadId, string messageId, string userId, bool isTurbo, string botUsername, string message, UserType userType)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			OnWhisperReceivedArgs args = new OnWhisperReceivedArgs
			{
				WhisperMessage = new WhisperMessage(badges, colorHex, color, username, displayName, emoteSet, threadId, messageId, userId, isTurbo, botUsername, message, userType)
			};
			client.RaiseEvent("OnWhisperReceived", args);
		}

		public static void InvokeWhisperSent(this TwitchClient client, string username, string receiver, string message)
		{
			OnWhisperSentArgs args = new OnWhisperSentArgs
			{
				Message = message,
				Receiver = receiver,
				Username = username
			};
			client.RaiseEvent("OnWhisperSent", args);
		}
	}
	public static class FollowersOnlyExt
	{
		private const int MaximumDurationAllowedDays = 90;

		public static void FollowersOnlyOn(this ITwitchClient client, JoinedChannel channel, TimeSpan requiredFollowTime)
		{
			if (requiredFollowTime > TimeSpan.FromDays(90.0))
			{
				throw new InvalidParameterException("The amount of time required to chat exceeded the maximum allowed by Twitch, which is 3 months.", client.TwitchUsername);
			}
			string text = $"{requiredFollowTime.Days}d {requiredFollowTime.Hours}h {requiredFollowTime.Minutes}m";
			client.SendMessage(channel, ".followers " + text);
		}

		public static void FollowersOnlyOn(this ITwitchClient client, string channel, TimeSpan requiredFollowTime)
		{
			if (requiredFollowTime > TimeSpan.FromDays(90.0))
			{
				throw new InvalidParameterException("The amount of time required to chat exceeded the maximum allowed by Twitch, which is 3 months.", client.TwitchUsername);
			}
			string text = $"{requiredFollowTime.Days}d {requiredFollowTime.Hours}h {requiredFollowTime.Minutes}m";
			client.SendMessage(channel, ".followers " + text);
		}

		public static void FollowersOnlyOff(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".followersoff");
		}

		public static void FollowersOnlyOff(this TwitchClient client, string channel)
		{
			client.SendMessage(channel, ".followersoff");
		}
	}
	public static class GetChannelModeratorsExt
	{
		public static void GetChannelModerators(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".mods");
		}

		public static void GetChannelModerators(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".mods");
		}
	}
	public static class HostExt
	{
		public static void Host(this ITwitchClient client, JoinedChannel channel, string userToHost)
		{
			client.SendMessage(channel, ".host " + userToHost);
		}

		public static void Host(this ITwitchClient client, string channel, string userToHost)
		{
			client.SendMessage(channel, ".host " + userToHost);
		}

		public static void Unhost(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".unhost");
		}

		public static void Unhost(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".unhost");
		}
	}
	public static class MarkerExt
	{
		public static void Marker(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".marker");
		}

		public static void Marker(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".marker");
		}
	}
	public static class ModExt
	{
		public static void Mod(this ITwitchClient client, JoinedChannel channel, string viewerToMod)
		{
			client.SendMessage(channel, ".mod " + viewerToMod);
		}

		public static void Mod(this ITwitchClient client, string channel, string viewerToMod)
		{
			client.SendMessage(channel, ".mod " + viewerToMod);
		}

		public static void Unmod(this ITwitchClient client, JoinedChannel channel, string viewerToUnmod)
		{
			client.SendMessage(channel, ".unmod " + viewerToUnmod);
		}

		public static void Unmod(this ITwitchClient client, string channel, string viewerToUnmod)
		{
			client.SendMessage(channel, ".unmod " + viewerToUnmod);
		}
	}
	public static class RaidExt
	{
		public static void Raid(this ITwitchClient client, JoinedChannel channel, string channelToRaid)
		{
			client.SendMessage(channel, ".raid " + channelToRaid);
		}

		public static void Raid(this ITwitchClient client, string channel, string channelToRaid)
		{
			client.SendMessage(channel, ".raid " + channelToRaid);
		}
	}
	public static class ReplyWhisperExt
	{
		public static void ReplyToLastWhisper(this ITwitchClient client, string message = "", bool dryRun = false)
		{
			if (client.PreviousWhisper != null)
			{
				client.SendWhisper(((TwitchLibMessage)client.PreviousWhisper).Username, message, dryRun);
			}
		}
	}
	public static class SlowModeExt
	{
		public static void SlowModeOn(this ITwitchClient client, JoinedChannel channel, TimeSpan messageCooldown)
		{
			if (messageCooldown > TimeSpan.FromDays(1.0))
			{
				throw new InvalidParameterException("The message cooldown time supplied exceeded the maximum allowed by Twitch, which is 1 day.", client.TwitchUsername);
			}
			client.SendMessage(channel, $".slow {messageCooldown.TotalSeconds}");
		}

		public static void SlowModeOn(this ITwitchClient client, string channel, TimeSpan messageCooldown)
		{
			if (messageCooldown > TimeSpan.FromDays(1.0))
			{
				throw new InvalidParameterException("The message cooldown time supplied exceeded the maximum allowed by Twitch, which is 1 day.", client.TwitchUsername);
			}
			client.SendMessage(channel, $".slow {messageCooldown.TotalSeconds}");
		}

		public static void SlowModeOff(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".slowoff");
		}

		public static void SlowModeOff(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".slowoff");
		}
	}
	public static class SubscribersOnly
	{
		public static void SubscribersOnlyOn(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".subscribers");
		}

		public static void SubscribersOnlyOn(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".subscribers");
		}

		public static void SubscribersOnlyOff(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".subscribersoff");
		}

		public static void SubscribersOnlyOff(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".subscribersoff");
		}
	}
	public static class TimeoutUserExt
	{
		public static void TimeoutUser(this ITwitchClient client, JoinedChannel channel, string viewer, TimeSpan duration, string message = "", bool dryRun = false)
		{
			client.SendMessage(channel, $".timeout {viewer} {duration.TotalSeconds} {message}", dryRun);
		}

		public static void TimeoutUser(this ITwitchClient client, string channel, string viewer, TimeSpan duration, string message = "", bool dryRun = false)
		{
			JoinedChannel joinedChannel = client.GetJoinedChannel(channel);
			if (joinedChannel != null)
			{
				client.TimeoutUser(joinedChannel, viewer, duration, message, dryRun);
			}
		}
	}
	public static class UnbanUserExt
	{
		public static void UnbanUser(this ITwitchClient client, JoinedChannel channel, string viewer, bool dryRun = false)
		{
			client.SendMessage(channel, ".unban " + viewer, dryRun);
		}

		public static void UnbanUser(this ITwitchClient client, string channel, string viewer, bool dryRun = false)
		{
			JoinedChannel joinedChannel = client.GetJoinedChannel(channel);
			if (joinedChannel != null)
			{
				client.UnbanUser(joinedChannel, viewer, dryRun);
			}
		}
	}
	public static class VIPExt
	{
		public static void VIP(this ITwitchClient client, JoinedChannel channel, string viewerToVIP)
		{
			client.SendMessage(channel, ".vip " + viewerToVIP);
		}

		public static void VIP(this ITwitchClient client, string channel, string viewerToVIP)
		{
			client.SendMessage(channel, ".vip " + viewerToVIP);
		}

		public static void UnVIP(this ITwitchClient client, JoinedChannel channel, string viewerToUnVIP)
		{
			client.SendMessage(channel, ".unvip " + viewerToUnVIP);
		}

		public static void UnVIP(this ITwitchClient client, string channel, string viewerToUnVIP)
		{
			client.SendMessage(channel, ".unvip " + viewerToUnVIP);
		}

		public static void GetVIPs(this ITwitchClient client, JoinedChannel channel)
		{
			client.SendMessage(channel, ".vips");
		}

		public static void GetVIPs(this ITwitchClient client, string channel)
		{
			client.SendMessage(channel, ".vips");
		}
	}
}
namespace TwitchLib.Client.Exceptions
{
	public class BadListenException : Exception
	{
		public BadListenException(string eventName, string additionalDetails = "")
			: base(string.IsNullOrEmpty(additionalDetails) ? ("You are listening to event '" + eventName + "', which is not currently allowed. See details: " + additionalDetails) : ("You are listening to event '" + eventName + "', which is not currently allowed."))
		{
		}
	}
	public class BadStateException : Exception
	{
		public BadStateException(string details)
			: base(details)
		{
		}
	}
	public class ClientNotConnectedException : Exception
	{
		public ClientNotConnectedException(string description)
			: base(description)
		{
		}
	}
	public class ClientNotInitializedException : Exception
	{
		public ClientNotInitializedException(string description)
			: base(description)
		{
		}
	}
	public class ErrorLoggingInException : Exception
	{
		public string Username { get; protected set; }

		public ErrorLoggingInException(string ircData, string twitchUsername)
			: base(ircData)
		{
			Username = twitchUsername;
		}
	}
	public class EventNotHandled : Exception
	{
		public EventNotHandled(string eventName, string additionalDetails = "")
			: base(string.IsNullOrEmpty(additionalDetails) ? ("To use this call, you must handle/subscribe to event: " + eventName) : ("To use this call, you must handle/subscribe to event: " + eventName + ", additional details: " + additionalDetails))
		{
		}
	}
	public class FailureToReceiveJoinConfirmationException
	{
		public string Channel { get; protected set; }

		public string Details { get; protected set; }

		public FailureToReceiveJoinConfirmationException(string channel, string details = null)
		{
			Channel = channel;
			Details = details;
		}
	}
	public class IllegalAssignmentException : Exception
	{
		public IllegalAssignmentException(string description)
			: base(description)
		{
		}
	}
	public class InvalidParameterException : Exception
	{
		public string Username { get; protected set; }

		public InvalidParameterException(string reasoning, string twitchUsername)
			: base(reasoning)
		{
			Username = twitchUsername;
		}
	}
}
namespace TwitchLib.Client.Events
{
	public class OnBeingHostedArgs : EventArgs
	{
		public BeingHostedNotification BeingHostedNotification;
	}
	public class OnChannelStateChangedArgs : EventArgs
	{
		public ChannelState ChannelState;

		public string Channel;
	}
	public class OnChatClearedArgs : EventArgs
	{
		public string Channel;
	}
	public class OnChatColorChangedArgs : EventArgs
	{
		public string Channel;
	}
	public class OnChatCommandReceivedArgs : EventArgs
	{
		public ChatCommand Command;
	}
	public class OnCommunitySubscriptionArgs : EventArgs
	{
		public CommunitySubscription GiftedSubscription;

		public string Channel;
	}
	public class OnConnectedArgs : EventArgs
	{
		public string BotUsername;

		public string AutoJoinChannel;
	}
	public class OnConnectionErrorArgs : EventArgs
	{
		pu

lib/TwitchLib.Client.Enums.dll

Decompiled 5 months ago
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project containing all of the enums used in TwitchLib.Client.")]
[assembly: AssemblyFileVersion("3.1.4")]
[assembly: AssemblyInformationalVersion("3.1.4")]
[assembly: AssemblyProduct("TwitchLib.Client.Enums")]
[assembly: AssemblyTitle("TwitchLib.Client.Enums")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/TwitchLib/TwitchLib.Client")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.4.0")]
namespace TwitchLib.Client.Enums
{
	public enum BadgeColor
	{
		Red = 10000,
		Blue = 5000,
		Green = 1000,
		Purple = 100,
		Gray = 1
	}
	public enum ChatColorPresets
	{
		Blue,
		Coral,
		DodgerBlue,
		SpringGreen,
		YellowGreen,
		Green,
		OrangeRed,
		Red,
		GoldenRod,
		HotPink,
		CadetBlue,
		SeaGreen,
		Chocolate,
		BlueViolet,
		Firebrick
	}
	public enum ClientProtocol
	{
		TCP,
		WebSocket
	}
	public enum CommercialLength
	{
		Seconds30 = 30,
		Seconds60 = 60,
		Seconds90 = 90,
		Seconds120 = 120,
		Seconds150 = 150,
		Seconds180 = 180
	}
	public enum Noisy
	{
		NotSet,
		True,
		False
	}
	public enum SendReceiveDirection
	{
		Sent,
		Received
	}
	public abstract class StringEnum
	{
		public string Value { get; }

		protected StringEnum(string value)
		{
			Value = value;
		}

		public override string ToString()
		{
			return Value;
		}
	}
	public enum SubscriptionPlan
	{
		NotSet,
		Prime,
		Tier1,
		Tier2,
		Tier3
	}
	public enum ThrottleType
	{
		MessageTooShort,
		MessageTooLong
	}
	public enum UserType : byte
	{
		Viewer,
		Moderator,
		GlobalModerator,
		Broadcaster,
		Admin,
		Staff
	}
}
namespace TwitchLib.Client.Enums.Internal
{
	public enum IrcCommand
	{
		Unknown,
		PrivMsg,
		Notice,
		Ping,
		Pong,
		Join,
		Part,
		HostTarget,
		ClearChat,
		ClearMsg,
		UserState,
		GlobalUserState,
		Nick,
		Pass,
		Cap,
		RPL_001,
		RPL_002,
		RPL_003,
		RPL_004,
		RPL_353,
		RPL_366,
		RPL_372,
		RPL_375,
		RPL_376,
		Whisper,
		RoomState,
		Reconnect,
		ServerChange,
		UserNotice,
		Mode
	}
}

lib/TwitchLib.Client.Models.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using TwitchLib.Client.Enums;
using TwitchLib.Client.Enums.Internal;
using TwitchLib.Client.Models.Builders;
using TwitchLib.Client.Models.Common;
using TwitchLib.Client.Models.Extensions.NetCore;
using TwitchLib.Client.Models.Extractors;
using TwitchLib.Client.Models.Internal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Project contains all of the models used in TwitchLib.Client.")]
[assembly: AssemblyFileVersion("3.1.5")]
[assembly: AssemblyInformationalVersion("3.1.5")]
[assembly: AssemblyProduct("TwitchLib.Client.Models")]
[assembly: AssemblyTitle("TwitchLib.Client.Models")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/TwitchLib/TwitchLib.Client")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.5.0")]
namespace TwitchLib.Client.Models
{
	public class BeingHostedNotification
	{
		public string BotUsername { get; }

		public string Channel { get; }

		public string HostedByChannel { get; }

		public bool IsAutoHosted { get; }

		public int Viewers { get; }

		public BeingHostedNotification(string botUsername, IrcMessage ircMessage)
		{
			Channel = ircMessage.Channel;
			BotUsername = botUsername;
			HostedByChannel = ircMessage.Message.Split(new char[1] { ' ' }).First();
			if (ircMessage.Message.Contains("up to "))
			{
				string[] array = ircMessage.Message.Split(new string[1] { "up to " }, StringSplitOptions.None);
				if (array[1].Contains(" ") && int.TryParse(array[1].Split(new char[1] { ' ' })[0], out var result))
				{
					Viewers = result;
				}
			}
			if (ircMessage.Message.Contains("auto hosting"))
			{
				IsAutoHosted = true;
			}
		}

		public BeingHostedNotification(string channel, string botUsername, string hostedByChannel, int viewers, bool isAutoHosted)
		{
			Channel = channel;
			BotUsername = botUsername;
			HostedByChannel = hostedByChannel;
			Viewers = viewers;
			IsAutoHosted = isAutoHosted;
		}
	}
	public class ChannelState
	{
		public string BroadcasterLanguage { get; }

		public string Channel { get; }

		public bool? EmoteOnly { get; }

		public TimeSpan? FollowersOnly { get; } = null;


		public bool Mercury { get; }

		public bool? R9K { get; }

		public bool? Rituals { get; }

		public string RoomId { get; }

		public int? SlowMode { get; }

		public bool? SubOnly { get; }

		public ChannelState(IrcMessage ircMessage)
		{
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "broadcaster-lang":
					BroadcasterLanguage = text;
					break;
				case "emote-only":
					EmoteOnly = Helpers.ConvertToBool(text);
					break;
				case "r9k":
					R9K = Helpers.ConvertToBool(text);
					break;
				case "rituals":
					Rituals = Helpers.ConvertToBool(text);
					break;
				case "slow":
				{
					int result2;
					bool flag = int.TryParse(text, out result2);
					SlowMode = (flag ? new int?(result2) : null);
					break;
				}
				case "subs-only":
					SubOnly = Helpers.ConvertToBool(text);
					break;
				case "followers-only":
				{
					if (int.TryParse(text, out var result) && result > -1)
					{
						FollowersOnly = TimeSpan.FromMinutes(result);
					}
					break;
				}
				case "room-id":
					RoomId = text;
					break;
				case "mercury":
					Mercury = Helpers.ConvertToBool(text);
					break;
				default:
					Console.WriteLine("[TwitchLib][ChannelState] Unaccounted for: " + key);
					break;
				}
			}
			Channel = ircMessage.Channel;
		}

		public ChannelState(bool r9k, bool rituals, bool subonly, int slowMode, bool emoteOnly, string broadcasterLanguage, string channel, TimeSpan followersOnly, bool mercury, string roomId)
		{
			R9K = r9k;
			Rituals = rituals;
			SubOnly = subonly;
			SlowMode = slowMode;
			EmoteOnly = emoteOnly;
			BroadcasterLanguage = broadcasterLanguage;
			Channel = channel;
			FollowersOnly = followersOnly;
			Mercury = mercury;
			RoomId = roomId;
		}
	}
	public class ChatCommand
	{
		public List<string> ArgumentsAsList { get; }

		public string ArgumentsAsString { get; }

		public ChatMessage ChatMessage { get; }

		public char CommandIdentifier { get; }

		public string CommandText { get; }

		public ChatCommand(ChatMessage chatMessage)
		{
			ChatCommand chatCommand = this;
			ChatMessage = chatMessage;
			string[] array = chatMessage.Message.Split(new char[1] { ' ' });
			CommandText = ((array != null) ? array[0].Substring(1, chatMessage.Message.Split(new char[1] { ' ' })[0].Length - 1) : null) ?? chatMessage.Message.Substring(1, chatMessage.Message.Length - 1);
			object obj;
			if (!chatMessage.Message.Contains(" "))
			{
				obj = "";
			}
			else
			{
				string message = chatMessage.Message;
				string[] array2 = chatMessage.Message.Split(new char[1] { ' ' });
				obj = message.Replace(((array2 != null) ? array2[0] : null) + " ", "");
			}
			ArgumentsAsString = (string)obj;
			if (!chatMessage.Message.Contains("\"") || chatMessage.Message.Count((char x) => x == '"') % 2 == 1)
			{
				ArgumentsAsList = chatMessage.Message.Split(new char[1] { ' ' })?.Where((string arg) => arg != chatMessage.Message[0] + chatCommand.CommandText).ToList() ?? new List<string>();
			}
			else
			{
				ArgumentsAsList = Helpers.ParseQuotesAndNonQuotes(ArgumentsAsString);
			}
			CommandIdentifier = chatMessage.Message[0];
		}

		public ChatCommand(ChatMessage chatMessage, string commandText, string argumentsAsString, List<string> argumentsAsList, char commandIdentifier)
		{
			ChatMessage = chatMessage;
			CommandText = commandText;
			ArgumentsAsString = argumentsAsString;
			ArgumentsAsList = argumentsAsList;
			CommandIdentifier = commandIdentifier;
		}
	}
	public class ChatMessage : TwitchLibMessage
	{
		protected readonly MessageEmoteCollection _emoteCollection;

		public List<KeyValuePair<string, string>> BadgeInfo { get; }

		public int Bits { get; }

		public double BitsInDollars { get; }

		public string Channel { get; }

		public CheerBadge CheerBadge { get; }

		public string CustomRewardId { get; }

		public string EmoteReplacedMessage { get; }

		public string Id { get; }

		public bool IsBroadcaster { get; }

		public bool IsHighlighted { get; internal set; }

		public bool IsMe { get; }

		public bool IsModerator { get; }

		public bool IsSkippingSubMode { get; internal set; }

		public bool IsSubscriber { get; }

		public bool IsVip { get; }

		public string Message { get; }

		public Noisy Noisy { get; }

		public string RawIrcMessage { get; }

		public string RoomId { get; }

		public int SubscribedMonthCount { get; }

		public string TmiSentTs { get; }

		public ChatMessage(string botUsername, IrcMessage ircMessage, ref MessageEmoteCollection emoteCollection, bool replaceEmotes = false)
		{
			//IL_05b0: Unknown result type (might be due to invalid IL or missing references)
			base.BotUsername = botUsername;
			RawIrcMessage = ircMessage.ToString();
			Message = ircMessage.Message;
			_emoteCollection = emoteCollection;
			base.Username = ircMessage.User;
			Channel = ircMessage.Channel;
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
					base.Badges = Helpers.ParseBadges(text);
					foreach (KeyValuePair<string, string> badge in base.Badges)
					{
						switch (badge.Key)
						{
						case "bits":
							CheerBadge = new CheerBadge(int.Parse(badge.Value));
							break;
						case "subscriber":
							if (SubscribedMonthCount == 0)
							{
								SubscribedMonthCount = int.Parse(badge.Value);
							}
							break;
						case "vip":
							IsVip = true;
							break;
						}
					}
					break;
				case "badge-info":
				{
					BadgeInfo = Helpers.ParseBadges(text);
					KeyValuePair<string, string> keyValuePair = BadgeInfo.Find((KeyValuePair<string, string> b) => b.Key == "founder");
					if (!keyValuePair.Equals(default(KeyValuePair<string, string>)))
					{
						IsSubscriber = true;
						SubscribedMonthCount = int.Parse(keyValuePair.Value);
						break;
					}
					KeyValuePair<string, string> keyValuePair2 = BadgeInfo.Find((KeyValuePair<string, string> b) => b.Key == "subscriber");
					if (!keyValuePair2.Equals(default(KeyValuePair<string, string>)))
					{
						SubscribedMonthCount = int.Parse(keyValuePair2.Value);
					}
					break;
				}
				case "bits":
					Bits = int.Parse(text);
					BitsInDollars = ConvertBitsToUsd(Bits);
					break;
				case "color":
					base.ColorHex = text;
					if (!string.IsNullOrWhiteSpace(base.ColorHex))
					{
						base.Color = TwitchLib.Client.Models.Extensions.NetCore.ColorTranslator.FromHtml(base.ColorHex);
					}
					break;
				case "custom-reward-id":
					CustomRewardId = text;
					break;
				case "display-name":
					base.DisplayName = text;
					break;
				case "emotes":
					base.EmoteSet = new EmoteSet(text, Message);
					break;
				case "id":
					Id = text;
					break;
				case "msg-id":
					handleMsgId(text);
					break;
				case "mod":
					IsModerator = Helpers.ConvertToBool(text);
					break;
				case "noisy":
					Noisy = (Noisy)(Helpers.ConvertToBool(text) ? 1 : 2);
					break;
				case "room-id":
					RoomId = text;
					break;
				case "subscriber":
					IsSubscriber = IsSubscriber || Helpers.ConvertToBool(text);
					break;
				case "tmi-sent-ts":
					TmiSentTs = text;
					break;
				case "turbo":
					base.IsTurbo = Helpers.ConvertToBool(text);
					break;
				case "user-id":
					base.UserId = text;
					break;
				case "user-type":
					switch (text)
					{
					case "mod":
						base.UserType = (UserType)1;
						break;
					case "global_mod":
						base.UserType = (UserType)2;
						break;
					case "admin":
						base.UserType = (UserType)4;
						break;
					case "staff":
						base.UserType = (UserType)5;
						break;
					default:
						base.UserType = (UserType)0;
						break;
					}
					break;
				}
			}
			if (Message.Length > 0 && (byte)Message[0] == 1 && (byte)Message[Message.Length - 1] == 1 && Message.StartsWith("\u0001ACTION ") && Message.EndsWith("\u0001"))
			{
				Message = Message.Trim(new char[1] { '\u0001' }).Substring(7);
				IsMe = true;
			}
			if (base.EmoteSet != null && Message != null && base.EmoteSet.Emotes.Count > 0)
			{
				string[] array = base.EmoteSet.RawEmoteSetString.Split(new char[1] { '/' });
				string[] array2 = array;
				foreach (string text2 in array2)
				{
					int num = text2.IndexOf(':');
					int num2 = text2.IndexOf(',');
					if (num2 == -1)
					{
						num2 = text2.Length;
					}
					int num3 = text2.IndexOf('-');
					if (num > 0 && num3 > num && num2 > num3 && int.TryParse(text2.Substring(num + 1, num3 - num - 1), out var result) && int.TryParse(text2.Substring(num3 + 1, num2 - num3 - 1), out var result2) && result >= 0 && result < result2 && result2 < Message.Length)
					{
						string id = text2.Substring(0, num);
						string text3 = Message.Substring(result, result2 - result + 1);
						_emoteCollection.Add(new MessageEmote(id, text3));
					}
				}
				if (replaceEmotes)
				{
					EmoteReplacedMessage = _emoteCollection.ReplaceEmotes(Message);
				}
			}
			if (base.EmoteSet == null)
			{
				base.EmoteSet = new EmoteSet((string)null, Message);
			}
			if (string.IsNullOrEmpty(base.DisplayName))
			{
				base.DisplayName = base.Username;
			}
			if (string.Equals(Channel, base.Username, StringComparison.InvariantCultureIgnoreCase))
			{
				base.UserType = (UserType)3;
				IsBroadcaster = true;
			}
			if (Channel.Split(new char[1] { ':' }).Length == 3 && string.Equals(Channel.Split(new char[1] { ':' })[1], base.UserId, StringComparison.InvariantCultureIgnoreCase))
			{
				base.UserType = (UserType)3;
				IsBroadcaster = true;
			}
		}

		public ChatMessage(string botUsername, string userId, string userName, string displayName, string colorHex, Color color, EmoteSet emoteSet, string message, UserType userType, string channel, string id, bool isSubscriber, int subscribedMonthCount, string roomId, bool isTurbo, bool isModerator, bool isMe, bool isBroadcaster, Noisy noisy, string rawIrcMessage, string emoteReplacedMessage, List<KeyValuePair<string, string>> badges, CheerBadge cheerBadge, int bits, double bitsInDollars)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			base.BotUsername = botUsername;
			base.UserId = userId;
			base.DisplayName = displayName;
			base.ColorHex = colorHex;
			base.Color = color;
			base.EmoteSet = emoteSet;
			Message = message;
			base.UserType = userType;
			Channel = channel;
			Id = id;
			IsSubscriber = isSubscriber;
			SubscribedMonthCount = subscribedMonthCount;
			RoomId = roomId;
			base.IsTurbo = isTurbo;
			IsModerator = isModerator;
			IsMe = isMe;
			IsBroadcaster = isBroadcaster;
			Noisy = noisy;
			RawIrcMessage = rawIrcMessage;
			EmoteReplacedMessage = emoteReplacedMessage;
			base.Badges = badges;
			CheerBadge = cheerBadge;
			Bits = bits;
			BitsInDollars = bitsInDollars;
			base.Username = userName;
		}

		private void handleMsgId(string val)
		{
			if (!(val == "highlighted-message"))
			{
				if (val == "skip-subs-mode-message")
				{
					IsSkippingSubMode = true;
				}
			}
			else
			{
				IsHighlighted = true;
			}
		}

		private static double ConvertBitsToUsd(int bits)
		{
			if (bits < 1500)
			{
				return (double)bits / 100.0 * 1.4;
			}
			if (bits < 5000)
			{
				return (double)bits / 1500.0 * 19.95;
			}
			if (bits < 10000)
			{
				return (double)bits / 5000.0 * 64.4;
			}
			if (bits < 25000)
			{
				return (double)bits / 10000.0 * 126.0;
			}
			return (double)bits / 25000.0 * 308.0;
		}
	}
	public class CheerBadge
	{
		public int CheerAmount { get; }

		public BadgeColor Color { get; }

		public CheerBadge(int cheerAmount)
		{
			//IL_0012: 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)
			CheerAmount = cheerAmount;
			Color = GetColor(cheerAmount);
		}

		private BadgeColor GetColor(int cheerAmount)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (cheerAmount >= 10000)
			{
				return (BadgeColor)10000;
			}
			if (cheerAmount >= 5000)
			{
				return (BadgeColor)5000;
			}
			if (cheerAmount >= 1000)
			{
				return (BadgeColor)1000;
			}
			return (BadgeColor)((cheerAmount < 100) ? 1 : 100);
		}
	}
	public class CommunitySubscription
	{
		private const string AnonymousGifterUserId = "274598607";

		public List<KeyValuePair<string, string>> Badges;

		public List<KeyValuePair<string, string>> BadgeInfo;

		public string Color;

		public string DisplayName;

		public string Emotes;

		public string Id;

		public string Login;

		public bool IsModerator;

		public bool IsAnonymous;

		public string MsgId;

		public int MsgParamMassGiftCount;

		public int MsgParamSenderCount;

		public SubscriptionPlan MsgParamSubPlan;

		public string RoomId;

		public bool IsSubscriber;

		public string SystemMsg;

		public string SystemMsgParsed;

		public string TmiSentTs;

		public bool IsTurbo;

		public string UserId;

		public UserType UserType;

		public CommunitySubscription(IrcMessage ircMessage)
		{
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_051b: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0524: Unknown result type (might be due to invalid IL or missing references)
			//IL_052d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
					Badges = Helpers.ParseBadges(text);
					break;
				case "badge-info":
					BadgeInfo = Helpers.ParseBadges(text);
					break;
				case "color":
					Color = text;
					break;
				case "display-name":
					DisplayName = text;
					break;
				case "emotes":
					Emotes = text;
					break;
				case "id":
					Id = text;
					break;
				case "login":
					Login = text;
					break;
				case "mod":
					IsModerator = Helpers.ConvertToBool(text);
					break;
				case "msg-id":
					MsgId = text;
					break;
				case "msg-param-sub-plan":
					switch (text)
					{
					case "prime":
						MsgParamSubPlan = (SubscriptionPlan)1;
						break;
					case "1000":
						MsgParamSubPlan = (SubscriptionPlan)2;
						break;
					case "2000":
						MsgParamSubPlan = (SubscriptionPlan)3;
						break;
					case "3000":
						MsgParamSubPlan = (SubscriptionPlan)4;
						break;
					default:
						throw new ArgumentOutOfRangeException("ToLower");
					}
					break;
				case "msg-param-mass-gift-count":
					MsgParamMassGiftCount = int.Parse(text);
					break;
				case "msg-param-sender-count":
					MsgParamSenderCount = int.Parse(text);
					break;
				case "room-id":
					RoomId = text;
					break;
				case "subscriber":
					IsSubscriber = Helpers.ConvertToBool(text);
					break;
				case "system-msg":
					SystemMsg = text;
					SystemMsgParsed = text.Replace("\\s", " ").Replace("\\n", "");
					break;
				case "tmi-sent-ts":
					TmiSentTs = text;
					break;
				case "turbo":
					IsTurbo = Helpers.ConvertToBool(text);
					break;
				case "user-id":
					UserId = text;
					if (UserId == "274598607")
					{
						IsAnonymous = true;
					}
					break;
				case "user-type":
					switch (text)
					{
					case "mod":
						UserType = (UserType)1;
						break;
					case "global_mod":
						UserType = (UserType)2;
						break;
					case "admin":
						UserType = (UserType)4;
						break;
					case "staff":
						UserType = (UserType)5;
						break;
					default:
						UserType = (UserType)0;
						break;
					}
					break;
				}
			}
		}
	}
	public class ConnectionCredentials
	{
		public const string DefaultWebSocketUri = "wss://irc-ws.chat.twitch.tv:443";

		public string TwitchWebsocketURI { get; }

		public string TwitchOAuth { get; }

		public string TwitchUsername { get; }

		public ConnectionCredentials(string twitchUsername, string twitchOAuth, string twitchWebsocketURI = "wss://irc-ws.chat.twitch.tv:443", bool disableUsernameCheck = false)
		{
			if (!disableUsernameCheck && !new Regex("^([a-zA-Z0-9][a-zA-Z0-9_]{3,25})$").Match(twitchUsername).Success)
			{
				throw new Exception("Twitch username does not appear to be valid. " + twitchUsername);
			}
			TwitchUsername = twitchUsername.ToLower();
			TwitchOAuth = twitchOAuth;
			if (!twitchOAuth.Contains(":"))
			{
				TwitchOAuth = "oauth:" + twitchOAuth.Replace("oauth", "");
			}
			TwitchWebsocketURI = twitchWebsocketURI;
		}
	}
	public class Emote
	{
		public string Id { get; }

		public string Name { get; }

		public int StartIndex { get; }

		public int EndIndex { get; }

		public string ImageUrl { get; }

		public Emote(string emoteId, string name, int emoteStartIndex, int emoteEndIndex)
		{
			Id = emoteId;
			Name = name;
			StartIndex = emoteStartIndex;
			EndIndex = emoteEndIndex;
			ImageUrl = "https://static-cdn.jtvnw.net/emoticons/v1/" + emoteId + "/1.0";
		}
	}
	public class EmoteSet
	{
		public List<Emote> Emotes { get; }

		public string RawEmoteSetString { get; }

		public EmoteSet(string rawEmoteSetString, string message)
		{
			RawEmoteSetString = rawEmoteSetString;
			EmoteExtractor emoteExtractor = new EmoteExtractor();
			Emotes = emoteExtractor.Extract(rawEmoteSetString, message).ToList();
		}

		public EmoteSet(IEnumerable<Emote> emotes, string emoteSetData)
		{
			RawEmoteSetString = emoteSetData;
			Emotes = emotes.ToList();
		}
	}
	public class ErrorEvent
	{
		public string Message { get; set; }
	}
	public class GiftedSubscription
	{
		private const string AnonymousGifterUserId = "274598607";

		public List<KeyValuePair<string, string>> Badges { get; }

		public List<KeyValuePair<string, string>> BadgeInfo { get; }

		public string Color { get; }

		public string DisplayName { get; }

		public string Emotes { get; }

		public string Id { get; }

		public bool IsModerator { get; }

		public bool IsSubscriber { get; }

		public bool IsTurbo { get; }

		public bool IsAnonymous { get; }

		public string Login { get; }

		public string MsgId { get; }

		public string MsgParamMonths { get; }

		public string MsgParamRecipientDisplayName { get; }

		public string MsgParamRecipientId { get; }

		public string MsgParamRecipientUserName { get; }

		public string MsgParamSubPlanName { get; }

		public SubscriptionPlan MsgParamSubPlan { get; }

		public string RoomId { get; }

		public string SystemMsg { get; }

		public string SystemMsgParsed { get; }

		public string TmiSentTs { get; }

		public string UserId { get; }

		public UserType UserType { get; }

		public GiftedSubscription(IrcMessage ircMessage)
		{
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c2: Unknown result type (might be due to invalid IL or missing references)
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
					Badges = Helpers.ParseBadges(text);
					break;
				case "badge-info":
					BadgeInfo = Helpers.ParseBadges(text);
					break;
				case "color":
					Color = text;
					break;
				case "display-name":
					DisplayName = text;
					break;
				case "emotes":
					Emotes = text;
					break;
				case "id":
					Id = text;
					break;
				case "login":
					Login = text;
					break;
				case "mod":
					IsModerator = Helpers.ConvertToBool(text);
					break;
				case "msg-id":
					MsgId = text;
					break;
				case "msg-param-months":
					MsgParamMonths = text;
					break;
				case "msg-param-recipient-display-name":
					MsgParamRecipientDisplayName = text;
					break;
				case "msg-param-recipient-id":
					MsgParamRecipientId = text;
					break;
				case "msg-param-recipient-user-name":
					MsgParamRecipientUserName = text;
					break;
				case "msg-param-sub-plan-name":
					MsgParamSubPlanName = text;
					break;
				case "msg-param-sub-plan":
					switch (text)
					{
					case "prime":
						MsgParamSubPlan = (SubscriptionPlan)1;
						break;
					case "1000":
						MsgParamSubPlan = (SubscriptionPlan)2;
						break;
					case "2000":
						MsgParamSubPlan = (SubscriptionPlan)3;
						break;
					case "3000":
						MsgParamSubPlan = (SubscriptionPlan)4;
						break;
					default:
						throw new ArgumentOutOfRangeException("ToLower");
					}
					break;
				case "room-id":
					RoomId = text;
					break;
				case "subscriber":
					IsSubscriber = Helpers.ConvertToBool(text);
					break;
				case "system-msg":
					SystemMsg = text;
					SystemMsgParsed = text.Replace("\\s", " ").Replace("\\n", "");
					break;
				case "tmi-sent-ts":
					TmiSentTs = text;
					break;
				case "turbo":
					IsTurbo = Helpers.ConvertToBool(text);
					break;
				case "user-id":
					UserId = text;
					if (UserId == "274598607")
					{
						IsAnonymous = true;
					}
					break;
				case "user-type":
					switch (text)
					{
					case "mod":
						UserType = (UserType)1;
						break;
					case "global_mod":
						UserType = (UserType)2;
						break;
					case "admin":
						UserType = (UserType)4;
						break;
					case "staff":
						UserType = (UserType)5;
						break;
					default:
						UserType = (UserType)0;
						break;
					}
					break;
				}
			}
		}

		public GiftedSubscription(List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string color, string displayName, string emotes, string id, string login, bool isModerator, string msgId, string msgParamMonths, string msgParamRecipientDisplayName, string msgParamRecipientId, string msgParamRecipientUserName, string msgParamSubPlanName, SubscriptionPlan msgParamSubPlan, string roomId, bool isSubscriber, string systemMsg, string systemMsgParsed, string tmiSentTs, bool isTurbo, UserType userType, string userId)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Badges = badges;
			BadgeInfo = badgeInfo;
			Color = color;
			DisplayName = displayName;
			Emotes = emotes;
			Id = id;
			Login = login;
			IsModerator = isModerator;
			MsgId = msgId;
			MsgParamMonths = msgParamMonths;
			MsgParamRecipientDisplayName = msgParamRecipientDisplayName;
			MsgParamRecipientId = msgParamRecipientId;
			MsgParamRecipientUserName = msgParamRecipientUserName;
			MsgParamSubPlanName = msgParamSubPlanName;
			MsgParamSubPlan = msgParamSubPlan;
			RoomId = roomId;
			IsSubscriber = isSubscriber;
			SystemMsg = systemMsg;
			SystemMsgParsed = systemMsgParsed;
			TmiSentTs = tmiSentTs;
			IsTurbo = isTurbo;
			UserType = userType;
			UserId = userId;
		}
	}
	public class HostingStarted
	{
		public string HostingChannel;

		public string TargetChannel;

		public int Viewers;

		public HostingStarted(IrcMessage ircMessage)
		{
			string[] array = ircMessage.Message.Split(new char[1] { ' ' });
			HostingChannel = ircMessage.Channel;
			TargetChannel = array[0];
			Viewers = ((!array[1].StartsWith("-")) ? int.Parse(array[1]) : 0);
		}

		public HostingStarted(string hostingChannel, string targetChannel, int viewers)
		{
			HostingChannel = hostingChannel;
			TargetChannel = targetChannel;
			Viewers = viewers;
		}
	}
	public class HostingStopped
	{
		public string HostingChannel;

		public int Viewers;

		public HostingStopped(IrcMessage ircMessage)
		{
			string[] array = ircMessage.Message.Split(new char[1] { ' ' });
			HostingChannel = ircMessage.Channel;
			Viewers = ((!array[1].StartsWith("-")) ? int.Parse(array[1]) : 0);
		}

		public HostingStopped(string hostingChannel, int viewers)
		{
			HostingChannel = hostingChannel;
			Viewers = viewers;
		}
	}
	public class JoinedChannel
	{
		public string Channel { get; }

		public ChannelState ChannelState { get; protected set; }

		public ChatMessage PreviousMessage { get; protected set; }

		public JoinedChannel(string channel)
		{
			Channel = channel;
		}

		public void HandleMessage(ChatMessage message)
		{
			PreviousMessage = message;
		}
	}
	public class MessageEmote
	{
		public delegate string ReplaceEmoteDelegate(MessageEmote caller);

		public enum EmoteSource
		{
			Twitch,
			FrankerFaceZ,
			BetterTwitchTv
		}

		public enum EmoteSize
		{
			Small,
			Medium,
			Large
		}

		public static readonly ReadOnlyCollection<string> TwitchEmoteUrls = new ReadOnlyCollection<string>(new string[3] { "https://static-cdn.jtvnw.net/emoticons/v1/{0}/1.0", "https://static-cdn.jtvnw.net/emoticons/v1/{0}/2.0", "https://static-cdn.jtvnw.net/emoticons/v1/{0}/3.0" });

		public static readonly ReadOnlyCollection<string> FrankerFaceZEmoteUrls = new ReadOnlyCollection<string>(new string[3] { "//cdn.frankerfacez.com/emoticon/{0}/1", "//cdn.frankerfacez.com/emoticon/{0}/2", "//cdn.frankerfacez.com/emoticon/{0}/4" });

		public static readonly ReadOnlyCollection<string> BetterTwitchTvEmoteUrls = new ReadOnlyCollection<string>(new string[3] { "//cdn.betterttv.net/emote/{0}/1x", "//cdn.betterttv.net/emote/{0}/2x", "//cdn.betterttv.net/emote/{0}/3x" });

		private readonly string _id;

		private readonly string _text;

		private readonly string _escapedText;

		private readonly EmoteSource _source;

		private readonly EmoteSize _size;

		public string Id => _id;

		public string Text => _text;

		public EmoteSource Source => _source;

		public EmoteSize Size => _size;

		public string ReplacementString => ReplacementDelegate(this);

		public static ReplaceEmoteDelegate ReplacementDelegate { get; set; } = SourceMatchingReplacementText;


		public string EscapedText => _escapedText;

		public static string SourceMatchingReplacementText(MessageEmote caller)
		{
			int size = (int)caller.Size;
			return caller.Source switch
			{
				EmoteSource.BetterTwitchTv => string.Format(BetterTwitchTvEmoteUrls[size], caller.Id), 
				EmoteSource.FrankerFaceZ => string.Format(FrankerFaceZEmoteUrls[size], caller.Id), 
				EmoteSource.Twitch => string.Format(TwitchEmoteUrls[size], caller.Id), 
				_ => caller.Text, 
			};
		}

		public MessageEmote(string id, string text, EmoteSource source = EmoteSource.Twitch, EmoteSize size = EmoteSize.Small, ReplaceEmoteDelegate replacementDelegate = null)
		{
			_id = id;
			_text = text;
			_escapedText = Regex.Escape(text);
			_source = source;
			_size = size;
			if (replacementDelegate != null)
			{
				ReplacementDelegate = replacementDelegate;
			}
		}
	}
	public class MessageEmoteCollection
	{
		public delegate bool EmoteFilterDelegate(MessageEmote emote);

		private readonly SortedList<string, MessageEmote> _emoteList;

		private const string BasePattern = "(\\b{0}\\b)";

		private string _currentPattern;

		private Regex _regex;

		private readonly EmoteFilterDelegate _preferredFilter;

		private string CurrentPattern
		{
			get
			{
				return _currentPattern;
			}
			set
			{
				if (_currentPattern == null || !_currentPattern.Equals(value))
				{
					_currentPattern = value;
					PatternChanged = true;
				}
			}
		}

		private Regex CurrentRegex
		{
			get
			{
				if (PatternChanged)
				{
					if (CurrentPattern != null)
					{
						_regex = new Regex(string.Format(CurrentPattern, ""));
						PatternChanged = false;
					}
					else
					{
						_regex = null;
					}
				}
				return _regex;
			}
		}

		private bool PatternChanged { get; set; }

		private EmoteFilterDelegate CurrentEmoteFilter { get; set; } = AllInclusiveEmoteFilter;


		public MessageEmoteCollection()
		{
			_emoteList = new SortedList<string, MessageEmote>();
			_preferredFilter = AllInclusiveEmoteFilter;
		}

		public MessageEmoteCollection(EmoteFilterDelegate preferredFilter)
			: this()
		{
			_preferredFilter = preferredFilter;
		}

		public void Add(MessageEmote emote)
		{
			if (!_emoteList.TryGetValue(emote.Text, out var _))
			{
				_emoteList.Add(emote.Text, emote);
			}
			if (CurrentPattern == null)
			{
				CurrentPattern = $"(\\b{emote.EscapedText}\\b)";
			}
			else
			{
				CurrentPattern = CurrentPattern + "|" + $"(\\b{emote.EscapedText}\\b)";
			}
		}

		public void Merge(IEnumerable<MessageEmote> emotes)
		{
			IEnumerator<MessageEmote> enumerator = emotes.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Add(enumerator.Current);
			}
			enumerator.Dispose();
		}

		public void Remove(MessageEmote emote)
		{
			if (_emoteList.ContainsKey(emote.Text))
			{
				_emoteList.Remove(emote.Text);
				string text = "(^\\(\\\\b" + emote.EscapedText + "\\\\b\\)\\|?)";
				string text2 = "(\\|\\(\\\\b" + emote.EscapedText + "\\\\b\\))";
				string text3 = Regex.Replace(CurrentPattern, text + "|" + text2, "");
				CurrentPattern = (text3.Equals("") ? null : text3);
			}
		}

		public void RemoveAll()
		{
			_emoteList.Clear();
			CurrentPattern = null;
		}

		public string ReplaceEmotes(string originalMessage, EmoteFilterDelegate del = null)
		{
			if (CurrentRegex == null)
			{
				return originalMessage;
			}
			if (del != null && del != CurrentEmoteFilter)
			{
				CurrentEmoteFilter = del;
			}
			string result = CurrentRegex.Replace(originalMessage, GetReplacementString);
			CurrentEmoteFilter = _preferredFilter;
			return result;
		}

		public static bool AllInclusiveEmoteFilter(MessageEmote emote)
		{
			return true;
		}

		public static bool TwitchOnlyEmoteFilter(MessageEmote emote)
		{
			return emote.Source == MessageEmote.EmoteSource.Twitch;
		}

		private string GetReplacementString(Match m)
		{
			if (!_emoteList.ContainsKey(m.Value))
			{
				return m.Value;
			}
			MessageEmote messageEmote = _emoteList[m.Value];
			return CurrentEmoteFilter(messageEmote) ? messageEmote.ReplacementString : m.Value;
		}
	}
	public class OutboundChatMessage
	{
		public string Channel { get; set; }

		public string Message { get; set; }

		public string Username { get; set; }

		public override string ToString()
		{
			string text = Username.ToLower();
			string text2 = Channel.ToLower();
			return ":" + text + "!" + text + "@" + text + ".tmi.twitch.tv PRIVMSG #" + text2 + " :" + Message;
		}
	}
	public class OutboundWhisperMessage
	{
		public string Username { get; set; }

		public string Receiver { get; set; }

		public string Message { get; set; }

		public override string ToString()
		{
			return ":" + Username + "~" + Username + "@" + Username + ".tmi.twitch.tv PRIVMSG #jtv :/w " + Receiver + " " + Message;
		}
	}
	public class OutgoingMessage
	{
		public string Channel { get; set; }

		public string Message { get; set; }

		public int Nonce { get; set; }

		public string Sender { get; set; }

		public MessageState State { get; set; }
	}
	public enum MessageState : byte
	{
		Normal,
		Queued,
		Failed
	}
	public class RaidNotification
	{
		public List<KeyValuePair<string, string>> Badges { get; }

		public List<KeyValuePair<string, string>> BadgeInfo { get; }

		public string Color { get; }

		public string DisplayName { get; }

		public string Emotes { get; }

		public string Id { get; }

		public string Login { get; }

		public bool Moderator { get; }

		public string MsgId { get; }

		public string MsgParamDisplayName { get; }

		public string MsgParamLogin { get; }

		public string MsgParamViewerCount { get; }

		public string RoomId { get; }

		public bool Subscriber { get; }

		public string SystemMsg { get; }

		public string SystemMsgParsed { get; }

		public string TmiSentTs { get; }

		public bool Turbo { get; }

		public string UserId { get; }

		public UserType UserType { get; }

		public RaidNotification(IrcMessage ircMessage)
		{
			//IL_0457: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Unknown result type (might be due to invalid IL or missing references)
			//IL_0469: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
					Badges = Helpers.ParseBadges(text);
					break;
				case "badge-info":
					BadgeInfo = Helpers.ParseBadges(text);
					break;
				case "color":
					Color = text;
					break;
				case "display-name":
					DisplayName = text;
					break;
				case "emotes":
					Emotes = text;
					break;
				case "login":
					Login = text;
					break;
				case "mod":
					Moderator = Helpers.ConvertToBool(text);
					break;
				case "msg-id":
					MsgId = text;
					break;
				case "msg-param-displayName":
					MsgParamDisplayName = text;
					break;
				case "msg-param-login":
					MsgParamLogin = text;
					break;
				case "msg-param-viewerCount":
					MsgParamViewerCount = text;
					break;
				case "room-id":
					RoomId = text;
					break;
				case "subscriber":
					Subscriber = Helpers.ConvertToBool(text);
					break;
				case "system-msg":
					SystemMsg = text;
					SystemMsgParsed = text.Replace("\\s", " ").Replace("\\n", "");
					break;
				case "tmi-sent-ts":
					TmiSentTs = text;
					break;
				case "turbo":
					Turbo = Helpers.ConvertToBool(text);
					break;
				case "user-id":
					UserId = text;
					break;
				case "user-type":
					switch (text)
					{
					case "mod":
						UserType = (UserType)1;
						break;
					case "global_mod":
						UserType = (UserType)2;
						break;
					case "admin":
						UserType = (UserType)4;
						break;
					case "staff":
						UserType = (UserType)5;
						break;
					default:
						UserType = (UserType)0;
						break;
					}
					break;
				}
			}
		}

		public RaidNotification(List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string color, string displayName, string emotes, string id, string login, bool moderator, string msgId, string msgParamDisplayName, string msgParamLogin, string msgParamViewerCount, string roomId, bool subscriber, string systemMsg, string systemMsgParsed, string tmiSentTs, bool turbo, UserType userType, string userId)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			Badges = badges;
			BadgeInfo = badgeInfo;
			Color = color;
			DisplayName = displayName;
			Emotes = emotes;
			Id = id;
			Login = login;
			Moderator = moderator;
			MsgId = msgId;
			MsgParamDisplayName = msgParamDisplayName;
			MsgParamLogin = msgParamLogin;
			MsgParamViewerCount = msgParamViewerCount;
			RoomId = roomId;
			Subscriber = subscriber;
			SystemMsg = systemMsg;
			SystemMsgParsed = systemMsgParsed;
			TmiSentTs = tmiSentTs;
			Turbo = turbo;
			UserType = userType;
			UserId = userId;
		}
	}
	public class ReSubscriber : SubscriberBase
	{
		public int Months => monthsInternal;

		public ReSubscriber(IrcMessage ircMessage)
			: base(ircMessage)
		{
		}

		public ReSubscriber(List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string colorHex, Color color, string displayName, string emoteSet, string id, string login, string systemMessage, string msgId, string msgParamCumulativeMonths, string msgParamStreakMonths, bool msgParamShouldShareStreak, string systemMessageParsed, string resubMessage, SubscriptionPlan subscriptionPlan, string subscriptionPlanName, string roomId, string userId, bool isModerator, bool isTurbo, bool isSubscriber, bool isPartner, string tmiSentTs, UserType userType, string rawIrc, string channel, int months = 0)
			: base(badges, badgeInfo, colorHex, color, displayName, emoteSet, id, login, systemMessage, msgId, msgParamCumulativeMonths, msgParamStreakMonths, msgParamShouldShareStreak, systemMessageParsed, resubMessage, subscriptionPlan, subscriptionPlanName, roomId, userId, isModerator, isTurbo, isSubscriber, isPartner, tmiSentTs, userType, rawIrc, channel, months)
		{
		}//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)

	}
	public class RitualNewChatter
	{
		public List<KeyValuePair<string, string>> Badges { get; }

		public List<KeyValuePair<string, string>> BadgeInfo { get; }

		public string Color { get; }

		public string DisplayName { get; }

		public string Emotes { get; }

		public string Id { get; }

		public bool IsModerator { get; }

		public bool IsSubscriber { get; }

		public bool IsTurbo { get; }

		public string Login { get; }

		public string Message { get; }

		public string MsgId { get; }

		public string MsgParamRitualName { get; }

		public string RoomId { get; }

		public string SystemMsgParsed { get; }

		public string SystemMsg { get; }

		public string TmiSentTs { get; }

		public string UserId { get; }

		public UserType UserType { get; }

		public RitualNewChatter(IrcMessage ircMessage)
		{
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_043d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0446: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			Message = ircMessage.Message;
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
					Badges = Helpers.ParseBadges(text);
					break;
				case "badge-info":
					BadgeInfo = Helpers.ParseBadges(text);
					break;
				case "color":
					Color = text;
					break;
				case "display-name":
					DisplayName = text;
					break;
				case "emotes":
					Emotes = text;
					break;
				case "id":
					Id = text;
					break;
				case "login":
					Login = text;
					break;
				case "mod":
					IsModerator = Helpers.ConvertToBool(text);
					break;
				case "msg-id":
					MsgId = text;
					break;
				case "msg-param-ritual-name":
					MsgParamRitualName = text;
					break;
				case "room-id":
					RoomId = text;
					break;
				case "subscriber":
					IsSubscriber = Helpers.ConvertToBool(text);
					break;
				case "system-msg":
					SystemMsg = text;
					SystemMsgParsed = text.Replace("\\s", " ").Replace("\\n", "");
					break;
				case "tmi-sent-ts":
					TmiSentTs = text;
					break;
				case "turbo":
					IsTurbo = Helpers.ConvertToBool(text);
					break;
				case "user-id":
					UserId = text;
					break;
				case "user-type":
					switch (text)
					{
					case "mod":
						UserType = (UserType)1;
						break;
					case "global_mod":
						UserType = (UserType)2;
						break;
					case "admin":
						UserType = (UserType)4;
						break;
					case "staff":
						UserType = (UserType)5;
						break;
					default:
						UserType = (UserType)0;
						break;
					}
					break;
				}
			}
		}
	}
	public class SentMessage
	{
		public List<KeyValuePair<string, string>> Badges { get; }

		public string Channel { get; }

		public string ColorHex { get; }

		public string DisplayName { get; }

		public string EmoteSet { get; }

		public bool IsModerator { get; }

		public bool IsSubscriber { get; }

		public string Message { get; }

		public UserType UserType { get; }

		public SentMessage(UserState state, string message)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			Badges = state.Badges;
			Channel = state.Channel;
			ColorHex = state.ColorHex;
			DisplayName = state.DisplayName;
			EmoteSet = state.EmoteSet;
			IsModerator = state.IsModerator;
			IsSubscriber = state.IsSubscriber;
			UserType = state.UserType;
			Message = message;
		}

		public SentMessage(List<KeyValuePair<string, string>> badges, string channel, string colorHex, string displayName, string emoteSet, bool isModerator, bool isSubscriber, UserType userType, string message)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Badges = badges;
			Channel = channel;
			ColorHex = colorHex;
			DisplayName = displayName;
			EmoteSet = emoteSet;
			IsModerator = isModerator;
			IsSubscriber = isSubscriber;
			UserType = userType;
			Message = message;
		}
	}
	public class Subscriber : SubscriberBase
	{
		public Subscriber(IrcMessage ircMessage)
			: base(ircMessage)
		{
		}

		public Subscriber(List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string colorHex, Color color, string displayName, string emoteSet, string id, string login, string systemMessage, string msgId, string msgParamCumulativeMonths, string msgParamStreakMonths, bool msgParamShouldShareStreak, string systemMessageParsed, string resubMessage, SubscriptionPlan subscriptionPlan, string subscriptionPlanName, string roomId, string userId, bool isModerator, bool isTurbo, bool isSubscriber, bool isPartner, string tmiSentTs, UserType userType, string rawIrc, string channel)
			: base(badges, badgeInfo, colorHex, color, displayName, emoteSet, id, login, systemMessage, msgId, msgParamCumulativeMonths, msgParamStreakMonths, msgParamShouldShareStreak, systemMessageParsed, resubMessage, subscriptionPlan, subscriptionPlanName, roomId, userId, isModerator, isTurbo, isSubscriber, isPartner, tmiSentTs, userType, rawIrc, channel, 0)
		{
		}//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)

	}
	public class SubscriberBase
	{
		protected readonly int monthsInternal;

		public List<KeyValuePair<string, string>> Badges { get; }

		public List<KeyValuePair<string, string>> BadgeInfo { get; }

		public string ColorHex { get; }

		public Color Color { get; }

		public string DisplayName { get; }

		public string EmoteSet { get; }

		public string Id { get; }

		public bool IsModerator { get; }

		public bool IsPartner { get; }

		public bool IsSubscriber { get; }

		public bool IsTurbo { get; }

		public string Login { get; }

		public string MsgId { get; }

		public string MsgParamCumulativeMonths { get; }

		public bool MsgParamShouldShareStreak { get; }

		public string MsgParamStreakMonths { get; }

		public string RawIrc { get; }

		public string ResubMessage { get; }

		public string RoomId { get; }

		public SubscriptionPlan SubscriptionPlan { get; } = (SubscriptionPlan)0;


		public string SubscriptionPlanName { get; }

		public string SystemMessage { get; }

		public string SystemMessageParsed { get; }

		public string TmiSentTs { get; }

		public string UserId { get; }

		public UserType UserType { get; }

		public string Channel { get; }

		protected SubscriberBase(IrcMessage ircMessage)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0505: Unknown result type (might be due to invalid IL or missing references)
			//IL_050e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0517: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0600: Unknown result type (might be due to invalid IL or missing references)
			//IL_0609: Unknown result type (might be due to invalid IL or missing references)
			//IL_0612: Unknown result type (might be due to invalid IL or missing references)
			RawIrc = ircMessage.ToString();
			ResubMessage = ircMessage.Message;
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
					Badges = Helpers.ParseBadges(text);
					foreach (KeyValuePair<string, string> badge in Badges)
					{
						if (badge.Key == "partner")
						{
							IsPartner = true;
						}
					}
					break;
				case "badge-info":
					BadgeInfo = Helpers.ParseBadges(text);
					break;
				case "color":
					ColorHex = text;
					if (!string.IsNullOrEmpty(ColorHex))
					{
						Color = TwitchLib.Client.Models.Extensions.NetCore.ColorTranslator.FromHtml(ColorHex);
					}
					break;
				case "display-name":
					DisplayName = text;
					break;
				case "emotes":
					EmoteSet = text;
					break;
				case "id":
					Id = text;
					break;
				case "login":
					Login = text;
					break;
				case "mod":
					IsModerator = ConvertToBool(text);
					break;
				case "msg-id":
					MsgId = text;
					break;
				case "msg-param-cumulative-months":
					MsgParamCumulativeMonths = text;
					break;
				case "msg-param-streak-months":
					MsgParamStreakMonths = text;
					break;
				case "msg-param-should-share-streak":
					MsgParamShouldShareStreak = Helpers.ConvertToBool(text);
					break;
				case "msg-param-sub-plan":
					switch (text.ToLower())
					{
					case "prime":
						SubscriptionPlan = (SubscriptionPlan)1;
						break;
					case "1000":
						SubscriptionPlan = (SubscriptionPlan)2;
						break;
					case "2000":
						SubscriptionPlan = (SubscriptionPlan)3;
						break;
					case "3000":
						SubscriptionPlan = (SubscriptionPlan)4;
						break;
					default:
						throw new ArgumentOutOfRangeException("ToLower");
					}
					break;
				case "msg-param-sub-plan-name":
					SubscriptionPlanName = text.Replace("\\s", " ");
					break;
				case "room-id":
					RoomId = text;
					break;
				case "subscriber":
					IsSubscriber = ConvertToBool(text);
					break;
				case "system-msg":
					SystemMessage = text;
					SystemMessageParsed = text.Replace("\\s", " ");
					break;
				case "tmi-sent-ts":
					TmiSentTs = text;
					break;
				case "turbo":
					IsTurbo = ConvertToBool(text);
					break;
				case "user-id":
					UserId = text;
					break;
				case "user-type":
					switch (text)
					{
					case "mod":
						UserType = (UserType)1;
						break;
					case "global_mod":
						UserType = (UserType)2;
						break;
					case "admin":
						UserType = (UserType)4;
						break;
					case "staff":
						UserType = (UserType)5;
						break;
					default:
						UserType = (UserType)0;
						break;
					}
					break;
				}
			}
		}

		internal SubscriberBase(List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string colorHex, Color color, string displayName, string emoteSet, string id, string login, string systemMessage, string msgId, string msgParamCumulativeMonths, string msgParamStreakMonths, bool msgParamShouldShareStreak, string systemMessageParsed, string resubMessage, SubscriptionPlan subscriptionPlan, string subscriptionPlanName, string roomId, string userId, bool isModerator, bool isTurbo, bool isSubscriber, bool isPartner, string tmiSentTs, UserType userType, string rawIrc, string channel, int months)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			Badges = badges;
			BadgeInfo = badgeInfo;
			ColorHex = colorHex;
			Color = color;
			DisplayName = displayName;
			EmoteSet = emoteSet;
			Id = id;
			Login = login;
			MsgId = msgId;
			MsgParamCumulativeMonths = msgParamCumulativeMonths;
			MsgParamStreakMonths = msgParamStreakMonths;
			MsgParamShouldShareStreak = msgParamShouldShareStreak;
			SystemMessage = systemMessage;
			SystemMessageParsed = systemMessageParsed;
			ResubMessage = resubMessage;
			SubscriptionPlan = subscriptionPlan;
			SubscriptionPlanName = subscriptionPlanName;
			RoomId = roomId;
			UserId = UserId;
			IsModerator = isModerator;
			IsTurbo = isTurbo;
			IsSubscriber = isSubscriber;
			IsPartner = isPartner;
			TmiSentTs = tmiSentTs;
			UserType = userType;
			RawIrc = rawIrc;
			monthsInternal = months;
			UserId = userId;
			Channel = channel;
		}

		private static bool ConvertToBool(string data)
		{
			return data == "1";
		}

		public override string ToString()
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			return $"Badges: {Badges.Count}, color hex: {ColorHex}, display name: {DisplayName}, emote set: {EmoteSet}, login: {Login}, system message: {SystemMessage}, msgId: {MsgId}, msgParamCumulativeMonths: {MsgParamCumulativeMonths}" + $"msgParamStreakMonths: {MsgParamStreakMonths}, msgParamShouldShareStreak: {MsgParamShouldShareStreak}, resub message: {ResubMessage}, months: {monthsInternal}, room id: {RoomId}, user id: {UserId}, mod: {IsModerator}, turbo: {IsTurbo}, sub: {IsSubscriber}, user type: {UserType}, raw irc: {RawIrc}";
		}
	}
	public abstract class TwitchLibMessage
	{
		public List<KeyValuePair<string, string>> Badges { get; protected set; }

		public string BotUsername { get; protected set; }

		public Color Color { get; protected set; }

		public string ColorHex { get; protected set; }

		public string DisplayName { get; protected set; }

		public EmoteSet EmoteSet { get; protected set; }

		public bool IsTurbo { get; protected set; }

		public string UserId { get; protected set; }

		public string Username { get; protected set; }

		public UserType UserType { get; protected set; }
	}
	public class UserBan
	{
		public string BanReason;

		public string Channel;

		public string Username;

		public UserBan(IrcMessage ircMessage)
		{
			Channel = ircMessage.Channel;
			Username = ircMessage.Message;
			if (ircMessage.Tags.TryGetValue("ban-reason", out var value))
			{
				BanReason = value;
			}
		}

		public UserBan(string channel, string username, string banReason)
		{
			Channel = channel;
			Username = username;
			BanReason = banReason;
		}
	}
	public class UserState
	{
		public List<KeyValuePair<string, string>> Badges { get; } = new List<KeyValuePair<string, string>>();


		public List<KeyValuePair<string, string>> BadgeInfo { get; } = new List<KeyValuePair<string, string>>();


		public string Channel { get; }

		public string ColorHex { get; }

		public string DisplayName { get; }

		public string EmoteSet { get; }

		public bool IsModerator { get; }

		public bool IsSubscriber { get; }

		public UserType UserType { get; }

		public UserState(IrcMessage ircMessage)
		{
			//IL_02a9: 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_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			Channel = ircMessage.Channel;
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
					Badges = Helpers.ParseBadges(text);
					break;
				case "badge-info":
					BadgeInfo = Helpers.ParseBadges(text);
					break;
				case "color":
					ColorHex = text;
					break;
				case "display-name":
					DisplayName = text;
					break;
				case "emote-sets":
					EmoteSet = text;
					break;
				case "mod":
					IsModerator = Helpers.ConvertToBool(text);
					break;
				case "subscriber":
					IsSubscriber = Helpers.ConvertToBool(text);
					break;
				case "user-type":
					switch (text)
					{
					case "mod":
						UserType = (UserType)1;
						break;
					case "global_mod":
						UserType = (UserType)2;
						break;
					case "admin":
						UserType = (UserType)4;
						break;
					case "staff":
						UserType = (UserType)5;
						break;
					default:
						UserType = (UserType)0;
						break;
					}
					break;
				default:
					Console.WriteLine("Unaccounted for [UserState]: " + key);
					break;
				}
			}
			if (string.Equals(ircMessage.User, Channel, StringComparison.InvariantCultureIgnoreCase))
			{
				UserType = (UserType)3;
			}
		}

		public UserState(List<KeyValuePair<string, string>> badges, List<KeyValuePair<string, string>> badgeInfo, string colorHex, string displayName, string emoteSet, string channel, bool isSubscriber, bool isModerator, UserType userType)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			Badges = badges;
			BadgeInfo = badgeInfo;
			ColorHex = colorHex;
			DisplayName = displayName;
			EmoteSet = emoteSet;
			Channel = channel;
			IsSubscriber = isSubscriber;
			IsModerator = isModerator;
			UserType = userType;
		}
	}
	public class UserTimeout
	{
		public string Channel;

		public int TimeoutDuration;

		public string TimeoutReason;

		public string Username;

		public UserTimeout(IrcMessage ircMessage)
		{
			Channel = ircMessage.Channel;
			Username = ircMessage.Message;
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				string text2 = key;
				string text3 = text2;
				if (!(text3 == "ban-duration"))
				{
					if (text3 == "ban-reason")
					{
						TimeoutReason = text;
					}
				}
				else
				{
					TimeoutDuration = int.Parse(text);
				}
			}
		}

		public UserTimeout(string channel, string username, int timeoutDuration, string timeoutReason)
		{
			Channel = channel;
			Username = username;
			TimeoutDuration = timeoutDuration;
			TimeoutReason = timeoutReason;
		}
	}
	public class WhisperCommand
	{
		public List<string> ArgumentsAsList { get; }

		public string ArgumentsAsString { get; }

		public char CommandIdentifier { get; }

		public string CommandText { get; }

		public WhisperMessage WhisperMessage { get; }

		public WhisperCommand(WhisperMessage whisperMessage)
		{
			WhisperCommand whisperCommand = this;
			WhisperMessage = whisperMessage;
			string[] array = whisperMessage.Message.Split(new char[1] { ' ' });
			CommandText = ((array != null) ? array[0].Substring(1, whisperMessage.Message.Split(new char[1] { ' ' })[0].Length - 1) : null) ?? whisperMessage.Message.Substring(1, whisperMessage.Message.Length - 1);
			string message = whisperMessage.Message;
			string[] array2 = whisperMessage.Message.Split(new char[1] { ' ' });
			ArgumentsAsString = message.Replace(((array2 != null) ? array2[0] : null) + " ", "");
			ArgumentsAsList = whisperMessage.Message.Split(new char[1] { ' ' })?.Where((string arg) => arg != whisperMessage.Message[0] + whisperCommand.CommandText).ToList() ?? new List<string>();
			CommandIdentifier = whisperMessage.Message[0];
		}

		public WhisperCommand(WhisperMessage whisperMessage, string commandText, string argumentsAsString, List<string> argumentsAsList, char commandIdentifier)
		{
			WhisperMessage = whisperMessage;
			CommandText = commandText;
			ArgumentsAsString = argumentsAsString;
			ArgumentsAsList = argumentsAsList;
			CommandIdentifier = commandIdentifier;
		}
	}
	public class WhisperMessage : TwitchLibMessage
	{
		public string MessageId { get; }

		public string ThreadId { get; }

		public string Message { get; }

		public WhisperMessage(List<KeyValuePair<string, string>> badges, string colorHex, Color color, string username, string displayName, EmoteSet emoteSet, string threadId, string messageId, string userId, bool isTurbo, string botUsername, string message, UserType userType)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			base.Badges = badges;
			base.ColorHex = colorHex;
			base.Color = color;
			base.Username = username;
			base.DisplayName = displayName;
			base.EmoteSet = emoteSet;
			ThreadId = threadId;
			MessageId = messageId;
			base.UserId = userId;
			base.IsTurbo = isTurbo;
			base.BotUsername = botUsername;
			Message = message;
			base.UserType = userType;
		}

		public WhisperMessage(IrcMessage ircMessage, string botUsername)
		{
			base.Username = ircMessage.User;
			base.BotUsername = botUsername;
			Message = ircMessage.Message;
			foreach (string key in ircMessage.Tags.Keys)
			{
				string text = ircMessage.Tags[key];
				switch (key)
				{
				case "badges":
				{
					base.Badges = new List<KeyValuePair<string, string>>();
					if (!Enumerable.Contains(text, '/'))
					{
						break;
					}
					if (!text.Contains(","))
					{
						base.Badges.Add(new KeyValuePair<string, string>(text.Split(new char[1] { '/' })[0], text.Split(new char[1] { '/' })[1]));
						break;
					}
					string[] array = text.Split(new char[1] { ',' });
					foreach (string text2 in array)
					{
						base.Badges.Add(new KeyValuePair<string, string>(text2.Split(new char[1] { '/' })[0], text2.Split(new char[1] { '/' })[1]));
					}
					break;
				}
				case "color":
					base.ColorHex = text;
					if (!string.IsNullOrEmpty(base.ColorHex))
					{
						base.Color = TwitchLib.Client.Models.Extensions.NetCore.ColorTranslator.FromHtml(base.ColorHex);
					}
					break;
				case "display-name":
					base.DisplayName = text;
					break;
				case "emotes":
					base.EmoteSet = new EmoteSet(text, Message);
					break;
				case "message-id":
					MessageId = text;
					break;
				case "thread-id":
					ThreadId = text;
					break;
				case "turbo":
					base.IsTurbo = Helpers.ConvertToBool(text);
					break;
				case "user-id":
					base.UserId = text;
					break;
				case "user-type":
					switch (text)
					{
					case "global_mod":
						base.UserType = (UserType)2;
						break;
					case "admin":
						base.UserType = (UserType)4;
						break;
					case "staff":
						base.UserType = (UserType)5;
						break;
					default:
						base.UserType = (UserType)0;
						break;
					}
					break;
				}
			}
			if (base.EmoteSet == null)
			{
				base.EmoteSet = new EmoteSet((string)null, Message);
			}
		}
	}
}
namespace TwitchLib.Client.Models.Internal
{
	public class IrcMessage
	{
		private readonly string[] _parameters;

		public readonly string User;

		public readonly string Hostmask;

		public readonly IrcCommand Command;

		public readonly Dictionary<string, string> Tags;

		public string Channel => Params.StartsWith("#") ? Params.Remove(0, 1) : Params;

		public string Params => (_parameters != null && _parameters.Length != 0) ? _parameters[0] : "";

		public string Message => Trailing;

		public string Trailing => (_parameters != null && _parameters.Length > 1) ? _parameters[_parameters.Length - 1] : "";

		public IrcMessage(string user)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			_parameters = null;
			User = user;
			Hostmask = null;
			Command = (IrcCommand)0;
			Tags = null;
		}

		public IrcMessage(IrcCommand command, string[] parameters, string hostmask, Dictionary<string, string> tags = null)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			int num = hostmask.IndexOf('!');
			User = ((num != -1) ? hostmask.Substring(0, num) : hostmask);
			Hostmask = hostmask;
			_parameters = parameters;
			Command = command;
			Tags = tags;
		}

		public new string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder(32);
			if (Tags != null)
			{
				string[] array = new string[Tags.Count];
				int num = 0;
				foreach (KeyValuePair<string, string> tag in Tags)
				{
					array[num] = tag.Key + "=" + tag.Value;
					num++;
				}
				if (array.Length != 0)
				{
					stringBuilder.Append("@").Append(string.Join(";", array)).Append(" ");
				}
			}
			if (!string.IsNullOrEmpty(Hostmask))
			{
				stringBuilder.Append(":").Append(Hostmask).Append(" ");
			}
			stringBuilder.Append(((object)(IrcCommand)(ref Command)).ToString().ToUpper().Replace("RPL_", ""));
			if (_parameters.Length == 0)
			{
				return stringBuilder.ToString();
			}
			if (_parameters[0] != null && _parameters[0].Length > 0)
			{
				stringBuilder.Append(" ").Append(_parameters[0]);
			}
			if (_parameters.Length > 1 && _parameters[1] != null && _parameters[1].Length > 0)
			{
				stringBuilder.Append(" :").Append(_parameters[1]);
			}
			return stringBuilder.ToString();
		}
	}
	public static class MsgIds
	{
		public const string AlreadyBanned = "already_banned";

		public const string AlreadyEmotesOff = "already_emotes_off";

		public const string AlreadyEmotesOn = "already_emotes_on";

		public const string AlreadyR9KOff = "already_r9k_off";

		public const string AlreadyR9KOn = "already_r9k_on";

		public const string AlreadySubsOff = "already_subs_off";

		public const string AlreadySubsOn = "already_subs_on";

		public const string BadHostHosting = "bad_host_hosting";

		public const string BadUnbanNoBan = "bad_unban_no_ban";

		public const string BanSuccess = "ban_success";

		public const string ColorChanged = "color_changed";

		public const string EmoteOnlyOff = "emote_only_off";

		public const string EmoteOnlyOn = "emote_only_on";

		public const string HighlightedMessage = "highlighted-message";

		public const string HostOff = "host_off";

		public const string HostOn = "host_on";

		public const string HostsRemaining = "host_remaining";

		public const string ModeratorsReceived = "room_mods";

		public const string NoMods = "no_mods";

		public const string NoVIPs = "no_vips";

		public const string MsgChannelSuspended = "msg_channel_suspended";

		public const string NoPermission = "no_permission";

		public const string Raid = "raid";

		public const string RaidErrorSelf = "raid_error_self";

		public const string RaidNoticeMature = "raid_notice_mature";

		public const string ReSubscription = "resub";

		public const string Ritual = "ritual";

		public const string R9KOff = "r9k_off";

		public const string R9KOn = "r9k_on";

		public const string SubGift = "subgift";

		public const string CommunitySubscription = "submysterygift";

		public const string Subscription = "sub";

		public const string SubsOff = "subs_off";

		public const string SubsOn = "subs_on";

		public const string TimeoutSuccess = "timeout_success";

		public const string UnbanSuccess = "unban_success";

		public const string UnrecognizedCmd = "unrecognized_cmd";

		public const string VIPsSuccess = "vips_success";

		public const string SkipSubsModeMessage = "skip-subs-mode-message";
	}
	public static class Tags
	{
		public const string Badges = "badges";

		public const string BadgeInfo = "badge-info";

		public const string BanDuration = "ban-duration";

		public const string BanReason = "ban-reason";

		public const string BroadcasterLang = "broadcaster-lang";

		public const string Bits = "bits";

		public const string Color = "color";

		public const string CustomRewardId = "custom-reward-id";

		public const string DisplayName = "display-name";

		public const string Emotes = "emotes";

		public const string EmoteOnly = "emote-only";

		public const string EmotesSets = "emote-sets";

		public const string FollowersOnly = "followers-only";

		public const string Id = "id";

		public const string Login = "login";

		public const string Mercury = "mercury";

		public const string MessageId = "message-id";

		public const string Mod = "mod";

		public const string MsgId = "msg-id";

		public const string MsgParamDisplayname = "msg-param-displayName";

		public const string MsgParamLogin = "msg-param-login";

		public const string MsgParamCumulativeMonths = "msg-param-cumulative-months";

		public const string MsgParamMonths = "msg-param-months";

		public const string MsgParamPromoGiftTotal = "msg-param-promo-gift-total";

		public const string MsgParamPromoName = "msg-param-promo-name";

		public const string MsgParamShouldShareStreak = "msg-param-should-share-streak";

		public const string MsgParamStreakMonths = "msg-param-streak-months";

		public const string MsgParamSubPlan = "msg-param-sub-plan";

		public const string MsgParamSubPlanName = "msg-param-sub-plan-name";

		public const string MsgParamViewerCount = "msg-param-viewerCount";

		public const string MsgParamRecipientDisplayname = "msg-param-recipient-display-name";

		public const string MsgParamRecipientId = "msg-param-recipient-id";

		public const string MsgParamRecipientUsername = "msg-param-recipient-user-name";

		public const string MsgParamRitualName = "msg-param-ritual-name";

		public const string MsgParamMassGiftCount = "msg-param-mass-gift-count";

		public const string MsgParamSenderCount = "msg-param-sender-count";

		public const string MsgParamSenderLogin = "msg-param-sender-login";

		public const string MsgParamSenderName = "msg-param-sender-name";

		public const string MsgParamThreshold = "msg-param-threshold";

		public const string Noisy = "noisy";

		public const string Rituals = "rituals";

		public const string RoomId = "room-id";

		public const string R9K = "r9k";

		public const string Slow = "slow";

		public const string Subscriber = "subscriber";

		public const string SubsOnly = "subs-only";

		public const string SystemMsg = "system-msg";

		public const string ThreadId = "thread-id";

		public const string TmiSentTs = "tmi-sent-ts";

		public const string Turbo = "turbo";

		public const string UserId = "user-id";

		public const string UserType = "user-type";
	}
}
namespace TwitchLib.Client.Models.Extractors
{
	public class EmoteExtractor
	{
		public IEnumerable<Emote> Extract(string rawEmoteSetString, string message)
		{
			if (string.IsNullOrEmpty(rawEmoteSetString) || string.IsNullOrEmpty(message))
			{
				yield break;
			}
			if (rawEmoteSetString.Contains("/"))
			{
				string[] array = rawEmoteSetString.Split(new char[1] { '/' });
				foreach (string emoteData in array)
				{
					string emoteId = emoteData.Split(new char[1] { ':' })[0];
					if (emoteData.Contains(","))
					{
						string[] array2 = emoteData.Replace(emoteId + ":", "").Split(new char[1] { ',' });
						foreach (string emote2 in array2)
						{
							yield return GetEmote(emote2, emoteId, message);
						}
					}
					else
					{
						yield return GetEmote(emoteData, emoteId, message, single: true);
					}
				}
				yield break;
			}
			string emoteId2 = rawEmoteSetString.Split(new char[1] { ':' })[0];
			if (rawEmoteSetString.Contains(","))
			{
				string[] array3 = rawEmoteSetString.Replace(emoteId2 + ":", "").Split(new char[1] { ',' });
				foreach (string emote in array3)
				{
					yield return GetEmote(emote, emoteId2, message);
				}
			}
			else
			{
				yield return GetEmote(rawEmoteSetString, emoteId2, message, single: true);
			}
		}

		private Emote GetEmote(string emoteData, string emoteId, string message, bool single = false)
		{
			int num = -1;
			int num2 = -1;
			if (single)
			{
				num = int.Parse(emoteData.Split(new char[1] { ':' })[1].Split(new char[1] { '-' })[0]);
				num2 = int.Parse(emoteData.Split(new char[1] { ':' })[1].Split(new char[1] { '-' })[1]);
			}
			else
			{
				num = int.Parse(emoteData.Split(new char[1] { '-' })[0]);
				num2 = int.Parse(emoteData.Split(new char[1] { '-' })[1]);
			}
			string name = message.Substring(num, num2 - num + 1);
			EmoteBuilder emoteBuilder = EmoteBuilder.Create().WithId(emoteId).WithName(name)
				.WithStartIndex(num)
				.WithEndIndex(num2);
			return emoteBuilder.Build();
		}
	}
	public interface IExtractor<TResult>
	{
		TResult Extract(IrcMessage ircMessage);
	}
}
namespace TwitchLib.Client.Models.Extensions.NetCore
{
	public static class ColorTranslator
	{
		public static Color FromHtml(string hexColor)
		{
			hexColor += 0;
			int argb = int.Parse(hexColor.Replace("#", ""), NumberStyles.HexNumber);
			return Color.FromArgb(argb);
		}
	}
}
namespace TwitchLib.Client.Models.Common
{
	public static class Helpers
	{
		public static List<string> ParseQuotesAndNonQuotes(string message)
		{
			List<string> list = new List<string>();
			if (message == "")
			{
				return new List<string>();
			}
			bool flag = message[0] != '"';
			string[] array = message.Split(new char[1] { '"' });
			foreach (string text in array)
			{
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				if (!flag)
				{
					list.Add(text);
					flag = true;
				}
				else
				{
					if (!text.Contains(" "))
					{
						continue;
					}
					string[] array2 = text.Split(new char[1] { ' ' });
					foreach (string text2 in array2)
					{
						if (!string.IsNullOrWhiteSpace(text2))
						{
							list.Add(text2);
							flag = false;
						}
					}
				}
			}
			return list;
		}

		public static List<KeyValuePair<string, string>> ParseBadges(string badgesStr)
		{
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
			if (Enumerable.Contains(badgesStr, '/'))
			{
				if (!badgesStr.Contains(","))
				{
					list.Add(new KeyValuePair<string, string>(badgesStr.Split(new char[1] { '/' })[0], badgesStr.Split(new char[1] { '/' })[1]));
				}
				else
				{
					string[] array = badgesStr.Split(new char[1] { ',' });
					foreach (string text in array)
					{
						list.Add(new KeyValuePair<string, string>(text.Split(new char[1] { '/' })[0], text.Split(new char[1] { '/' })[1]));
					}
				}
			}
			return list;
		}

		public static string ParseToken(string token, string message)
		{
			string result = string.Empty;
			for (int num = message.IndexOf(token, StringComparison.InvariantCultureIgnoreCase); num > -1; num = message.IndexOf(token, num + token.Length, StringComparison.InvariantCultureIgnoreCase))
			{
				result = new string(message.Substring(num).TakeWhile((char x) => x != ';' && x != ' ').ToArray()).Split(new char[1] { '=' }).LastOrDefault();
			}
			return result;
		}

		public static bool ConvertToBool(string data)
		{
			return data == "1";
		}
	}
}
namespace TwitchLib.Client.Models.Builders
{
	public sealed class BeingHostedNotificationBuilder : IBuilder<BeingHostedNotification>, IFromIrcMessageBuilder<BeingHostedNotification>
	{
		private string _botUsername;

		private string _channel;

		private string _hostedByChannel;

		private bool _isAutoHosted;

		private int _viewers;

		public BeingHostedNotificationBuilder WithBotUsername(string botUsername)
		{
			_botUsername = botUsername;
			return this;
		}

		public BeingHostedNotificationBuilder WithChannel(string channel)
		{
			_channel = channel;
			return this;
		}

		public BeingHostedNotificationBuilder WithHostedByChannel(string hostedByChannel)
		{
			_hostedByChannel = hostedByChannel;
			return this;
		}

		public BeingHostedNotificationBuilder WithIsAutoHosted(bool isAutoHosted)
		{
			_isAutoHosted = isAutoHosted;
			return this;
		}

		public BeingHostedNotificationBuilder WithViewers(int viewers)
		{
			_viewers = viewers;
			return this;
		}

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

		public BeingHostedNotification Build()
		{
			return new BeingHostedNotification(_channel, _botUsername, _hostedByChannel, _viewers, _isAutoHosted);
		}

		public BeingHostedNotification BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject)
		{
			string botUsername = fromIrcMessageBuilderDataObject.AditionalData.ToString();
			return new BeingHostedNotification(botUsername, fromIrcMessageBuilderDataObject.Message);
		}
	}
	public sealed class ChannelStateBuilder : IBuilder<ChannelState>, IFromIrcMessageBuilder<ChannelState>
	{
		private string _broadcasterLanguage;

		private string _channel;

		private bool _emoteOnly;

		private TimeSpan _followersOnly;

		private bool _mercury;

		private bool _r9K;

		private bool _rituals;

		private string _roomId;

		private int _slowMode;

		private bool _subOnly;

		private ChannelStateBuilder()
		{
		}

		public ChannelStateBuilder WithBroadcasterLanguage(string broadcasterLanguage)
		{
			_broadcasterLanguage = broadcasterLanguage;
			return this;
		}

		public ChannelStateBuilder WithChannel(string channel)
		{
			_channel = channel;
			return this;
		}

		public ChannelStateBuilder WithEmoteOnly(bool emoteOnly)
		{
			_emoteOnly = emoteOnly;
			return this;
		}

		public ChannelStateBuilder WIthFollowersOnly(TimeSpan followersOnly)
		{
			_followersOnly = followersOnly;
			return this;
		}

		public ChannelStateBuilder WithMercury(bool mercury)
		{
			_mercury = mercury;
			return this;
		}

		public ChannelStateBuilder WithR9K(bool r9k)
		{
			_r9K = r9k;
			return this;
		}

		public ChannelStateBuilder WithRituals(bool rituals)
		{
			_rituals = rituals;
			return this;
		}

		public ChannelStateBuilder WithRoomId(string roomId)
		{
			_roomId = roomId;
			return this;
		}

		public ChannelStateBuilder WithSlowMode(int slowMode)
		{
			_slowMode = slowMode;
			return this;
		}

		public ChannelStateBuilder WithSubOnly(bool subOnly)
		{
			_subOnly = subOnly;
			return this;
		}

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

		public ChannelState Build()
		{
			return new ChannelState(_r9K, _rituals, _subOnly, _slowMode, _emoteOnly, _broadcasterLanguage, _channel, _followersOnly, _mercury, _roomId);
		}

		public ChannelState BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject)
		{
			return new ChannelState(fromIrcMessageBuilderDataObject.Message);
		}
	}
	public sealed class ChatCommandBuilder : IBuilder<ChatCommand>
	{
		private readonly List<string> _argumentsAsList = new List<string>();

		private string _argumentsAsString;

		private ChatMessage _chatMessage;

		private char _commandIdentifier;

		private string _commandText;

		private ChatCommandBuilder()
		{
		}

		public ChatCommandBuilder WithArgumentsAsList(params string[] argumentsList)
		{
			_argumentsAsList.AddRange(argumentsList);
			return this;
		}

		public ChatCommandBuilder WithArgumentsAsString(string argumentsAsString)
		{
			_argumentsAsString = argumentsAsString;
			return this;
		}

		public ChatCommandBuilder WithChatMessage(ChatMessage chatMessage)
		{
			_chatMessage = chatMessage;
			return this;
		}

		public ChatCommandBuilder WithCommandIdentifier(char commandIdentifier)
		{
			_commandIdentifier = commandIdentifier;
			return this;
		}

		public ChatCommandBuilder WithCommandText(string commandText)
		{
			_commandText = commandText;
			return this;
		}

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

		public ChatCommand Build()
		{
			return new ChatCommand(_chatMessage, _commandText, _argumentsAsString, _argumentsAsList, _commandIdentifier);
		}

		public ChatCommand BuildFromChatMessage(ChatMessage chatMessage)
		{
			return new ChatCommand(chatMessage);
		}
	}
	public sealed class ChatMessageBuilder : IBuilder<ChatMessage>
	{
		private TwitchLibMessage _twitchLibMessage;

		private readonly List<KeyValuePair<string, string>> BadgeInfo = new List<KeyValuePair<string, string>>();

		private int _bits;

		private double _bitsInDollars;

		private string _channel;

		private CheerBadge _cheerBadge;

		private string _emoteReplacedMessage;

		private string _id;

		private bool _isBroadcaster;

		private bool _isMe;

		private bool _isModerator;

		private bool _isSubscriber;

		private string _message;

		private Noisy _noisy;

		private string _rawIrcMessage;

		private string _roomId;

		private int _subscribedMonthCount;

		private ChatMessageBuilder()
		{
			_twitchLibMessage = TwitchLibMessageBuilder.Create().Build();
		}

		public ChatMessageBuilder WithTwitchLibMessage(TwitchLibMessage twitchLibMessage)
		{
			_twitchLibMessage = twitchLibMessage;
			return this;
		}

		public ChatMessageBuilder WithBadgeInfos(params KeyValuePair<string, string>[] badgeInfos)
		{
			BadgeInfo.AddRange(badgeInfos);
			return this;
		}

		public ChatMessageBuilder WithBits(int bits)
		{
			_bits = bits;
			return this;
		}

		public ChatMessageBuilder WithBitsInDollars(double bitsInDollars)
		{
			_bitsInDollars = bitsInDollars;
			return this;
		}

		public ChatMessageBuilder WithChannel(string channel)
		{
			_channel = channel;
			return this;
		}

		public ChatMessageBuilder WithCheerBadge(CheerBadge cheerBadge)
		{
			_cheerBadge = cheerBadge;
			return this;
		}

		public ChatMessageBuilder WithEmoteReplaceMessage(string emoteReplaceMessage)
		{
			_emoteReplacedMessage = emoteReplaceMessage;
			return this;
		}

		public ChatMessageBuilder WithId(string id)
		{
			_id = id;
			return this;
		}

		public ChatMessageBuilder WithIsBroadcaster(bool isBroadcaster)
		{
			_isBroadcaster = isBroadcaster;
			return this;
		}

		public ChatMessageBuilder WithIsMe(bool isMe)
		{
			_isMe = isMe;
			return this;
		}

		public ChatMessageBuilder WithIsModerator(bool isModerator)
		{
			_isModerator = isModerator;
			return this;
		}

		public ChatMessageBuilder WithIsSubscriber(bool isSubscriber)
		{
			_isSubscriber = isSubscriber;
			return this;
		}

		public ChatMessageBuilder WithMessage(string message)
		{
			_message = message;
			return this;
		}

		public ChatMessageBuilder WithNoisy(Noisy noisy)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			_noisy = noisy;
			return this;
		}

		public ChatMessageBuilder WithRawIrcMessage(string rawIrcMessage)
		{
			_rawIrcMessage = rawIrcMessage;
			return this;
		}

		public ChatMessageBuilder WithRoomId(string roomId)
		{
			_roomId = roomId;
			return this;
		}

		public ChatMessageBuilder WithSubscribedMonthCount(int subscribedMonthCount)
		{
			_subscribedMonthCount = subscribedMonthCount;
			return this;
		}

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

		public ChatMessage Build()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			return new ChatMessage(_twitchLibMessage.BotUsername, _twitchLibMessage.UserId, _twitchLibMessage.Username, _twitchLibMessage.DisplayName, _twitchLibMessage.ColorHex, _twitchLibMessage.Color, _twitchLibMessage.EmoteSet, _message, _twitchLibMessage.UserType, _channel, _id, _isSubscriber, _subscribedMonthCount, _roomId, _twitchLibMessage.IsTurbo, _isModerator, _isMe, _isBroadcaster, _noisy, _rawIrcMessage, _emoteReplacedMessage, _twitchLibMessage.Badges, _cheerBadge, _bits, _bitsInDollars);
		}
	}
	public sealed class CheerBadgeBuilder : IBuilder<CheerBadge>
	{
		private int _cheerAmount;

		public CheerBadgeBuilder WithCheerAmount(int cheerAmount)
		{
			_cheerAmount = cheerAmount;
			return this;
		}

		public CheerBadge Build()
		{
			return new CheerBadge(_cheerAmount);
		}
	}
	public sealed class CommunitySubscriptionBuilder : IFromIrcMessageBuilder<CommunitySubscription>
	{
		private CommunitySubscriptionBuilder()
		{
		}

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

		public CommunitySubscription BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject)
		{
			return new CommunitySubscription(fromIrcMessageBuilderDataObject.Message);
		}
	}
	public sealed class ConnectionCredentialsBuilder : IBuilder<ConnectionCredentials>
	{
		private string _twitchUsername;

		private string _twitchOAuth;

		private string _twitchWebsocketURI = "wss://irc-ws.chat.twitch.tv:443";

		private bool _disableUsernameCheck;

		private ConnectionCredentialsBuilder()
		{
		}

		public ConnectionCredentialsBuilder WithTwitchUsername(string twitchUsername)
		{
			_twitchUsername = twitchUsername;
			return this;
		}

		public ConnectionCredentialsBuilder WithTwitchOAuth(string twitchOAuth)
		{
			_twitchOAuth = twitchOAuth;
			return this;
		}

		public ConnectionCredentialsBuilder WithTwitchWebSocketUri(string twitchWebSocketUri)
		{
			_twitchWebsocketURI = twitchWebSocketUri;
			return this;
		}

		public ConnectionCredentialsBuilder WithDisableUsernameCheck(bool disableUsernameCheck)
		{
			_disableUsernameCheck = disableUsernameCheck;
			return this;
		}

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

		public ConnectionCredentials Build()
		{
			return new ConnectionCredentials(_twitchUsername, _twitchOAuth, _twitchWebsocketURI, _disableUsernameCheck);
		}
	}
	public sealed class EmoteBuilder : IBuilder<Emote>
	{
		private string _id;

		private string _name;

		private int _startIndex;

		private int _endIndex;

		private EmoteBuilder()
		{
		}

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

		public EmoteBuilder WithId(string id)
		{
			_id = id;
			return this;
		}

		public EmoteBuilder WithName(string name)
		{
			_name = name;
			return this;
		}

		public EmoteBuilder WithStartIndex(int startIndex)
		{
			_startIndex = startIndex;
			return this;
		}

		public EmoteBuilder WithEndIndex(int endIndex)
		{
			_endIndex = endIndex;
			return this;
		}

		public Emote Build()
		{
			return new Emote(_id, _name, _startIndex, _endIndex);
		}
	}
	public sealed class ErrorEventBuilder : IBuilder<ErrorEvent>
	{
		private string _message;

		private ErrorEventBuilder()
		{
		}

		public ErrorEventBuilder WithMessage(string message)
		{
			_message = message;
			return this;
		}

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

		public ErrorEvent Build()
		{
			return new ErrorEvent
			{
				Message = _message
			};
		}
	}
	public class FromIrcMessageBuilderDataObject
	{
		public IrcMessage Message { get; set; }

		public object AditionalData { get; set; }
	}
	public sealed class GiftedSubscriptionBuilder : IBuilder<GiftedSubscription>, IFromIrcMessageBuilder<GiftedSubscription>
	{
		private readonly List<KeyValuePair<string, string>> _badges = new List<KeyValuePair<string, string>>();

		private readonly List<KeyValuePair<string, string>> _badgeInfo = new List<KeyValuePair<string, string>>();

		private string _color;

		private string _displayName;

		private string _emotes;

		private string _id;

		private bool _isModerator;

		private bool _isSubscriber;

		private bool _isTurbo;

		private string _login;

		private string _msgId;

		private string _msgParamMonths;

		private string _msgParamRecipientDisplayName;

		private string _msgParamRecipientId;

		private string _msgParamRecipientUserName;

		private string _msgParamSubPlanName;

		private SubscriptionPlan _msgParamSubPlan;

		private string _roomId;

		private string _systemMsg;

		private string _systemMsgParsed;

		private string _tmiSentTs;

		private string _userId;

		private UserType _userType;

		private GiftedSubscriptionBuilder()
		{
		}

		public GiftedSubscriptionBuilder WithBadges(params KeyValuePair<string, string>[] badges)
		{
			_badges.AddRange(badges);
			return this;
		}

		public GiftedSubscriptionBuilder WithBadgeInfos(params KeyValuePair<string, string>[] badgeInfos)
		{
			_badgeInfo.AddRange(badgeInfos);
			return this;
		}

		public GiftedSubscriptionBuilder WithColor(string color)
		{
			_color = color;
			return this;
		}

		public GiftedSubscriptionBuilder WithDisplayName(string displayName)
		{
			_displayName = displayName;
			return this;
		}

		public GiftedSubscriptionBuilder WithEmotes(string emotes)
		{
			_emotes = emotes;
			return this;
		}

		public GiftedSubscriptionBuilder WithId(string id)
		{
			_id = id;
			return this;
		}

		public GiftedSubscriptionBuilder WithIsModerator(bool isModerator)
		{
			_isModerator = isModerator;
			return this;
		}

		public GiftedSubscriptionBuilder WithIsSubscriber(bool isSubscriber)
		{
			_isSubscriber = isSubscriber;
			return this;
		}

		public GiftedSubscriptionBuilder WithIsTurbo(bool isTurbo)
		{
			_isTurbo = isTurbo;
			return this;
		}

		public GiftedSubscriptionBuilder WithLogin(string login)
		{
			_login = login;
			return this;
		}

		public GiftedSubscriptionBuilder WithMessageId(string msgId)
		{
			_msgId = msgId;
			return this;
		}

		public GiftedSubscriptionBuilder WithMsgParamCumulativeMonths(string msgParamMonths)
		{
			_msgParamMonths = msgParamMonths;
			return this;
		}

		public GiftedSubscriptionBuilder WithMsgParamRecipientDisplayName(string msgParamRecipientDisplayName)
		{
			_msgParamRecipientDisplayName = msgParamRecipientDisplayName;
			return this;
		}

		public GiftedSubscriptionBuilder WithMsgParamRecipientId(string msgParamRecipientId)
		{
			_msgParamRecipientId = msgParamRecipientId;
			return this;
		}

		public GiftedSubscriptionBuilder WithMsgParamRecipientUserName(string msgParamRecipientUserName)
		{
			_msgParamRecipientUserName = msgParamRecipientUserName;
			return this;
		}

		public GiftedSubscriptionBuilder WithMsgParamSubPlanName(string msgParamSubPlanName)
		{
			_msgParamSubPlanName = msgParamSubPlanName;
			return this;
		}

		public GiftedSubscriptionBuilder WithMsgParamSubPlan(SubscriptionPlan msgParamSubPlan)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			_msgParamSubPlan = msgParamSubPlan;
			return this;
		}

		public GiftedSubscriptionBuilder WithRoomId(string roomId)
		{
			_roomId = roomId;
			return this;
		}

		public GiftedSubscriptionBuilder WithSystemMsg(string systemMsg)
		{
			_systemMsg = systemMsg;
			return this;
		}

		public GiftedSubscriptionBuilder WithSystemMsgParsed(string systemMsgParsed)
		{
			_systemMsgParsed = systemMsgParsed;
			return this;
		}

		public GiftedSubscriptionBuilder WithTmiSentTs(string tmiSentTs)
		{
			_tmiSentTs = tmiSentTs;
			return this;
		}

		public GiftedSubscriptionBuilder WithUserId(string userId)
		{
			_userId = userId;
			return this;
		}

		public GiftedSubscriptionBuilder WithUserType(UserType userType)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			_userType = userType;
			return this;
		}

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

		public GiftedSubscription Build()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			return new GiftedSubscription(_badges, _badgeInfo, _color, _displayName, _emotes, _id, _login, _isModerator, _msgId, _msgParamMonths, _msgParamRecipientDisplayName, _msgParamRecipientId, _msgParamRecipientUserName, _msgParamSubPlanName, _msgParamSubPlan, _roomId, _isSubscriber, _systemMsg, _systemMsgParsed, _tmiSentTs, _isTurbo, _userType, _userId);
		}

		public GiftedSubscription BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject)
		{
			return new GiftedSubscription(fromIrcMessageBuilderDataObject.Message);
		}
	}
	public sealed class HostingStartedBuilder : IBuilder<HostingStarted>, IFromIrcMessageBuilder<HostingStarted>
	{
		private string _hostingChannel;

		private string _targetChannel;

		private int _viewers;

		private HostingStartedBuilder()
		{
		}

		public HostingStartedBuilder WithHostingChannel(string hostingChannel)
		{
			_hostingChannel = hostingChannel;
			return this;
		}

		public HostingStartedBuilder WithTargetChannel(string targetChannel)
		{
			_targetChannel = targetChannel;
			return this;
		}

		public HostingStartedBuilder WithViewvers(int viewers)
		{
			_viewers = viewers;
			return this;
		}

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

		public HostingStarted Build()
		{
			return new HostingStarted(_hostingChannel, _targetChannel, _viewers);
		}

		public HostingStarted BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject)
		{
			return new HostingStarted(fromIrcMessageBuilderDataObject.Message);
		}
	}
	public sealed class HostingStoppedBuilder : IBuilder<HostingStopped>, IFromIrcMessageBuilder<HostingStopped>
	{
		private string _hostingChannel;

		private int _viewers;

		private HostingStoppedBuilder()
		{
		}

		public HostingStoppedBuilder WithHostingChannel(string hostingChannel)
		{
			_hostingChannel = hostingChannel;
			return this;
		}

		public HostingStoppedBuilder WithViewvers(int viewers)
		{
			_viewers = viewers;
			return this;
		}

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

		public HostingStopped Build()
		{
			return new HostingStopped(_hostingChannel, _viewers);
		}

		public HostingStopped BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject)
		{
			return new HostingStopped(fromIrcMessageBuilderDataObject.Message);
		}
	}
	public interface IBuilder<T>
	{
		T Build();
	}
	public interface IFromIrcMessageBuilder<T>
	{
		T BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject);
	}
	public sealed class IrcMessageBuilder : IBuilder<IrcMessage>
	{
		private IrcCommand _ircCommand;

		private readonly List<string> _parameters = new List<string>();

		private string _hostmask;

		private Dictionary<string, string> _tags;

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

		private IrcMessageBuilder()
		{
		}

		public IrcMessageBuilder WithCommand(IrcCommand ircCommand)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			_ircCommand = ircCommand;
			return Builder();
		}

		public IrcMessageBuilder WithParameter(params string[] parameters)
		{
			_parameters.AddRange(parameters);
			return Builder();
		}

		private IrcMessageBuilder Builder()
		{
			return this;
		}

		public IrcMessage BuildWithUserOnly(string user)
		{
			return new IrcMessage(user);
		}

		public IrcMessageBuilder WithHostMask(string hostMask)
		{
			_hostmask = hostMask;
			return Builder();
		}

		public IrcMessageBuilder WithTags(Dictionary<string, string> tags)
		{
			_tags = tags;
			return Builder();
		}

		public IrcMessage Build()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return new IrcMessage(_ircCommand, _parameters.ToArray(), _hostmask, _tags);
		}
	}
	public sealed class OutboundChatMessageBuilder : IBuilder<OutboundChatMessage>
	{
		private string _channel;

		private string _message;

		private string _userName;

		private OutboundChatMessageBuilder()
		{
		}

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

		public OutboundChatMessageBuilder WithChannel(string channel)
		{
			_channel = channel;
			return this;
		}

		public OutboundChatMessageBuilder WithMessage(string message)
		{
			_message = message;
			return this;
		}

		public OutboundChatMessageBuilder WithUsername(string userName)
		{
			_userName = userName;
			return this;
		}

		public OutboundChatMessage Build()
		{
			return new OutboundChatMessage
			{
				Channel = _channel,
				Message = _message,
				Username = _userName
			};
		}
	}
	public sealed class OutboundWhisperMessageBuilder : IBuilder<OutboundWhisperMessage>
	{
		private string _username;

		private string _receiver;

		private string _message;

		private OutboundWhisperMessageBuilder()
		{
		}

		public OutboundWhisperMessageBuilder WithUsername(string username)
		{
			_username = username;
			return this;
		}

		public OutboundWhisperMessageBuilder WithReceiver(string receiver)
		{
			_receiver = receiver;
			return this;
		}

		public OutboundWhisperMessageBuilder WithMessage(string message)
		{
			_message = message;
			return this;
		}

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

		public OutboundWhisperMessage Build()
		{
			return new OutboundWhisperMessage
			{
				Message = _message,
				Receiver = _receiver,
				Username = _username
			};
		}
	}
	public sealed class OutgoingMessageBuilder : IBuilder<OutgoingMessage>
	{
		private string _channel;

		private string _message;

		private int _nonce;

		private string _sender;

		private MessageState _messageState;

		private OutgoingMessageBuilder()
		{
		}

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

		public OutgoingMessageBuilder WithChannel(string channel)
		{
			_channel = channel;
			return this;
		}

		public OutgoingMessageBuilder WithMessage(string message)
		{
			_message = message;
			return this;
		}

		public OutgoingMessageBuilder WithNonce(int nonce)
		{
			_nonce = nonce;
			return this;
		}

		public OutgoingMessageBuilder WithSender(string sender)
		{
			_sender = sender;
			return this;
		}

		public OutgoingMessageBuilder WithMessageState(MessageState messageState)
		{
			_messageState = messageState;
			return this;
		}

		public OutgoingMessage Build()
		{
			return new OutgoingMessage
			{
				Channel = _channel,
				Message = _message,
				Nonce = _nonce,
				Sender = _sender,
				State = _messageState
			};
		}
	}
	public sealed class RaidNotificationBuilder : IBuilder<RaidNotification>, IFromIrcMessageBuilder<RaidNotification>
	{
		private readonly List<KeyValuePair<string, string>> _badges = new List<KeyValuePair<string, string>>();

		private readonly List<KeyValuePair<string, string>> _badgeInfo = new List<KeyValuePair<string, string>>();

		private string _color;

		private string _displayName;

		private string _emotes;

		private string _id;

		private bool _isModerator;

		private bool _isSubscriber;

		private bool _isTurbo;

		private string _login;

		private string _msgId;

		private string _msgParamDisplayName;

		private string _msgParamLogin;

		private string _msgParamViewerCount;

		private string _roomId;

		private string _systemMsg;

		private string _systemMsgParsed;

		private string _tmiSentTs;

		private string _userId;

		private UserType _userType;

		public RaidNotificationBuilder WithBadges(params KeyValuePair<string, string>[] badges)
		{
			_badges.AddRange(badges);
			return this;
		}

		public RaidNotificationBuilder WithBadgeInfos(params KeyValuePair<string, string>[] badgeInfos)
		{
			_badgeInfo.AddRange(badgeInfos);
			return this;
		}

		public RaidNotificationBuilder WithColor(string color)
		{
			_color = color;
			return this;
		}

		public RaidNotificationBuilder WithDisplayName(string displayName)
		{
			_displayName = displayName;
			return this;
		}

		public RaidNotificationBuilder WithEmotes(string emotes)
		{
			_emotes = emotes;
			return this;
		}

		public RaidNotificationBuilder WithId(string id)
		{
			_id = id;
			return this;
		}

		public RaidNotificationBuilder WithIsModerator(bool isModerator)
		{
			_isModerator = isModerator;
			return this;
		}

		public RaidNotificationBuilder WithIsSubscriber(bool isSubscriber)
		{
			_isSubscriber = isSubscriber;
			return this;
		}

		public RaidNotificationBuilder WithIsTurbo(bool isTurbo)
		{
			_isTurbo = isTurbo;
			return this;
		}

		public RaidNotificationBuilder WithLogin(string login)
		{
			_login = login;
			return this;
		}

		public RaidNotificationBuilder WithMessageId(string msgId)
		{
			_msgId = msgId;
			return this;
		}

		public RaidNotificationBuilder WithMsgParamDisplayName(string msgParamDisplayName)
		{
			_msgParamDisplayName = msgParamDisplayName;
			return this;
		}

		public RaidNotificationBuilder WithMsgParamLogin(string msgParamLogin)
		{
			_msgParamLogin = msgParamLogin;
			return this;
		}

		public RaidNotificationBuilder WithMsgParamViewerCount(string msgParamViewerCount)
		{
			_msgParamViewerCount = msgParamViewerCount;
			return this;
		}

		public RaidNotificationBuilder WithRoomId(string roomId)
		{
			_roomId = roomId;
			return this;
		}

		public RaidNotificationBuilder WithSystemMsg(string systemMsg)
		{
			_systemMsg = systemMsg;
			return this;
		}

		public RaidNotificationBuilder WithSystemMsgParsed(string systemMsgParsed)
		{
			_systemMsgParsed = systemMsgParsed;
			return this;
		}

		public RaidNotificationBuilder WithTmiSentTs(string tmiSentTs)
		{
			_tmiSentTs = tmiSentTs;
			return this;
		}

		public RaidNotificationBuilder WithUserId(string userId)
		{
			_userId = userId;
			return this;
		}

		public RaidNotificationBuilder WithUserType(UserType userType)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			_userType = userType;
			return this;
		}

		private RaidNotificationBuilder()
		{
		}

		public RaidNotification Build()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			return new RaidNotification(_badges, _badgeInfo, _color, _displayName, _emotes, _id, _login, _isModerator, _msgId, _msgParamDisplayName, _msgParamLogin, _msgParamViewerCount, _roomId, _isSubscriber, _systemMsg, _systemMsgParsed, _tmiSentTs, _isTurbo, _userType, _userId);
		}

		public RaidNotification BuildFromIrcMessage(FromIrcMessageBuilderDataObject fromIrcMessageBuilderDataObject)
		{
			return new RaidNotification(fromIrcMessageBuilderDataObject.Message);
		}
	}
	public sealed class ReSubscriberBuilder : SubscriberBaseBuilder, IBuilder<ReSubscriber>, IFromIrcMessageBuilder<ReSu

lib/TwitchLib.Communication.dll

Decompiled 5 months ago
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TwitchLib.Communication.Clients;
using TwitchLib.Communication.Enums;
using TwitchLib.Communication.Events;
using TwitchLib.Communication.Interfaces;
using TwitchLib.Communication.Models;
using TwitchLib.Communication.Services;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy, Prom3theu5, Syzuna, LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyDescription("Connection library used throughout TwitchLib to replace third party depedencies.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TwitchLib.Communication")]
[assembly: AssemblyTitle("TwitchLib.Communication")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/TwitchLib/TwitchLib.Communication")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace TwitchLib.Communication.Services
{
	public class Throttlers
	{
		public readonly BlockingCollection<Tuple<DateTime, string>> SendQueue = new BlockingCollection<Tuple<DateTime, string>>();

		public readonly BlockingCollection<Tuple<DateTime, string>> WhisperQueue = new BlockingCollection<Tuple<DateTime, string>>();

		public bool ResetThrottlerRunning;

		public bool ResetWhisperThrottlerRunning;

		public int SentCount = 0;

		public int WhispersSent = 0;

		public Task ResetThrottler;

		public Task ResetWhisperThrottler;

		private readonly TimeSpan _throttlingPeriod;

		private readonly TimeSpan _whisperThrottlingPeriod;

		private readonly IClient _client;

		public bool Reconnecting { get; set; } = false;


		public bool ShouldDispose { get; set; } = false;


		public CancellationTokenSource TokenSource { get; set; }

		public Throttlers(IClient client, TimeSpan throttlingPeriod, TimeSpan whisperThrottlingPeriod)
		{
			_throttlingPeriod = throttlingPeriod;
			_whisperThrottlingPeriod = whisperThrottlingPeriod;
			_client = client;
		}

		public void StartThrottlingWindowReset()
		{
			ResetThrottler = Task.Run(async delegate
			{
				ResetThrottlerRunning = true;
				while (!ShouldDispose && !Reconnecting)
				{
					Interlocked.Exchange(ref SentCount, 0);
					await Task.Delay(_throttlingPeriod, TokenSource.Token);
				}
				ResetThrottlerRunning = false;
				return Task.CompletedTask;
			});
		}

		public void StartWhisperThrottlingWindowReset()
		{
			ResetWhisperThrottler = Task.Run(async delegate
			{
				ResetWhisperThrottlerRunning = true;
				while (!ShouldDispose && !Reconnecting)
				{
					Interlocked.Exchange(ref WhispersSent, 0);
					await Task.Delay(_whisperThrottlingPeriod, TokenSource.Token);
				}
				ResetWhisperThrottlerRunning = false;
				return Task.CompletedTask;
			});
		}

		public void IncrementSentCount()
		{
			Interlocked.Increment(ref SentCount);
		}

		public void IncrementWhisperCount()
		{
			Interlocked.Increment(ref WhispersSent);
		}

		public Task StartSenderTask()
		{
			StartThrottlingWindowReset();
			return Task.Run(async delegate
			{
				try
				{
					while (!ShouldDispose)
					{
						await Task.Delay(_client.Options.SendDelay);
						if (SentCount == _client.Options.MessagesAllowedInPeriod)
						{
							_client.MessageThrottled(new OnMessageThrottledEventArgs
							{
								Message = "Message Throttle Occured. Too Many Messages within the period specified in WebsocketClientOptions.",
								AllowedInPeriod = _client.Options.MessagesAllowedInPeriod,
								Period = _client.Options.ThrottlingPeriod,
								SentMessageCount = Interlocked.CompareExchange(ref SentCount, 0, 0)
							});
						}
						else if (_client.IsConnected && !ShouldDispose)
						{
							Tuple<DateTime, string> msg = SendQueue.Take(TokenSource.Token);
							if (!(msg.Item1.Add(_client.Options.SendCacheItemTimeout) < DateTime.UtcNow))
							{
								try
								{
									IClient client = _client;
									IClient client2 = client;
									if (client2 is WebSocketClient ws)
									{
										await ws.SendAsync(Encoding.UTF8.GetBytes(msg.Item2));
									}
									else if (client2 is TwitchLib.Communication.Clients.TcpClient tcp)
									{
										await tcp.SendAsync(msg.Item2);
									}
									IncrementSentCount();
								}
								catch (Exception ex3)
								{
									Exception ex2 = ex3;
									_client.SendFailed(new OnSendFailedEventArgs
									{
										Data = msg.Item2,
										Exception = ex2
									});
									break;
								}
							}
						}
					}
				}
				catch (Exception ex3)
				{
					Exception ex = ex3;
					_client.SendFailed(new OnSendFailedEventArgs
					{
						Data = "",
						Exception = ex
					});
					_client.Error(new OnErrorEventArgs
					{
						Exception = ex
					});
				}
			});
		}

		public Task StartWhisperSenderTask()
		{
			StartWhisperThrottlingWindowReset();
			return Task.Run(async delegate
			{
				try
				{
					while (!ShouldDispose)
					{
						await Task.Delay(_client.Options.SendDelay);
						if (WhispersSent == _client.Options.WhispersAllowedInPeriod)
						{
							_client.WhisperThrottled(new OnWhisperThrottledEventArgs
							{
								Message = "Whisper Throttle Occured. Too Many Whispers within the period specified in ClientOptions.",
								AllowedInPeriod = _client.Options.WhispersAllowedInPeriod,
								Period = _client.Options.WhisperThrottlingPeriod,
								SentWhisperCount = Interlocked.CompareExchange(ref WhispersSent, 0, 0)
							});
						}
						else if (_client.IsConnected && !ShouldDispose)
						{
							Tuple<DateTime, string> msg = WhisperQueue.Take(TokenSource.Token);
							if (!(msg.Item1.Add(_client.Options.SendCacheItemTimeout) < DateTime.UtcNow))
							{
								try
								{
									IClient client = _client;
									IClient client2 = client;
									if (client2 is WebSocketClient ws)
									{
										await ws.SendAsync(Encoding.UTF8.GetBytes(msg.Item2));
									}
									else if (client2 is TwitchLib.Communication.Clients.TcpClient tcp)
									{
										await tcp.SendAsync(msg.Item2);
									}
									IncrementSentCount();
								}
								catch (Exception ex3)
								{
									Exception ex2 = ex3;
									_client.SendFailed(new OnSendFailedEventArgs
									{
										Data = msg.Item2,
										Exception = ex2
									});
									break;
								}
							}
						}
					}
				}
				catch (Exception ex3)
				{
					Exception ex = ex3;
					_client.SendFailed(new OnSendFailedEventArgs
					{
						Data = "",
						Exception = ex
					});
					_client.Error(new OnErrorEventArgs
					{
						Exception = ex
					});
				}
			});
		}
	}
}
namespace TwitchLib.Communication.Models
{
	public class ClientOptions : IClientOptions
	{
		public int SendQueueCapacity { get; set; } = 10000;


		public TimeSpan SendCacheItemTimeout { get; set; } = TimeSpan.FromMinutes(30.0);


		public ushort SendDelay { get; set; } = 50;


		public ReconnectionPolicy ReconnectionPolicy { get; set; } = new ReconnectionPolicy(3000, (int?)10);


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


		public int DisconnectWait { get; set; } = 20000;


		public ClientType ClientType { get; set; } = ClientType.Chat;


		public TimeSpan ThrottlingPeriod { get; set; } = TimeSpan.FromSeconds(30.0);


		public int MessagesAllowedInPeriod { get; set; } = 100;


		public TimeSpan WhisperThrottlingPeriod { get; set; } = TimeSpan.FromSeconds(60.0);


		public int WhispersAllowedInPeriod { get; set; } = 100;


		public int WhisperQueueCapacity { get; set; } = 10000;

	}
	public class ReconnectionPolicy
	{
		private readonly int _reconnectStepInterval;

		private readonly int? _initMaxAttempts;

		private int _minReconnectInterval;

		private readonly int _maxReconnectInterval;

		private int? _maxAttempts;

		private int _attemptsMade;

		public ReconnectionPolicy()
		{
			_reconnectStepInterval = 3000;
			_minReconnectInterval = 3000;
			_maxReconnectInterval = 30000;
			_maxAttempts = null;
			_initMaxAttempts = null;
			_attemptsMade = 0;
		}

		public void SetMaxAttempts(int attempts)
		{
			_maxAttempts = attempts;
		}

		public void Reset()
		{
			_attemptsMade = 0;
			_minReconnectInterval = _reconnectStepInterval;
			_maxAttempts = _initMaxAttempts;
		}

		public void SetAttemptsMade(int count)
		{
			_attemptsMade = count;
		}

		public ReconnectionPolicy(int minReconnectInterval, int maxReconnectInterval, int? maxAttempts)
		{
			_reconnectStepInterval = minReconnectInterval;
			_minReconnectInterval = ((minReconnectInterval > maxReconnectInterval) ? maxReconnectInterval : minReconnectInterval);
			_maxReconnectInterval = maxReconnectInterval;
			_maxAttempts = maxAttempts;
			_initMaxAttempts = maxAttempts;
			_attemptsMade = 0;
		}

		public ReconnectionPolicy(int minReconnectInterval, int maxReconnectInterval)
		{
			_reconnectStepInterval = minReconnectInterval;
			_minReconnectInterval = ((minReconnectInterval > maxReconnectInterval) ? maxReconnectInterval : minReconnectInterval);
			_maxReconnectInterval = maxReconnectInterval;
			_maxAttempts = null;
			_initMaxAttempts = null;
			_attemptsMade = 0;
		}

		public ReconnectionPolicy(int reconnectInterval)
		{
			_reconnectStepInterval = reconnectInterval;
			_minReconnectInterval = reconnectInterval;
			_maxReconnectInterval = reconnectInterval;
			_maxAttempts = null;
			_initMaxAttempts = null;
			_attemptsMade = 0;
		}

		public ReconnectionPolicy(int reconnectInterval, int? maxAttempts)
		{
			_reconnectStepInterval = reconnectInterval;
			_minReconnectInterval = reconnectInterval;
			_maxReconnectInterval = reconnectInterval;
			_maxAttempts = maxAttempts;
			_initMaxAttempts = maxAttempts;
			_attemptsMade = 0;
		}

		internal void ProcessValues()
		{
			_attemptsMade++;
			if (_minReconnectInterval < _maxReconnectInterval)
			{
				_minReconnectInterval += _reconnectStepInterval;
			}
			if (_minReconnectInterval > _maxReconnectInterval)
			{
				_minReconnectInterval = _maxReconnectInterval;
			}
		}

		public int GetReconnectInterval()
		{
			return _minReconnectInterval;
		}

		public bool AreAttemptsComplete()
		{
			return _attemptsMade == _maxAttempts;
		}
	}
}
namespace TwitchLib.Communication.Interfaces
{
	public interface IClient
	{
		TimeSpan DefaultKeepAliveInterval { get; set; }

		int SendQueueLength { get; }

		int WhisperQueueLength { get; }

		bool IsConnected { get; }

		IClientOptions Options { get; }

		event EventHandler<OnConnectedEventArgs> OnConnected;

		event EventHandler<OnDataEventArgs> OnData;

		event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

		event EventHandler<OnErrorEventArgs> OnError;

		event EventHandler<OnFatalErrorEventArgs> OnFatality;

		event EventHandler<OnMessageEventArgs> OnMessage;

		event EventHandler<OnMessageThrottledEventArgs> OnMessageThrottled;

		event EventHandler<OnWhisperThrottledEventArgs> OnWhisperThrottled;

		event EventHandler<OnSendFailedEventArgs> OnSendFailed;

		event EventHandler<OnStateChangedEventArgs> OnStateChanged;

		event EventHandler<OnReconnectedEventArgs> OnReconnected;

		void Close(bool callDisconnect = true);

		void Dispose();

		bool Open();

		bool Send(string message);

		bool SendWhisper(string message);

		void Reconnect();

		void MessageThrottled(OnMessageThrottledEventArgs eventArgs);

		void SendFailed(OnSendFailedEventArgs eventArgs);

		void Error(OnErrorEventArgs eventArgs);

		void WhisperThrottled(OnWhisperThrottledEventArgs eventArgs);
	}
	public interface IClientOptions
	{
		ClientType ClientType { get; set; }

		int DisconnectWait { get; set; }

		int MessagesAllowedInPeriod { get; set; }

		ReconnectionPolicy ReconnectionPolicy { get; set; }

		TimeSpan SendCacheItemTimeout { get; set; }

		ushort SendDelay { get; set; }

		int SendQueueCapacity { get; set; }

		TimeSpan ThrottlingPeriod { get; set; }

		bool UseSsl { get; set; }

		TimeSpan WhisperThrottlingPeriod { get; set; }

		int WhispersAllowedInPeriod { get; set; }

		int WhisperQueueCapacity { get; set; }
	}
}
namespace TwitchLib.Communication.Events
{
	public class OnConnectedEventArgs : EventArgs
	{
	}
	public class OnDataEventArgs : EventArgs
	{
		public byte[] Data;
	}
	public class OnDisconnectedEventArgs : EventArgs
	{
	}
	public class OnErrorEventArgs : EventArgs
	{
		public Exception Exception { get; set; }
	}
	public class OnFatalErrorEventArgs : EventArgs
	{
		public string Reason;
	}
	public class OnMessageEventArgs : EventArgs
	{
		public string Message;
	}
	public class OnMessageThrottledEventArgs : EventArgs
	{
		public string Message { get; set; }

		public int SentMessageCount { get; set; }

		public TimeSpan Period { get; set; }

		public int AllowedInPeriod { get; set; }
	}
	public class OnReconnectedEventArgs : EventArgs
	{
	}
	public class OnSendFailedEventArgs : EventArgs
	{
		public string Data;

		public Exception Exception;
	}
	public class OnStateChangedEventArgs : EventArgs
	{
		public bool IsConnected;

		public bool WasConnected;
	}
	public class OnWhisperThrottledEventArgs : EventArgs
	{
		public string Message { get; set; }

		public int SentWhisperCount { get; set; }

		public TimeSpan Period { get; set; }

		public int AllowedInPeriod { get; set; }
	}
}
namespace TwitchLib.Communication.Enums
{
	public enum ClientType
	{
		Chat,
		PubSub
	}
}
namespace TwitchLib.Communication.Clients
{
	public class TcpClient : IClient
	{
		private readonly string _server = "irc.chat.twitch.tv";

		private StreamReader _reader;

		private StreamWriter _writer;

		private readonly Throttlers _throttlers;

		private CancellationTokenSource _tokenSource = new CancellationTokenSource();

		private bool _stopServices;

		private bool _networkServicesRunning;

		private Task[] _networkTasks;

		private Task _monitorTask;

		public TimeSpan DefaultKeepAliveInterval { get; set; }

		public int SendQueueLength => _throttlers.SendQueue.Count;

		public int WhisperQueueLength => _throttlers.WhisperQueue.Count;

		public bool IsConnected => Client?.Connected ?? false;

		public IClientOptions Options { get; }

		private int Port => (Options != null) ? (Options.UseSsl ? 443 : 80) : 0;

		public System.Net.Sockets.TcpClient Client { get; private set; }

		public event EventHandler<OnConnectedEventArgs> OnConnected;

		public event EventHandler<OnDataEventArgs> OnData;

		public event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

		public event EventHandler<OnErrorEventArgs> OnError;

		public event EventHandler<OnFatalErrorEventArgs> OnFatality;

		public event EventHandler<OnMessageEventArgs> OnMessage;

		public event EventHandler<OnMessageThrottledEventArgs> OnMessageThrottled;

		public event EventHandler<OnWhisperThrottledEventArgs> OnWhisperThrottled;

		public event EventHandler<OnSendFailedEventArgs> OnSendFailed;

		public event EventHandler<OnStateChangedEventArgs> OnStateChanged;

		public event EventHandler<OnReconnectedEventArgs> OnReconnected;

		public TcpClient(IClientOptions options = null)
		{
			Options = options ?? new ClientOptions();
			_throttlers = new Throttlers(this, Options.ThrottlingPeriod, Options.WhisperThrottlingPeriod)
			{
				TokenSource = _tokenSource
			};
			InitializeClient();
		}

		private void InitializeClient()
		{
			Client = new System.Net.Sockets.TcpClient();
			if (_monitorTask == null)
			{
				_monitorTask = StartMonitorTask();
			}
			else if (_monitorTask.IsCompleted)
			{
				_monitorTask = StartMonitorTask();
			}
		}

		public bool Open()
		{
			try
			{
				if (IsConnected)
				{
					return true;
				}
				Task.Run(delegate
				{
					InitializeClient();
					Client.Connect(_server, Port);
					if (Options.UseSsl)
					{
						SslStream sslStream = new SslStream(Client.GetStream(), leaveInnerStreamOpen: false);
						sslStream.AuthenticateAsClient(_server);
						_reader = new StreamReader(sslStream);
						_writer = new StreamWriter(sslStream);
					}
					else
					{
						_reader = new StreamReader(Client.GetStream());
						_writer = new StreamWriter(Client.GetStream());
					}
				}).Wait(10000);
				if (!IsConnected)
				{
					return Open();
				}
				StartNetworkServices();
				return true;
			}
			catch (Exception)
			{
				InitializeClient();
				return false;
			}
		}

		public void Close(bool callDisconnect = true)
		{
			_reader?.Dispose();
			_writer?.Dispose();
			Client?.Close();
			_stopServices = callDisconnect;
			CleanupServices();
			InitializeClient();
			this.OnDisconnected?.Invoke(this, new OnDisconnectedEventArgs());
		}

		public void Reconnect()
		{
			Close();
			Open();
			this.OnReconnected?.Invoke(this, new OnReconnectedEventArgs());
		}

		public bool Send(string message)
		{
			try
			{
				if (!IsConnected || SendQueueLength >= Options.SendQueueCapacity)
				{
					return false;
				}
				_throttlers.SendQueue.Add(new Tuple<DateTime, string>(DateTime.UtcNow, message));
				return true;
			}
			catch (Exception exception)
			{
				this.OnError?.Invoke(this, new OnErrorEventArgs
				{
					Exception = exception
				});
				throw;
			}
		}

		public bool SendWhisper(string message)
		{
			try
			{
				if (!IsConnected || WhisperQueueLength >= Options.WhisperQueueCapacity)
				{
					return false;
				}
				_throttlers.WhisperQueue.Add(new Tuple<DateTime, string>(DateTime.UtcNow, message));
				return true;
			}
			catch (Exception exception)
			{
				this.OnError?.Invoke(this, new OnErrorEventArgs
				{
					Exception = exception
				});
				throw;
			}
		}

		private void StartNetworkServices()
		{
			_networkServicesRunning = true;
			_networkTasks = new Task[3]
			{
				StartListenerTask(),
				_throttlers.StartSenderTask(),
				_throttlers.StartWhisperSenderTask()
			}.ToArray();
			if (_networkTasks.Any((Task c) => c.IsFaulted))
			{
				_networkServicesRunning = false;
				CleanupServices();
			}
		}

		public Task SendAsync(string message)
		{
			return Task.Run(async delegate
			{
				await _writer.WriteLineAsync(message);
				await _writer.FlushAsync();
			});
		}

		private Task StartListenerTask()
		{
			return Task.Run(async delegate
			{
				while (IsConnected && _networkServicesRunning)
				{
					try
					{
						string input = await _reader.ReadLineAsync();
						this.OnMessage?.Invoke(this, new OnMessageEventArgs
						{
							Message = input
						});
					}
					catch (Exception ex)
					{
						this.OnError?.Invoke(this, new OnErrorEventArgs
						{
							Exception = ex
						});
					}
				}
			});
		}

		private Task StartMonitorTask()
		{
			return Task.Run(delegate
			{
				bool flag = false;
				try
				{
					bool isConnected = IsConnected;
					while (!_tokenSource.IsCancellationRequested)
					{
						if (isConnected == IsConnected)
						{
							Thread.Sleep(200);
						}
						else
						{
							this.OnStateChanged?.Invoke(this, new OnStateChangedEventArgs
							{
								IsConnected = IsConnected,
								WasConnected = isConnected
							});
							if (IsConnected)
							{
								this.OnConnected?.Invoke(this, new OnConnectedEventArgs());
							}
							if (!IsConnected && !_stopServices)
							{
								if (isConnected && Options.ReconnectionPolicy != null && !Options.ReconnectionPolicy.AreAttemptsComplete())
								{
									flag = true;
									break;
								}
								this.OnDisconnected?.Invoke(this, new OnDisconnectedEventArgs());
							}
							isConnected = IsConnected;
						}
					}
				}
				catch (Exception exception)
				{
					this.OnError?.Invoke(this, new OnErrorEventArgs
					{
						Exception = exception
					});
				}
				if (flag && !_stopServices)
				{
					Reconnect();
				}
			}, _tokenSource.Token);
		}

		private void CleanupServices()
		{
			_tokenSource.Cancel();
			_tokenSource = new CancellationTokenSource();
			_throttlers.TokenSource = _tokenSource;
			if (_stopServices)
			{
				Task[] networkTasks = _networkTasks;
				if (networkTasks != null && networkTasks.Length != 0 && !Task.WaitAll(_networkTasks, 15000))
				{
					this.OnFatality?.Invoke(this, new OnFatalErrorEventArgs
					{
						Reason = "Fatal network error. Network services fail to shut down."
					});
					_stopServices = false;
					_throttlers.Reconnecting = false;
					_networkServicesRunning = false;
				}
			}
		}

		public void WhisperThrottled(OnWhisperThrottledEventArgs eventArgs)
		{
			this.OnWhisperThrottled?.Invoke(this, eventArgs);
		}

		public void MessageThrottled(OnMessageThrottledEventArgs eventArgs)
		{
			this.OnMessageThrottled?.Invoke(this, eventArgs);
		}

		public void SendFailed(OnSendFailedEventArgs eventArgs)
		{
			this.OnSendFailed?.Invoke(this, eventArgs);
		}

		public void Error(OnErrorEventArgs eventArgs)
		{
			this.OnError?.Invoke(this, eventArgs);
		}

		public void Dispose()
		{
			Close();
			_throttlers.ShouldDispose = true;
			_tokenSource.Cancel();
			Thread.Sleep(500);
			_tokenSource.Dispose();
			Client?.Dispose();
			GC.Collect();
		}
	}
	public class WebSocketClient : IClient
	{
		private readonly Throttlers _throttlers;

		private CancellationTokenSource _tokenSource = new CancellationTokenSource();

		private bool _stopServices;

		private bool _networkServicesRunning;

		private Task[] _networkTasks;

		private Task _monitorTask;

		public TimeSpan DefaultKeepAliveInterval { get; set; }

		public int SendQueueLength => _throttlers.SendQueue.Count;

		public int WhisperQueueLength => _throttlers.WhisperQueue.Count;

		public bool IsConnected
		{
			get
			{
				ClientWebSocket client = Client;
				return client != null && client.State == WebSocketState.Open;
			}
		}

		public IClientOptions Options { get; }

		public ClientWebSocket Client { get; private set; }

		private string Url { get; }

		public event EventHandler<OnConnectedEventArgs> OnConnected;

		public event EventHandler<OnDataEventArgs> OnData;

		public event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

		public event EventHandler<OnErrorEventArgs> OnError;

		public event EventHandler<OnFatalErrorEventArgs> OnFatality;

		public event EventHandler<OnMessageEventArgs> OnMessage;

		public event EventHandler<OnMessageThrottledEventArgs> OnMessageThrottled;

		public event EventHandler<OnWhisperThrottledEventArgs> OnWhisperThrottled;

		public event EventHandler<OnSendFailedEventArgs> OnSendFailed;

		public event EventHandler<OnStateChangedEventArgs> OnStateChanged;

		public event EventHandler<OnReconnectedEventArgs> OnReconnected;

		public WebSocketClient(IClientOptions options = null)
		{
			Options = options ?? new ClientOptions();
			switch (Options.ClientType)
			{
			case ClientType.Chat:
				Url = (Options.UseSsl ? "wss://irc-ws.chat.twitch.tv:443" : "ws://irc-ws.chat.twitch.tv:80");
				break;
			case ClientType.PubSub:
				Url = (Options.UseSsl ? "wss://pubsub-edge.twitch.tv:443" : "ws://pubsub-edge.twitch.tv:80");
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			_throttlers = new Throttlers(this, Options.ThrottlingPeriod, Options.WhisperThrottlingPeriod)
			{
				TokenSource = _tokenSource
			};
		}

		private void InitializeClient()
		{
			Client?.Abort();
			Client = new ClientWebSocket();
			if (_monitorTask == null)
			{
				_monitorTask = StartMonitorTask();
			}
			else if (_monitorTask.IsCompleted)
			{
				_monitorTask = StartMonitorTask();
			}
		}

		public bool Open()
		{
			try
			{
				if (IsConnected)
				{
					return true;
				}
				InitializeClient();
				Client.ConnectAsync(new Uri(Url), _tokenSource.Token).Wait(10000);
				if (!IsConnected)
				{
					return Open();
				}
				StartNetworkServices();
				return true;
			}
			catch (WebSocketException)
			{
				InitializeClient();
				return false;
			}
		}

		public void Close(bool callDisconnect = true)
		{
			Client?.Abort();
			_stopServices = callDisconnect;
			CleanupServices();
			InitializeClient();
			this.OnDisconnected?.Invoke(this, new OnDisconnectedEventArgs());
		}

		public void Reconnect()
		{
			Close();
			Open();
			this.OnReconnected?.Invoke(this, new OnReconnectedEventArgs());
		}

		public bool Send(string message)
		{
			try
			{
				if (!IsConnected || SendQueueLength >= Options.SendQueueCapacity)
				{
					return false;
				}
				_throttlers.SendQueue.Add(new Tuple<DateTime, string>(DateTime.UtcNow, message));
				return true;
			}
			catch (Exception exception)
			{
				this.OnError?.Invoke(this, new OnErrorEventArgs
				{
					Exception = exception
				});
				throw;
			}
		}

		public bool SendWhisper(string message)
		{
			try
			{
				if (!IsConnected || WhisperQueueLength >= Options.WhisperQueueCapacity)
				{
					return false;
				}
				_throttlers.WhisperQueue.Add(new Tuple<DateTime, string>(DateTime.UtcNow, message));
				return true;
			}
			catch (Exception exception)
			{
				this.OnError?.Invoke(this, new OnErrorEventArgs
				{
					Exception = exception
				});
				throw;
			}
		}

		private void StartNetworkServices()
		{
			_networkServicesRunning = true;
			_networkTasks = new Task[3]
			{
				StartListenerTask(),
				_throttlers.StartSenderTask(),
				_throttlers.StartWhisperSenderTask()
			}.ToArray();
			if (_networkTasks.Any((Task c) => c.IsFaulted))
			{
				_networkServicesRunning = false;
				CleanupServices();
			}
		}

		public Task SendAsync(byte[] message)
		{
			return Client.SendAsync(new ArraySegment<byte>(message), WebSocketMessageType.Text, endOfMessage: true, _tokenSource.Token);
		}

		private Task StartListenerTask()
		{
			return Task.Run(async delegate
			{
				string message = "";
				while (IsConnected && _networkServicesRunning)
				{
					byte[] buffer = new byte[1024];
					WebSocketReceiveResult result;
					try
					{
						result = await Client.ReceiveAsync(new ArraySegment<byte>(buffer), _tokenSource.Token);
					}
					catch
					{
						InitializeClient();
						break;
					}
					if (result != null)
					{
						switch (result.MessageType)
						{
						case WebSocketMessageType.Close:
							Close();
							break;
						case WebSocketMessageType.Text:
							if (!result.EndOfMessage)
							{
								message += Encoding.UTF8.GetString(buffer).TrimEnd(new char[1]);
								continue;
							}
							message += Encoding.UTF8.GetString(buffer).TrimEnd(new char[1]);
							this.OnMessage?.Invoke(this, new OnMessageEventArgs
							{
								Message = message
							});
							break;
						default:
							throw new ArgumentOutOfRangeException();
						case WebSocketMessageType.Binary:
							break;
						}
						message = "";
					}
				}
			});
		}

		private Task StartMonitorTask()
		{
			return Task.Run(delegate
			{
				bool flag = false;
				try
				{
					bool isConnected = IsConnected;
					while (!_tokenSource.IsCancellationRequested)
					{
						if (isConnected == IsConnected)
						{
							Thread.Sleep(200);
						}
						else
						{
							this.OnStateChanged?.Invoke(this, new OnStateChangedEventArgs
							{
								IsConnected = (Client.State == WebSocketState.Open),
								WasConnected = isConnected
							});
							if (IsConnected)
							{
								this.OnConnected?.Invoke(this, new OnConnectedEventArgs());
							}
							if (!IsConnected && !_stopServices)
							{
								if (isConnected && Options.ReconnectionPolicy != null && !Options.ReconnectionPolicy.AreAttemptsComplete())
								{
									flag = true;
									break;
								}
								this.OnDisconnected?.Invoke(this, new OnDisconnectedEventArgs());
								if (Client.CloseStatus.HasValue && Client.CloseStatus != WebSocketCloseStatus.NormalClosure)
								{
									this.OnError?.Invoke(this, new OnErrorEventArgs
									{
										Exception = new Exception(Client.CloseStatus.ToString() + " " + Client.CloseStatusDescription)
									});
								}
							}
							isConnected = IsConnected;
						}
					}
				}
				catch (Exception exception)
				{
					this.OnError?.Invoke(this, new OnErrorEventArgs
					{
						Exception = exception
					});
				}
				if (flag && !_stopServices)
				{
					Reconnect();
				}
			}, _tokenSource.Token);
		}

		private void CleanupServices()
		{
			_tokenSource.Cancel();
			_tokenSource = new CancellationTokenSource();
			_throttlers.TokenSource = _tokenSource;
			if (_stopServices)
			{
				Task[] networkTasks = _networkTasks;
				if (networkTasks != null && networkTasks.Length != 0 && !Task.WaitAll(_networkTasks, 15000))
				{
					this.OnFatality?.Invoke(this, new OnFatalErrorEventArgs
					{
						Reason = "Fatal network error. Network services fail to shut down."
					});
					_stopServices = false;
					_throttlers.Reconnecting = false;
					_networkServicesRunning = false;
				}
			}
		}

		public void WhisperThrottled(OnWhisperThrottledEventArgs eventArgs)
		{
			this.OnWhisperThrottled?.Invoke(this, eventArgs);
		}

		public void MessageThrottled(OnMessageThrottledEventArgs eventArgs)
		{
			this.OnMessageThrottled?.Invoke(this, eventArgs);
		}

		public void SendFailed(OnSendFailedEventArgs eventArgs)
		{
			this.OnSendFailed?.Invoke(this, eventArgs);
		}

		public void Error(OnErrorEventArgs eventArgs)
		{
			this.OnError?.Invoke(this, eventArgs);
		}

		public void Dispose()
		{
			Close();
			_throttlers.ShouldDispose = true;
			_tokenSource.Cancel();
			Thread.Sleep(500);
			_tokenSource.Dispose();
			Client?.Dispose();
			GC.Collect();
		}
	}
}

lib/TwitchLib.PubSub.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Timers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using TwitchLib.Communication.Clients;
using TwitchLib.Communication.Enums;
using TwitchLib.Communication.Events;
using TwitchLib.Communication.Interfaces;
using TwitchLib.Communication.Models;
using TwitchLib.PubSub.Common;
using TwitchLib.PubSub.Enums;
using TwitchLib.PubSub.Events;
using TwitchLib.PubSub.Interfaces;
using TwitchLib.PubSub.Models;
using TwitchLib.PubSub.Models.Responses;
using TwitchLib.PubSub.Models.Responses.Messages;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("swiftyspiffy,Prom3theu5,Syzuna,LuckyNoS7evin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2019")]
[assembly: AssemblyDescription("PubSub component of TwitchLib. This component allows you to access Twitch's PubSub event system and subscribe/unsubscribe from topics.")]
[assembly: AssemblyFileVersion("3.1.4")]
[assembly: AssemblyInformationalVersion("3.1.5")]
[assembly: AssemblyProduct("TwitchLib.PubSub")]
[assembly: AssemblyTitle("TwitchLib.PubSub")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/TwitchLib/TwitchLib.PubSub")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("3.1.4.0")]
namespace TwitchLib.PubSub
{
	public class TwitchPubSub : ITwitchPubSub
	{
		private readonly WebSocketClient _socket;

		private readonly List<PreviousRequest> _previousRequests = new List<PreviousRequest>();

		private readonly Semaphore _previousRequestsSemaphore = new Semaphore(1, 1);

		private readonly ILogger<TwitchPubSub> _logger;

		private readonly System.Timers.Timer _pingTimer = new System.Timers.Timer();

		private readonly System.Timers.Timer _pongTimer = new System.Timers.Timer();

		private bool _pongReceived = false;

		private readonly List<string> _topicList = new List<string>();

		private readonly Dictionary<string, string> _topicToChannelId = new Dictionary<string, string>();

		private static readonly Random Random = new Random();

		public event EventHandler OnPubSubServiceConnected;

		public event EventHandler<OnPubSubServiceErrorArgs> OnPubSubServiceError;

		public event EventHandler OnPubSubServiceClosed;

		public event EventHandler<OnListenResponseArgs> OnListenResponse;

		public event EventHandler<OnTimeoutArgs> OnTimeout;

		public event EventHandler<OnBanArgs> OnBan;

		public event EventHandler<OnMessageDeletedArgs> OnMessageDeleted;

		public event EventHandler<OnUnbanArgs> OnUnban;

		public event EventHandler<OnUntimeoutArgs> OnUntimeout;

		public event EventHandler<OnHostArgs> OnHost;

		public event EventHandler<OnSubscribersOnlyArgs> OnSubscribersOnly;

		public event EventHandler<OnSubscribersOnlyOffArgs> OnSubscribersOnlyOff;

		public event EventHandler<OnClearArgs> OnClear;

		public event EventHandler<OnEmoteOnlyArgs> OnEmoteOnly;

		public event EventHandler<OnEmoteOnlyOffArgs> OnEmoteOnlyOff;

		public event EventHandler<OnR9kBetaArgs> OnR9kBeta;

		public event EventHandler<OnR9kBetaOffArgs> OnR9kBetaOff;

		public event EventHandler<OnBitsReceivedArgs> OnBitsReceived;

		public event EventHandler<OnChannelCommerceReceivedArgs> OnChannelCommerceReceived;

		public event EventHandler<OnStreamUpArgs> OnStreamUp;

		public event EventHandler<OnStreamDownArgs> OnStreamDown;

		public event EventHandler<OnViewCountArgs> OnViewCount;

		public event EventHandler<OnWhisperArgs> OnWhisper;

		public event EventHandler<OnChannelSubscriptionArgs> OnChannelSubscription;

		public event EventHandler<OnChannelExtensionBroadcastArgs> OnChannelExtensionBroadcast;

		public event EventHandler<OnFollowArgs> OnFollow;

		public event EventHandler<OnCustomRewardCreatedArgs> OnCustomRewardCreated;

		public event EventHandler<OnCustomRewardUpdatedArgs> OnCustomRewardUpdated;

		public event EventHandler<OnCustomRewardDeletedArgs> OnCustomRewardDeleted;

		public event EventHandler<OnRewardRedeemedArgs> OnRewardRedeemed;

		public event EventHandler<OnLeaderboardEventArgs> OnLeaderboardSubs;

		public event EventHandler<OnLeaderboardEventArgs> OnLeaderboardBits;

		public event EventHandler<OnRaidUpdateArgs> OnRaidUpdate;

		public event EventHandler<OnRaidUpdateV2Args> OnRaidUpdateV2;

		public event EventHandler<OnRaidGoArgs> OnRaidGo;

		public event EventHandler<OnLogArgs> OnLog;

		public event EventHandler<OnCommercialArgs> OnCommercial;

		public TwitchPubSub(ILogger<TwitchPubSub> logger = null)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			_logger = logger;
			ClientOptions val = new ClientOptions
			{
				ClientType = (ClientType)1
			};
			_socket = new WebSocketClient((IClientOptions)(object)val);
			_socket.OnConnected += Socket_OnConnected;
			_socket.OnError += OnError;
			_socket.OnMessage += OnMessage;
			_socket.OnDisconnected += Socket_OnDisconnected;
			_pongTimer.Interval = 15000.0;
			_pongTimer.Elapsed += PongTimerTick;
		}

		private void OnError(object sender, OnErrorEventArgs e)
		{
			_logger?.LogError($"OnError in PubSub Websocket connection occured! Exception: {e.Exception}");
			this.OnPubSubServiceError?.Invoke(this, new OnPubSubServiceErrorArgs
			{
				Exception = e.Exception
			});
		}

		private void OnMessage(object sender, OnMessageEventArgs e)
		{
			_logger?.LogDebug("Received Websocket OnMessage: " + e.Message);
			this.OnLog?.Invoke(this, new OnLogArgs
			{
				Data = e.Message
			});
			ParseMessage(e.Message);
		}

		private void Socket_OnDisconnected(object sender, EventArgs e)
		{
			_logger?.LogWarning("PubSub Websocket connection closed");
			_pingTimer.Stop();
			_pongTimer.Stop();
			this.OnPubSubServiceClosed?.Invoke(this, null);
		}

		private void Socket_OnConnected(object sender, EventArgs e)
		{
			_logger?.LogInformation("PubSub Websocket connection established");
			_pingTimer.Interval = 180000.0;
			_pingTimer.Elapsed += PingTimerTick;
			_pingTimer.Start();
			this.OnPubSubServiceConnected?.Invoke(this, null);
		}

		private void PingTimerTick(object sender, ElapsedEventArgs e)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			_pongReceived = false;
			JObject val = new JObject((object)new JProperty("type", (object)"PING"));
			_socket.Send(((object)val).ToString());
			_pongTimer.Start();
		}

		private void PongTimerTick(object sender, ElapsedEventArgs e)
		{
			_pongTimer.Stop();
			if (_pongReceived)
			{
				_pongReceived = false;
			}
			else
			{
				_socket.Close(true);
			}
		}

		private void ParseMessage(string message)
		{
			switch ((((object)((JToken)JObject.Parse(message)).SelectToken("type"))?.ToString())?.ToLower())
			{
			case "response":
			{
				Response response = new Response(message);
				if (_previousRequests.Count == 0)
				{
					break;
				}
				bool flag = false;
				_previousRequestsSemaphore.WaitOne();
				try
				{
					int num = 0;
					while (num < _previousRequests.Count)
					{
						PreviousRequest previousRequest = _previousRequests[num];
						if (string.Equals(previousRequest.Nonce, response.Nonce, StringComparison.CurrentCulture))
						{
							_previousRequests.RemoveAt(num);
							this.OnListenResponse?.Invoke(this, new OnListenResponseArgs
							{
								Response = response,
								Topic = previousRequest.Topic,
								Successful = response.Successful
							});
							flag = true;
						}
						else
						{
							num++;
						}
					}
				}
				finally
				{
					_previousRequestsSemaphore.Release();
				}
				if (flag)
				{
					return;
				}
				break;
			}
			case "message":
			{
				Message message2 = new Message(message);
				_topicToChannelId.TryGetValue(message2.Topic, out var value);
				value = value ?? "";
				switch (message2.Topic.Split(new char[1] { '.' })[0])
				{
				case "channel-subscribe-events-v1":
				{
					ChannelSubscription subscription = message2.MessageData as ChannelSubscription;
					this.OnChannelSubscription?.Invoke(this, new OnChannelSubscriptionArgs
					{
						Subscription = subscription,
						ChannelId = value
					});
					return;
				}
				case "whispers":
				{
					Whisper whisper = (Whisper)message2.MessageData;
					this.OnWhisper?.Invoke(this, new OnWhisperArgs
					{
						Whisper = whisper,
						ChannelId = value
					});
					return;
				}
				case "chat_moderator_actions":
				{
					ChatModeratorActions chatModeratorActions = message2.MessageData as ChatModeratorActions;
					string text = "";
					string text2 = message2.Topic.Split(new char[1] { '.' })[2];
					switch (chatModeratorActions?.ModerationAction.ToLower())
					{
					case "timeout":
						if (chatModeratorActions.Args.Count > 2)
						{
							text = chatModeratorActions.Args[2];
						}
						this.OnTimeout?.Invoke(this, new OnTimeoutArgs
						{
							TimedoutBy = chatModeratorActions.CreatedBy,
							TimedoutById = chatModeratorActions.CreatedByUserId,
							TimedoutUserId = chatModeratorActions.TargetUserId,
							TimeoutDuration = TimeSpan.FromSeconds(int.Parse(chatModeratorActions.Args[1])),
							TimeoutReason = text,
							TimedoutUser = chatModeratorActions.Args[0],
							ChannelId = value
						});
						return;
					case "ban":
						if (chatModeratorActions.Args.Count > 1)
						{
							text = chatModeratorActions.Args[1];
						}
						this.OnBan?.Invoke(this, new OnBanArgs
						{
							BannedBy = chatModeratorActions.CreatedBy,
							BannedByUserId = chatModeratorActions.CreatedByUserId,
							BannedUserId = chatModeratorActions.TargetUserId,
							BanReason = text,
							BannedUser = chatModeratorActions.Args[0],
							ChannelId = value
						});
						return;
					case "delete":
						this.OnMessageDeleted?.Invoke(this, new OnMessageDeletedArgs
						{
							DeletedBy = chatModeratorActions.CreatedBy,
							DeletedByUserId = chatModeratorActions.CreatedByUserId,
							TargetUserId = chatModeratorActions.TargetUserId,
							TargetUser = chatModeratorActions.Args[0],
							Message = chatModeratorActions.Args[1],
							MessageId = chatModeratorActions.Args[2],
							ChannelId = value
						});
						return;
					case "unban":
						this.OnUnban?.Invoke(this, new OnUnbanArgs
						{
							UnbannedBy = chatModeratorActions.CreatedBy,
							UnbannedByUserId = chatModeratorActions.CreatedByUserId,
							UnbannedUserId = chatModeratorActions.TargetUserId,
							UnbannedUser = chatModeratorActions.Args[0],
							ChannelId = value
						});
						return;
					case "untimeout":
						this.OnUntimeout?.Invoke(this, new OnUntimeoutArgs
						{
							UntimeoutedBy = chatModeratorActions.CreatedBy,
							UntimeoutedByUserId = chatModeratorActions.CreatedByUserId,
							UntimeoutedUserId = chatModeratorActions.TargetUserId,
							UntimeoutedUser = chatModeratorActions.Args[0],
							ChannelId = value
						});
						return;
					case "host":
						this.OnHost?.Invoke(this, new OnHostArgs
						{
							HostedChannel = chatModeratorActions.Args[0],
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					case "subscribers":
						this.OnSubscribersOnly?.Invoke(this, new OnSubscribersOnlyArgs
						{
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					case "subscribersoff":
						this.OnSubscribersOnlyOff?.Invoke(this, new OnSubscribersOnlyOffArgs
						{
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					case "clear":
						this.OnClear?.Invoke(this, new OnClearArgs
						{
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					case "emoteonly":
						this.OnEmoteOnly?.Invoke(this, new OnEmoteOnlyArgs
						{
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					case "emoteonlyoff":
						this.OnEmoteOnlyOff?.Invoke(this, new OnEmoteOnlyOffArgs
						{
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					case "r9kbeta":
						this.OnR9kBeta?.Invoke(this, new OnR9kBetaArgs
						{
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					case "r9kbetaoff":
						this.OnR9kBetaOff?.Invoke(this, new OnR9kBetaOffArgs
						{
							Moderator = chatModeratorActions.CreatedBy,
							ChannelId = value
						});
						return;
					}
					break;
				}
				case "channel-bits-events-v1":
					if (message2.MessageData is ChannelBitsEvents channelBitsEvents)
					{
						this.OnBitsReceived?.Invoke(this, new OnBitsReceivedArgs
						{
							BitsUsed = channelBitsEvents.BitsUsed,
							ChannelId = channelBitsEvents.ChannelId,
							ChannelName = channelBitsEvents.ChannelName,
							ChatMessage = channelBitsEvents.ChatMessage,
							Context = channelBitsEvents.Context,
							Time = channelBitsEvents.Time,
							TotalBitsUsed = channelBitsEvents.TotalBitsUsed,
							UserId = channelBitsEvents.UserId,
							Username = channelBitsEvents.Username
						});
						return;
					}
					break;
				case "channel-commerce-events-v1":
					if (message2.MessageData is ChannelCommerceEvents channelCommerceEvents)
					{
						this.OnChannelCommerceReceived?.Invoke(this, new OnChannelCommerceReceivedArgs
						{
							Username = channelCommerceEvents.Username,
							DisplayName = channelCommerceEvents.DisplayName,
							ChannelName = channelCommerceEvents.ChannelName,
							UserId = channelCommerceEvents.UserId,
							ChannelId = channelCommerceEvents.ChannelId,
							Time = channelCommerceEvents.Time,
							ItemImageURL = channelCommerceEvents.ItemImageURL,
							ItemDescription = channelCommerceEvents.ItemDescription,
							SupportsChannel = channelCommerceEvents.SupportsChannel,
							PurchaseMessage = channelCommerceEvents.PurchaseMessage
						});
						return;
					}
					break;
				case "channel-ext-v1":
				{
					ChannelExtensionBroadcast channelExtensionBroadcast = message2.MessageData as ChannelExtensionBroadcast;
					this.OnChannelExtensionBroadcast?.Invoke(this, new OnChannelExtensionBroadcastArgs
					{
						Messages = channelExtensionBroadcast.Messages,
						ChannelId = value
					});
					return;
				}
				case "video-playback-by-id":
				{
					VideoPlayback videoPlayback = message2.MessageData as VideoPlayback;
					switch (videoPlayback?.Type)
					{
					case VideoPlaybackType.StreamDown:
						this.OnStreamDown?.Invoke(this, new OnStreamDownArgs
						{
							ServerTime = videoPlayback.ServerTime
						});
						return;
					case VideoPlaybackType.StreamUp:
						this.OnStreamUp?.Invoke(this, new OnStreamUpArgs
						{
							PlayDelay = videoPlayback.PlayDelay,
							ServerTime = videoPlayback.ServerTime
						});
						return;
					case VideoPlaybackType.ViewCount:
						this.OnViewCount?.Invoke(this, new OnViewCountArgs
						{
							ServerTime = videoPlayback.ServerTime,
							Viewers = videoPlayback.Viewers
						});
						return;
					case VideoPlaybackType.Commercial:
						this.OnCommercial?.Invoke(this, new OnCommercialArgs
						{
							ServerTime = videoPlayback.ServerTime,
							Length = videoPlayback.Length
						});
						return;
					}
					break;
				}
				case "following":
				{
					Following following = (Following)message2.MessageData;
					following.FollowedChannelId = message2.Topic.Split(new char[1] { '.' })[1];
					this.OnFollow?.Invoke(this, new OnFollowArgs
					{
						FollowedChannelId = following.FollowedChannelId,
						DisplayName = following.DisplayName,
						UserId = following.UserId,
						Username = following.Username
					});
					return;
				}
				case "community-points-channel-v1":
				{
					CommunityPointsChannel communityPointsChannel = message2.MessageData as CommunityPointsChannel;
					CommunityPointsChannelType? communityPointsChannelType = communityPointsChannel?.Type;
					CommunityPointsChannelType? communityPointsChannelType2 = communityPointsChannelType;
					if (communityPointsChannelType2.HasValue)
					{
						switch (communityPointsChannelType2.GetValueOrDefault())
						{
						case CommunityPointsChannelType.RewardRedeemed:
							this.OnRewardRedeemed?.Invoke(this, new OnRewardRedeemedArgs
							{
								TimeStamp = communityPointsChannel.TimeStamp,
								ChannelId = communityPointsChannel.ChannelId,
								Login = communityPointsChannel.Login,
								DisplayName = communityPointsChannel.DisplayName,
								Message = communityPointsChannel.Message,
								RewardId = communityPointsChannel.RewardId,
								RewardTitle = communityPointsChannel.RewardTitle,
								RewardPrompt = communityPointsChannel.RewardPrompt,
								RewardCost = communityPointsChannel.RewardCost,
								Status = communityPointsChannel.Status,
								RedemptionId = communityPointsChannel.RedemptionId
							});
							break;
						case CommunityPointsChannelType.CustomRewardUpdated:
							this.OnCustomRewardUpdated?.Invoke(this, new OnCustomRewardUpdatedArgs
							{
								TimeStamp = communityPointsChannel.TimeStamp,
								ChannelId = communityPointsChannel.ChannelId,
								RewardId = communityPointsChannel.RewardId,
								RewardTitle = communityPointsChannel.RewardTitle,
								RewardPrompt = communityPointsChannel.RewardPrompt,
								RewardCost = communityPointsChannel.RewardCost
							});
							break;
						case CommunityPointsChannelType.CustomRewardCreated:
							this.OnCustomRewardCreated?.Invoke(this, new OnCustomRewardCreatedArgs
							{
								TimeStamp = communityPointsChannel.TimeStamp,
								ChannelId = communityPointsChannel.ChannelId,
								RewardId = communityPointsChannel.RewardId,
								RewardTitle = communityPointsChannel.RewardTitle,
								RewardPrompt = communityPointsChannel.RewardPrompt,
								RewardCost = communityPointsChannel.RewardCost
							});
							break;
						case CommunityPointsChannelType.CustomRewardDeleted:
							this.OnCustomRewardDeleted?.Invoke(this, new OnCustomRewardDeletedArgs
							{
								TimeStamp = communityPointsChannel.TimeStamp,
								ChannelId = communityPointsChannel.ChannelId,
								RewardId = communityPointsChannel.RewardId,
								RewardTitle = communityPointsChannel.RewardTitle,
								RewardPrompt = communityPointsChannel.RewardPrompt
							});
							break;
						}
					}
					return;
				}
				case "leaderboard-events-v1":
				{
					LeaderboardEvents leaderboardEvents = message2.MessageData as LeaderboardEvents;
					LeaderBoardType? leaderBoardType = leaderboardEvents?.Type;
					LeaderBoardType? leaderBoardType2 = leaderBoardType;
					if (leaderBoardType2.HasValue)
					{
						switch (leaderBoardType2.GetValueOrDefault())
						{
						case LeaderBoardType.BitsUsageByChannel:
							this.OnLeaderboardBits?.Invoke(this, new OnLeaderboardEventArgs
							{
								ChannelId = leaderboardEvents.ChannelId,
								TopList = leaderboardEvents.Top
							});
							break;
						case LeaderBoardType.SubGiftSent:
							this.OnLeaderboardSubs?.Invoke(this, new OnLeaderboardEventArgs
							{
								ChannelId = leaderboardEvents.ChannelId,
								TopList = leaderboardEvents.Top
							});
							break;
						}
					}
					return;
				}
				case "raid":
				{
					RaidEvents raidEvents = message2.MessageData as RaidEvents;
					RaidType? raidType = raidEvents?.Type;
					RaidType? raidType2 = raidType;
					if (raidType2.HasValue)
					{
						switch (raidType2.GetValueOrDefault())
						{
						case RaidType.RaidUpdate:
							this.OnRaidUpdate?.Invoke(this, new OnRaidUpdateArgs
							{
								Id = raidEvents.Id,
								ChannelId = raidEvents.ChannelId,
								TargetChannelId = raidEvents.TargetChannelId,
								AnnounceTime = raidEvents.AnnounceTime,
								RaidTime = raidEvents.RaidTime,
								RemainingDurationSeconds = raidEvents.RemainigDurationSeconds,
								ViewerCount = raidEvents.ViewerCount
							});
							break;
						case RaidType.RaidUpdateV2:
							this.OnRaidUpdateV2?.Invoke(this, new OnRaidUpdateV2Args
							{
								Id = raidEvents.Id,
								ChannelId = raidEvents.ChannelId,
								TargetChannelId = raidEvents.TargetChannelId,
								TargetLogin = raidEvents.TargetLogin,
								TargetDisplayName = raidEvents.TargetDisplayName,
								TargetProfileImage = raidEvents.TargetProfileImage,
								ViewerCount = raidEvents.ViewerCount
							});
							break;
						case RaidType.RaidGo:
							this.OnRaidGo?.Invoke(this, new OnRaidGoArgs
							{
								Id = raidEvents.Id,
								ChannelId = raidEvents.ChannelId,
								TargetChannelId = raidEvents.TargetChannelId,
								TargetLogin = raidEvents.TargetLogin,
								TargetDisplayName = raidEvents.TargetDisplayName,
								TargetProfileImage = raidEvents.TargetProfileImage,
								ViewerCount = raidEvents.ViewerCount
							});
							break;
						}
					}
					return;
				}
				}
				break;
			}
			case "pong":
				_pongReceived = true;
				return;
			case "reconnect":
				_socket.Close(true);
				break;
			}
			UnaccountedFor(message);
		}

		private static string GenerateNonce()
		{
			return new string((from s in Enumerable.Repeat("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 8)
				select s[Random.Next(s.Length)]).ToArray());
		}

		private void ListenToTopic(string topic)
		{
			_topicList.Add(topic);
		}

		private void ListenToTopics(params string[] topics)
		{
			foreach (string item in topics)
			{
				_topicList.Add(item);
			}
		}

		public void SendTopics(string oauth = null, bool unlisten = false)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			if (oauth != null && oauth.Contains("oauth:"))
			{
				oauth = oauth.Replace("oauth:", "");
			}
			string text = GenerateNonce();
			JArray val = new JArray();
			_previousRequestsSemaphore.WaitOne();
			try
			{
				foreach (string topic in _topicList)
				{
					_previousRequests.Add(new PreviousRequest(text, PubSubRequestType.ListenToTopic, topic));
					val.Add((JToken)new JValue(topic));
				}
			}
			finally
			{
				_previousRequestsSemaphore.Release();
			}
			JObject val2 = new JObject(new object[3]
			{
				(object)new JProperty("type", (object)((!unlisten) ? "LISTEN" : "UNLISTEN")),
				(object)new JProperty("nonce", (object)text),
				(object)new JProperty("data", (object)new JObject((object)new JProperty("topics", (object)val)))
			});
			if (oauth != null)
			{
				((JContainer)(JObject)((JToken)val2).SelectToken("data")).Add((object)new JProperty("auth_token", (object)oauth));
			}
			_socket.Send(((object)val2).ToString());
			_topicList.Clear();
		}

		private void UnaccountedFor(string message)
		{
			_logger?.LogInformation("[TwitchPubSub] " + message);
		}

		public void ListenToFollows(string channelId)
		{
			string text = "following." + channelId;
			_topicToChannelId[text] = channelId;
			ListenToTopic(text);
		}

		public void ListenToChatModeratorActions(string myTwitchId, string channelTwitchId)
		{
			string text = "chat_moderator_actions." + myTwitchId + "." + channelTwitchId;
			_topicToChannelId[text] = channelTwitchId;
			ListenToTopic(text);
		}

		public void ListenToChannelExtensionBroadcast(string channelId, string extensionId)
		{
			string text = "channel-ext-v1." + channelId + "-" + extensionId + "-broadcast";
			_topicToChannelId[text] = channelId;
			ListenToTopic(text);
		}

		public void ListenToBitsEvents(string channelTwitchId)
		{
			string text = "channel-bits-events-v1." + channelTwitchId;
			_topicToChannelId[text] = channelTwitchId;
			ListenToTopic(text);
		}

		public void ListenToCommerce(string channelTwitchId)
		{
			string text = "channel-commerce-events-v1." + channelTwitchId;
			_topicToChannelId[text] = channelTwitchId;
			ListenToTopic(text);
		}

		public void ListenToVideoPlayback(string channelTwitchId)
		{
			string text = "video-playback-by-id." + channelTwitchId;
			_topicToChannelId[text] = channelTwitchId;
			ListenToTopic(text);
		}

		public void ListenToWhispers(string channelTwitchId)
		{
			string text = "whispers." + channelTwitchId;
			_topicToChannelId[text] = channelTwitchId;
			ListenToTopic(text);
		}

		public void ListenToRewards(string channelTwitchId)
		{
			string text = "community-points-channel-v1." + channelTwitchId;
			_topicToChannelId[text] = channelTwitchId;
			ListenToTopic(text);
		}

		public void ListenToLeaderboards(string channelTwitchId)
		{
			string text = "leaderboard-events-v1.bits-usage-by-channel-v1-" + channelTwitchId + "-WEEK";
			string text2 = "leaderboard-events-v1.sub-gift-sent-" + channelTwitchId + "-WEEK";
			_topicToChannelId[text] = channelTwitchId;
			_topicToChannelId[text2] = channelTwitchId;
			ListenToTopics(text, text2);
		}

		public void ListenToRaid(string channelTwitchId)
		{
			string text = "raid." + channelTwitchId;
			_topicToChannelId[text] = channelTwitchId;
			ListenToTopic(text);
		}

		public void ListenToSubscriptions(string channelId)
		{
			string text = "channel-subscribe-events-v1." + channelId;
			_topicToChannelId[text] = channelId;
			ListenToTopic(text);
		}

		public void Connect()
		{
			_socket.Open();
		}

		public void Disconnect()
		{
			_socket.Close(true);
		}

		public void TestMessageParser(string testJsonString)
		{
			ParseMessage(testJsonString);
		}
	}
}
namespace TwitchLib.PubSub.Models
{
	public class LeaderBoard
	{
		public int Place { get; set; }

		public int Score { get; set; }

		public string UserId { get; set; }
	}
	public class PreviousRequest
	{
		public string Nonce { get; }

		public PubSubRequestType RequestType { get; }

		public string Topic { get; }

		public PreviousRequest(string nonce, PubSubRequestType requestType, string topic = "none set")
		{
			Nonce = nonce;
			RequestType = requestType;
			Topic = topic;
		}
	}
}
namespace TwitchLib.PubSub.Models.Responses
{
	public class Message
	{
		public readonly MessageData MessageData;

		public string Topic { get; }

		public Message(string jsonStr)
		{
			JToken val = ((JToken)JObject.Parse(jsonStr)).SelectToken("data");
			Topic = ((object)val.SelectToken("topic"))?.ToString();
			string jsonStr2 = ((object)val.SelectToken("message")).ToString();
			string topic = Topic;
			switch ((topic != null) ? topic.Split(new char[1] { '.' })[0] : null)
			{
			case "chat_moderator_actions":
				MessageData = new ChatModeratorActions(jsonStr2);
				break;
			case "channel-bits-events-v1":
				MessageData = new ChannelBitsEvents(jsonStr2);
				break;
			case "video-playback-by-id":
				MessageData = new VideoPlayback(jsonStr2);
				break;
			case "whispers":
				MessageData = new Whisper(jsonStr2);
				break;
			case "channel-subscribe-events-v1":
				MessageData = new ChannelSubscription(jsonStr2);
				break;
			case "channel-ext-v1":
				MessageData = new ChannelExtensionBroadcast(jsonStr2);
				break;
			case "following":
				MessageData = new Following(jsonStr2);
				break;
			case "community-points-channel-v1":
				MessageData = new CommunityPointsChannel(jsonStr2);
				break;
			case "leaderboard-events-v1":
				MessageData = new LeaderboardEvents(jsonStr2);
				break;
			case "raid":
				MessageData = new RaidEvents(jsonStr2);
				break;
			}
		}
	}
	public class Response
	{
		public string Error { get; }

		public string Nonce { get; }

		public bool Successful { get; }

		public Response(string json)
		{
			Error = ((object)((JToken)JObject.Parse(json)).SelectToken("error"))?.ToString();
			Nonce = ((object)((JToken)JObject.Parse(json)).SelectToken("nonce"))?.ToString();
			if (string.IsNullOrWhiteSpace(Error))
			{
				Successful = true;
			}
		}
	}
}
namespace TwitchLib.PubSub.Models.Responses.Messages
{
	public class ChannelBitsEvents : MessageData
	{
		public string Username { get; }

		public string ChannelName { get; }

		public string UserId { get; }

		public string ChannelId { get; }

		public string Time { get; }

		public string ChatMessage { get; }

		public int BitsUsed { get; }

		public int TotalBitsUsed { get; }

		public string Context { get; }

		public ChannelBitsEvents(string jsonStr)
		{
			JObject val = JObject.Parse(jsonStr);
			Username = ((object)((JToken)val).SelectToken("data").SelectToken("user_name"))?.ToString();
			ChannelName = ((object)((JToken)val).SelectToken("data").SelectToken("channel_name"))?.ToString();
			UserId = ((object)((JToken)val).SelectToken("data").SelectToken("user_id"))?.ToString();
			ChannelId = ((object)((JToken)val).SelectToken("data").SelectToken("channel_id"))?.ToString();
			Time = ((object)((JToken)val).SelectToken("data").SelectToken("time"))?.ToString();
			ChatMessage = ((object)((JToken)val).SelectToken("data").SelectToken("chat_message"))?.ToString();
			BitsUsed = int.Parse(((object)((JToken)val).SelectToken("data").SelectToken("bits_used")).ToString());
			TotalBitsUsed = int.Parse(((object)((JToken)val).SelectToken("data").SelectToken("total_bits_used")).ToString());
			Context = ((object)((JToken)val).SelectToken("data").SelectToken("context"))?.ToString();
		}
	}
	public class ChannelCommerceEvents : MessageData
	{
		public string Username { get; }

		public string DisplayName { get; }

		public string ChannelName { get; }

		public string UserId { get; }

		public string ChannelId { get; }

		public string Time { get; }

		public string ItemImageURL { get; }

		public string ItemDescription { get; }

		public bool SupportsChannel { get; }

		public string PurchaseMessage { get; }

		public ChannelCommerceEvents(string jsonStr)
		{
			JObject val = JObject.Parse(jsonStr);
			Username = ((object)((JToken)val).SelectToken("data").SelectToken("user_name"))?.ToString();
			DisplayName = ((object)((JToken)val).SelectToken("data").SelectToken("display_name"))?.ToString();
			ChannelName = ((object)((JToken)val).SelectToken("data").SelectToken("channel_name"))?.ToString();
			UserId = ((object)((JToken)val).SelectToken("data").SelectToken("user_id"))?.ToString();
			ChannelId = ((object)((JToken)val).SelectToken("data").SelectToken("channel_id"))?.ToString();
			Time = ((object)((JToken)val).SelectToken("data").SelectToken("time"))?.ToString();
			ItemImageURL = ((object)((JToken)val).SelectToken("data").SelectToken("image_item_url"))?.ToString();
			ItemDescription = ((object)((JToken)val).SelectToken("data").SelectToken("item_description"))?.ToString();
			SupportsChannel = bool.Parse(((object)((JToken)val).SelectToken("data").SelectToken("supports_channel"))?.ToString() ?? throw new InvalidOperationException());
			PurchaseMessage = ((object)((JToken)val).SelectToken("data").SelectToken("purchase_message").SelectToken("message"))?.ToString();
		}
	}
	public class ChannelExtensionBroadcast : MessageData
	{
		public List<string> Messages { get; } = new List<string>();


		public ChannelExtensionBroadcast(string jsonStr)
		{
			JObject val = JObject.Parse(jsonStr);
			foreach (JToken item in (IEnumerable<JToken>)val["content"])
			{
				Messages.Add(((object)item).ToString());
			}
		}
	}
	public class ChannelSubscription : MessageData
	{
		public string Username { get; }

		public string DisplayName { get; }

		public string RecipientName { get; }

		public string RecipientDisplayName { get; }

		public string ChannelName { get; }

		public string UserId { get; }

		public string ChannelId { get; }

		public string RecipientId { get; }

		public DateTime Time { get; }

		public SubscriptionPlan SubscriptionPlan { get; }

		public string SubscriptionPlanName { get; }

		public int? Months { get; }

		public int? CumulativeMonths { get; }

		public int? StreakMonths { get; }

		public string Context { get; }

		public SubMessage SubMessage { get; }

		public bool? IsGift { get; }

		public int? MultiMonthDuration { get; }

		public ChannelSubscription(string jsonStr)
		{
			JObject val = JObject.Parse(jsonStr);
			Username = ((object)((JToken)val).SelectToken("user_name"))?.ToString();
			DisplayName = ((object)((JToken)val).SelectToken("display_name"))?.ToString();
			RecipientName = ((object)((JToken)val).SelectToken("recipient_user_name"))?.ToString();
			RecipientDisplayName = ((object)((JToken)val).SelectToken("recipient_display_name"))?.ToString();
			ChannelName = ((object)((JToken)val).SelectToken("channel_name"))?.ToString();
			UserId = ((object)((JToken)val).SelectToken("user_id"))?.ToString();
			RecipientId = ((object)((JToken)val).SelectToken("recipient_id"))?.ToString();
			ChannelId = ((object)((JToken)val).SelectToken("channel_id"))?.ToString();
			Time = Helpers.DateTimeStringToObject(((object)((JToken)val).SelectToken("time"))?.ToString());
			switch (((object)((JToken)val).SelectToken("sub_plan")).ToString().ToLower())
			{
			case "prime":
				SubscriptionPlan = SubscriptionPlan.Prime;
				break;
			case "1000":
				SubscriptionPlan = SubscriptionPlan.Tier1;
				break;
			case "2000":
				SubscriptionPlan = SubscriptionPlan.Tier2;
				break;
			case "3000":
				SubscriptionPlan = SubscriptionPlan.Tier3;
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			SubscriptionPlanName = ((object)((JToken)val).SelectToken("sub_plan_name"))?.ToString();
			SubMessage = new SubMessage(((JToken)val).SelectToken("sub_message"));
			string text = ((object)((JToken)val).SelectToken("is_gift"))?.ToString();
			if (text != null)
			{
				IsGift = Convert.ToBoolean(text.ToString());
			}
			string text2 = ((object)((JToken)val).SelectToken("multi_month_duration"))?.ToString();
			if (text2 != null)
			{
				MultiMonthDuration = int.Parse(text2.ToString());
			}
			Context = ((object)((JToken)val).SelectToken("context"))?.ToString();
			JToken val2 = ((JToken)val).SelectToken("months");
			if (val2 != null)
			{
				Months = int.Parse(((object)val2).ToString());
			}
			JToken val3 = ((JToken)val).SelectToken("cumulative_months");
			if (val3 != null)
			{
				CumulativeMonths = int.Parse(((object)val3).ToString());
			}
			JToken val4 = ((JToken)val).SelectToken("streak_months");
			if (val4 != null)
			{
				StreakMonths = int.Parse(((object)val4).ToString());
			}
		}
	}
	public class ChatModeratorActions : MessageData
	{
		public string Type { get; }

		public string ModerationAction { get; }

		public List<string> Args { get; } = new List<string>();


		public string CreatedBy { get; }

		public string CreatedByUserId { get; }

		public string TargetUserId { get; }

		public ChatModeratorActions(string jsonStr)
		{
			JToken val = ((JToken)JObject.Parse(jsonStr)).SelectToken("data");
			Type = ((object)val.SelectToken("type"))?.ToString();
			ModerationAction = ((object)val.SelectToken("moderation_action"))?.ToString();
			if (val.SelectToken("args") != null)
			{
				foreach (JToken item in (IEnumerable<JToken>)val.SelectToken("args"))
				{
					Args.Add(((object)item).ToString());
				}
			}
			CreatedBy = ((object)val.SelectToken("created_by")).ToString();
			CreatedByUserId = ((object)val.SelectToken("created_by_user_id")).ToString();
			TargetUserId = ((object)val.SelectToken("target_user_id")).ToString();
		}
	}
	public class CommunityPointsChannel : MessageData
	{
		public CommunityPointsChannelType Type { get; protected set; }

		public DateTime TimeStamp { get; protected set; }

		public string ChannelId { get; protected set; }

		public string Login { get; protected set; }

		public string DisplayName { get; protected set; }

		public string Message { get; protected set; }

		public Guid RewardId { get; protected set; }

		public string RewardTitle { get; protected set; }

		public string RewardPrompt { get; protected set; }

		public int RewardCost { get; protected set; }

		public string Status { get; protected set; }

		public Guid RedemptionId { get; protected set; }

		public CommunityPointsChannel(string jsonStr)
		{
			JToken val = (JToken)(object)JObject.Parse(jsonStr);
			switch (((object)val.SelectToken("type")).ToString())
			{
			case "reward-redeemed":
				Type = CommunityPointsChannelType.RewardRedeemed;
				break;
			case "custom-reward-created":
				Type = CommunityPointsChannelType.CustomRewardCreated;
				break;
			case "custom-reward-updated":
				Type = CommunityPointsChannelType.CustomRewardUpdated;
				break;
			case "custom-reward-deleted":
				Type = CommunityPointsChannelType.CustomRewardDeleted;
				break;
			default:
				Type = (CommunityPointsChannelType)(-1);
				break;
			}
			TimeStamp = DateTime.Parse(((object)val.SelectToken("data.timestamp")).ToString());
			switch (Type)
			{
			case CommunityPointsChannelType.RewardRedeemed:
				ChannelId = ((object)val.SelectToken("data.redemption.channel_id")).ToString();
				Login = ((object)val.SelectToken("data.redemption.user.login")).ToString();
				DisplayName = ((object)val.SelectToken("data.redemption.user.display_name")).ToString();
				RewardId = Guid.Parse(((object)val.SelectToken("data.redemption.reward.id")).ToString());
				RewardTitle = ((object)val.SelectToken("data.redemption.reward.title")).ToString();
				RewardPrompt = ((object)val.SelectToken("data.redemption.reward.prompt")).ToString();
				RewardCost = int.Parse(((object)val.SelectToken("data.redemption.reward.cost")).ToString());
				Message = ((object)val.SelectToken("data.redemption.user_input"))?.ToString();
				Status = ((object)val.SelectToken("data.redemption.status")).ToString();
				RedemptionId = Guid.Parse(((object)val.SelectToken("data.redemption.id")).ToString());
				break;
			case CommunityPointsChannelType.CustomRewardUpdated:
				ChannelId = ((object)val.SelectToken("data.updated_reward.channel_id")).ToString();
				RewardId = Guid.Parse(((object)val.SelectToken("data.updated_reward.id")).ToString());
				RewardTitle = ((object)val.SelectToken("data.updated_reward.title")).ToString();
				RewardPrompt = ((object)val.SelectToken("data.updated_reward.prompt")).ToString();
				RewardCost = int.Parse(((object)val.SelectToken("data.updated_reward.cost")).ToString());
				break;
			case CommunityPointsChannelType.CustomRewardCreated:
				ChannelId = ((object)val.SelectToken("data.new_reward.channel_id")).ToString();
				RewardId = Guid.Parse(((object)val.SelectToken("data.new_reward.id")).ToString());
				RewardTitle = ((object)val.SelectToken("data.new_reward.title")).ToString();
				RewardPrompt = ((object)val.SelectToken("data.new_reward.prompt")).ToString();
				RewardCost = int.Parse(((object)val.SelectToken("data.new_reward.cost")).ToString());
				break;
			case CommunityPointsChannelType.CustomRewardDeleted:
				ChannelId = ((object)val.SelectToken("data.deleted_reward.channel_id")).ToString();
				RewardId = Guid.Parse(((object)val.SelectToken("data.deleted_reward.id")).ToString());
				RewardTitle = ((object)val.SelectToken("data.deleted_reward.title")).ToString();
				RewardPrompt = ((object)val.SelectToken("data.deleted_reward.prompt")).ToString();
				break;
			}
		}
	}
	public class Following : MessageData
	{
		public string DisplayName { get; }

		public string Username { get; }

		public string UserId { get; }

		public string FollowedChannelId { get; internal set; }

		public Following(string jsonStr)
		{
			JObject val = JObject.Parse(jsonStr);
			DisplayName = ((object)val["display_name"]).ToString();
			Username = ((object)val["username"]).ToString();
			UserId = ((object)val["user_id"]).ToString();
		}
	}
	public class LeaderboardEvents : MessageData
	{
		public LeaderBoardType Type { get; private set; }

		public string ChannelId { get; private set; }

		public List<LeaderBoard> Top { get; private set; } = new List<LeaderBoard>();


		public LeaderboardEvents(string jsonStr)
		{
			//IL_009c: 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_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			JToken val = (JToken)(object)JObject.Parse(jsonStr);
			string text = ((object)val.SelectToken("identifier.domain")).ToString();
			string text2 = text;
			if (!(text2 == "bits-usage-by-channel-v1"))
			{
				if (text2 == "sub-gift-sent")
				{
					Type = LeaderBoardType.SubGiftSent;
				}
			}
			else
			{
				Type = LeaderBoardType.BitsUsageByChannel;
			}
			switch (Type)
			{
			case LeaderBoardType.BitsUsageByChannel:
				ChannelId = ((object)val.SelectToken("identifier.grouping_key")).ToString();
				{
					foreach (JToken item in val[(object)"top"].Children())
					{
						Top.Add(new LeaderBoard
						{
							Place = int.Parse(((object)item.SelectToken("rank")).ToString()),
							Score = int.Parse(((object)item.SelectToken("score")).ToString()),
							UserId = ((object)item.SelectToken("entry_key")).ToString()
						});
					}
					break;
				}
			case LeaderBoardType.SubGiftSent:
				ChannelId = ((object)val.SelectToken("identifier.grouping_key")).ToString();
				{
					foreach (JToken item2 in val[(object)"top"].Children())
					{
						Top.Add(new LeaderBoard
						{
							Place = int.Parse(((object)item2.SelectToken("rank")).ToString()),
							Score = int.Parse(((object)item2.SelectToken("score")).ToString()),
							UserId = ((object)item2.SelectToken("entry_key")).ToString()
						});
					}
					break;
				}
			}
		}
	}
	public abstract class MessageData
	{
	}
	public class RaidEvents : MessageData
	{
		public RaidType Type { get; protected set; }

		public Guid Id { get; protected set; }

		public string ChannelId { get; protected set; }

		public string TargetChannelId { get; protected set; }

		public string TargetLogin { get; protected set; }

		public string TargetDisplayName { get; protected set; }

		public string TargetProfileImage { get; protected set; }

		public DateTime AnnounceTime { get; protected set; }

		public DateTime RaidTime { get; protected set; }

		public int RemainigDurationSeconds { get; protected set; }

		public int ViewerCount { get; protected set; }

		public RaidEvents(string jsonStr)
		{
			JToken val = (JToken)(object)JObject.Parse(jsonStr);
			switch (((object)val.SelectToken("type")).ToString())
			{
			case "raid_update":
				Type = RaidType.RaidUpdate;
				break;
			case "raid_update_v2":
				Type = RaidType.RaidUpdateV2;
				break;
			case "raid_go_v2":
				Type = RaidType.RaidGo;
				break;
			}
			switch (Type)
			{
			case RaidType.RaidUpdate:
				Id = Guid.Parse(((object)val.SelectToken("raid.id")).ToString());
				ChannelId = ((object)val.SelectToken("raid.source_id")).ToString();
				TargetChannelId = ((object)val.SelectToken("raid.target_id")).ToString();
				AnnounceTime = DateTime.Parse(((object)val.SelectToken("raid.announce_time")).ToString());
				RaidTime = DateTime.Parse(((object)val.SelectToken("raid.raid_time")).ToString());
				RemainigDurationSeconds = int.Parse(((object)val.SelectToken("raid.remaining_duration_seconds")).ToString());
				ViewerCount = int.Parse(((object)val.SelectToken("raid.viewer_count")).ToString());
				break;
			case RaidType.RaidUpdateV2:
				Id = Guid.Parse(((object)val.SelectToken("raid.id")).ToString());
				ChannelId = ((object)val.SelectToken("raid.source_id")).ToString();
				TargetChannelId = ((object)val.SelectToken("raid.target_id")).ToString();
				TargetLogin = ((object)val.SelectToken("raid.target_login")).ToString();
				TargetDisplayName = ((object)val.SelectToken("raid.target_display_name")).ToString();
				TargetProfileImage = ((object)val.SelectToken("raid.target_profile_image")).ToString();
				ViewerCount = int.Parse(((object)val.SelectToken("raid.viewer_count")).ToString());
				break;
			case RaidType.RaidGo:
				Id = Guid.Parse(((object)val.SelectToken("raid.id")).ToString());
				ChannelId = ((object)val.SelectToken("raid.source_id")).ToString();
				TargetChannelId = ((object)val.SelectToken("raid.target_id")).ToString();
				TargetLogin = ((object)val.SelectToken("raid.target_login")).ToString();
				TargetDisplayName = ((object)val.SelectToken("raid.target_display_name")).ToString();
				TargetProfileImage = ((object)val.SelectToken("raid.target_profile_image")).ToString();
				ViewerCount = int.Parse(((object)val.SelectToken("raid.viewer_count")).ToString());
				break;
			}
		}
	}
	public class SubMessage : MessageData
	{
		public class Emote
		{
			public int Start { get; }

			public int End { get; }

			public int Id { get; }

			public Emote(JToken json)
			{
				Start = int.Parse(((object)json.SelectToken("start")).ToString());
				End = int.Parse(((object)json.SelectToken("end")).ToString());
				Id = int.Parse(((object)json.SelectToken("id")).ToString());
			}
		}

		public string Message { get; }

		public List<Emote> Emotes { get; } = new List<Emote>();


		public SubMessage(JToken json)
		{
			Message = ((object)json.SelectToken("message"))?.ToString();
			foreach (JToken item in (IEnumerable<JToken>)json.SelectToken("emotes"))
			{
				Emotes.Add(new Emote(item));
			}
		}
	}
	public class VideoPlayback : MessageData
	{
		public VideoPlaybackType Type { get; }

		public string ServerTime { get; }

		public int PlayDelay { get; }

		public int Viewers { get; }

		public int Length { get; }

		public VideoPlayback(string jsonStr)
		{
			JToken val = (JToken)(object)JObject.Parse(jsonStr);
			switch (((object)val.SelectToken("type")).ToString())
			{
			case "stream-up":
				Type = VideoPlaybackType.StreamUp;
				break;
			case "stream-down":
				Type = VideoPlaybackType.StreamDown;
				break;
			case "viewcount":
				Type = VideoPlaybackType.ViewCount;
				break;
			case "commercial":
				Type = VideoPlaybackType.Commercial;
				break;
			}
			ServerTime = ((object)val.SelectToken("server_time"))?.ToString();
			switch (Type)
			{
			case VideoPlaybackType.StreamUp:
				PlayDelay = int.Parse(((object)val.SelectToken("play_delay")).ToString());
				break;
			case VideoPlaybackType.ViewCount:
				Viewers = int.Parse(((object)val.SelectToken("viewers")).ToString());
				break;
			case VideoPlaybackType.StreamDown:
				break;
			case VideoPlaybackType.Commercial:
				Length = int.Parse(((object)val.SelectToken("length")).ToString());
				break;
			}
		}
	}
	public class Whisper : MessageData
	{
		public class DataObjThread
		{
			public class SpamInfoObj
			{
				public string Likelihood { get; }

				public long LastMarkedNotSpam { get; }

				public SpamInfoObj(JToken json)
				{
					Likelihood = ((object)json.SelectToken("likelihood")).ToString();
					LastMarkedNotSpam = long.Parse(((object)json.SelectToken("last_marked_not_spam")).ToString());
				}
			}

			public string Id { get; }

			public long LastRead { get; }

			public bool Archived { get; }

			public bool Muted { get; }

			public SpamInfoObj SpamInfo { get; }

			public DataObjThread(JToken json)
			{
				Id = ((object)json.SelectToken("id")).ToString();
				LastRead = long.Parse(((object)json.SelectToken("last_read")).ToString());
				Archived = bool.Parse(((object)json.SelectToken("archived")).ToString());
				Muted = bool.Parse(((object)json.SelectToken("muted")).ToString());
				SpamInfo = new SpamInfoObj(json.SelectToken("spam_info"));
			}
		}

		public class DataObjWhisperReceived
		{
			public class TagsObj
			{
				public class EmoteObj
				{
					public int Id { get; protected set; }

					public int Start { get; protected set; }

					public int End { get; protected set; }

					public EmoteObj(JToken json)
					{
						Id = int.Parse(((object)json.SelectToken("id")).ToString());
						Start = int.Parse(((object)json.SelectToken("start")).ToString());
						End = int.Parse(((object)json.SelectToken("end")).ToString());
					}
				}

				public readonly List<EmoteObj> Emotes = new List<EmoteObj>();

				public readonly List<Badge> Badges = new List<Badge>();

				public string Login { get; protected set; }

				public string DisplayName { get; protected set; }

				public string Color { get; protected set; }

				public string UserType { get; protected set; }

				public TagsObj(JToken json)
				{
					Login = ((object)json.SelectToken("login"))?.ToString();
					DisplayName = ((object)json.SelectToken("login"))?.ToString();
					Color = ((object)json.SelectToken("color"))?.ToString();
					UserType = ((object)json.SelectToken("user_type"))?.ToString();
					foreach (JToken item in (IEnumerable<JToken>)json.SelectToken("emotes"))
					{
						Emotes.Add(new EmoteObj(item));
					}
					foreach (JToken item2 in (IEnumerable<JToken>)json.SelectToken("badges"))
					{
						Badges.Add(new Badge(item2));
					}
				}
			}

			public class RecipientObj
			{
				public string Id { get; protected set; }

				public string Username { get; protected set; }

				public string DisplayName { get; protected set; }

				public string Color { get; protected set; }

				public string UserType { get; protected set; }

				public List<Badge> Badges { get; protected set; } = new List<Badge>();


				public RecipientObj(JToken json)
				{
					Id = ((object)json.SelectToken("id")).ToString();
					Username = ((object)json.SelectToken("username"))?.ToString();
					DisplayName = ((object)json.SelectToken("display_name"))?.ToString();
					Color = ((object)json.SelectToken("color"))?.ToString();
					UserType = ((object)json.SelectToken("user_type"))?.ToString();
					foreach (JToken item in (IEnumerable<JToken>)json.SelectToken("badges"))
					{
						Badges.Add(new Badge(item));
					}
				}
			}

			public class Badge
			{
				public string Id { get; protected set; }

				public string Version { get; protected set; }

				public Badge(JToken json)
				{
					Id = ((object)json.SelectToken("id"))?.ToString();
					Version = ((object)json.SelectToken("version"))?.ToString();
				}
			}

			public string Id { get; protected set; }

			public string ThreadId { get; protected set; }

			public string Body { get; protected set; }

			public long SentTs { get; protected set; }

			public string FromId { get; protected set; }

			public TagsObj Tags { get; protected set; }

			public RecipientObj Recipient { get; protected set; }

			public string Nonce { get; protected set; }

			public DataObjWhisperReceived(JToken json)
			{
				Id = ((object)json.SelectToken("id")).ToString();
				ThreadId = ((object)json.SelectToken("thread_id"))?.ToString();
				Body = ((object)json.SelectToken("body"))?.ToString();
				SentTs = long.Parse(((object)json.SelectToken("sent_ts")).ToString());
				FromId = ((object)json.SelectToken("from_id")).ToString();
				Tags = new TagsObj(json.SelectToken("tags"));
				Recipient = new RecipientObj(json.SelectToken("recipient"));
				Nonce = ((object)json.SelectToken("nonce"))?.ToString();
			}
		}

		public string Type { get; }

		public WhisperType TypeEnum { get; }

		public string Data { get; }

		public DataObjWhisperReceived DataObjectWhisperReceived { get; }

		public DataObjThread DataObjectThread { get; }

		public Whisper(string jsonStr)
		{
			JObject val = JObject.Parse(jsonStr);
			Type = ((object)((JToken)val).SelectToken("type")).ToString();
			Data = ((object)((JToken)val).SelectToken("data")).ToString();
			string type = Type;
			string text = type;
			if (!(text == "whisper_received"))
			{
				if (text == "thread")
				{
					TypeEnum = WhisperType.Thread;
					DataObjectThread = new DataObjThread(((JToken)val).SelectToken("data_object"));
				}
				else
				{
					TypeEnum = WhisperType.Unknown;
				}
			}
			else
			{
				TypeEnum = WhisperType.WhisperReceived;
				DataObjectWhisperReceived = new DataObjWhisperReceived(((JToken)val).SelectToken("data_object"));
			}
		}
	}
}
namespace TwitchLib.PubSub.Interfaces
{
	public interface ITwitchPubSub
	{
		event EventHandler<OnBanArgs> OnBan;

		event EventHandler<OnBitsReceivedArgs> OnBitsReceived;

		event EventHandler<OnChannelExtensionBroadcastArgs> OnChannelExtensionBroadcast;

		event EventHandler<OnChannelSubscriptionArgs> OnChannelSubscription;

		event EventHandler<OnClearArgs> OnClear;

		event EventHandler<OnChannelCommerceReceivedArgs> OnChannelCommerceReceived;

		event EventHandler<OnEmoteOnlyArgs> OnEmoteOnly;

		event EventHandler<OnEmoteOnlyOffArgs> OnEmoteOnlyOff;

		event EventHandler<OnFollowArgs> OnFollow;

		event EventHandler<OnHostArgs> OnHost;

		event EventHandler<OnMessageDeletedArgs> OnMessageDeleted;

		event EventHandler<OnListenResponseArgs> OnListenResponse;

		event EventHandler OnPubSubServiceClosed;

		event EventHandler OnPubSubServiceConnected;

		event EventHandler<OnPubSubServiceErrorArgs> OnPubSubServiceError;

		event EventHandler<OnR9kBetaArgs> OnR9kBeta;

		event EventHandler<OnR9kBetaOffArgs> OnR9kBetaOff;

		event EventHandler<OnStreamDownArgs> OnStreamDown;

		event EventHandler<OnStreamUpArgs> OnStreamUp;

		event EventHandler<OnSubscribersOnlyArgs> OnSubscribersOnly;

		event EventHandler<OnSubscribersOnlyOffArgs> OnSubscribersOnlyOff;

		event EventHandler<OnTimeoutArgs> OnTimeout;

		event EventHandler<OnUnbanArgs> OnUnban;

		event EventHandler<OnUntimeoutArgs> OnUntimeout;

		event EventHandler<OnViewCountArgs> OnViewCount;

		event EventHandler<OnWhisperArgs> OnWhisper;

		event EventHandler<OnCustomRewardCreatedArgs> OnCustomRewardCreated;

		event EventHandler<OnCustomRewardUpdatedArgs> OnCustomRewardUpdated;

		event EventHandler<OnCustomRewardDeletedArgs> OnCustomRewardDeleted;

		event EventHandler<OnRewardRedeemedArgs> OnRewardRedeemed;

		event EventHandler<OnLeaderboardEventArgs> OnLeaderboardSubs;

		event EventHandler<OnLeaderboardEventArgs> OnLeaderboardBits;

		event EventHandler<OnRaidUpdateArgs> OnRaidUpdate;

		event EventHandler<OnRaidUpdateV2Args> OnRaidUpdateV2;

		event EventHandler<OnRaidGoArgs> OnRaidGo;

		event EventHandler<OnLogArgs> OnLog;

		void Connect();

		void Disconnect();

		void ListenToBitsEvents(string channelTwitchId);

		void ListenToChannelExtensionBroadcast(string channelId, string extensionId);

		void ListenToChatModeratorActions(string myTwitchId, string channelTwitchId);

		void ListenToCommerce(string channelTwitchId);

		void ListenToFollows(string channelId);

		void ListenToSubscriptions(string channelId);

		void ListenToVideoPlayback(string channelName);

		void ListenToWhispers(string channelTwitchId);

		void ListenToRewards(string channelTwitchId);

		void ListenToLeaderboards(string channelTwitchId);

		void ListenToRaid(string channelTwitchId);

		void SendTopics(string oauth = null, bool unlisten = false);

		void TestMessageParser(string testJsonString);
	}
}
namespace TwitchLib.PubSub.Events
{
	public class OnBanArgs : EventArgs
	{
		public string BannedUserId;

		public string BannedUser;

		public string BanReason;

		public string BannedBy;

		public string BannedByUserId;

		public string ChannelId;
	}
	public class OnBitsReceivedArgs : EventArgs
	{
		public string Username;

		public string ChannelName;

		public string UserId;

		public string ChannelId;

		public string Time;

		public string ChatMessage;

		public int BitsUsed;

		public int TotalBitsUsed;

		public string Context;
	}
	public class OnChannelCommerceReceivedArgs : EventArgs
	{
		public string Username;

		public string DisplayName;

		public string ChannelName;

		public string UserId;

		public string ChannelId;

		public string Time;

		public string ItemImageURL;

		public string ItemDescription;

		public bool SupportsChannel;

		public string PurchaseMessage;
	}
	public class OnChannelExtensionBroadcastArgs : EventArgs
	{
		public List<string> Messages;

		public string ChannelId;
	}
	public class OnChannelSubscriptionArgs : EventArgs
	{
		public ChannelSubscription Subscription;

		public string ChannelId;
	}
	public class OnClearArgs : EventArgs
	{
		public string Moderator;

		public string ChannelId;
	}
	public class OnCommercialArgs : EventArgs
	{
		public int Length;

		public string ServerTime;
	}
	public class OnCustomRewardCreatedArgs : EventArgs
	{
		public DateTime TimeStamp;

		public string ChannelId;

		public Guid RewardId;

		public string RewardTitle;

		public string RewardPrompt;

		public int RewardCost;
	}
	public class OnCustomRewardDeletedArgs
	{
		public DateTime TimeStamp;

		public string ChannelId;

		public Guid RewardId;

		public string RewardTitle;

		public string RewardPrompt;
	}
	public class OnCustomRewardUpdatedArgs : EventArgs
	{
		public DateTime TimeStamp;

		public string ChannelId;

		public Guid RewardId;

		public string RewardTitle;

		public string RewardPrompt;

		public int RewardCost;
	}
	public class OnEmoteOnlyArgs : EventArgs
	{
		public string Moderator;

		public string ChannelId;
	}
	public class OnEmoteOnlyOffArgs : EventArgs
	{
		public string Moderator;

		public string ChannelId;
	}
	public class OnFollowArgs : EventArgs
	{
		public string FollowedChannelId;

		public string DisplayName;

		public string Username;

		public string UserId;
	}
	public class OnHostArgs : EventArgs
	{
		public string Moderator;

		public string HostedChannel;

		public string ChannelId;
	}
	public class OnLeaderboardEventArgs : EventArgs
	{
		public string ChannelId;

		public List<LeaderBoard> TopList;
	}
	public class OnListenResponseArgs : EventArgs
	{
		public string Topic;

		public Response Response;

		public bool Successful;
	}
	public class OnLogArgs : EventArgs
	{
		public string Data;
	}
	public class OnMessageDeletedArgs : EventArgs
	{
		public string TargetUser;

		public string TargetUserId;

		public string DeletedBy;

		public string DeletedByUserId;

		public string Message;

		public string MessageId;

		public string ChannelId;
	}
	public class OnPubSubServiceErrorArgs : EventArgs
	{
		public Exception Exception;
	}
	public class OnR9kBetaArgs : EventArgs
	{
		public string Moderator;

		public string ChannelId;
	}
	public class OnR9kBetaOffArgs : EventArgs
	{
		public string Moderator;

		public string ChannelId;
	}
	public class OnRaidGoArgs : EventArgs
	{
		public string ChannelId;

		public Guid Id;

		public string TargetChannelId;

		public string TargetLogin;

		public string TargetDisplayName;

		public string TargetProfileImage;

		public int ViewerCount;
	}
	public class OnRaidUpdateArgs : EventArgs
	{
		public string ChannelId;

		public Guid Id;

		public string TargetChannelId;

		public DateTime AnnounceTime;

		public DateTime RaidTime;

		public int RemainingDurationSeconds;

		public int ViewerCount;
	}
	public class OnRaidUpdateV2Args : EventArgs
	{
		public string ChannelId;

		public Guid Id;

		public string TargetChannelId;

		public string TargetLogin;

		public string TargetDisplayName;

		public string TargetProfileImage;

		public int ViewerCount;
	}
	public class OnRewardRedeemedArgs : EventArgs
	{
		public DateTime TimeStamp;

		public string ChannelId;

		public string Login;

		public string DisplayName;

		public string Message;

		public Guid RewardId;

		public string RewardTitle;

		public string RewardPrompt;

		public int RewardCost;

		public string Status;

		public Guid RedemptionId;
	}
	public class OnStreamDownArgs : EventArgs
	{
		public string ServerTime;
	}
	public class OnStreamUpArgs : EventArgs
	{
		public string ServerTime;

		public int PlayDelay;
	}
	public class OnSubscribersOnlyArgs : EventArgs
	{
		public string Moderator;

		public string ChannelId;
	}
	public class OnSubscribersOnlyOffArgs : EventArgs
	{
		public string Moderator;

		public string ChannelId;
	}
	public class OnTimeoutArgs : EventArgs
	{
		public string TimedoutUserId;

		public string TimedoutUser;

		public TimeSpan TimeoutDuration;

		public string TimeoutReason;

		public string TimedoutBy;

		public string TimedoutById;

		public string ChannelId;
	}
	public class OnUnbanArgs : EventArgs
	{
		public string UnbannedUser;

		public string UnbannedUserId;

		public string UnbannedBy;

		public string UnbannedByUserId;

		public string ChannelId;
	}
	public class OnUntimeoutArgs : EventArgs
	{
		public string UntimeoutedUser;

		public string UntimeoutedUserId;

		public string UntimeoutedBy;

		public string UntimeoutedByUserId;

		public string ChannelId;
	}
	public class OnViewCountArgs : EventArgs
	{
		public string ServerTime;

		public int Viewers;
	}
	public class OnWhisperArgs : EventArgs
	{
		public Whisper Whisper;

		public string ChannelId;
	}
}
namespace TwitchLib.PubSub.Enums
{
	public enum CommunityPointsChannelType
	{
		RewardRedeemed,
		CustomRewardUpdated,
		CustomRewardCreated,
		CustomRewardDeleted
	}
	public enum LeaderBoardType
	{
		BitsUsageByChannel,
		SubGiftSent
	}
	public enum PubSubRequestType
	{
		ListenToTopic
	}
	public enum RaidType
	{
		RaidUpdate,
		RaidUpdateV2,
		RaidGo
	}
	public enum SubscriptionPlan
	{
		NotSet,
		Prime,
		Tier1,
		Tier2,
		Tier3
	}
	public enum VideoPlaybackType
	{
		StreamUp,
		StreamDown,
		ViewCount,
		Commercial
	}
	public enum WhisperType
	{
		WhisperReceived,
		Thread,
		Unknown
	}
}
namespace TwitchLib.PubSub.Common
{
	public static class Helpers
	{
		public static DateTime DateTimeStringToObject(string dateTime)
		{
			return (dateTime == null) ? default(DateTime) : Convert.ToDateTime(dateTime);
		}

		public static string Base64Encode(string plainText)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(plainText);
			return Convert.ToBase64String(bytes);
		}
	}
}

lib/TwitchLib.Unity.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using System.Net.Security;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using TwitchLib.Api;
using TwitchLib.Api.Core.Interfaces;
using TwitchLib.Api.Interfaces;
using TwitchLib.Api.Services;
using TwitchLib.Api.Services.Events;
using TwitchLib.Api.Services.Events.FollowerService;
using TwitchLib.Api.Services.Events.LiveStreamMonitor;
using TwitchLib.Client;
using TwitchLib.Client.Enums;
using TwitchLib.Client.Events;
using TwitchLib.Client.Exceptions;
using TwitchLib.Client.Interfaces;
using TwitchLib.Communication.Events;
using TwitchLib.Communication.Interfaces;
using TwitchLib.PubSub;
using TwitchLib.PubSub.Events;
using TwitchLib.PubSub.Interfaces;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("TwitchLib")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright 2019")]
[assembly: AssemblyDescription("Unity wrapper system for TwitchLib")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("TwitchLib.Unity")]
[assembly: AssemblyTitle("TwitchLib.Unity")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/TwitchLib/TwitchLib.Unity")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace TwitchLib.Unity;

public class Api : TwitchAPI
{
	public void Invoke<T>(Task<T> func, Action<T> action)
	{
		if (func == null)
		{
			throw new ArgumentNullException("func");
		}
		if (action == null)
		{
			throw new ArgumentNullException("action");
		}
		InvokeInternal(func, action);
	}

	public void Invoke(Task func, Action action)
	{
		if (func == null)
		{
			throw new ArgumentNullException("func");
		}
		if (action == null)
		{
			throw new ArgumentNullException("action");
		}
		InvokeInternal(func, action);
	}

	public IEnumerator InvokeAsync<T>(Task<T> func, Action<T> action)
	{
		if (func == null)
		{
			throw new ArgumentNullException("func");
		}
		if (action == null)
		{
			throw new ArgumentNullException("action");
		}
		bool requestCompleted = false;
		InvokeInternal(func, delegate(T result)
		{
			action(result);
			requestCompleted = true;
		});
		yield return (object)new WaitUntil((Func<bool>)(() => requestCompleted));
	}

	public IEnumerator InvokeAsync(Task func)
	{
		if (func == null)
		{
			throw new ArgumentNullException("func");
		}
		bool requestCompleted = false;
		InvokeInternal(func, delegate
		{
			requestCompleted = true;
		});
		yield return (object)new WaitUntil((Func<bool>)(() => requestCompleted));
	}

	private void InvokeInternal(Task func, Action action)
	{
		ThreadDispatcher.EnsureCreated("InvokeInternal");
		func.ContinueWith(delegate(Task x)
		{
			x.Wait();
			ThreadDispatcher.Enqueue(delegate
			{
				action();
			});
		});
	}

	private void InvokeInternal<T>(Task<T> func, Action<T> action)
	{
		ThreadDispatcher.EnsureCreated("InvokeInternal");
		func.ContinueWith(delegate(Task<T> x)
		{
			T value = x.Result;
			ThreadDispatcher.Enqueue(delegate
			{
				action(value);
			});
		});
	}

	public Api()
		: base((ILoggerFactory)null, (IRateLimiter)null, (IApiSettings)null, (IHttpCallHandler)null)
	{
	}
}
public class CertificateValidationFix : MonoBehaviour
{
	[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
	private static void FixCertificateValidation()
	{
		ServicePointManager.ServerCertificateValidationCallback = CertificateValidationMonoFix;
	}

	private static bool CertificateValidationMonoFix(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
	{
		bool result = true;
		if (sslPolicyErrors == SslPolicyErrors.None)
		{
			return true;
		}
		X509ChainStatus[] chainStatus = chain.ChainStatus;
		foreach (X509ChainStatus x509ChainStatus in chainStatus)
		{
			if (x509ChainStatus.Status != X509ChainStatusFlags.RevocationStatusUnknown)
			{
				chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
				chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
				chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
				chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
				if (!chain.Build((X509Certificate2)certificate))
				{
					result = false;
				}
			}
		}
		return result;
	}
}
public class Client : TwitchClient, ITwitchClient
{
	public bool OverrideBeingHostedCheck { get; set; }

	public event EventHandler<OnLogArgs> OnLog;

	public event EventHandler<OnConnectedArgs> OnConnected;

	public event EventHandler<OnJoinedChannelArgs> OnJoinedChannel;

	public event EventHandler<OnIncorrectLoginArgs> OnIncorrectLogin;

	public event EventHandler<OnChannelStateChangedArgs> OnChannelStateChanged;

	public event EventHandler<OnUserStateChangedArgs> OnUserStateChanged;

	public event EventHandler<OnMessageReceivedArgs> OnMessageReceived;

	public event EventHandler<OnWhisperReceivedArgs> OnWhisperReceived;

	public event EventHandler<OnMessageSentArgs> OnMessageSent;

	public event EventHandler<OnWhisperSentArgs> OnWhisperSent;

	public event EventHandler<OnChatCommandReceivedArgs> OnChatCommandReceived;

	public event EventHandler<OnWhisperCommandReceivedArgs> OnWhisperCommandReceived;

	public event EventHandler<OnUserJoinedArgs> OnUserJoined;

	public event EventHandler<OnModeratorJoinedArgs> OnModeratorJoined;

	public event EventHandler<OnModeratorLeftArgs> OnModeratorLeft;

	public event EventHandler<OnNewSubscriberArgs> OnNewSubscriber;

	public event EventHandler<OnReSubscriberArgs> OnReSubscriber;

	public event EventHandler OnHostLeft;

	public event EventHandler<OnExistingUsersDetectedArgs> OnExistingUsersDetected;

	public event EventHandler<OnUserLeftArgs> OnUserLeft;

	public event EventHandler<OnHostingStartedArgs> OnHostingStarted;

	public event EventHandler<OnHostingStoppedArgs> OnHostingStopped;

	public event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

	public event EventHandler<OnConnectionErrorArgs> OnConnectionError;

	public event EventHandler<OnChatClearedArgs> OnChatCleared;

	public event EventHandler<OnUserTimedoutArgs> OnUserTimedout;

	public event EventHandler<OnLeftChannelArgs> OnLeftChannel;

	public event EventHandler<OnUserBannedArgs> OnUserBanned;

	public event EventHandler<OnModeratorsReceivedArgs> OnModeratorsReceived;

	public event EventHandler<OnChatColorChangedArgs> OnChatColorChanged;

	public event EventHandler<OnSendReceiveDataArgs> OnSendReceiveData;

	public event EventHandler<OnNowHostingArgs> OnNowHosting;

	public event EventHandler<OnBeingHostedArgs> OnBeingHosted;

	public event EventHandler<OnRaidNotificationArgs> OnRaidNotification;

	public event EventHandler<OnGiftedSubscriptionArgs> OnGiftedSubscription;

	public event EventHandler OnSelfRaidError;

	public event EventHandler OnNoPermissionError;

	public event EventHandler OnRaidedChannelIsMatureAudience;

	public event EventHandler<OnRitualNewChatterArgs> OnRitualNewChatter;

	public event EventHandler<OnFailureToReceiveJoinConfirmationArgs> OnFailureToReceiveJoinConfirmation;

	public event EventHandler<OnUnaccountedForArgs> OnUnaccountedFor;

	public event EventHandler<OnMessageClearedArgs> OnMessageCleared;

	public event EventHandler<OnReconnectedEventArgs> OnReconnected;

	public event EventHandler<OnWhisperThrottledEventArgs> OnWhisperThrottled;

	public event EventHandler<OnMessageThrottledEventArgs> OnMessageThrottled;

	public event EventHandler<OnCommunitySubscriptionArgs> OnCommunitySubscription;

	public event EventHandler<OnErrorEventArgs> OnError;

	public event EventHandler<OnVIPsReceivedArgs> OnVIPsReceived;

	public Client()
		: base((IClient)null, (ClientProtocol)1, (ILogger<TwitchClient>)null)
	{
		ThreadDispatcher.EnsureCreated(".ctor");
		((TwitchClient)this).OverrideBeingHostedCheck = true;
		((TwitchClient)this).OnLog += delegate(object sender, OnLogArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnLog?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnConnected += delegate(object sender, OnConnectedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnConnected?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnJoinedChannel += delegate(object sender, OnJoinedChannelArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnJoinedChannel?.Invoke(sender, e);
			});
			if (this.OnBeingHosted != null && e.Channel.ToLower() != ((TwitchClient)this).TwitchUsername && !OverrideBeingHostedCheck)
			{
				ThreadDispatcher.Enqueue(delegate
				{
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					throw new BadListenException("BeingHosted", "You cannot listen to OnBeingHosted unless you are connected to the broadcaster's channel as the broadcaster. You may override this by setting the TwitchClient property OverrideBeingHostedCheck to true.");
				});
			}
		};
		((TwitchClient)this).OnIncorrectLogin += delegate(object sender, OnIncorrectLoginArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnIncorrectLogin?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnChannelStateChanged += delegate(object sender, OnChannelStateChangedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChannelStateChanged?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnUserStateChanged += delegate(object sender, OnUserStateChangedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUserStateChanged?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnMessageReceived += delegate(object sender, OnMessageReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnMessageReceived?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnWhisperReceived += delegate(object sender, OnWhisperReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnWhisperReceived?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnMessageSent += delegate(object sender, OnMessageSentArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnMessageSent?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnWhisperSent += delegate(object sender, OnWhisperSentArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnWhisperSent?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnChatCommandReceived += delegate(object sender, OnChatCommandReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChatCommandReceived?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnWhisperCommandReceived += delegate(object sender, OnWhisperCommandReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnWhisperCommandReceived?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnUserJoined += delegate(object sender, OnUserJoinedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUserJoined?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnModeratorJoined += delegate(object sender, OnModeratorJoinedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnModeratorJoined?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnModeratorLeft += delegate(object sender, OnModeratorLeftArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnModeratorLeft?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnNewSubscriber += delegate(object sender, OnNewSubscriberArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnNewSubscriber?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnReSubscriber += delegate(object sender, OnReSubscriberArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnReSubscriber?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnHostLeft += delegate(object sender, EventArgs arg)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnHostLeft?.Invoke(sender, arg);
			});
		};
		((TwitchClient)this).OnExistingUsersDetected += delegate(object sender, OnExistingUsersDetectedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnExistingUsersDetected?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnUserLeft += delegate(object sender, OnUserLeftArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUserLeft?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnHostingStarted += delegate(object sender, OnHostingStartedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnHostingStarted?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnHostingStopped += delegate(object sender, OnHostingStoppedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnHostingStopped?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnDisconnected += delegate(object sender, OnDisconnectedEventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnDisconnected?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnConnectionError += delegate(object sender, OnConnectionErrorArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnConnectionError?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnChatCleared += delegate(object sender, OnChatClearedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChatCleared?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnUserTimedout += delegate(object sender, OnUserTimedoutArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUserTimedout?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnLeftChannel += delegate(object sender, OnLeftChannelArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnLeftChannel?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnUserBanned += delegate(object sender, OnUserBannedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUserBanned?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnModeratorsReceived += delegate(object sender, OnModeratorsReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnModeratorsReceived?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnChatColorChanged += delegate(object sender, OnChatColorChangedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChatColorChanged?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnSendReceiveData += delegate(object sender, OnSendReceiveDataArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnSendReceiveData?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnNowHosting += delegate(object sender, OnNowHostingArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnNowHosting?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnBeingHosted += delegate(object sender, OnBeingHostedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnBeingHosted?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnRaidNotification += delegate(object sender, OnRaidNotificationArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnRaidNotification?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnGiftedSubscription += delegate(object sender, OnGiftedSubscriptionArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnGiftedSubscription?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnRaidedChannelIsMatureAudience += delegate(object sender, EventArgs arg)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnRaidedChannelIsMatureAudience?.Invoke(sender, arg);
			});
		};
		((TwitchClient)this).OnRitualNewChatter += delegate(object sender, OnRitualNewChatterArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnRitualNewChatter?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnFailureToReceiveJoinConfirmation += delegate(object sender, OnFailureToReceiveJoinConfirmationArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnFailureToReceiveJoinConfirmation?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnUnaccountedFor += delegate(object sender, OnUnaccountedForArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUnaccountedFor?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnSelfRaidError += delegate(object sender, EventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnSelfRaidError?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnNoPermissionError += delegate(object sender, EventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnNoPermissionError?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnMessageCleared += delegate(object sender, OnMessageClearedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnMessageCleared?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnReconnected += delegate(object sender, OnReconnectedEventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnReconnected?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnWhisperThrottled += delegate(object sender, OnWhisperThrottledEventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnWhisperThrottled?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnMessageThrottled += delegate(object sender, OnMessageThrottledEventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnMessageThrottled?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnCommunitySubscription += delegate(object sender, OnCommunitySubscriptionArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnCommunitySubscription?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnError += delegate(object sender, OnErrorEventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnError?.Invoke(sender, e);
			});
		};
		((TwitchClient)this).OnVIPsReceived += delegate(object sender, OnVIPsReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnVIPsReceived?.Invoke(sender, e);
			});
		};
	}

	private void HandleNotInitialized()
	{
		ThreadDispatcher.Enqueue(delegate
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			throw new ClientNotInitializedException("The twitch client has not been initialized and cannot be used. Please call Initialize();");
		});
	}
}
public static class ColorExtension
{
	public static Color ToUnity(this Color color)
	{
		//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_0029: Unknown result type (might be due to invalid IL or missing references)
		return new Color((float)(int)color.R, (float)(int)color.G, (float)(int)color.B, (float)(int)color.A);
	}
}
public class PubSub : TwitchPubSub, ITwitchPubSub
{
	public event EventHandler OnPubSubServiceConnected;

	public event EventHandler<OnPubSubServiceErrorArgs> OnPubSubServiceError;

	public event EventHandler OnPubSubServiceClosed;

	public event EventHandler<OnListenResponseArgs> OnListenResponse;

	public event EventHandler<OnTimeoutArgs> OnTimeout;

	public event EventHandler<OnBanArgs> OnBan;

	public event EventHandler<OnUnbanArgs> OnUnban;

	public event EventHandler<OnUntimeoutArgs> OnUntimeout;

	public event EventHandler<OnHostArgs> OnHost;

	public event EventHandler<OnSubscribersOnlyArgs> OnSubscribersOnly;

	public event EventHandler<OnSubscribersOnlyOffArgs> OnSubscribersOnlyOff;

	public event EventHandler<OnClearArgs> OnClear;

	public event EventHandler<OnEmoteOnlyArgs> OnEmoteOnly;

	public event EventHandler<OnEmoteOnlyOffArgs> OnEmoteOnlyOff;

	public event EventHandler<OnR9kBetaArgs> OnR9kBeta;

	public event EventHandler<OnR9kBetaOffArgs> OnR9kBetaOff;

	public event EventHandler<OnBitsReceivedArgs> OnBitsReceived;

	public event EventHandler<OnStreamUpArgs> OnStreamUp;

	public event EventHandler<OnStreamDownArgs> OnStreamDown;

	public event EventHandler<OnViewCountArgs> OnViewCount;

	public event EventHandler<OnWhisperArgs> OnWhisper;

	public event EventHandler<OnChannelSubscriptionArgs> OnChannelSubscription;

	public event EventHandler<OnChannelCommerceReceivedArgs> OnChannelCommerceReceived;

	public event EventHandler<OnChannelExtensionBroadcastArgs> OnChannelExtensionBroadcast;

	public event EventHandler<OnFollowArgs> OnFollow;

	public event EventHandler<OnCustomRewardCreatedArgs> OnCustomRewardCreated;

	public event EventHandler<OnCustomRewardUpdatedArgs> OnCustomRewardUpdated;

	public event EventHandler<OnCustomRewardDeletedArgs> OnCustomRewardDeleted;

	public event EventHandler<OnRewardRedeemedArgs> OnRewardRedeemed;

	public event EventHandler<OnLeaderboardEventArgs> OnLeaderboardSubs;

	public event EventHandler<OnLeaderboardEventArgs> OnLeaderboardBits;

	public event EventHandler<OnRaidUpdateArgs> OnRaidUpdate;

	public event EventHandler<OnRaidUpdateV2Args> OnRaidUpdateV2;

	public event EventHandler<OnRaidGoArgs> OnRaidGo;

	public event EventHandler<OnMessageDeletedArgs> OnMessageDeleted;

	public event EventHandler<OnLogArgs> OnLog;

	public PubSub(EndPoint proxy = null)
		: base((ILogger<TwitchPubSub>)null)
	{
		ThreadDispatcher.EnsureCreated(".ctor");
		((TwitchPubSub)this).OnPubSubServiceConnected += delegate(object sender, EventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnPubSubServiceConnected?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnPubSubServiceError += delegate(object sender, OnPubSubServiceErrorArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnPubSubServiceError?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnPubSubServiceClosed += delegate(object sender, EventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnPubSubServiceClosed?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnListenResponse += delegate(object sender, OnListenResponseArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnListenResponse?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnTimeout += delegate(object sender, OnTimeoutArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnTimeout?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnBan += delegate(object sender, OnBanArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnBan?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnUnban += delegate(object sender, OnUnbanArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUnban?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnUntimeout += delegate(object sender, OnUntimeoutArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnUntimeout?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnHost += delegate(object sender, OnHostArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnHost?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnSubscribersOnly += delegate(object sender, OnSubscribersOnlyArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnSubscribersOnly?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnSubscribersOnlyOff += delegate(object sender, OnSubscribersOnlyOffArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnSubscribersOnlyOff?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnClear += delegate(object sender, OnClearArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnClear?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnEmoteOnly += delegate(object sender, OnEmoteOnlyArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnEmoteOnly?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnEmoteOnlyOff += delegate(object sender, OnEmoteOnlyOffArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnEmoteOnlyOff?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnR9kBeta += delegate(object sender, OnR9kBetaArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnR9kBeta?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnR9kBetaOff += delegate(object sender, OnR9kBetaOffArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnR9kBetaOff?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnBitsReceived += delegate(object sender, OnBitsReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnBitsReceived?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnStreamUp += delegate(object sender, OnStreamUpArgs arg)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnStreamUp(sender, arg);
			});
		};
		((TwitchPubSub)this).OnStreamDown += delegate(object sender, OnStreamDownArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnStreamDown?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnViewCount += delegate(object sender, OnViewCountArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnViewCount?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnWhisper += delegate(object sender, OnWhisperArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnWhisper?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnChannelSubscription += delegate(object sender, OnChannelSubscriptionArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChannelSubscription?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnChannelCommerceReceived += delegate(object sender, OnChannelCommerceReceivedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChannelCommerceReceived?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnChannelExtensionBroadcast += delegate(object sender, OnChannelExtensionBroadcastArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChannelExtensionBroadcast?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnFollow += delegate(object sender, OnFollowArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnFollow?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnCustomRewardCreated += delegate(object sender, OnCustomRewardCreatedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnCustomRewardCreated?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnCustomRewardUpdated += delegate(object sender, OnCustomRewardUpdatedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnCustomRewardUpdated?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnCustomRewardDeleted += delegate(object sender, OnCustomRewardDeletedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnCustomRewardDeleted?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnRewardRedeemed += delegate(object sender, OnRewardRedeemedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnRewardRedeemed?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnLeaderboardSubs += delegate(object sender, OnLeaderboardEventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnLeaderboardSubs?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnLeaderboardBits += delegate(object sender, OnLeaderboardEventArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnLeaderboardBits?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnRaidUpdate += delegate(object sender, OnRaidUpdateArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnRaidUpdate?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnRaidUpdateV2 += delegate(object sender, OnRaidUpdateV2Args e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnRaidUpdateV2?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnRaidGo += delegate(object sender, OnRaidGoArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnRaidGo?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnMessageDeleted += delegate(object sender, OnMessageDeletedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnMessageDeleted?.Invoke(sender, e);
			});
		};
		((TwitchPubSub)this).OnLog += delegate(object sender, OnLogArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnLog?.Invoke(sender, e);
			});
		};
	}
}
public class ThreadDispatcher : MonoBehaviour
{
	private static ThreadDispatcher _instance;

	private static Queue<Action> _executionQueue = new Queue<Action>();

	public static void EnsureCreated([CallerMemberName] string callerMemberName = null)
	{
		if (Application.isPlaying && ((Object)(object)_instance == (Object)null || (Object)(object)((Component)_instance).gameObject == (Object)null))
		{
			_instance = CreateThreadDispatcherSingleton(callerMemberName);
		}
	}

	public static void Enqueue(Action action)
	{
		_executionQueue.Enqueue(action);
	}

	private void Update()
	{
		int count = _executionQueue.Count;
		for (int i = 0; i < count; i++)
		{
			_executionQueue.Dequeue()();
		}
	}

	private static ThreadDispatcher CreateThreadDispatcherSingleton(string callerMemberName)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!UnityThread.CurrentIsMainThread)
		{
			throw new InvalidOperationException("The " + callerMemberName + " can only be created from the main thread. Did you accidentally delete the ThreadDispatcher in your scene?");
		}
		ThreadDispatcher threadDispatcher = new GameObject("ThreadDispatcher").AddComponent<ThreadDispatcher>();
		Object.DontDestroyOnLoad((Object)(object)threadDispatcher);
		return threadDispatcher;
	}
}
public class UnityFollowerService : FollowerService
{
	public event EventHandler<OnServiceStartedArgs> OnServiceStarted;

	public event EventHandler<OnServiceStoppedArgs> OnServiceStopped;

	public event EventHandler<OnNewFollowersDetectedArgs> OnNewFollowersDetected;

	public UnityFollowerService(ITwitchAPI api, int checkIntervalSeconds = 60, int queryCount = 25)
		: base(api, checkIntervalSeconds, queryCount, 1000)
	{
		ThreadDispatcher.EnsureCreated(".ctor");
		((ApiService)this).OnServiceStarted += delegate(object sender, OnServiceStartedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnServiceStarted?.Invoke(sender, e);
			});
		};
		((ApiService)this).OnServiceStopped += delegate(object sender, OnServiceStoppedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnServiceStopped?.Invoke(sender, e);
			});
		};
		((FollowerService)this).OnNewFollowersDetected += delegate(object sender, OnNewFollowersDetectedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnNewFollowersDetected?.Invoke(sender, e);
			});
		};
	}
}
public class UnityLiveStreamMonitor : LiveStreamMonitorService
{
	public event EventHandler<OnStreamOnlineArgs> OnStreamOnline;

	public event EventHandler<OnStreamOfflineArgs> OnStreamOffline;

	public event EventHandler<OnStreamUpdateArgs> OnStreamUpdate;

	public event EventHandler<OnServiceStartedArgs> OnServiceStarted;

	public event EventHandler<OnServiceStoppedArgs> OnServiceStopped;

	public event EventHandler<OnChannelsSetArgs> OnChannelsSet;

	public UnityLiveStreamMonitor(ITwitchAPI api, int checkIntervalSeconds = 60, int maxStreamRequestCountPerRequest = 100)
		: base(api, checkIntervalSeconds, maxStreamRequestCountPerRequest)
	{
		ThreadDispatcher.EnsureCreated(".ctor");
		((LiveStreamMonitorService)this).OnStreamOnline += delegate(object sender, OnStreamOnlineArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnStreamOnline?.Invoke(sender, e);
			});
		};
		((LiveStreamMonitorService)this).OnStreamOffline += delegate(object sender, OnStreamOfflineArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnStreamOffline?.Invoke(sender, e);
			});
		};
		((LiveStreamMonitorService)this).OnStreamUpdate += delegate(object sender, OnStreamUpdateArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnStreamUpdate?.Invoke(sender, e);
			});
		};
		((ApiService)this).OnServiceStarted += delegate(object sender, OnServiceStartedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnServiceStarted?.Invoke(sender, e);
			});
		};
		((ApiService)this).OnServiceStopped += delegate(object sender, OnServiceStoppedArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnServiceStopped?.Invoke(sender, e);
			});
		};
		((ApiService)this).OnChannelsSet += delegate(object sender, OnChannelsSetArgs e)
		{
			ThreadDispatcher.Enqueue(delegate
			{
				this.OnChannelsSet?.Invoke(sender, e);
			});
		};
	}
}
public class UnityThread : MonoBehaviour
{
	private static Thread _mainThread;

	public static Thread Main => _mainThread;

	public static bool CurrentIsMainThread => _mainThread == null || _mainThread == Thread.CurrentThread;

	[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
	private static void SetMainUnityThread()
	{
		_mainThread = Thread.CurrentThread;
	}
}

lib/VsTwitch.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates.Missions.BrotherEncounter;
using HG;
using HG.Reflection;
using Microsoft.Extensions.Logging;
using On.EntityStates.Missions.BrotherEncounter;
using On.RoR2;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.Artifacts;
using RoR2.CharacterAI;
using RoR2.Networking;
using RoR2.UI;
using Tiltify;
using Tiltify.Events;
using TwitchLib.Api;
using TwitchLib.Api.Helix.Models.Users;
using TwitchLib.Client;
using TwitchLib.Client.Events;
using TwitchLib.Client.Models;
using TwitchLib.Communication.Events;
using TwitchLib.PubSub;
using TwitchLib.PubSub.Events;
using TwitchLib.Unity;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("VsTwitch")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("VsTwitch")]
[assembly: AssemblyTitle("VsTwitch")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace VsTwitch;

public class Configuration
{
	public enum VoteStrategies
	{
		MaxVote,
		MaxVoteRandomTie,
		Percentile
	}

	public ConfigEntry<string> TwitchChannel { get; set; }

	public ConfigEntry<string> TwitchClientID { get; set; }

	public ConfigEntry<string> TwitchUsername { get; set; }

	public ConfigEntry<string> TwitchOAuth { get; set; }

	public ConfigEntry<bool> TwitchDebugLogs { get; set; }

	public ConfigEntry<bool> EnableItemVoting { get; set; }

	public ConfigEntry<int> VoteDurationSec { get; set; }

	public ConfigEntry<VoteStrategies> VoteStrategy { get; set; }

	public ConfigEntry<bool> EnableBitEvents { get; set; }

	public ConfigEntry<int> BitsThreshold { get; set; }

	public ConfigEntry<int> CurrentBits { get; set; }

	public ConfigEntry<bool> PublishToChat { get; set; }

	public ConfigEntry<string> TiltifyCampaignId { get; set; }

	public ConfigEntry<float> BitStormWeight { get; set; }

	public ConfigEntry<float> BountyWeight { get; set; }

	public ConfigEntry<float> ShrineOfOrderWeight { get; set; }

	public ConfigEntry<float> ShrineOfTheMountainWeight { get; set; }

	public ConfigEntry<float> TitanWeight { get; set; }

	public ConfigEntry<float> LunarWispWeight { get; set; }

	public ConfigEntry<float> MithrixWeight { get; set; }

	public ConfigEntry<float> ElderLemurianWeight { get; set; }

	public ConfigEntry<bool> ChannelPointsEnable { get; set; }

	public ConfigEntry<string> ChannelPointsAllyBeetle { get; set; }

	public ConfigEntry<string> ChannelPointsAllyLemurian { get; set; }

	public ConfigEntry<string> ChannelPointsAllyElderLemurian { get; set; }

	public ConfigEntry<string> ChannelPointsRustedKey { get; set; }

	public ConfigEntry<string> ChannelPointsBitStorm { get; set; }

	public ConfigEntry<string> ChannelPointsBounty { get; set; }

	public ConfigEntry<string> ChannelPointsShrineOfOrder { get; set; }

	public ConfigEntry<string> ChannelPointsShrineOfTheMountain { get; set; }

	public ConfigEntry<string> ChannelPointsTitan { get; set; }

	public ConfigEntry<string> ChannelPointsLunarWisp { get; set; }

	public ConfigEntry<string> ChannelPointsMithrix { get; set; }

	public ConfigEntry<string> ChannelPointsElderLemurian { get; set; }

	public ConfigEntry<bool> SimpleUI { get; set; }

	public ConfigEntry<bool> EnableChoosingLunarItems { get; set; }

	public ConfigEntry<bool> ForceUniqueRolls { get; set; }

	public ConfigEntry<bool> EnableLanguageEdits { get; set; }

	public Configuration(BaseUnityPlugin plugin, UnityAction reloadChannelPoints)
	{
		TwitchChannel = plugin.Config.Bind<string>("Twitch", "Channel", "", "Your Twitch channel name");
		TwitchClientID = (TwitchUsername = plugin.Config.Bind<string>("Twitch", "ClientID", "q6batx0epp608isickayubi39itsckt", "Client ID used to get ImplicitOAuth value"));
		TwitchUsername = plugin.Config.Bind<string>("Twitch", "Username", "", "Your Twitch username");
		TwitchOAuth = plugin.Config.Bind<string>("Twitch", "ImplicitOAuth", "", "Implicit OAuth code (this is not your password - it's a generated password!). See the README/Mod Description in the thunderstore to see how to get it.");
		TwitchDebugLogs = plugin.Config.Bind<bool>("Twitch", "DebugLogs", false, "Enable debug logging for Twitch - will spam to the console!");
		EnableItemVoting = plugin.Config.Bind<bool>("Twitch", "EnableItemVoting", true, "Enable item voting on Twitch.");
		VoteDurationSec = plugin.Config.Bind<int>("Twitch", "VoteDurationdSec", 20, "How long to allow twitch voting.");
		VoteStrategy = plugin.Config.Bind<VoteStrategies>("Twitch", "VoteStrategy", VoteStrategies.MaxVote, "How to tabulate votes. One of: MaxVote, MaxVoteRandomTie, Percentile");
		EnableBitEvents = plugin.Config.Bind<bool>("Twitch", "EnableBitEvents", true, "Enable bit events from Twitch.");
		BitsThreshold = plugin.Config.Bind<int>("Twitch", "BitsThreshold", 1500, "How many Bits are needed before something happens.");
		CurrentBits = plugin.Config.Bind<int>("Twitch", "CurrentBits", 0, "(DO NOT EDIT) How many Bits have currently been donated.");
		PublishToChat = plugin.Config.Bind<bool>("Twitch", "PublishToChat", true, "Publish events (like voting) to Twitch chat.");
		TiltifyCampaignId = plugin.Config.Bind<string>("Tiltify", "CampaignId", "", "Tiltify Campaign ID to track donations");
		BitStormWeight = plugin.Config.Bind<float>("Event", "BitStormWeight", 1f, "Weight for the bit storm bit event. Set to 0 to disable.");
		BountyWeight = plugin.Config.Bind<float>("Event", "BountyWeight", 1f, "Weight for the doppleganger bit event. Set to 0 to disable.");
		ShrineOfOrderWeight = plugin.Config.Bind<float>("Event", "ShrineOfOrderWeight", 1f, "Weight for the Shrine of Order bit event. Set to 0 to disable.");
		ShrineOfTheMountainWeight = plugin.Config.Bind<float>("Event", "ShrineOfTheMountainWeight", 1f, "Weight for the Shrine of the Mountain bit event. Set to 0 to disable.");
		TitanWeight = plugin.Config.Bind<float>("Event", "TitanWeight", 1f, "Weight for the Aurelionite bit event. Set to 0 to disable.");
		LunarWispWeight = plugin.Config.Bind<float>("Event", "LunarWispWeight", 1f, "Weight for the Lunar Chimera (Wisp) bit event. Set to 0 to disable.");
		MithrixWeight = plugin.Config.Bind<float>("Event", "MithrixWeight", 1f, "Weight for the Mithrix bit event. Set to 0 to disable.");
		ElderLemurianWeight = plugin.Config.Bind<float>("Event", "ElderLemurianWeight", 1f, "Weight for the Elder Lemurian bit event. Set to 0 to disable.");
		ChannelPointsEnable = plugin.Config.Bind<bool>("ChannelPoints", "Enable", true, "Enable all Channel Point features.");
		ChannelPointsAllyBeetle = plugin.Config.Bind<string>("ChannelPoints", "AllyBeetle", "", "(Case Sensitive!) Channel Points Title to spawn Ally Elite Beetle. Leave empty to disable.");
		ChannelPointsAllyLemurian = plugin.Config.Bind<string>("ChannelPoints", "AllyLemurian", "", "(Case Sensitive!) Channel Points Title to spawn Ally Elite Lemurian. Leave empty to disable.");
		ChannelPointsAllyElderLemurian = plugin.Config.Bind<string>("ChannelPoints", "AllyElderLemurian", "", "(Case Sensitive!) Channel Points Title to spawn Ally Elite Elder Lemurian. Leave empty to disable.");
		ChannelPointsRustedKey = plugin.Config.Bind<string>("ChannelPoints", "RustedKey", "", "(Case Sensitive!) Channel Points Title to give everyone a Rusted Key. Leave empty to disable.");
		ChannelPointsBitStorm = plugin.Config.Bind<string>("ChannelPoints", "BitStorm", "", "(Case Sensitive!) Channel Points Title for the bit storm bit event. Leave empty to disable.");
		ChannelPointsBounty = plugin.Config.Bind<string>("ChannelPoints", "Bounty", "", "(Case Sensitive!) Channel Points Title for the doppleganger bit event. Leave empty to disable.");
		ChannelPointsShrineOfOrder = plugin.Config.Bind<string>("ChannelPoints", "ShrineOfOrder", "", "(Case Sensitive!) Channel Points Title for the Shrine of Order bit event. Leave empty to disable.");
		ChannelPointsShrineOfTheMountain = plugin.Config.Bind<string>("ChannelPoints", "ShrineOfTheMountain", "", "(Case Sensitive!) Channel Points Title for the Shrine of the Mountain bit event. Leave empty to disable.");
		ChannelPointsTitan = plugin.Config.Bind<string>("ChannelPoints", "Titan", "", "(Case Sensitive!) Channel Points Title for the Aurelionite bit event. Leave empty to disable.");
		ChannelPointsLunarWisp = plugin.Config.Bind<string>("ChannelPoints", "LunarWisp", "", "(Case Sensitive!) Channel Points Title for the Lunar Chimera (Wisp) bit event. Leave empty to disable.");
		ChannelPointsMithrix = plugin.Config.Bind<string>("ChannelPoints", "Mithrix", "", "(Case Sensitive!) Channel Points Title for the Mithrix bit event. Leave empty to disable.");
		ChannelPointsElderLemurian = plugin.Config.Bind<string>("ChannelPoints", "ElderLemurian", "", "(Case Sensitive!) Channel Points Title for the Elder Lemurian bit event. Leave empty to disable.");
		SimpleUI = plugin.Config.Bind<bool>("UI", "SimpleUI", false, "Simplify the UI. Set to true if you are playing Multiplayer.");
		EnableChoosingLunarItems = plugin.Config.Bind<bool>("Behaviour", "EnableChoosingLunarItems", true, "Twitch Chat chooses items when opening lunar chests (pods)");
		ForceUniqueRolls = plugin.Config.Bind<bool>("Behaviour", "ForceUniqueRolls", false, "Ensure, when rolling for items, that they are always different. This doesn't affect multi-shops.");
		EnableLanguageEdits = plugin.Config.Bind<bool>("Language", "EnableLanguageEdits", true, "Enable all Language Edits.");
		ApplyRiskOfOptions(reloadChannelPoints);
	}

	private void ApplyRiskOfOptions(UnityAction reloadChannelPoints)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		//IL_0030: 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_0041: Expected O, but got Unknown
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Expected O, but got Unknown
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Expected O, but got Unknown
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Expected O, but got Unknown
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: 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)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Expected O, but got Unknown
		//IL_009a: Expected O, but got Unknown
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Expected O, but got Unknown
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Expected O, but got Unknown
		//IL_00c9: Expected O, but got Unknown
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Expected O, but got Unknown
		//IL_00d5: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Expected O, but got Unknown
		//IL_00f1: Expected O, but got Unknown
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Expected O, but got Unknown
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Expected O, but got Unknown
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Expected O, but got Unknown
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Expected O, but got Unknown
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Expected O, but got Unknown
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Expected O, but got Unknown
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Expected O, but got Unknown
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Expected O, but got Unknown
		//IL_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Expected O, but got Unknown
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Expected O, but got Unknown
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0304: Unknown result type (might be due to invalid IL or missing references)
		//IL_030c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0316: Expected O, but got Unknown
		//IL_031b: Expected O, but got Unknown
		//IL_0316: Unknown result type (might be due to invalid IL or missing references)
		//IL_0320: Expected O, but got Unknown
		//IL_0342: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Expected O, but got Unknown
		//IL_0353: Unknown result type (might be due to invalid IL or missing references)
		//IL_035d: Expected O, but got Unknown
		//IL_0364: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Expected O, but got Unknown
		//IL_0375: Unknown result type (might be due to invalid IL or missing references)
		//IL_037a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0386: Expected O, but got Unknown
		//IL_0381: Unknown result type (might be due to invalid IL or missing references)
		//IL_038b: Expected O, but got Unknown
		try
		{
			ModSettingsManager.SetModDescription("Fight Twitch chat. Item voting, bit events, channel points integration, and more!");
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(TwitchChannel, new InputFieldConfig
			{
				restartRequired = true
			}));
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(TwitchUsername, new InputFieldConfig
			{
				restartRequired = true
			}));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(TwitchDebugLogs));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableItemVoting));
			ModSettingsManager.AddOption((BaseOption)new IntSliderOption(VoteDurationSec, new IntSliderConfig
			{
				min = 1,
				max = 120,
				checkIfDisabled = (IsDisabledDelegate)(() => !EnableItemVoting.Value)
			}));
			ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)VoteStrategy, new ChoiceConfig
			{
				restartRequired = true,
				checkIfDisabled = (IsDisabledDelegate)(() => !EnableItemVoting.Value)
			}));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PublishToChat, new CheckBoxConfig
			{
				checkIfDisabled = (IsDisabledDelegate)(() => !EnableItemVoting.Value)
			}));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableBitEvents));
			ModSettingsManager.AddOption((BaseOption)new IntSliderOption(BitsThreshold, new IntSliderConfig
			{
				min = 100,
				max = 100000
			}));
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(TiltifyCampaignId, new InputFieldConfig
			{
				restartRequired = true
			}));
			foreach (ConfigEntry<float> item in new List<ConfigEntry<float>> { BitStormWeight, BountyWeight, ShrineOfOrderWeight, ShrineOfTheMountainWeight, TitanWeight, LunarWispWeight, MithrixWeight, ElderLemurianWeight })
			{
				ModSettingsManager.AddOption((BaseOption)new StepSliderOption(item, new StepSliderConfig
				{
					min = 0f,
					max = 10f,
					increment = 1f
				}));
			}
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ChannelPointsEnable));
			ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Re-apply Channel Points Config", "ChannelPoints", "Reload Channel Points settings in the game. You MUST click this button if you've changed any entries on this Channel Points page for it to take effect!", "Apply", reloadChannelPoints));
			foreach (ConfigEntry<string> item2 in new List<ConfigEntry<string>>
			{
				ChannelPointsAllyBeetle, ChannelPointsAllyLemurian, ChannelPointsAllyElderLemurian, ChannelPointsRustedKey, ChannelPointsBitStorm, ChannelPointsBounty, ChannelPointsShrineOfOrder, ChannelPointsShrineOfTheMountain, ChannelPointsTitan, ChannelPointsLunarWisp,
				ChannelPointsMithrix, ChannelPointsElderLemurian
			})
			{
				ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(item2, new InputFieldConfig
				{
					checkIfDisabled = (IsDisabledDelegate)(() => !ChannelPointsEnable.Value)
				}));
			}
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(SimpleUI));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableChoosingLunarItems));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ForceUniqueRolls));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableLanguageEdits, new CheckBoxConfig
			{
				restartRequired = true
			}));
		}
		catch (Exception data)
		{
			Log.Exception(data);
		}
	}
}
internal class EventDirector : MonoBehaviour
{
	private class ForceChargingHandle : IDisposable
	{
		private readonly EventDirector eventDirector;

		private int disposed;

		public ForceChargingHandle(EventDirector eventDirector)
		{
			this.eventDirector = eventDirector;
			disposed = 0;
		}

		public void Dispose()
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			int num = Interlocked.Exchange(ref disposed, 1);
			if (num != 1)
			{
				int num2 = Interlocked.Decrement(ref eventDirector.forceChargingCount);
				if (num2 < 0)
				{
					Log.Error("Something didn't correctly ref count ForceChargingState!");
					Log.Exception(new Exception());
					Interlocked.Exchange(ref eventDirector.forceChargingCount, 0);
					num2 = 0;
				}
				Log.Error($"EventDirector::ForceChargingState::Count = {num2}");
				if (num2 == 0)
				{
					Log.Error("EventDirector::ForceChargingState::Enabled = false");
					TeleporterInteraction.UpdateMonstersClear -= new hook_UpdateMonstersClear(eventDirector.TeleporterInteraction_UpdateMonstersClear);
					eventDirector.SetTeleporterCrystals(enabled: false);
				}
			}
		}
	}

	private BlockingCollection<Func<EventDirector, IEnumerator>> eventQueue;

	private bool previousState;

	private int forceChargingCount;

	public event EventHandler<bool> OnProcessingEventsChanged;

	public void Awake()
	{
		eventQueue = new BlockingCollection<Func<EventDirector, IEnumerator>>();
		previousState = false;
		forceChargingCount = 0;
	}

	public void OnDestroy()
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		if (Interlocked.Exchange(ref forceChargingCount, 0) > 0)
		{
			TeleporterInteraction.UpdateMonstersClear -= new hook_UpdateMonstersClear(TeleporterInteraction_UpdateMonstersClear);
		}
	}

	public void Update()
	{
		bool flag = ShouldProcessEvents();
		if (flag != previousState)
		{
			previousState = flag;
			try
			{
				this.OnProcessingEventsChanged?.Invoke(this, flag);
			}
			catch (Exception data)
			{
				Log.Exception(data);
			}
		}
		if (!flag || !eventQueue.TryTake(out var item))
		{
			return;
		}
		try
		{
			((MonoBehaviour)this).StartCoroutine(Wrap(item(this)));
		}
		catch (Exception data2)
		{
			Log.Exception(data2);
		}
	}

	public void AddEvent(Func<EventDirector, IEnumerator> eventToQueue)
	{
		eventQueue.Add(eventToQueue);
	}

	public void ClearEvents()
	{
		Func<EventDirector, IEnumerator> item;
		while (eventQueue.TryTake(out item))
		{
		}
	}

	private void SetTeleporterCrystals(bool enabled)
	{
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Expected O, but got Unknown
		if (!Object.op_Implicit((Object)(object)TeleporterInteraction.instance))
		{
			return;
		}
		ChildLocator component = ((Component)((Component)TeleporterInteraction.instance).GetComponent<ModelLocator>().modelTransform).GetComponent<ChildLocator>();
		if (Object.op_Implicit((Object)(object)component))
		{
			if (enabled)
			{
				((Component)component.FindChild("TimeCrystalProps")).gameObject.SetActive(true);
			}
			Transform val = component.FindChild("TimeCrystalBeaconBlocker");
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/TimeCrystalDeath"), new EffectData
			{
				origin = ((Component)val).transform.position
			}, true);
			((Component)val).gameObject.SetActive(enabled);
		}
	}

	public IDisposable CreateOpenTeleporterObjectiveHandle()
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Expected O, but got Unknown
		int num = Interlocked.Increment(ref forceChargingCount);
		Log.Error($"EventDirector::ForceChargingState::Count = {num}");
		if (num == 1)
		{
			Log.Error("EventDirector::ForceChargingState::Enabled = true");
			TeleporterInteraction.UpdateMonstersClear += new hook_UpdateMonstersClear(TeleporterInteraction_UpdateMonstersClear);
			SetTeleporterCrystals(enabled: true);
		}
		return new ForceChargingHandle(this);
	}

	private IEnumerator Wrap(IEnumerator coroutine)
	{
		while (true)
		{
			if (!ShouldProcessEvents())
			{
				yield return null;
				continue;
			}
			if (!coroutine.MoveNext())
			{
				break;
			}
			yield return coroutine.Current;
		}
	}

	private void TeleporterInteraction_UpdateMonstersClear(orig_UpdateMonstersClear orig, TeleporterInteraction self)
	{
		FieldInfo field = typeof(TeleporterInteraction).GetField("monstersCleared", BindingFlags.Instance | BindingFlags.NonPublic);
		field.SetValue(self, false);
	}

	private bool ShouldProcessEvents()
	{
		//IL_008d: 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)
		if (!((Behaviour)this).enabled)
		{
			return false;
		}
		if (!NetworkServer.active)
		{
			return false;
		}
		if (!Object.op_Implicit((Object)(object)Run.instance) || Run.instance.isGameOverServer)
		{
			return false;
		}
		if (!Object.op_Implicit((Object)(object)Stage.instance) || Stage.instance.completed)
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)GameOverController.instance))
		{
			return false;
		}
		FixedTimeStamp entryTime = Stage.instance.entryTime;
		if (((FixedTimeStamp)(ref entryTime)).timeSince < 6f)
		{
			return false;
		}
		if (SceneExitController.isRunning)
		{
			return false;
		}
		if (Object.op_Implicit((Object)(object)TeleporterInteraction.instance) && TeleporterInteraction.instance.isInFinalSequence)
		{
			return false;
		}
		return true;
	}
}
[RequireComponent(typeof(MonsterSpawner))]
internal class EventFactory : MonoBehaviour
{
	private MonsterSpawner spawner;

	public void Awake()
	{
		if (!Object.op_Implicit((Object)(object)spawner))
		{
			spawner = ((Component)this).gameObject.AddComponent<MonsterSpawner>();
		}
	}

	public Func<EventDirector, IEnumerator> BroadcastChat(ChatMessageBase message)
	{
		return (EventDirector director) => BroadcastChatInternal(message);
	}

	private IEnumerator BroadcastChatInternal(ChatMessageBase message)
	{
		Chat.SendBroadcastChat(message);
		yield break;
	}

	public Func<EventDirector, IEnumerator> SpawnItem(PickupIndex pickupIndex)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		return (EventDirector director) => SpawnItemInternal(pickupIndex);
	}

	private IEnumerator SpawnItemInternal(PickupIndex pickupIndex)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		PickupDef itemdef = PickupCatalog.GetPickupDef(pickupIndex);
		if ((int)itemdef.equipmentIndex != -1)
		{
			if (RunArtifactManager.instance.IsArtifactEnabled(Artifacts.Command))
			{
				ItemManager.GiveToAllPlayers(pickupIndex);
			}
			else
			{
				ItemManager.DropToAllPlayers(pickupIndex, Vector3.up * 10f);
			}
		}
		else
		{
			ItemManager.GiveToAllPlayers(pickupIndex);
		}
		yield break;
	}

	public Func<EventDirector, IEnumerator> CreateBounty()
	{
		return (EventDirector director) => CreateBountyInternal();
	}

	private IEnumerator CreateBountyInternal()
	{
		try
		{
			DoppelgangerInvasionManager.PerformInvasion(new Xoroshiro128Plus((ulong)Random.Range(0f, 10000f)));
			string rollMessage = "<color=#" + ColorUtility.ToHtmlStringRGB(Color.red) + "><size=120%>HOLD ON TO YER BOOTY!!</size></color>";
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = rollMessage
			});
		}
		catch (Exception ex)
		{
			Exception e = ex;
			Log.Exception(e);
		}
		yield break;
	}

	public Func<EventDirector, IEnumerator> CreateBitStorm()
	{
		return (EventDirector director) => CreateBitStormInternal();
	}

	private IEnumerator CreateBitStormInternal()
	{
		try
		{
			foreach (PlayerCharacterMasterController controller in PlayerCharacterMasterController.instances)
			{
				if (!controller.master.IsDeadAndOutOfLivesServer())
				{
					CharacterBody body = controller.master.GetBody();
					MeteorStormController component = Object.Instantiate<GameObject>(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/MeteorStorm"), body.corePosition, Quaternion.identity).GetComponent<MeteorStormController>();
					component.owner = ((Component)this).gameObject;
					component.ownerDamage = body.damage * 2f;
					component.isCrit = Util.CheckRoll(body.crit, body.master);
					component.waveCount *= 3;
					NetworkServer.Spawn(((Component)component).gameObject);
				}
			}
			string rollMessage = "<color=#9147ff><size=150%>HERE COMES THE BITS!!</size></color>";
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = rollMessage
			});
		}
		catch (Exception ex)
		{
			Exception e = ex;
			Log.Exception(e);
		}
		yield break;
	}

	public Func<EventDirector, IEnumerator> TriggerShrineOfOrder()
	{
		return (EventDirector director) => TriggerShrineOfOrderInternal();
	}

	private IEnumerator TriggerShrineOfOrderInternal()
	{
		try
		{
			foreach (PlayerCharacterMasterController controller in PlayerCharacterMasterController.instances)
			{
				if (controller.master.IsDeadAndOutOfLivesServer())
				{
					continue;
				}
				Inventory inventory = controller.master.inventory;
				if (Object.op_Implicit((Object)(object)inventory))
				{
					inventory.ShrineRestackInventory(RoR2Application.rng);
					CharacterBody body = controller.master.GetBody();
					if (Object.op_Implicit((Object)(object)body))
					{
						Chat.SendBroadcastChat((ChatMessageBase)new SubjectFormatChatMessage
						{
							subjectAsCharacterBody = body,
							baseToken = "SHRINE_RESTACK_USE_MESSAGE"
						});
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
						{
							origin = body.corePosition,
							rotation = Quaternion.identity,
							scale = body.bestFitRadius * 2f,
							color = Color32.op_Implicit(new Color(1f, 0.23f, 0.6337214f))
						}, true);
					}
				}
			}
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = "<color=#9147ff>Twitch Chat decides you should have 'better' items.</color>"
			});
		}
		catch (Exception ex)
		{
			Exception e = ex;
			Log.Exception(e);
		}
		yield break;
	}

	public Func<EventDirector, IEnumerator> TriggerShrineOfTheMountain(int count = 1)
	{
		return (EventDirector director) => TriggerShrineOfTheMountainInternal(count);
	}

	private IEnumerator TriggerShrineOfTheMountainInternal(int count)
	{
		if (SceneCatalog.GetSceneDefForCurrentScene().isFinalStage)
		{
			foreach (TeamComponent teamComponent in TeamComponent.GetTeamMembers((TeamIndex)2))
			{
				CharacterBody body2 = teamComponent.body;
				if (Object.op_Implicit((Object)(object)body2) && body2.inventory.GetItemCount(Items.ExtraLife) == 0 && body2.inventory.GetItemCount(Items.ExtraLifeConsumed) == 0)
				{
					body2.inventory.GiveItem(Items.ExtraLife, 1);
					body2.inventory.GiveRandomItems(Run.instance.livingPlayerCount, false, true);
				}
			}
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = "<color=#9147ff>Twitch Chat feels the last stage should be harder.</color>"
			});
			yield break;
		}
		if (Object.op_Implicit((Object)(object)TeleporterInteraction.instance) && !TeleporterInteraction.instance.isIdle)
		{
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = "<color=#9147ff>Twitch Chat feels the boss should be harder on the next stage.</color>"
			});
		}
		yield return (object)new WaitUntil((Func<bool>)(() => Object.op_Implicit((Object)(object)TeleporterInteraction.instance) && TeleporterInteraction.instance.isIdle));
		try
		{
			if (Object.op_Implicit((Object)(object)TeleporterInteraction.instance))
			{
				int i = 0;
				while (i < count)
				{
					TeleporterInteraction.instance.AddShrineStack();
					int num = i + 1;
					i = num;
				}
				foreach (PlayerCharacterMasterController controller in PlayerCharacterMasterController.instances)
				{
					CharacterBody body = controller.master.GetBody();
					if (Object.op_Implicit((Object)(object)body))
					{
						Chat.SendBroadcastChat((ChatMessageBase)new SubjectFormatChatMessage
						{
							subjectAsCharacterBody = body,
							baseToken = "SHRINE_BOSS_USE_MESSAGE"
						});
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
						{
							origin = body.corePosition,
							rotation = Quaternion.identity,
							scale = body.bestFitRadius * 2f,
							color = Color32.op_Implicit(new Color(0.7372549f, 77f / 85f, 0.94509804f))
						}, true);
					}
				}
			}
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = "<color=#9147ff>Twitch Chat feels the boss should be harder on this stage.</color>"
			});
		}
		catch (Exception e)
		{
			Log.Exception(e);
		}
	}

	public Func<EventDirector, IEnumerator> CreateMonster(string monster, EliteIndex eliteIndex)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		return CreateMonster(monster, 1, eliteIndex);
	}

	public Func<EventDirector, IEnumerator> CreateMonster(string monster, int num = 1, EliteIndex eliteIndex = -1)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		return (EventDirector director) => CreateMonsterInternal(director, monster, num, eliteIndex);
	}

	private IEnumerator CreateMonsterInternal(EventDirector director, string monster, int num, EliteIndex eliteIndex)
	{
		//IL_0023: 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)
		CombatSquad squad = spawner.SpawnMonsters(monster, eliteIndex, FindFirstAliveBody(), num, director);
		string characterName = null;
		foreach (CharacterMaster member2 in squad.readOnlyMembersList)
		{
			if (characterName == null)
			{
				characterName = Util.GetBestBodyName(member2.GetBodyObject());
			}
			SpawnedMonster spawnedMonster = ((Component)member2).gameObject.AddComponent<SpawnedMonster>();
			spawnedMonster.teleportWhenOOB = true;
			CharacterBody body = member2.GetBody();
			if (Object.op_Implicit((Object)(object)body))
			{
				body.bodyFlags = (BodyFlags)(body.bodyFlags | 1);
			}
		}
		if (characterName == null)
		{
			characterName = "monster";
		}
		string pluralize = ((squad.readOnlyMembersList.Count == 1) ? (characterName + " jumps") : $"{squad.readOnlyMembersList.Count} {characterName}'s jump");
		string message = "<color=#9147ff>" + pluralize + " out of the void...</color>";
		Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
		{
			baseToken = message
		});
		if (!MonsterSpawner.Monsters.Brother.Equals(monster) && !MonsterSpawner.Monsters.BrotherGlass.Equals(monster))
		{
			yield break;
		}
		squad.onMemberLost += delegate
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			if (squad.memberCount == 0)
			{
				SimpleChatMessage val = new SimpleChatMessage();
				val.baseToken = "BROTHER_DIALOGUE_FORMAT";
				val.paramTokens = new string[1] { "I'll be back" };
				Chat.SendBroadcastChat((ChatMessageBase)(object)val);
			}
		};
	}

	public Func<EventDirector, IEnumerator> CreateAlly(string name, string monster, EliteIndex eliteIndex = -1)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		return (EventDirector director) => CreateAllyInternal(name, monster, eliteIndex);
	}

	private IEnumerator CreateAllyInternal(string name, string monster, EliteIndex eliteIndex)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		string nameEscaped = Util.EscapeRichTextForTextMeshPro(name);
		CharacterBody summonerBody = FindFirstAliveBody();
		CombatSquad squad = spawner.SpawnAllies(monster, eliteIndex, summonerBody);
		string message = "<color=#" + ColorUtility.ToHtmlStringRGB(Color.green) + ">" + nameEscaped + "</color><color=#9147ff> enters the game to help you...</color>";
		Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
		{
			baseToken = message
		});
		squad.onMemberLost += delegate(CharacterMaster member)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			if (squad.memberCount == 0)
			{
				string[] array = (string[])typeof(GlobalEventManager).GetField("standardDeathQuoteTokens", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
				Chat.SendBroadcastChat((ChatMessageBase)new PlayerDeathChatMessage
				{
					subjectAsCharacterBody = member.GetBody(),
					baseToken = array[Random.Range(0, array.Length)]
				});
			}
		};
		foreach (CharacterMaster member2 in squad.readOnlyMembersList)
		{
			((Component)member2).gameObject.AddComponent<SetDontDestroyOnLoad>();
			ForceNameChange nameChange = ((Component)member2).gameObject.AddComponent<ForceNameChange>();
			nameChange.NameToken = nameEscaped;
			SpawnedMonster spawnedMonster = ((Component)member2).gameObject.AddComponent<SpawnedMonster>();
			spawnedMonster.teleportWhenOOB = false;
			member2.inventory.GiveItem(Items.HealWhileSafe, Run.instance.livingPlayerCount);
			member2.inventory.GiveItem(Items.Infusion, Run.instance.livingPlayerCount);
			if (!((Object)(object)summonerBody == (Object)null))
			{
				CharacterMaster summonerMaster = summonerBody.master;
				member2.inventory.GiveItem(Items.Hoof, summonerMaster.inventory.GetItemCount(Items.Hoof));
				member2.inventory.GiveItem(Items.SprintBonus, summonerMaster.inventory.GetItemCount(Items.SprintBonus));
				if (Object.op_Implicit((Object)(object)summonerMaster) && Object.op_Implicit((Object)(object)summonerMaster.minionOwnership.ownerMaster))
				{
					_ = summonerMaster.minionOwnership.ownerMaster;
				}
				member2.minionOwnership.SetOwner(summonerBody.master);
				AIOwnership aIOwnership = ((Component)member2).gameObject.GetComponent<AIOwnership>();
				if (Object.op_Implicit((Object)(object)aIOwnership) && Object.op_Implicit((Object)(object)summonerBody.master))
				{
					aIOwnership.ownerMaster = summonerBody.master;
				}
				BaseAI baseAI = ((Component)member2).gameObject.GetComponent<BaseAI>();
				if (Object.op_Implicit((Object)(object)baseAI))
				{
					baseAI.leader.gameObject = ((Component)summonerBody).gameObject;
					baseAI.fullVision = true;
					ApplyFollowingAI(baseAI);
				}
			}
		}
		yield break;
	}

	private void ApplyFollowingAI(BaseAI baseAI)
	{
		//IL_001a: 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_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_019a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Unknown result type (might be due to invalid IL or missing references)
		//IL_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_0287: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
		AISkillDriver val = ((Component)baseAI).gameObject.AddComponent<AISkillDriver>();
		val.customName = "ReturnToOwnerLeash";
		val.skillSlot = (SkillSlot)(-1);
		val.requiredSkill = null;
		val.requireSkillReady = false;
		val.requireEquipmentReady = false;
		val.minUserHealthFraction = float.NegativeInfinity;
		val.maxUserHealthFraction = float.PositiveInfinity;
		val.minTargetHealthFraction = float.NegativeInfinity;
		val.maxTargetHealthFraction = float.PositiveInfinity;
		val.minDistance = 50f;
		val.maxDistance = float.PositiveInfinity;
		val.selectionRequiresTargetLoS = false;
		val.selectionRequiresOnGround = false;
		val.moveTargetType = (TargetType)2;
		val.activationRequiresTargetLoS = false;
		val.activationRequiresAimConfirmation = false;
		val.movementType = (MovementType)1;
		val.moveInputScale = 1f;
		val.aimType = (AimType)3;
		val.ignoreNodeGraph = false;
		val.shouldSprint = true;
		val.shouldFireEquipment = false;
		val.buttonPressType = (ButtonPressType)0;
		val.driverUpdateTimerOverride = 3f;
		val.resetCurrentEnemyOnNextDriverSelection = true;
		val.noRepeat = false;
		val.nextHighPriorityOverride = null;
		AISkillDriver val2 = ((Component)baseAI).gameObject.AddComponent<AISkillDriver>();
		val2.customName = "ReturnToLeaderDefault";
		val2.skillSlot = (SkillSlot)(-1);
		val2.requiredSkill = null;
		val2.requireSkillReady = false;
		val2.requireEquipmentReady = false;
		val2.minUserHealthFraction = float.NegativeInfinity;
		val2.maxUserHealthFraction = float.PositiveInfinity;
		val2.minTargetHealthFraction = float.NegativeInfinity;
		val2.maxTargetHealthFraction = float.PositiveInfinity;
		val2.minDistance = 15f;
		val2.maxDistance = float.PositiveInfinity;
		val2.selectionRequiresTargetLoS = false;
		val2.selectionRequiresOnGround = false;
		val2.moveTargetType = (TargetType)2;
		val2.activationRequiresTargetLoS = false;
		val2.activationRequiresAimConfirmation = false;
		val2.movementType = (MovementType)1;
		val2.moveInputScale = 1f;
		val2.aimType = (AimType)1;
		val2.ignoreNodeGraph = false;
		val2.shouldSprint = true;
		val2.shouldFireEquipment = false;
		val2.buttonPressType = (ButtonPressType)0;
		val2.driverUpdateTimerOverride = -1f;
		val2.resetCurrentEnemyOnNextDriverSelection = false;
		val2.noRepeat = false;
		val2.nextHighPriorityOverride = null;
		AISkillDriver val3 = ((Component)baseAI).gameObject.AddComponent<AISkillDriver>();
		val3.customName = "WaitNearLeaderDefault";
		val3.skillSlot = (SkillSlot)(-1);
		val3.requiredSkill = null;
		val3.requireSkillReady = false;
		val3.requireEquipmentReady = false;
		val3.minUserHealthFraction = float.NegativeInfinity;
		val3.maxUserHealthFraction = float.PositiveInfinity;
		val3.minTargetHealthFraction = float.NegativeInfinity;
		val3.maxTargetHealthFraction = float.PositiveInfinity;
		val3.minDistance = 0f;
		val3.maxDistance = float.PositiveInfinity;
		val3.selectionRequiresTargetLoS = false;
		val3.selectionRequiresOnGround = false;
		val3.moveTargetType = (TargetType)2;
		val3.activationRequiresTargetLoS = false;
		val3.activationRequiresAimConfirmation = false;
		val3.movementType = (MovementType)0;
		val3.moveInputScale = 1f;
		val3.aimType = (AimType)3;
		val3.ignoreNodeGraph = false;
		val3.shouldSprint = false;
		val3.shouldFireEquipment = false;
		val3.buttonPressType = (ButtonPressType)0;
		val3.driverUpdateTimerOverride = -1f;
		val3.resetCurrentEnemyOnNextDriverSelection = false;
		val3.noRepeat = false;
		val3.nextHighPriorityOverride = null;
		PropertyInfo property = typeof(BaseAI).GetProperty("skillDrivers", BindingFlags.Instance | BindingFlags.Public);
		if (property != null)
		{
			property.SetValue(baseAI, ((Component)baseAI).gameObject.GetComponents<AISkillDriver>(), null);
		}
	}

	private CharacterBody FindFirstAliveBody()
	{
		foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
		{
			CharacterMaster master = instance.master;
			CharacterBody body = master.GetBody();
			if ((Object)(object)body != (Object)null)
			{
				return body;
			}
		}
		return null;
	}
}
internal class ForceNameChange : MonoBehaviour
{
	private CharacterMaster body;

	public string NameToken { get; set; }

	public void Awake()
	{
		body = ((Component)this).GetComponent<CharacterMaster>();
	}

	public void Update()
	{
		if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.GetBody()) && !body.GetBody().baseNameToken.Equals(NameToken))
		{
			body.GetBody().baseNameToken = NameToken;
		}
	}
}
internal class ItemManager
{
	public static void GiveToAllPlayers(PickupIndex pickupIndex)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		if (!NetworkServer.active)
		{
			Log.Warning("[Server] function 'System.Void ItemManager::GiveToAllPlayers()' called on client");
			return;
		}
		foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
		{
			CharacterMaster master = instance.master;
			GiveToPlayer(master, pickupIndex);
		}
	}

	public static void GiveToPlayer(CharacterMaster characterMaster, PickupIndex pickupIndex)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Invalid comparison between Unknown and I4
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		if (!NetworkServer.active)
		{
			Log.Warning("[Server] function 'System.Void ItemManager::GiveToPlayer()' called on client");
			return;
		}
		PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
		if ((int)pickupDef.equipmentIndex != -1)
		{
			characterMaster.inventory.SetEquipmentIndex(pickupDef.equipmentIndex);
		}
		else
		{
			characterMaster.inventory.GiveItem(pickupDef.itemIndex, 1);
		}
		GenericPickupController.SendPickupMessage(characterMaster, pickupIndex);
	}

	public static void DropToAllPlayers(PickupIndex pickupIndex, Vector3 velocity)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		if (!NetworkServer.active)
		{
			Log.Warning("[Server] function 'System.Void ItemManager::DropToAllPlayers()' called on client");
			return;
		}
		foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
		{
			CharacterMaster master = instance.master;
			DropToPlayer(master, pickupIndex, velocity);
		}
	}

	public static void DropToPlayer(CharacterMaster characterMaster, PickupIndex pickupIndex, Vector3 velocity)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: 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_0044: 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)
		if (!NetworkServer.active)
		{
			Log.Warning("[Server] function 'System.Void ItemManager::DropToPlayer()' called on client");
			return;
		}
		CharacterBody body = characterMaster.GetBody();
		if ((Object)(object)body != (Object)null)
		{
			PickupDropletController.CreatePickupDroplet(pickupIndex, body.corePosition + Vector3.up * 1.5f, velocity);
		}
	}
}
internal class MonsterSpawner : MonoBehaviour
{
	private class SpawnFinalizer
	{
		public CombatSquad CombatSquad { get; set; }

		public EliteIndex EliteIndex { get; set; }

		public bool IsBoss { get; set; }

		public void OnCardSpawned(SpawnResult spawnResult)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Invalid comparison between Unknown and I4
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (spawnResult.success)
			{
				CharacterMaster component = spawnResult.spawnedInstance.GetComponent<CharacterMaster>();
				if (Object.op_Implicit((Object)(object)CombatSquad))
				{
					CombatSquad.AddMember(component);
				}
				EliteDef eliteDef = EliteCatalog.GetEliteDef(EliteIndex);
				EquipmentIndex val = (EquipmentIndex)((!((Object)(object)eliteDef != (Object)null)) ? (-1) : ((int)eliteDef.eliteEquipmentDef.equipmentIndex));
				if ((int)val != -1)
				{
					component.inventory.SetEquipmentIndex(val);
				}
				float num = 1f;
				float num2 = 1f;
				num += Run.instance.difficultyCoefficient / 1.5f;
				num2 += Run.instance.difficultyCoefficient / 15f;
				int num3 = Mathf.Max(1, Run.instance.livingPlayerCount);
				num *= Mathf.Pow((float)num3, 0.75f);
				component.inventory.GiveItem(Items.BoostHp, Mathf.RoundToInt((float)Mathf.RoundToInt(num - 1f) * 10f));
				component.inventory.GiveItem(Items.BoostDamage, Mathf.RoundToInt((float)Mathf.RoundToInt(num2 - 1f) * 10f));
				component.isBoss = IsBoss;
			}
		}
	}

	public class Monsters
	{
		public static readonly string ArchWisp = "SpawnCards/CharacterSpawnCards/cscArchWisp";

		public static readonly string BackupDrone = "SpawnCards/CharacterSpawnCards/cscBackupDrone";

		public static readonly string Beetle = "SpawnCards/CharacterSpawnCards/cscBeetle";

		public static readonly string BeetleCrystal = "SpawnCards/CharacterSpawnCards/cscBeetleCrystal";

		public static readonly string BeetleGuard = "SpawnCards/CharacterSpawnCards/cscBeetleGuard";

		public static readonly string BeetleGuardAlly = "SpawnCards/CharacterSpawnCards/cscBeetleGuardAlly";

		public static readonly string BeetleGuardCrystal = "SpawnCards/CharacterSpawnCards/cscBeetleGuardCrystal";

		public static readonly string BeetleQueen = "SpawnCards/CharacterSpawnCards/cscBeetleQueen";

		public static readonly string Bell = "SpawnCards/CharacterSpawnCards/cscBell";

		public static readonly string Bison = "SpawnCards/CharacterSpawnCards/cscBison";

		public static readonly string Brother = "SpawnCards/CharacterSpawnCards/cscBrother";

		public static readonly string BrotherGlass = "SpawnCards/CharacterSpawnCards/cscBrotherGlass";

		public static readonly string BrotherHurt = "SpawnCards/CharacterSpawnCards/cscBrotherHurt";

		public static readonly string ClayBoss = "SpawnCards/CharacterSpawnCards/cscClayBoss";

		public static readonly string ClayBruiser = "SpawnCards/CharacterSpawnCards/cscClayBruiser";

		public static readonly string ElectricWorm = "SpawnCards/CharacterSpawnCards/cscElectricWorm";

		public static readonly string Golem = "SpawnCards/CharacterSpawnCards/cscGolem";

		public static readonly string Gravekeeper = "SpawnCards/CharacterSpawnCards/cscGravekeeper";

		public static readonly string GreaterWisp = "SpawnCards/CharacterSpawnCards/cscGreaterWisp";

		public static readonly string HermitCrab = "SpawnCards/CharacterSpawnCards/cscHermitCrab";

		public static readonly string Imp = "SpawnCards/CharacterSpawnCards/cscImp";

		public static readonly string ImpBoss = "SpawnCards/CharacterSpawnCards/cscImpBoss";

		public static readonly string Jellyfish = "SpawnCards/CharacterSpawnCards/cscJellyfish";

		public static readonly string Lemurian = "SpawnCards/CharacterSpawnCards/cscLemurian";

		public static readonly string LemurianBruiser = "SpawnCards/CharacterSpawnCards/cscLemurianBruiser";

		public static readonly string LesserWisp = "SpawnCards/CharacterSpawnCards/cscLesserWisp";

		public static readonly string LunarGolem = "SpawnCards/CharacterSpawnCards/cscLunarGolem";

		public static readonly string LunarWisp = "SpawnCards/CharacterSpawnCards/cscLunarWisp";

		public static readonly string MagmaWorm = "SpawnCards/CharacterSpawnCards/cscMagmaWorm";

		public static readonly string MiniMushroom = "SpawnCards/CharacterSpawnCards/cscMiniMushroom";

		public static readonly string Nullifier = "SpawnCards/CharacterSpawnCards/cscNullifier";

		public static readonly string Parent = "SpawnCards/CharacterSpawnCards/cscParent";

		public static readonly string ParentPod = "SpawnCards/CharacterSpawnCards/cscParentPod";

		public static readonly string RoboBallBoss = "SpawnCards/CharacterSpawnCards/cscRoboBallBoss";

		public static readonly string RoboBallMini = "SpawnCards/CharacterSpawnCards/cscRoboBallMini";

		public static readonly string Scav = "SpawnCards/CharacterSpawnCards/cscScav";

		public static readonly string ScavLunar = "SpawnCards/CharacterSpawnCards/cscScavLunar";

		public static readonly string SquidTurret = "SpawnCards/CharacterSpawnCards/cscSquidTurret";

		public static readonly string SuperRoboBallBoss = "SpawnCards/CharacterSpawnCards/cscSuperRoboBallBoss";

		public static readonly string TitanGold = "SpawnCards/CharacterSpawnCards/cscTitanGold";

		public static readonly string TitanGoldAlly = "SpawnCards/CharacterSpawnCards/cscTitanGoldAlly";

		public static readonly string Vagrant = "SpawnCards/CharacterSpawnCards/cscVagrant";

		public static readonly string Vulture = "SpawnCards/CharacterSpawnCards/cscVulture";

		public static readonly string Grandparent = "SpawnCards/CharacterSpawnCards/cscGrandparent";

		public static readonly string TitanBlackBeach = "SpawnCards/CharacterSpawnCards/cscTitanBlackBeach";

		public static readonly string TitanDampCave = "SpawnCards/CharacterSpawnCards/cscTitanDampCave";

		public static readonly string TitanGolemPlains = "SpawnCards/CharacterSpawnCards/cscTitanGolemPlains";

		public static readonly string TitanGooLake = "SpawnCards/CharacterSpawnCards/cscTitanGooLake";

		private Monsters()
		{
		}
	}

	public CombatSquad SpawnAllies(string spawnCard, EliteIndex eliteIndex = -1, CharacterBody targetBody = null, int numMonsters = 1)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		return SpawnMonstersInternal(spawnCard, eliteIndex, targetBody, numMonsters, null, (TeamIndex)1);
	}

	public CombatSquad SpawnMonsters(string spawnCard, EliteIndex eliteIndex = -1, CharacterBody targetBody = null, int numMonsters = 1, EventDirector director = null)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		return SpawnMonstersInternal(spawnCard, eliteIndex, targetBody, numMonsters, director, (TeamIndex)2);
	}

	private CombatSquad SpawnMonstersInternal(string spawnCard, EliteIndex eliteIndex, CharacterBody targetBody, int numMonsters, EventDirector director, TeamIndex teamIndex)
	{
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Expected O, but got Unknown
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: 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_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Expected O, but got Unknown
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Invalid comparison between Unknown and I4
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Expected O, but got Unknown
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Invalid comparison between Unknown and I4
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Expected O, but got Unknown
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: 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_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Expected O, but got Unknown
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Invalid comparison between Unknown and I4
		CombatSquad group = ((Component)this).gameObject.AddComponent<CombatSquad>();
		IDisposable chargingHandle = null;
		if (Object.op_Implicit((Object)(object)director))
		{
			chargingHandle = director.CreateOpenTeleporterObjectiveHandle();
		}
		group.onMemberLost += delegate
		{
			if (group.memberCount == 0)
			{
				chargingHandle?.Dispose();
				Object.Destroy((Object)(object)group);
			}
		};
		DirectorPlacementRule val = ((!Object.op_Implicit((Object)(object)targetBody)) ? new DirectorPlacementRule
		{
			placementMode = (PlacementMode)4
		} : new DirectorPlacementRule
		{
			placementMode = (PlacementMode)1,
			minDistance = 8f,
			maxDistance = 20f,
			spawnOnTarget = targetBody.transform
		});
		SpawnCard val2 = LegacyResourcesAPI.Load<SpawnCard>(spawnCard);
		if (!Object.op_Implicit((Object)(object)val2))
		{
			Object.Destroy((Object)(object)group);
			return null;
		}
		val2.directorCreditCost = 0;
		SpawnFinalizer @object = new SpawnFinalizer
		{
			CombatSquad = group,
			EliteIndex = eliteIndex,
			IsBoss = ((int)teamIndex != 1)
		};
		DirectorSpawnRequest val3 = new DirectorSpawnRequest(val2, val, RoR2Application.rng)
		{
			ignoreTeamMemberLimit = true,
			teamIndexOverride = teamIndex,
			onSpawnedServer = @object.OnCardSpawned
		};
		if ((int)teamIndex == 1)
		{
			val3.summonerBodyObject = ((Component)targetBody).gameObject;
		}
		bool flag = false;
		for (int i = 0; i < numMonsters; i++)
		{
			GameObject val4 = DirectorCore.instance.TrySpawnObject(val3);
			if (!Object.op_Implicit((Object)(object)val4))
			{
				Log.Warning("Could not spawn monster near target body, spawning randomly on map");
				DirectorSpawnRequest val5 = new DirectorSpawnRequest(val2, new DirectorPlacementRule
				{
					placementMode = (PlacementMode)4
				}, RoR2Application.rng)
				{
					ignoreTeamMemberLimit = true,
					teamIndexOverride = teamIndex,
					onSpawnedServer = @object.OnCardSpawned
				};
				if ((int)teamIndex == 1)
				{
					val5.summonerBodyObject = ((Component)targetBody).gameObject;
				}
				val4 = DirectorCore.instance.TrySpawnObject(val5);
			}
			if (Object.op_Implicit((Object)(object)val4))
			{
				flag = true;
			}
		}
		if (!flag)
		{
			Log.Error("Couldn't spawn any monster!");
			chargingHandle?.Dispose();
			Object.Destroy((Object)(object)group);
			return null;
		}
		return group;
	}
}
internal class SpawnedMonster : MonoBehaviour
{
	public int suicideProtection = 0;

	public bool teleportWhenOOB = true;
}
internal interface IItemRoller<T>
{
	void RollForItem(List<T> indices, Action<T> callback);
}
internal class ItemRollerManager : IItemRoller<PickupIndex>
{
	private readonly ReaderWriterLockSlim cacheLock;

	private readonly IVoteStrategy<PickupIndex> voteStrategy;

	private readonly BlockingCollection<Vote> voteQueue;

	private Vote currentVote;

	private Vote previousVote;

	private int id;

	public event EventHandler<IDictionary<int, PickupIndex>> OnVoteStart;

	public ItemRollerManager(IVoteStrategy<PickupIndex> voteStrategy)
	{
		cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
		voteQueue = new BlockingCollection<Vote>();
		this.voteStrategy = voteStrategy;
		id = 1;
	}

	public int QueueSize()
	{
		cacheLock.EnterReadLock();
		try
		{
			return voteQueue.Count;
		}
		finally
		{
			cacheLock.ExitReadLock();
		}
	}

	public void EndVote()
	{
		OnVoteEnd();
	}

	public void ClearVotes()
	{
		cacheLock.EnterWriteLock();
		try
		{
			Vote item;
			while (voteQueue.TryTake(out item))
			{
			}
			EndVote();
			previousVote = null;
		}
		finally
		{
			cacheLock.ExitWriteLock();
		}
	}

	private void OnVoteEnd()
	{
		try
		{
			cacheLock.EnterWriteLock();
			try
			{
				if (currentVote != null)
				{
					currentVote.EndVote();
					previousVote = currentVote;
					currentVote = null;
				}
			}
			finally
			{
				cacheLock.ExitWriteLock();
			}
			TryStartVote();
		}
		catch (Exception data)
		{
			Log.Exception(data);
		}
	}

	public void RollForItem(List<PickupIndex> indices, Action<PickupIndex> callback)
	{
		Vote vote = new Vote(indices, voteStrategy, Interlocked.Increment(ref id));
		vote.OnVoteStart += this.OnVoteStart;
		vote.OnVoteEnd += delegate(object sender, PickupIndex e)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			callback?.Invoke(e);
		};
		cacheLock.EnterWriteLock();
		try
		{
			if (isSameVote(vote, currentVote))
			{
				Log.Warning(string.Format("WARNING: Not adding roll for {0} with id {1} ", string.Join(", ", vote.GetCandidates().Values), vote.GetId()) + "because the previous vote was exactly that. There might be another mod causing issues making rolling busted.");
				return;
			}
			Log.Info(string.Format("Adding roll for {0} with id {1}", string.Join(", ", vote.GetCandidates().Values), vote.GetId()));
			voteQueue.Add(vote);
		}
		finally
		{
			cacheLock.ExitWriteLock();
		}
		TryStartVote();
	}

	private bool isSameVote(Vote vote, Vote lastVote)
	{
		if (vote == null || lastVote == null)
		{
			return false;
		}
		HashSet<PickupIndex> hashSet = new HashSet<PickupIndex>(vote.GetCandidates().Values);
		HashSet<PickupIndex> equals = new HashSet<PickupIndex>(lastVote.GetCandidates().Values);
		return hashSet.SetEquals(equals);
	}

	public void AddVote(string username, int index)
	{
		cacheLock.EnterReadLock();
		try
		{
			currentVote?.AddVote(username, index);
		}
		finally
		{
			cacheLock.ExitReadLock();
		}
	}

	private void TryStartVote()
	{
		cacheLock.EnterWriteLock();
		try
		{
			if (currentVote != null)
			{
				return;
			}
			while (true)
			{
				if (!voteQueue.TryTake(out currentVote))
				{
					return;
				}
				if (!isSameVote(previousVote, currentVote))
				{
					break;
				}
				Log.Warning(string.Format("WARNING: Not starting vote for {0} with id {1} ", string.Join(", ", currentVote.GetCandidates().Values), currentVote.GetId()) + "because the previous vote was exactly that. There might be another mod causing issues making rolling busted.");
			}
			currentVote.StartVote();
		}
		finally
		{
			cacheLock.ExitWriteLock();
		}
	}
}
internal class Vote
{
	private readonly Dictionary<int, PickupIndex> indices;

	private readonly IVoteStrategy<PickupIndex> strategy;

	private readonly Dictionary<string, PickupIndex> votes;

	private readonly int id;

	public event EventHandler<IDictionary<int, PickupIndex>> OnVoteStart;

	public event EventHandler<PickupIndex> OnVoteEnd;

	public Vote(List<PickupIndex> indices, IVoteStrategy<PickupIndex> strategy, int id)
	{
		//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_002f: Unknown result type (might be due to invalid IL or missing references)
		this.indices = new Dictionary<int, PickupIndex>();
		int num = 1;
		foreach (PickupIndex index in indices)
		{
			this.indices[num] = index;
			num++;
		}
		this.strategy = strategy;
		votes = new Dictionary<string, PickupIndex>();
		this.id = id;
	}

	public IDictionary<int, PickupIndex> GetCandidates()
	{
		return new ReadOnlyDictionary<int, PickupIndex>(indices);
	}

	public int GetId()
	{
		return id;
	}

	public void StartVote()
	{
		this.OnVoteStart?.Invoke(this, GetCandidates());
	}

	public void AddVote(string username, int index)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		if (indices.TryGetValue(index, out var value))
		{
			votes[username] = value;
		}
	}

	public void EndVote()
	{
		//IL_0071: 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)
		if (indices.Count == 0)
		{
			this.OnVoteEnd?.Invoke(this, PickupIndex.none);
			return;
		}
		PickupIndex[] array = (PickupIndex[])(object)new PickupIndex[indices.Values.Count];
		indices.Values.CopyTo(array, 0);
		this.OnVoteEnd?.Invoke(this, strategy.GetWinner(votes, array));
	}
}
public interface IVoteStrategy<T>
{
	T GetWinner(Dictionary<string, T> votes, T[] allChoices);
}
public class MaxRandTieVoteStrategy<T> : IVoteStrategy<T>
{
	public T GetWinner(Dictionary<string, T> votes, T[] allChoices)
	{
		if (votes.Count == 0)
		{
			return allChoices[Random.Range(0, allChoices.Length)];
		}
		Dictionary<T, int> dictionary = new Dictionary<T, int>();
		foreach (KeyValuePair<string, T> vote in votes)
		{
			if (dictionary.TryGetValue(vote.Value, out var value))
			{
				dictionary[vote.Value] = value + 1;
			}
			else
			{
				dictionary[vote.Value] = 1;
			}
		}
		List<T> list = new List<T>();
		int num = -1;
		foreach (KeyValuePair<T, int> item in dictionary)
		{
			if (item.Value > num)
			{
				list.Clear();
				list.Add(item.Key);
				num = item.Value;
			}
			else if (item.Value == num)
			{
				list.Add(item.Key);
			}
		}
		return list[Random.Range(0, list.Count)];
	}
}
public class MaxVoteStrategy<T> : IVoteStrategy<T>
{
	public T GetWinner(Dictionary<string, T> votes, T[] allChoices)
	{
		if (votes.Count == 0)
		{
			return allChoices[0];
		}
		Dictionary<T, int> dictionary = new Dictionary<T, int>();
		foreach (KeyValuePair<string, T> vote in votes)
		{
			if (dictionary.TryGetValue(vote.Value, out var value))
			{
				dictionary[vote.Value] = value + 1;
			}
			else
			{
				dictionary[vote.Value] = 1;
			}
		}
		T result = default(T);
		int num = -1;
		foreach (KeyValuePair<T, int> item in dictionary)
		{
			if (item.Value > num)
			{
				result = item.Key;
				num = item.Value;
			}
		}
		return result;
	}
}
public class PercentileVoteStrategy<T> : IVoteStrategy<T>
{
	public T GetWinner(Dictionary<string, T> votes, T[] allChoices)
	{
		if (votes.Count == 0)
		{
			return allChoices[Random.Range(0, allChoices.Length)];
		}
		Dictionary<T, int> dictionary = new Dictionary<T, int>();
		foreach (KeyValuePair<string, T> vote in votes)
		{
			int num = (dictionary.TryGetValue(vote.Value, out var value) ? value : 0);
			num = (dictionary[vote.Value] = num + 1);
		}
		int count = votes.Count;
		int num3 = Random.Range(0, count);
		T result = allChoices[Random.Range(0, allChoices.Length)];
		foreach (KeyValuePair<T, int> item in dictionary)
		{
			if (num3 <= item.Value)
			{
				result = item.Key;
				break;
			}
			num3 -= item.Value;
		}
		return result;
	}
}
internal class LanguageOverride
{
	private readonly Dictionary<string, string> StringsByToken;

	public const string STREAMER_TOKEN = "{streamer}";

	private string _StreamerName;

	public string StreamerName
	{
		get
		{
			return _StreamerName;
		}
		set
		{
			if (!string.IsNullOrWhiteSpace(value))
			{
				_StreamerName = Util.EscapeRichTextForTextMeshPro(value.Trim());
			}
			else
			{
				_StreamerName = "Streamer";
			}
		}
	}

	public LanguageOverride()
	{
		StreamerName = "Streamer";
		StringsByToken = new Dictionary<string, string>
		{
			{ "BROTHER_DIALOGUE_FORMAT", "<color=#c6d5ff><size=120%>Twitch Chat: {0}</color></size>" },
			{ "BROTHER_SPAWN_PHASE1_1", "Get that F key warmed up, {streamer}" },
			{ "BROTHER_SPAWN_PHASE1_2", "Time to get one hit KO'd, {streamer}" },
			{ "BROTHER_SPAWN_PHASE1_3", "No amount of character guide Youtube videos can save you now, {streamer}" },
			{ "BROTHER_SPAWN_PHASE1_4", "Your DPS is absolute trash, {streamer}" },
			{ "BROTHER_DAMAGEDEALT_1", "git gud" },
			{ "BROTHER_DAMAGEDEALT_2", "Too much bungus, not enough movement speed" },
			{ "BROTHER_DAMAGEDEALT_3", "trash. no cap." },
			{ "BROTHER_DAMAGEDEALT_4", "Needs more rusted keys" },
			{ "BROTHER_DAMAGEDEALT_5", "THIS IS MY SWAMP" },
			{ "BROTHER_DAMAGEDEALT_6", "Stop feeding" },
			{ "BROTHER_DAMAGEDEALT_7", "MOM, GET THE CAMERA" },
			{ "BROTHER_DAMAGEDEALT_8", "Chat, finds a way" },
			{ "BROTHER_DAMAGEDEALT_9", "baited" },
			{ "BROTHER_DAMAGEDEALT_10", "I bet you main Huntress" },
			{ "BROTHER_KILL_1", "ur mad" },
			{ "BROTHER_KILL_2", "gg ez" },
			{ "BROTHER_KILL_3", "PogU" },
			{ "BROTHER_KILL_4", "{streamer} is typing..." },
			{ "BROTHER_KILL_5", "Sent {streamer} straight to the shadow realm" },
			{ "BROTHERHURT_DAMAGEDEALT_1", "Get down from that ramp and fight me like a man" },
			{ "BROTHERHURT_DAMAGEDEALT_2", "/votekick {streamer}" },
			{ "BROTHERHURT_DAMAGEDEALT_3", "UNO REVERSE CARD" },
			{ "BROTHERHURT_DAMAGEDEALT_4", "don't choke" },
			{ "BROTHERHURT_DAMAGEDEALT_5", "consider those cheeks CLAPPED" },
			{ "BROTHERHURT_DAMAGEDEALT_6", "boop" },
			{ "BROTHERHURT_DAMAGEDEALT_7", "It was at this moment, {streamer} knew, they f***ed up" },
			{ "BROTHERHURT_DAMAGEDEALT_8", "YEET" },
			{ "BROTHERHURT_DAMAGEDEALT_9", "OOF" },
			{ "BROTHERHURT_DAMAGEDEALT_10", "You're gonna love my bits." },
			{ "BROTHERHURT_KILL_1", "get rekt m8" },
			{ "BROTHERHURT_KILL_2", "BE GONE, THOT" },
			{ "BROTHERHURT_KILL_3", "THIS IS MY CHANNEL NOW" },
			{ "BROTHERHURT_KILL_4", "WASTED" },
			{ "BROTHERHURT_KILL_5", "gg ez" },
			{ "BROTHERHURT_DEATH_1", "You had to have gotten good rolls, {streamer}" },
			{ "BROTHERHURT_DEATH_2", "{streamer} STONKS = PURCHAS" },
			{ "BROTHERHURT_DEATH_3", "I wish it didn't have to come to this {streamer}... [prepares bits]" },
			{ "BROTHERHURT_DEATH_4", "Twitch.exe has encountered a fatal error" },
			{ "BROTHERHURT_DEATH_5", "WoolieGaming is typing..." },
			{ "BROTHERHURT_DEATH_6", "I am become salt" },
			{ "CUTSCENE_INTRO_FLAVOR_1", "UES 'Poggers' " },
			{ "CUTSCENE_INTRO_FLAVOR_2", "Last known coordinates of the UES 'TriHard'" },
			{ "CUTSCENE_INTRO_SUBTITLE_1", "We're here, {streamer}. The Twitch alert came from this exact coordinate." },
			{ "CUTSCENE_INTRO_SUBTITLE_2", "This channel... it isn't on any subscriptions we know. This area isn't even marked as followed... " },
			{ "CUTSCENE_INTRO_SUBTITLE_3", "Any visuals on the hype train?" },
			{ "CUTSCENE_INTRO_SUBTITLE_4", "No sir... just Prime subs." },
			{ "CUTSCENE_INTRO_SUBTITLE_5", "Any signs of streamers?" },
			{ "CUTSCENE_INTRO_SUBTITLE_6", "....No sir. Bioscanner is dark." },
			{ "CUTSCENE_INTRO_SUBTITLE_7", "Sir... the Twitch alert. It mentioned... it mentioned a mod we have never seen before." },
			{ "CUTSCENE_INTRO_SUBTITLE_8", "Emotes, and bits, and..." },
			{ "CUTSCENE_INTRO_SUBTITLE_9", "...Sir... do you think we're ready?" },
			{ "CUTSCENE_INTRO_SUBTITLE_10", "Sir?" },
			{ "GENERIC_OUTRO_FLAVOR", "..and so {streamer} left, knowing they shamelessly shook down their Twitch Chat for all their worth." },
			{ "COMMANDO_OUTRO_FLAVOR", "..and so {streamer} left, satisfied with the fact that they bested Twitch Chat with THE WORST survivor in the current meta." },
			{ "HUNTRESS_OUTRO_FLAVOR", "..and so {streamer} left, knowing they would get absolutely CLAPPED if Twitch Chat had made them play literally any other character." },
			{ "ENGI_OUTRO_FLAVOR", "..and so {streamer} left, more BUNGUS than man, and yet, more man than Twitch Chat." },
			{ "TREEBOT_OUTRO_FLAVOR", "..and so {streamer} left, reduced to a lifeless desk plant after the Captain decided they needed their fuel array back." },
			{ "CROCO_OUTRO_FLAVOR", "..and so {streamer} left, reveling in the fact that, according to Twitch Chat, they are the GOODEST BOI." },
			{ "LOADER_OUTRO_FLAVOR", "..and so {streamer} left, knowing that they were the only viable melee character." },
			{ "MERC_OUTRO_FLAVOR", "..and so {streamer} left, their sword as dull as the idiots still watching this on Twitch." },
			{ "CAPTAIN_OUTRO_FLAVOR", "..and so {streamer} left, forever haunted by flashbacks of meteor showers and mutiny." },
			{ "TOOLBOT_OUTRO_FLAVOR", "..and so {streamer} left, with multiple counts of vehicular manslaughter and a thirst for blood." },
			{ "MAGE_OUTRO_FLAVOR", "..and so {streamer} left, wishing Twitch chat had thrown in a few more goat hooves." },
			{ "DIFFICULTY_BAR_0", "ResidentSleeper" },
			{ "DIFFICULTY_BAR_1", "CoolStoryBob" },
			{ "DIFFICULTY_BAR_2", "Jebaited" },
			{ "DIFFICULTY_BAR_3", "Kreygasm" },
			{ "DIFFICULTY_BAR_4", "TriHard" },
			{ "DIFFICULTY_BAR_5", "MrDestructoid" },
			{ "DIFFICULTY_BAR_6", "TheIlluminati" },
			{ "DIFFICULTY_BAR_7", "PJSalt" },
			{ "DIFFICULTY_BAR_8", "BibleThump" },
			{ "DIFFICULTY_BAR_9", "KAPPAKAPPA" },
			{ "TITLE_SINGLEPLAYER", "Fight Chat" },
			{ "TITLE_MULTIPLAYER", "Fight Chat w/ Friends" },
			{ "DIFFICULTY_EASY_NAME", "LUL" },
			{ "DIFFICULTY_NORMAL_NAME", "PogChamp" },
			{ "DIFFICULTY_HARD_NAME", "NotLikeThis" },
			{ "BROTHER_BODY_NAME", "Twitch Chat" },
			{ "BROTHER_BODY_SUBTITLE", "Oppressor of {streamer}" }
		};
	}

	internal bool TryGetLocalizedStringByToken(string token, out string result)
	{
		if (StringsByToken.TryGetValue(token, out result))
		{
			result = result.Replace("{streamer}", StreamerName);
			return true;
		}
		return false;
	}
}
internal static class Log
{
	private static ManualLogSource _logSource;

	internal static void Init(ManualLogSource logSource)
	{
		_logSource = logSource;
	}

	internal static void Debug(object data)
	{
		_logSource.LogDebug(data);
	}

	internal static void Error(object data)
	{
		_logSource.LogError(data);
	}

	internal static void Exception(Exception data)
	{
		_logSource.LogError((object)data);
	}

	internal static void Fatal(object data)
	{
		_logSource.LogFatal(data);
	}

	internal static void Info(object data)
	{
		_logSource.LogInfo(data);
	}

	internal static void Message(object data)
	{
		_logSource.LogMessage(data);
	}

	internal static void Warning(object data)
	{
		_logSource.LogWarning(data);
	}
}
internal class OnDonationArgs : EventArgs
{
	public double Amount;

	public string Name;

	public string Comment;
}
internal class TiltifyManager
{
	private TiltifyWebSocket tiltifyWebsocket;

	private string campaignId;

	public event EventHandler<OnDonationArgs> OnDonationReceived;

	public event EventHandler<EventArgs> OnConnected;

	public event EventHandler<EventArgs> OnDisconnected;

	public void Connect(string campaignId)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Expected O, but got Unknown
		Disconnect();
		if (string.IsNullOrWhiteSpace(campaignId))
		{
			throw new ArgumentException("Tiltify campaign ID must be specified!", "campaignId");
		}
		this.campaignId = campaignId;
		try
		{
			tiltifyWebsocket = new TiltifyWebSocket((ILogger<TiltifyWebSocket>)null, (WebSocketClientOptions)null);
			tiltifyWebsocket.OnLog += TiltifyWebsocket_OnLog;
			tiltifyWebsocket.OnTiltifyServiceConnected += TiltifyWebsocket_OnTiltifyServiceConnected;
			tiltifyWebsocket.OnCampaignDonation += TiltifyWebsocket_OnCampaignDonation;
			tiltifyWebsocket.Connect();
			tiltifyWebsocket.OnTiltifyServiceClosed += TiltifyWebsocket_OnTiltifyServiceClosed;
		}
		catch (Exception ex)
		{
			tiltifyWebsocket = null;
			throw ex;
		}
	}

	private void TiltifyWebsocket_OnLog(object sender, OnLogArgs e)
	{
		Log.Info("[Tiltify Websocket] " + e.Data);
	}

	private void TiltifyWebsocket_OnCampaignDonation(object sender, OnCampaignDonationArgs e)
	{
		this.OnDonationReceived(this, new OnDonationArgs
		{
			Amount = e.Donation.Amount,
			Name = e.Donation.Name,
			Comment = e.Donation.Comment
		});
	}

	private void TiltifyWebsocket_OnTiltifyServiceClosed(object sender, EventArgs e)
	{
		this.OnDisconnected(this, e);
	}

	private void TiltifyWebsocket_OnTiltifyServiceConnected(object sender, EventArgs e)
	{
		if (!string.IsNullOrWhiteSpace(campaignId))
		{
			tiltifyWebsocket.ListenToCampaignDonations(campaignId);
			tiltifyWebsocket.SendTopics(false);
		}
		this.OnConnected(this, e);
	}

	public void Disconnect()
	{
		if (tiltifyWebsocket != null && tiltifyWebsocket.IsConnected)
		{
			tiltifyWebsocket.Disconnect();
		}
		tiltifyWebsocket = null;
		campaignId = null;
		this.OnDisconnected(this, EventArgs.Empty);
	}

	public bool IsConnected()
	{
		return tiltifyWebsocket != null && tiltifyWebsocket.IsConnected;
	}
}
internal class UpdateBitsEvent : EventArgs
{
	public int Bits { get; set; }
}
internal class BitsManager
{
	public int BitGoal { get; set; }

	public int Bits { get; private set; }

	public event EventHandler<UpdateBitsEvent> OnUpdateBits;

	public BitsManager()
		: this(0)
	{
	}

	public BitsManager(int initialBits)
	{
		Bits = initialBits;
		BitGoal = int.MaxValue;
	}

	public void AddBits(int bits)
	{
		if (bits > 0)
		{
			Bits += bits;
			this.OnUpdateBits?.Invoke(this, new UpdateBitsEvent
			{
				Bits = Bits
			});
		}
	}

	public void ResetBits(bool subtractGoal)
	{
		if (subtractGoal)
		{
			Bits = Math.Max(0, Bits - BitGoal);
		}
		else
		{
			Bits = 0;
		}
		this.OnUpdateBits?.Invoke(this, new UpdateBitsEvent
		{
			Bits = Bits
		});
	}
}
internal class ChannelPointsManager
{
	private readonly Dictionary<string, Action<ChannelPointsManager, OnRewardRedeemedArgs>> channelEvents;

	public ChannelPointsManager()
	{
		channelEvents = new Dictionary<string, Action<ChannelPointsManager, OnRewardRedeemedArgs>>();
	}

	public bool RegisterEvent(string eventName, Action<ChannelPointsManager, OnRewardRedeemedArgs> e)
	{
		if (string.IsNullOrWhiteSpace(eventName))
		{
			return false;
		}
		channelEvents[eventName] = e;
		return true;
	}

	public bool UnregisterEvent(string eventName)
	{
		if (!channelEvents.ContainsKey(eventName))
		{
			return false;
		}
		channelEvents.Remove(eventName);
		return true;
	}

	public bool TriggerEvent(OnRewardRedeemedArgs e)
	{
		if (!channelEvents.ContainsKey(e.RewardTitle))
		{
			return false;
		}
		try
		{
			channelEvents[e.RewardTitle](this, e);
			return true;
		}
		catch (Exception data)
		{
			Log.Exception(data);
			return false;
		}
	}
}
internal class TwitchConstants
{
	public const string TWITCH_COLOR_MAIN = "9147ff";

	public const string TWITCH_COLOR_MAIN_ACCENT = "772ce7";
}
internal class TwitchManager
{
	private Client TwitchClient = null;

	private Api TwitchApi = null;

	private PubSub TwitchPubSub = null;

	private string Channel;

	public string Username { get; private set; }

	public bool DebugLogs { get; set; }

	public event EventHandler<OnMessageReceivedArgs> OnMessageReceived;

	public event EventHandler<OnRewardRedeemedArgs> OnRewardRedeemed;

	public event EventHandler<OnJoinedChannelArgs> OnConnected;

	public event EventHandler<OnDisconnectedEventArgs> OnDisconnected;

	public TwitchManager()
	{
		DebugLogs = false;
	}

	public void Connect(string channel, string oauthToken, string username, string clientId)
	{
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Expected O, but got Unknown
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Expected O, but got Unknown
		//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ee: Expected O, but got Unknown
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Expected O, but got Unknown
		Disconnect();
		LogDebug("TwitchManager::Connect");
		if (channel == null || channel.Trim().Length == 0)
		{
			throw new ArgumentException("Twitch channel must be specified!", "channel");
		}
		if (oauthToken == null || oauthToken.Trim().Length == 0)
		{
			throw new ArgumentException("Twitch OAuth password must be specified!", "oauthToken");
		}
		if (username == null || username.Trim().Length == 0)
		{
			throw new ArgumentException("Twitch username must be specified!", "username");
		}
		Channel = channel;
		Username = username;
		LogDebug("[Twitch API] Creating...");
		TwitchApi = new Api();
		string twitchApiOauthToken = oauthToken;
		if (twitchApiOauthToken.StartsWith("oauth:"))
		{
			twitchApiOauthToken = twitchApiOauthToken.Substring("oauth:".Length);
		}
		((TwitchAPI)TwitchApi).Settings.AccessToken = twitchApiOauthToken;
		((TwitchAPI)TwitchApi).Settings.ClientId = clientId;
		string channelId = null;
		try
		{
			LogDebug("[Twitch API] Trying to find channel ID...");
			Task<GetUsersResponse> usersAsync = ((TwitchAPI)TwitchApi).Helix.Users.GetUsersAsync((List<string>)null, new List<string>(new string[1] { channel }), (string)null);
			usersAsync.Wait();
			if (usersAsync.Result.Users.Length != 1)
			{
				throw new ArgumentException("Couldn't find Twitch user/channel " + channel + "!");
			}
			channelId = usersAsync.Result.Users[0].Id;
			Log.Info("[Twitch API] Channel ID for " + channel + " = " + channelId);
		}
		catch (Exception ex)
		{
			if (ex is ArgumentException)
			{
				throw ex;
			}
			Log.Exception(ex);
		}
		LogDebug("[Twitch Client] Creating...");
		ConnectionCredentials val = new ConnectionCredentials(username, oauthToken, "wss://irc-ws.chat.twitch.tv:443", false);
		TwitchClient = new Client();
		((TwitchClient)TwitchClient).Initialize(val, channel, '!', '!', true);
		TwitchClient.OnLog += TwitchClient_OnLog;
		TwitchClient.OnJoinedChannel += this.OnConnected;
		TwitchClient.OnMessageReceived += this.OnMessageReceived;
		TwitchClient.OnConnected += TwitchClient_OnConnected;
		TwitchClient.OnDisconnected += this.OnDisconnected;
		LogDebug("[Twitch Client] Connecting...");
		((TwitchClient)TwitchClient).Connect();
		if (channelId == null || channelId.Trim().Length == 0)
		{
			return;
		}
		LogDebug("[Twitch PubSub] Creating...");
		TwitchPubSub = new PubSub((EndPoint)null);
		TwitchPubSub.OnLog += TwitchPubSub_OnLog;
		TwitchPubSub.OnPubSubServiceConnected += delegate
		{
			Log.Info("[Twitch PubSub] Sending topics to listen too...");
			((TwitchPubSub)TwitchPubSub).ListenToRewards(channelId);
			((TwitchPubSub)TwitchPubSub).SendTopics(twitchApiOauthToken, false);
		};
		TwitchPubSub.OnPubSubServiceError += delegate(object sender, OnPubSubServiceErrorArgs e)
		{
			Log.Error($"[Twitch PubSub] ERROR: {e.Exception}");
		};
		TwitchPubSub.OnPubSubServiceClosed += delegate
		{
			Log.Info("[Twitch PubSub] Connection closed");
		};
		TwitchPubSub.OnListenResponse += delegate(object sender, OnListenResponseArgs e)
		{
			if (!e.Successful)
			{
				Log.Error($"[Twitch PubSub] Failed to listen! Response: {e.Response}");
			}
			else
			{
				Log.Info($"[Twitch PubSub] Listening to {e.Topic} - {e.Response}");
			}
		};
		TwitchPubSub.OnRewardRedeemed += this.OnRewardRedeemed;
		Log.Info("[Twitch PubSub] Connecting...");
		((TwitchPubSub)TwitchPubSub).Connect();
	}

	public void Disconnect()
	{
		LogDebug("TwitchManager::Disconnect");
		if (TwitchClient != null)
		{
			((TwitchClient)TwitchClient).Disconnect();
			TwitchClient = null;
		}
		if (TwitchPubSub != null)
		{
			((TwitchPubSub)TwitchPubSub).Disconnect();
			TwitchPubSub = null;
		}
		if (TwitchApi != null)
		{
			TwitchApi = null;
		}
	}

	public bool IsConnected()
	{
		return TwitchClient != null && ((TwitchClient)TwitchClient).IsConnected;
	}

	public void SendMessage(string message)
	{
		if (!IsConnected())
		{
			Log.Warning("[Twitch Client] Not connected to Twitch!");
		}
		else
		{
			((TwitchClient)TwitchClient).SendMessage(Channel, message, false);
		}
	}

	private void TwitchClient_OnConnected(object sender, OnConnectedArgs e)
	{
		Log.Info("[Twitch Client] Connected to Twitch using username: " + e.BotUsername);
	}

	private void TwitchPubSub_OnLog(object sender, OnLogArgs e)
	{
		LogDebug("[Twitch PubSub] " + e.Data);
	}

	private void TwitchClient_OnLog(object sender, OnLogArgs e)
	{
		LogDebug($"[Twitch Client] {e.DateTime}: {e.BotUsername} - {e.Data}");
	}

	private void LogDebug(string message)
	{
		if (DebugLogs)
		{
			Log.Debug(message);
		}
	}
}
internal class VoteItems : MonoBehaviour
{
	private static readonly int OFFSET_VERTICAL = -128;

	private static readonly int OFFSET_HORIZONTAL = 128;

	private static readonly int TEXT_HEIGHT = 24;

	private GameObject notificationGameObject;

	private GenericNotification notification;

	private float startTime;

	private float duration;

	private int voteIndex;

	private string longTermTitle;

	public void Awake()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		notificationGameObject = Object.Instantiate<GameObject>(LegacyResourcesAPI.Load<GameObject>("Prefabs/NotificationPanel2"));
		SetPosition(new Vector3((float)(Screen.width / 2), (float)(Screen.height / 2), 0f) + new Vector3(0f, (float)OFFSET_VERTICAL, 0f));
		if ((Object)(object)notificationGameObject != (Object)null)
		{
			notification = notificationGameObject.GetComponent<GenericNotification>();
			((Component)notification).transform.SetParent(((Component)RoR2Application.instance.mainCanvas).transform);
			((Behaviour)notification.iconImage).enabled = false;
		}
		else
		{
			Log.Error("Could not load Prefabs/NotificationPanel2, object is null!");
		}
		voteIndex = 0;
		longTermTitle = "";
	}

	public void OnDestroy()
	{
		if ((Object)(object)notificationGameObject != (Object)null)
		{
			Object.Destroy((Object)(object)notificationGameObject);
		}
		notificationGameObject = null;
		notification = null;
	}

	private float GetTimeLeft()
	{
		return duration - (Run.instance.fixedTime - startTime);
	}

	public void Update()
	{
		float num = (Run.instance.fixedTime - startTime) / duration;
		if ((Object)(object)notification == (Object)null || num > 1f)
		{
			Object.Destroy((Object)(object)this);
			return;
		}
		notification.SetNotificationT(num);
		if (voteIndex != 0)
		{
			string arg = "";
			if (voteIndex == 1)
			{
				double num2 = Math.Max(0.0, Math.Round(GetTimeLeft()));
				arg = $"({num2} sec)";
			}
			FieldInfo field = typeof(LanguageTextMeshController).GetField("resolvedString", BindingFlags.Instance | BindingFlags.NonPublic);
			field.SetValue(notification.titleText, $"{voteIndex}: {longTermTitle} {arg}");
			MethodInfo method = typeof(LanguageTextMeshController).GetMethod("UpdateLabel", BindingFlags.Instance | BindingFlags.NonPublic);
			method.Invoke(notification.titleText, new object[0]);
		}
		else
		{
			double num3 = Math.Max(0.0, Math.Round(GetTimeLeft()));
			FieldInfo field2 = typeof(LanguageTextMeshController).GetField("resolvedString", BindingFlags.Instance | BindingFlags.NonPublic);
			field2.SetValue(notification.titleText, $"Twitch vote for one item! ({num3} sec)");
			MethodInfo method2 = typeof(LanguageTextMeshController).GetMethod("UpdateLabel", BindingFlags.Instance | BindingFlags.NonPublic);
			method2.Invoke(notification.titleText, new object[0]);
		}
	}

	public void SetItems(List<PickupIndex> items, float duration, int voteIndex = 0)
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Invalid comparison between Unknown and I4
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Invalid comparison between Unknown and I4
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: 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_0150: Invalid comparison between Unknown and I4
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Invalid comparison between Unknown and I4
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: 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_01ef: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)notification == (Object)null)
		{
			Log.Error("Cannot set items for notification, object is null!");
			return;
		}
		startTime = Run.instance.fixedTime;
		this.duration = duration;
		if (voteIndex != 0)
		{
			((Behaviour)notification.iconImage).enabled = true;
			PickupIndex val = items[voteIndex - 1];
			PickupDef pickupDef = PickupCatalog.GetPickupDef(val);
			if ((int)pickupDef.equipmentIndex != -1)
			{
				notification.SetEquipment(EquipmentCatalog.GetEquipmentDef(pickupDef.equipmentIndex));
			}
			else if ((int)pickupDef.artifactIndex != -1)
			{
				notification.SetArtifact(ArtifactCatalog.GetArtifactDef(pickupDef.artifactIndex));
			}
			else if ((int)pickupDef.itemIndex != -1)
			{
				notification.SetItem(ItemCatalog.GetItemDef(pickupDef.itemIndex));
			}
			this.voteIndex = voteIndex;
			FieldInfo field = typeof(LanguageTextMeshController).GetField("resolvedString", BindingFlags.Instance | BindingFlags.NonPublic);
			longTermTitle = (string)field.GetValue(notification.titleText);
		}
		else
		{
			for (int i = 0; i < items.Count; i++)
			{
				PickupDef pickupDef2 = PickupCatalog.GetPickupDef(items[i]);
				GameObject val2 = (((int)pickupDef2.equipmentIndex == -1) ? CreateIcon(ItemCatalog.GetItemDef(pickupDef2.itemIndex).pickupIconSprite) : CreateIcon(EquipmentCatalog.GetEquipmentDef(pickupDef2.equipmentIndex).pickupIconSprite));
				val2.transform.SetParent(((Component)notification).transform);
				val2.transform.position = new Vector3((float)(Screen.width / 2), (float)(Screen.height / 2), 0f) + new Vector3((float)(i * OFFSET_HORIZONTAL - OFFSET_HORIZONTAL), (float)(OFFSET_VERTICAL + TEXT_HEIGHT), 0f);
			}
			longTermTitle = "";
			this.voteIndex = 0;
		}
	}

	public void SetPosition(Vector3 position)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		notificationGameObject.transform.position = position;
	}

	private static GameObject CreateIcon(Sprite pickupIcon)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("VoteItem_Icon");
		val.AddComponent<Image>().sprite = pickupIcon;
		if ((Object)(object)val.GetComponent<CanvasRenderer>() == (Object)null)
		{
			val.AddComponent<CanvasRenderer>();
		}
		if ((Object)(object)val.GetComponent<RectTransform>() == (Object)null)
		{
			val.AddComponent<RectTransform>();
		}
		val.GetComponent<RectTransform>().sizeDelta = new Vector2(64f, 64f);
		return val;
	}
}
[BepInPlugin("com.justinderby.vstwitch", "VsTwitch", "1.0.14")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class VsTwitch : BaseUnityPlugin
{
	private static readonly char[] SPACE = new char[1] { ' ' };

	public const string GUID = "com.justinderby.vstwitch";

	public const string ModName = "VsTwitch";

	public const string Version = "1.0.14";

	public static VsTwitch Instance;

	private TwitchManager twitchManager;

	private BitsManager bitsManager;

	private ChannelPointsManager channelPointsManager;

	private ItemRollerManager itemRollerManager;

	private LanguageOverride languageOverride;

	private EventDirector eventDirector;

	private EventFactory eventFactory;

	private TiltifyManager tiltifyManager;

	private Configuration configuration;

	private static void DumpAssemblies()
	{
		Log.Error("===== DUMPING ASSEMBLY INFORMATION =====");
		AppDomain currentDomain = AppDomain.CurrentDomain;
		Assembly[] assemblies = currentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			Log.Error(assembly.FullName + ", " + assembly.Location);
		}
		Log.Error("===== FINISHED DUMPING ASSEMBLY INFORMATION =====");
	}

	public void Awake()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Expected O, but got Unknown
		//IL_0203: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Expected O, but got Unknown
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Expected O, but got Unknown
		Log.Init(((BaseUnityPlugin)this).Logger);
		Instance = SingletonHelper.Assign<VsTwitch>(Instance, this);
		configuration = new Configuration((BaseUnityPlugin)(object)this, (UnityAction)delegate
		{
			SetUpChannelPoints();
		});
		if ((Object)(object)((Component)this).gameObject.GetComponent<EventDirector>() == (Object)null)
		{
			eventDirector = ((Component)this).gameObject.AddComponent<EventDirector>();
			eventDirector.OnProcessingEventsChanged += delegate(object sender, bool processing)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Expected O, but got Unknown
				//IL_0044: 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_0059: Expected O, but got Unknown
				Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
				{
					baseToken = "<color=#9147ff>VsTwitch:</color> Events " + (processing ? "enabled" : "paused") + "."
				});
				try
				{
					if (!twitchManager.IsConnected())
					{
						Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
						{
							baseToken = "<color=#9147ff>VsTwitch:</color> [WARNING] Not connected to Twitch!"
						});
					}
				}
				catch (Exception data)
				{
					Log.Error(data);
				}
			};
		}
		if ((Object)(object)((Component)this).gameObject.GetComponent<EventFactory>() == (Object)null)
		{
			eventFactory = ((Component)this).gameObject.AddComponent<EventFactory>();
		}
		bitsManager = new BitsManager(configuration.CurrentBits.Value);
		SetUpChannelPoints();
		twitchManager = new TwitchManager
		{
			DebugLogs = configuration.TwitchDebugLogs.Value
		};
		configuration.TwitchDebugLogs.SettingChanged += delegate
		{
			twitchManager.DebugLogs = configuration.TwitchDebugLogs.Value;
		};
		IVoteStrategy<PickupIndex> voteStrategy;
		switch (configuration.VoteStrategy.Value)
		{
		case Configuration.VoteStrategies.Percentile:
			Log.Info("Twitch Voting Strategy: Percentile");
			voteStrategy = new PercentileVoteStrategy<PickupIndex>();
			break;
		case Configuration.VoteStrategies.MaxVoteRandomTie:
			Log.Info("Twitch Voting Strategy: MaxVoteRandomTie");
			voteStrategy = new MaxRandTieVoteStrategy<PickupIndex>();
			break;
		case Configuration.VoteStrategies.MaxVote:
			Log.Info("Twitch Voting Strategy: MaxVote");
			voteStrategy = new MaxVoteStrategy<PickupIndex>();
			break;
		default:
			Log.Error($"Invalid setting for Twitch.VoteStrategy ({configuration.VoteStrategy.Value})! Using MaxVote strategy.");
			voteStrategy = new MaxVoteStrategy<PickupIndex>();
			break;
		}
		itemRollerManager = new ItemRollerManager(voteStrategy);
		languageOverride = new LanguageOverride
		{
			StreamerName = configuration.TwitchChannel.Value
		};
		tiltifyManager = new TiltifyManager();
		NetworkManagerSystem.onStartHostGlobal += GameNetworkManager_onStartHostGlobal;
		NetworkManagerSystem.onStopHostGlobal += GameNetworkManager_onStopHostGlobal;
		Language.GetLocalizedStringByToken += new hook_GetLocalizedStringByToken(Language_GetLocalizedStringByToken);
		Run.OnEnable += new hook_OnEnable(Run_OnEnable);
		Run.OnDisable += new hook_OnDisable(Run_OnDisable);
		itemRollerManager.OnVoteStart += ItemRollerManager_OnVoteStart;
		bitsManager.BitGoal = configuration.BitsThreshold.Value;
		bitsManager.OnUpdateBits += BitsManager_OnUpdateBits;
		twitchManager.OnConnected += delegate(object sender, OnJoinedChannelArgs joinedChannel)
		{
			Log.Info("Connected to Twitch! Watching " + joinedChannel.Channel + "...");
			Chat.AddMessage("<color=#9147ff>Connected to Twitch!</color> Watching " + joinedChannel.Channel + "...");
		};
		twitchManager.OnDisconnected += delegate
		{
			Log.Info("Disconnected from Twitch!");
			Chat.AddMessage("<color=#9147ff>Disconnected from Twitch!</color>");
		};
		twitchManager.OnMessageReceived += TwitchManager_OnMessageReceived;
		twitchManager.OnRewardRedeemed += TwitchManager_OnRewardRedeemed;
		tiltifyManager.OnConnected += delegate
		{
			Log.Info("Connected to Tiltify!");
			Chat.AddMessage("<color=#9147ff>Connected to Tiltify!</color>");
		};
		tiltifyManager.OnDisconnected += delegate
		{
			Log.Info("Disconnected from Tiltify!");
			Chat.AddMessage("<color=#9147ff>Disconnected from Tiltify!</color>");
		};
		tiltifyManager.OnDonationReceived += TiltifyManager_OnDonationReceived;
	}

	private void SetUpChannelPoints()
	{
		channelPointsManager = new ChannelPointsManager();
		if (channelPointsManager.RegisterEvent(configuration.ChannelPointsAllyBeetle.Value, delegate(ChannelPointsManager manager, OnRewardRedeemedArgs e)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			eventDirector.AddEvent(eventFactory.CreateAlly(e.DisplayName, MonsterSpawner.Monsters.Beetle, RollForElite(forceElite: true)));
		}))
		{
			Log.Info("Successfully registered Channel Points event: Ally Beetle (" + configuration.ChannelPointsAllyBeetle.Value + ")");
		}
		else
		{
			Log.Warning("Could not register Channel Points event: Ally Beetle");
		}
		if (channelPointsManager.RegisterEvent(configuration.ChannelPointsAllyLemurian.Value, delegate(ChannelPointsManager manager, OnRewardRedeemedArgs e)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			eventDirector.AddEvent(eventFactory.CreateAlly(e.DisplayName, MonsterSpawner.Monsters.Lemurian, RollForElite(forceElite: true)));
		}))
		{
			Log.Info("Successfully registered Channel Points event: Ally Lemurian (" + configuration.ChannelPointsAllyLemurian.Value + ")");
		}
		else
		{
			Log.Warning("Could not register Channel Points event: Ally Lemurian");
		}
		if (channelPointsManager.RegisterEvent(configuration.ChannelPointsAllyElderLemurian.Value, delegate(ChannelPointsManager manager, OnRewardRedeemedArgs e)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			eventDirector.AddEvent(eventFactory.CreateAlly(e.DisplayName, MonsterSpawner.Monsters.LemurianBruiser, RollForElite(forceElite: true)));
		}))
		{
			Log.Info("Successfully registered Channel Points event: Ally Elder Lemurian (" + configuration.ChannelPointsAllyElderLemurian.Value + ")");
		}
		else
		{
			Log.Warning("Could not register Channel Points event: Ally Elder Lemurian");
		}
		if (channelPointsManager.RegisterEvent(configuration.ChannelPointsRustedKey.Value, delegate(ChannelPointsManager manager, OnRewardRedeemedArgs e)
		{
			GiveRustedKey(e.DisplayName);
		}))
		{
			Log.Info("Successfully registered Channel Points event: Rusted Key (" + configuration.ChannelPointsRustedKey.Value + ")");
		}
		else
		{
			Log.Warning("Could not register Channel Points event: Rusted Key");
		}
		if (channelPointsManager.RegisterEvent(configuration.ChannelPointsBitStorm.Value, delegate(ChannelPointsManager manager, OnRewardRedeemedArgs e)
		{
			UsedChannelPoints(e);
			eventDirector.AddEvent(eventFactory.CreateBitStorm());
		}))
		{
			Log.Info("Successfully registered Channel Points event: Bit Storm (" + configuration.ChannelPointsBitStorm.Value + ")");
		}
		else
		{
			Log.Warning("Could not register Channel Points event: Bit Storm");
		}
		if (channelPointsManager.RegisterEvent(configuration.ChannelPointsBounty.Value, delegate(ChannelPointsManager manager, OnRewardRedeemedArgs e)
		{
			UsedChannelPoints(e);
			eventDirector.AddEvent(eventFactory.CreateBounty());
		}))
		{
			Log.Info("Successfully registered Channel Points event: Bounty (" + configuration.ChannelPointsBounty.Value + ")");
		}
		else
		{
			Log.Warning("Could not register Channel Points event: Bounty");
		}
		if (channelPointsManager.RegisterEvent(configuration.ChannelPointsShrineOfOrder.Value, delegate(ChannelPointsManager manager, OnRewardRedeemedArgs e)
		{
			UsedChannelPoints(e);
			eventDirector.AddEvent(eventFactory.TriggerShrineOfOrder());
		}))
		{
			Log.Info("Successfully registered Channel Points event: Shrine Of Order (" + configuration.ChannelPointsShrineOfOrder.Value + ")");
		}
		else
		{
			Log.Warning("Could not register Channel Points event: Shrine Of Order");