Decompiled source of Divination Logger v1.2.0

BepInEx/plugins/MiniExcel.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
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 MiniExcelLibs.Attributes;
using MiniExcelLibs.Csv;
using MiniExcelLibs.Exceptions;
using MiniExcelLibs.OpenXml;
using MiniExcelLibs.OpenXml.Constants;
using MiniExcelLibs.OpenXml.Models;
using MiniExcelLibs.OpenXml.SaveByTemplate;
using MiniExcelLibs.OpenXml.Styles;
using MiniExcelLibs.Utils;
using MiniExcelLibs.WriteAdapter;
using MiniExcelLibs.Zip;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Mini-Software")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Wei Lin, 2021 onwards")]
[assembly: AssemblyDescription("Fast, Low-Memory, Easy Excel .NET helper to import/export/template spreadsheet\r\nGithub : https://github.com/mini-software/MiniExcel\r\nGitee : https://gitee.com/dotnetchina/MiniExcel\r\nIssues : https://github.com/mini-software/MiniExcel/issues\r\nTodo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true")]
[assembly: AssemblyFileVersion("1.39.0.0")]
[assembly: AssemblyInformationalVersion("1.39.0+177f86e4fe70324abbc343c51b5ce381537f9f77")]
[assembly: AssemblyProduct("MiniExcel")]
[assembly: AssemblyTitle("MiniExcel")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/mini-software/MiniExcel")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: AssemblyVersion("1.39.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 MiniExcelLibs
{
	internal class ExcelReaderFactory
	{
		internal static IExcelReader GetProvider(Stream stream, ExcelType excelType, IConfiguration configuration)
		{
			return excelType switch
			{
				ExcelType.CSV => new CsvReader(stream, configuration), 
				ExcelType.XLSX => new ExcelOpenXmlSheetReader(stream, configuration), 
				_ => throw new NotSupportedException("Please Issue for me"), 
			};
		}
	}
	internal class ExcelWriterFactory
	{
		internal static IExcelWriter GetProvider(Stream stream, object value, string sheetName, ExcelType excelType, IConfiguration configuration, bool printHeader)
		{
			if (string.IsNullOrEmpty(sheetName))
			{
				throw new InvalidDataException("Sheet name can not be empty or null");
			}
			return excelType switch
			{
				ExcelType.UNKNOWN => throw new InvalidDataException("Please specify excelType"), 
				ExcelType.CSV => new CsvWriter(stream, value, configuration, printHeader), 
				ExcelType.XLSX => new ExcelOpenXmlSheetWriter(stream, value, sheetName, configuration, printHeader), 
				_ => throw new NotSupportedException("Please Issue for me"), 
			};
		}
	}
	internal class ExcelTemplateFactory
	{
		internal static IExcelTemplateAsync GetProvider(Stream stream, IConfiguration configuration, ExcelType excelType = ExcelType.XLSX)
		{
			if (excelType == ExcelType.XLSX)
			{
				InputValueExtractor inputValueExtractor = new InputValueExtractor();
				return new ExcelOpenXmlTemplate(stream, configuration, inputValueExtractor);
			}
			throw new NotSupportedException("Please Issue for me");
		}
	}
	public enum ExcelType
	{
		XLSX,
		CSV,
		UNKNOWN
	}
	public interface IConfiguration
	{
	}
	public abstract class Configuration : IConfiguration
	{
		public CultureInfo Culture { get; set; } = CultureInfo.InvariantCulture;


		public DynamicExcelColumn[] DynamicColumns { get; set; }

		public int BufferSize { get; set; } = 524288;


		public bool FastMode { get; set; }

		public bool DynamicColumnFirst { get; set; }
	}
	internal interface IExcelReader : IDisposable
	{
		IEnumerable<IDictionary<string, object>> Query(bool UseHeaderRow, string sheetName, string startCell);

		IEnumerable<T> Query<T>(string sheetName, string startCell) where T : class, new();

		Task<IEnumerable<IDictionary<string, object>>> QueryAsync(bool UseHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default(CancellationToken));

		Task<IEnumerable<T>> QueryAsync<T>(string sheetName, string startCell, CancellationToken cancellationToken = default(CancellationToken)) where T : class, new();

		IEnumerable<IDictionary<string, object>> QueryRange(bool UseHeaderRow, string sheetName, string startCell, string endCell);

		IEnumerable<T> QueryRange<T>(string sheetName, string startCell, string endCell) where T : class, new();

		Task<IEnumerable<IDictionary<string, object>>> QueryAsyncRange(bool UseHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default(CancellationToken));

		Task<IEnumerable<T>> QueryAsyncRange<T>(string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default(CancellationToken)) where T : class, new();
	}
	internal interface IExcelTemplate
	{
		void SaveAsByTemplate(string templatePath, object value);

		void SaveAsByTemplate(byte[] templateBtyes, object value);

		void MergeSameCells(string path);

		void MergeSameCells(byte[] fileInBytes);
	}
	internal interface IExcelTemplateAsync : IExcelTemplate
	{
		Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken cancellationToken = default(CancellationToken));

		Task SaveAsByTemplateAsync(byte[] templateBtyes, object value, CancellationToken cancellationToken = default(CancellationToken));

		Task MergeSameCellsAsync(string path, CancellationToken cancellationToken = default(CancellationToken));

		Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken cancellationToken = default(CancellationToken));
	}
	internal interface IExcelWriter
	{
		int[] SaveAs();

		Task<int[]> SaveAsAsync(CancellationToken cancellationToken = default(CancellationToken));

		int Insert(bool overwriteSheet = false);

		Task<int> InsertAsync(bool overwriteSheet = false, CancellationToken cancellationToken = default(CancellationToken));
	}
	public interface IMiniExcelDataReader : IDataReader, IDataRecord, IDisposable
	{
		Task CloseAsync();

		Task<string> GetNameAsync(int i, CancellationToken cancellationToken = default(CancellationToken));

		Task<object> GetValueAsync(int i, CancellationToken cancellationToken = default(CancellationToken));

		Task<bool> NextResultAsync(CancellationToken cancellationToken = default(CancellationToken));

		Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken));
	}
	public static class MiniExcel
	{
		public static string LISENCE_CODE;

		public static async Task<int> InsertAsync(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
			{
				throw new NotSupportedException("MiniExcel's Insert does not support the .xlsm format");
			}
			if (!File.Exists(path))
			{
				return (await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, overwriteFile: false, cancellationToken)).FirstOrDefault();
			}
			if (excelType == ExcelType.CSV)
			{
				using (FileStream stream2 = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan))
				{
					return await stream2.InsertAsync(value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken);
				}
			}
			using FileStream stream2 = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan);
			return await stream2.InsertAsync(value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken);
		}

		public static async Task<int> InsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default(CancellationToken))
		{
			stream.Seek(0L, SeekOrigin.End);
			if (excelType == ExcelType.CSV)
			{
				object value2 = ((value is IEnumerable || value is IDataReader) ? value : new object[1] { value }.AsEnumerable());
				return await ExcelWriterFactory.GetProvider(stream, value2, sheetName, excelType, configuration, printHeader: false).InsertAsync(overwriteSheet, cancellationToken);
			}
			IConfiguration configuration2 = configuration ?? new OpenXmlConfiguration
			{
				FastMode = true
			};
			return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration2, printHeader).InsertAsync(overwriteSheet, cancellationToken);
		}

		public static async Task<int[]> SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
			{
				throw new NotSupportedException("MiniExcel's SaveAs does not support the .xlsm format");
			}
			using FileStream stream = (overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew));
			return await stream.SaveAsAsync(value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, cancellationToken);
		}

		public static async Task<int[]> SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(cancellationToken);
		}

		public static async Task MergeSameCellsAsync(string mergedFilePath, string path, ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			await Task.Run(delegate
			{
				MergeSameCells(mergedFilePath, path, excelType, configuration);
			}, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static async Task MergeSameCellsAsync(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, cancellationToken);
		}

		public static async Task MergeSameCellsAsync(this Stream stream, byte[] fileBytes, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(fileBytes, cancellationToken);
		}

		public static async Task<IEnumerable<dynamic>> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			return await Task.Run(() => Query(path, useHeaderRow, sheetName, excelType, startCell, configuration), cancellationToken);
		}

		public static async Task<IEnumerable<T>> QueryAsync<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken)) where T : class, new()
		{
			return await ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).QueryAsync<T>(sheetName, startCell, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static async Task<IEnumerable<T>> QueryAsync<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken)) where T : class, new()
		{
			return await Task.Run(() => Query<T>(path, sheetName, excelType, startCell, configuration), cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static async Task<IEnumerable<dynamic>> QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			TaskCompletionSource<IEnumerable<dynamic>> tcs = new TaskCompletionSource<IEnumerable<object>>();
			cancellationToken.Register(delegate
			{
				tcs.TrySetCanceled();
			});
			await Task.Run(delegate
			{
				try
				{
					tcs.TrySetResult(stream.Query(useHeaderRow, sheetName, excelType, startCell, configuration));
				}
				catch (Exception exception)
				{
					tcs.TrySetException(exception);
				}
			}, cancellationToken);
			return await tcs.Task;
		}

		public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			await Task.Run(delegate
			{
				SaveAsByTemplate(path, templatePath, value, configuration);
			}, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			await Task.Run(delegate
			{
				SaveAsByTemplate(path, templateBytes, value, configuration);
			}, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		[Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")]
		public static async Task<DataTable> QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			return await Task.Run(() => QueryAsDataTable(path, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration), cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		[Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")]
		public static async Task<DataTable> QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			return await Task.Run(() => stream.QueryAsDataTable(useHeaderRow, sheetName, excelType, startCell, configuration), cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static MiniExcelDataReader GetReader(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			return new MiniExcelDataReader(FileHelper.OpenSharedRead(path), useHeaderRow, sheetName, excelType, startCell, configuration);
		}

		public static MiniExcelDataReader GetReader(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			return new MiniExcelDataReader(stream, useHeaderRow, sheetName, excelType, startCell, configuration);
		}

		public static int Insert(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false)
		{
			if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
			{
				throw new NotSupportedException("MiniExcel's Insert does not support the .xlsm format");
			}
			if (!File.Exists(path))
			{
				return SaveAs(path, value, printHeader, sheetName, excelType, configuration).FirstOrDefault();
			}
			if (excelType == ExcelType.CSV)
			{
				using (FileStream stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan))
				{
					return stream.Insert(value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet);
				}
			}
			using FileStream stream2 = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan);
			return stream2.Insert(value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet);
		}

		public static int Insert(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false)
		{
			stream.Seek(0L, SeekOrigin.End);
			if (excelType == ExcelType.CSV)
			{
				object value2 = ((value is IEnumerable || value is IDataReader) ? value : new object[1] { value }.AsEnumerable());
				return ExcelWriterFactory.GetProvider(stream, value2, sheetName, excelType, configuration, printHeader: false).Insert(overwriteSheet);
			}
			IConfiguration configuration2 = configuration ?? new OpenXmlConfiguration
			{
				FastMode = true
			};
			return ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration2, printHeader).Insert(overwriteSheet);
		}

		public static int[] SaveAs(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false)
		{
			if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
			{
				throw new NotSupportedException("MiniExcel's SaveAs does not support the .xlsm format");
			}
			using FileStream stream = (overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew));
			return stream.SaveAs(value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration);
		}

		public static int[] SaveAs(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
		{
			return ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAs();
		}

		public static IEnumerable<T> Query<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
		{
			using FileStream stream = FileHelper.OpenSharedRead(path);
			foreach (T item in stream.Query<T>(sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration))
			{
				yield return item;
			}
		}

		public static IEnumerable<T> Query<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
		{
			using IExcelReader excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration);
			foreach (T item in excelReader.Query<T>(sheetName, startCell))
			{
				yield return item;
			}
		}

		public static IEnumerable<dynamic> Query(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			using FileStream stream = FileHelper.OpenSharedRead(path);
			foreach (object item in stream.Query(useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration))
			{
				yield return item;
			}
		}

		public static IEnumerable<dynamic> Query(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			using IExcelReader excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration);
			foreach (IDictionary<string, object> item in excelReader.Query(useHeaderRow, sheetName, startCell))
			{
				yield return item.Aggregate(new ExpandoObject(), delegate(IDictionary<string, object> dict, KeyValuePair<string, object> p)
				{
					dict.Add(p);
					return dict;
				});
			}
		}

		public static IEnumerable<dynamic> QueryRange(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "a1", string endCell = "", IConfiguration configuration = null)
		{
			using FileStream stream = FileHelper.OpenSharedRead(path);
			foreach (object item in stream.QueryRange(useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), (startCell == "") ? "a1" : startCell, endCell, configuration))
			{
				yield return item;
			}
		}

		public static IEnumerable<dynamic> QueryRange(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "a1", string endCell = "", IConfiguration configuration = null)
		{
			using IExcelReader excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration);
			foreach (IDictionary<string, object> item in excelReader.QueryRange(useHeaderRow, sheetName, (startCell == "") ? "a1" : startCell, endCell))
			{
				yield return item.Aggregate(new ExpandoObject(), delegate(IDictionary<string, object> dict, KeyValuePair<string, object> p)
				{
					dict.Add(p);
					return dict;
				});
			}
		}

		public static void SaveAsByTemplate(string path, string templatePath, object value, IConfiguration configuration = null)
		{
			using FileStream stream = File.Create(path);
			stream.SaveAsByTemplate(templatePath, value, configuration);
		}

		public static void SaveAsByTemplate(string path, byte[] templateBytes, object value, IConfiguration configuration = null)
		{
			using FileStream stream = File.Create(path);
			stream.SaveAsByTemplate(templateBytes, value, configuration);
		}

		public static void SaveAsByTemplate(this Stream stream, string templatePath, object value, IConfiguration configuration = null)
		{
			ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templatePath, value);
		}

		public static void SaveAsByTemplate(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null)
		{
			ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templateBytes, value);
		}

		public static void MergeSameCells(string mergedFilePath, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
		{
			using FileStream stream = File.Create(mergedFilePath);
			stream.MergeSameCells(path, excelType, configuration);
		}

		public static void MergeSameCells(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
		{
			ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(path);
		}

		public static void MergeSameCells(this Stream stream, byte[] filePath, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
		{
			ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(filePath);
		}

		[Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")]
		public static DataTable QueryAsDataTable(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			using FileStream stream = FileHelper.OpenSharedRead(path);
			return stream.QueryAsDataTable(useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration);
		}

		public static DataTable QueryAsDataTable(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			if (sheetName == null && excelType != ExcelType.CSV)
			{
				sheetName = stream.GetSheetNames(configuration as OpenXmlConfiguration).First();
			}
			DataTable dataTable = new DataTable(sheetName);
			bool flag = true;
			IEnumerable<IDictionary<string, object>> enumerable = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).Query(UseHeaderRow: false, sheetName, startCell);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (IDictionary<string, object> item in enumerable)
			{
				if (flag)
				{
					foreach (KeyValuePair<string, object> item2 in item)
					{
						string text = ((!useHeaderRow) ? item2.Key : item2.Value?.ToString());
						if (!string.IsNullOrWhiteSpace(text))
						{
							DataColumn column = new DataColumn(text, typeof(object))
							{
								Caption = text
							};
							dataTable.Columns.Add(column);
							dictionary.Add(item2.Key, text);
						}
					}
					dataTable.BeginLoadData();
					flag = false;
					if (useHeaderRow)
					{
						continue;
					}
				}
				DataRow dataRow = dataTable.NewRow();
				foreach (KeyValuePair<string, string> item3 in dictionary)
				{
					dataRow[item3.Value] = item[item3.Key];
				}
				dataTable.Rows.Add(dataRow);
			}
			dataTable.EndLoadData();
			return dataTable;
		}

		public static List<string> GetSheetNames(string path, OpenXmlConfiguration config = null)
		{
			using FileStream stream = FileHelper.OpenSharedRead(path);
			return stream.GetSheetNames(config);
		}

		public static List<string> GetSheetNames(this Stream stream, OpenXmlConfiguration config = null)
		{
			config = config ?? OpenXmlConfiguration.DefaultConfig;
			ExcelOpenXmlZip excelOpenXmlZip = new ExcelOpenXmlZip(stream);
			return (from s in new ExcelOpenXmlSheetReader(stream, config).GetWorkbookRels(excelOpenXmlZip.entries)
				select s.Name).ToList();
		}

		public static List<SheetInfo> GetSheetInformations(string path, OpenXmlConfiguration config = null)
		{
			using FileStream stream = FileHelper.OpenSharedRead(path);
			return stream.GetSheetInformations(config);
		}

		public static List<SheetInfo> GetSheetInformations(this Stream stream, OpenXmlConfiguration config = null)
		{
			config = config ?? OpenXmlConfiguration.DefaultConfig;
			ExcelOpenXmlZip excelOpenXmlZip = new ExcelOpenXmlZip(stream);
			return new ExcelOpenXmlSheetReader(stream, config).GetWorkbookRels(excelOpenXmlZip.entries).Select((SheetRecord s, int i) => s.ToSheetInfo((uint)i)).ToList();
		}

		public static ICollection<string> GetColumns(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			using FileStream stream = FileHelper.OpenSharedRead(path);
			return stream.GetColumns(useHeaderRow, sheetName, excelType, startCell, configuration);
		}

		public static ICollection<string> GetColumns(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			return (stream.Query(useHeaderRow, sheetName, excelType, startCell, configuration).FirstOrDefault() as IDictionary<string, object>)?.Keys;
		}

		public static void ConvertCsvToXlsx(string csv, string xlsx)
		{
			using FileStream csv2 = FileHelper.OpenSharedRead(csv);
			using FileStream xlsx2 = new FileStream(xlsx, FileMode.CreateNew);
			ConvertCsvToXlsx(csv2, xlsx2);
		}

		public static void ConvertCsvToXlsx(Stream csv, Stream xlsx)
		{
			IEnumerable<object> value = csv.Query(useHeaderRow: false, null, ExcelType.CSV);
			xlsx.SaveAs(value, printHeader: false);
		}

		public static void ConvertXlsxToCsv(string xlsx, string csv)
		{
			using FileStream xlsx2 = FileHelper.OpenSharedRead(xlsx);
			using FileStream csv2 = new FileStream(csv, FileMode.CreateNew);
			ConvertXlsxToCsv(xlsx2, csv2);
		}

		public static void ConvertXlsxToCsv(Stream xlsx, Stream csv)
		{
			IEnumerable<object> value = xlsx.Query(useHeaderRow: false, null, ExcelType.XLSX);
			csv.SaveAs(value, printHeader: false, "Sheet1", ExcelType.CSV);
		}
	}
	public class MiniExcelDataReader : MiniExcelDataReaderBase
	{
		private readonly IEnumerator<IDictionary<string, object>> _source;

		private readonly int _fieldCount;

		private readonly List<string> _keys;

		private readonly Stream _stream;

		private bool _isFirst = true;

		private bool _disposed;

		public override int FieldCount => _fieldCount;

		internal MiniExcelDataReader(Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
		{
			_stream = stream ?? throw new ArgumentNullException("stream");
			_source = _stream.Query(useHeaderRow, sheetName, excelType, startCell, configuration).Cast<IDictionary<string, object>>().GetEnumerator();
			if (_source.MoveNext())
			{
				_keys = _source.Current?.Keys.ToList() ?? new List<string>();
				_fieldCount = _keys.Count;
			}
		}

		public override object GetValue(int i)
		{
			if (_source.Current == null)
			{
				throw new InvalidOperationException("No current row available.");
			}
			return _source.Current[_keys[i]];
		}

		public override bool Read()
		{
			if (_isFirst)
			{
				_isFirst = false;
				return true;
			}
			return _source.MoveNext();
		}

		public override string GetName(int i)
		{
			return _keys[i];
		}

		public override int GetOrdinal(string name)
		{
			return _keys.IndexOf(name);
		}

		protected override void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				if (disposing)
				{
					_stream?.Dispose();
					_source?.Dispose();
				}
				_disposed = true;
			}
			base.Dispose(disposing);
		}

		public new void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}
	}
	public abstract class MiniExcelDataReaderBase : IMiniExcelDataReader, IDataReader, IDataRecord, IDisposable
	{
		public virtual object this[int i] => null;

		public virtual object this[string name] => null;

		public virtual int Depth { get; }

		public virtual bool IsClosed { get; }

		public virtual int RecordsAffected { get; }

		public virtual int FieldCount { get; }

		public virtual bool GetBoolean(int i)
		{
			return false;
		}

		public virtual byte GetByte(int i)
		{
			return 0;
		}

		public virtual long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferOffset, int length)
		{
			return 0L;
		}

		public virtual char GetChar(int i)
		{
			return '\0';
		}

		public virtual long GetChars(int i, long fieldOffset, char[] buffer, int bufferOffset, int length)
		{
			return 0L;
		}

		public virtual IDataReader GetData(int i)
		{
			return null;
		}

		public virtual string GetDataTypeName(int i)
		{
			return string.Empty;
		}

		public virtual DateTime GetDateTime(int i)
		{
			return DateTime.MinValue;
		}

		public virtual decimal GetDecimal(int i)
		{
			return 0m;
		}

		public virtual double GetDouble(int i)
		{
			return 0.0;
		}

		public virtual Type GetFieldType(int i)
		{
			return null;
		}

		public virtual float GetFloat(int i)
		{
			return 0f;
		}

		public virtual Guid GetGuid(int i)
		{
			return Guid.Empty;
		}

		public virtual short GetInt16(int i)
		{
			return 0;
		}

		public virtual int GetInt32(int i)
		{
			return 0;
		}

		public virtual long GetInt64(int i)
		{
			return 0L;
		}

		public virtual int GetOrdinal(string name)
		{
			return 0;
		}

		public virtual DataTable GetSchemaTable()
		{
			return null;
		}

		public virtual string GetString(int i)
		{
			return string.Empty;
		}

		public virtual int GetValues(object[] values)
		{
			return 0;
		}

		public virtual bool IsDBNull(int i)
		{
			return false;
		}

		public virtual bool NextResult()
		{
			return false;
		}

		public virtual Task<bool> NextResultAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (cancellationToken.IsCancellationRequested)
			{
				return MiniExcelTask.FromCanceled<bool>(cancellationToken);
			}
			try
			{
				return NextResult() ? Task.FromResult(result: true) : Task.FromResult(result: false);
			}
			catch (Exception exception)
			{
				return MiniExcelTask.FromException<bool>(exception);
			}
		}

		public abstract string GetName(int i);

		public virtual Task<string> GetNameAsync(int i, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (cancellationToken.IsCancellationRequested)
			{
				return MiniExcelTask.FromCanceled<string>(cancellationToken);
			}
			try
			{
				return Task.FromResult(GetName(i));
			}
			catch (Exception exception)
			{
				return MiniExcelTask.FromException<string>(exception);
			}
		}

		public abstract object GetValue(int i);

		public virtual Task<object> GetValueAsync(int i, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (cancellationToken.IsCancellationRequested)
			{
				return MiniExcelTask.FromCanceled<object>(cancellationToken);
			}
			try
			{
				return Task.FromResult(GetValue(i));
			}
			catch (Exception exception)
			{
				return MiniExcelTask.FromException<object>(exception);
			}
		}

		public abstract bool Read();

		public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (cancellationToken.IsCancellationRequested)
			{
				return MiniExcelTask.FromCanceled<bool>(cancellationToken);
			}
			try
			{
				return Read() ? Task.FromResult(result: true) : Task.FromResult(result: false);
			}
			catch (Exception exception)
			{
				return MiniExcelTask.FromException<bool>(exception);
			}
		}

		public virtual void Close()
		{
		}

		public virtual Task CloseAsync()
		{
			try
			{
				Close();
				return MiniExcelTask.CompletedTask;
			}
			catch (Exception exception)
			{
				return MiniExcelTask.FromException(exception);
			}
		}

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

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				Close();
			}
		}
	}
	internal class MiniExcelTask
	{
		public static Task CompletedTask = Task.CompletedTask;

		public static Task FromException(Exception exception)
		{
			return Task.FromException(exception);
		}

		public static Task<T> FromException<T>(Exception exception)
		{
			return Task.FromException<T>(exception);
		}

		public static Task FromCanceled(CancellationToken cancellationToken)
		{
			return Task.FromCanceled(cancellationToken);
		}

		public static Task<T> FromCanceled<T>(CancellationToken cancellationToken)
		{
			return Task.FromCanceled<T>(cancellationToken);
		}
	}
	public class MemberGetter
	{
		private readonly Func<object, object> m_getFunc;

		public MemberGetter(PropertyInfo property)
		{
			m_getFunc = CreateGetterDelegate(property);
		}

		public MemberGetter(FieldInfo fieldInfo)
		{
			m_getFunc = CreateGetterDelegate(fieldInfo);
		}

		public object Invoke(object instance)
		{
			return m_getFunc(instance);
		}

		private static Func<object, object> CreateGetterDelegate(PropertyInfo property)
		{
			ParameterExpression parameterExpression = Expression.Parameter(typeof(object));
			return Expression.Lambda<Func<object, object>>(Expression.Convert(Expression.Property(Expression.Convert(parameterExpression, property.DeclaringType), property), typeof(object)), new ParameterExpression[1] { parameterExpression }).Compile();
		}

		private static Func<object, object> CreateGetterDelegate(FieldInfo fieldInfo)
		{
			ParameterExpression parameterExpression = Expression.Parameter(typeof(object));
			return Expression.Lambda<Func<object, object>>(Expression.Convert(Expression.Field(Expression.Convert(parameterExpression, fieldInfo.DeclaringType), fieldInfo), typeof(object)), new ParameterExpression[1] { parameterExpression }).Compile();
		}
	}
	public class MemberSetter
	{
		private readonly Action<object, object> setFunc;

		public MemberSetter(PropertyInfo property)
		{
			if (property == null)
			{
				throw new ArgumentNullException("property");
			}
			setFunc = CreateSetterDelegate(property);
		}

		public void Invoke(object instance, object value)
		{
			setFunc(instance, value);
		}

		private static Action<object, object> CreateSetterDelegate(PropertyInfo property)
		{
			ParameterExpression parameterExpression = Expression.Parameter(typeof(object));
			ParameterExpression parameterExpression2 = Expression.Parameter(typeof(object));
			UnaryExpression instance = Expression.Convert(parameterExpression, property.DeclaringType);
			UnaryExpression unaryExpression = Expression.Convert(parameterExpression2, property.PropertyType);
			return Expression.Lambda<Action<object, object>>(Expression.Call(instance, property.GetSetMethod(nonPublic: true), unaryExpression), new ParameterExpression[2] { parameterExpression, parameterExpression2 }).Compile();
		}
	}
	public abstract class Member
	{
	}
	public class Property : Member
	{
		private static readonly ConcurrentDictionary<Type, Property[]> m_cached = new ConcurrentDictionary<Type, Property[]>();

		private readonly MemberGetter m_geter;

		private readonly MemberSetter m_seter;

		public bool CanRead { get; private set; }

		public bool CanWrite { get; private set; }

		public PropertyInfo Info { get; private set; }

		public string Name { get; protected set; }

		public Property(PropertyInfo property)
		{
			Name = property.Name;
			Info = property;
			if (property.CanRead)
			{
				CanRead = true;
				m_geter = new MemberGetter(property);
			}
			if (property.CanWrite)
			{
				CanWrite = true;
				m_seter = new MemberSetter(property);
			}
		}

		public static Property[] GetProperties(Type type)
		{
			return m_cached.GetOrAdd(type, (Type t) => (from p in t.GetProperties()
				select new Property(p)).ToArray());
		}

		public object GetValue(object instance)
		{
			if (m_geter == null)
			{
				throw new NotSupportedException();
			}
			return m_geter.Invoke(instance);
		}

		public void SetValue(object instance, object value)
		{
			if (m_seter == null)
			{
				throw new NotSupportedException(Name + " can't set value");
			}
			m_seter.Invoke(instance, value);
		}
	}
}
namespace MiniExcelLibs.Zip
{
	internal class ExcelOpenXmlZip : IDisposable
	{
		private readonly Dictionary<string, ZipArchiveEntry> _entries;

		private bool _disposed;

		internal MiniExcelZipArchive zipFile;

		public ReadOnlyCollection<ZipArchiveEntry> entries;

		private static readonly XmlReaderSettings XmlSettings = new XmlReaderSettings
		{
			IgnoreComments = true,
			IgnoreWhitespace = true,
			XmlResolver = null
		};

		public ExcelOpenXmlZip(Stream fileStream, ZipArchiveMode mode = ZipArchiveMode.Read, bool leaveOpen = false, Encoding entryNameEncoding = null)
		{
			zipFile = new MiniExcelZipArchive(fileStream, mode, leaveOpen, entryNameEncoding);
			_entries = new Dictionary<string, ZipArchiveEntry>(StringComparer.OrdinalIgnoreCase);
			try
			{
				entries = zipFile.Entries;
			}
			catch (InvalidDataException ex)
			{
				throw new InvalidDataException("It's not legal excel zip, please check or issue for me. " + ex.Message);
			}
			foreach (ZipArchiveEntry entry in zipFile.Entries)
			{
				_entries.Add(entry.FullName.Replace('\\', '/'), entry);
			}
		}

		public ZipArchiveEntry GetEntry(string path)
		{
			if (_entries.TryGetValue(path, out var value))
			{
				return value;
			}
			return null;
		}

		public XmlReader GetXmlReader(string path)
		{
			ZipArchiveEntry entry = GetEntry(path);
			if (entry != null)
			{
				return XmlReader.Create(entry.Open(), XmlSettings);
			}
			return null;
		}

		~ExcelOpenXmlZip()
		{
			Dispose(disposing: false);
		}

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

		private void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				if (disposing && zipFile != null)
				{
					zipFile.Dispose();
					zipFile = null;
				}
				_disposed = true;
			}
		}
	}
	public class MiniExcelZipArchive : ZipArchive
	{
		public MiniExcelZipArchive(Stream stream, ZipArchiveMode mode, bool leaveOpen, Encoding entryNameEncoding)
			: base(stream, mode, leaveOpen, entryNameEncoding)
		{
		}

		public new void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}
	}
	internal class ZipPackageInfo
	{
		public ZipArchiveEntry ZipArchiveEntry { get; set; }

		public string ContentType { get; set; }

		public ZipPackageInfo(ZipArchiveEntry zipArchiveEntry, string contentType)
		{
			ZipArchiveEntry = zipArchiveEntry;
			ContentType = contentType;
		}
	}
}
namespace MiniExcelLibs.WriteAdapter
{
	internal class AsyncEnumerableWriteAdapter<T> : IAsyncMiniExcelWriteAdapter
	{
		private readonly IAsyncEnumerable<T> _values;

		private readonly Configuration _configuration;

		private IAsyncEnumerator<T> _enumerator;

		private bool _empty;

		public AsyncEnumerableWriteAdapter(IAsyncEnumerable<T> values, Configuration configuration)
		{
			_values = values;
			_configuration = configuration;
		}

		public async Task<List<ExcelColumnInfo>> GetColumnsAsync()
		{
			if (CustomPropertyHelper.TryGetTypeColumnInfo(typeof(T), _configuration, out var props))
			{
				return props;
			}
			_enumerator = _values.GetAsyncEnumerator();
			if (!(await _enumerator.MoveNextAsync()))
			{
				_empty = true;
				return null;
			}
			return CustomPropertyHelper.GetColumnInfoFromValue(_enumerator.Current, _configuration);
		}

		public async IAsyncEnumerable<IAsyncEnumerable<CellWriteInfo>> GetRowsAsync(List<ExcelColumnInfo> props, [EnumeratorCancellation] CancellationToken cancellationToken)
		{
			if (_empty)
			{
				yield break;
			}
			if (_enumerator == null)
			{
				_enumerator = _values.GetAsyncEnumerator();
				if (!(await _enumerator.MoveNextAsync()))
				{
					yield break;
				}
			}
			do
			{
				cancellationToken.ThrowIfCancellationRequested();
				yield return GetRowValuesAsync(_enumerator.Current, props);
			}
			while (await _enumerator.MoveNextAsync());
		}

		public static async IAsyncEnumerable<CellWriteInfo> GetRowValuesAsync(T currentValue, List<ExcelColumnInfo> props)
		{
			int column = 1;
			foreach (ExcelColumnInfo prop in props)
			{
				if (prop == null)
				{
					column++;
					continue;
				}
				if ((object)currentValue is IDictionary<string, object> dictionary)
				{
					yield return new CellWriteInfo(dictionary[prop.Key.ToString()], column, prop);
				}
				else if ((object)currentValue is IDictionary dictionary2)
				{
					yield return new CellWriteInfo(dictionary2[prop.Key], column, prop);
				}
				else
				{
					yield return new CellWriteInfo(prop.Property.GetValue(currentValue), column, prop);
				}
				column++;
			}
		}
	}
	internal class DataReaderWriteAdapter : IMiniExcelWriteAdapter
	{
		private readonly IDataReader _reader;

		private readonly Configuration _configuration;

		public DataReaderWriteAdapter(IDataReader reader, Configuration configuration)
		{
			_reader = reader;
			_configuration = configuration;
		}

		public bool TryGetKnownCount(out int count)
		{
			count = 0;
			return false;
		}

		public List<ExcelColumnInfo> GetColumns()
		{
			List<ExcelColumnInfo> list = new List<ExcelColumnInfo>();
			for (int i = 0; i < _reader.FieldCount; i++)
			{
				string columnName = _reader.GetName(i);
				if (!_configuration.DynamicColumnFirst)
				{
					ExcelColumnInfo columnInfosFromDynamicConfiguration = CustomPropertyHelper.GetColumnInfosFromDynamicConfiguration(columnName, _configuration);
					list.Add(columnInfosFromDynamicConfiguration);
				}
				else if (_configuration.DynamicColumns.Any((DynamicExcelColumn a) => string.Equals(a.Key, columnName, StringComparison.OrdinalIgnoreCase)))
				{
					ExcelColumnInfo columnInfosFromDynamicConfiguration2 = CustomPropertyHelper.GetColumnInfosFromDynamicConfiguration(columnName, _configuration);
					list.Add(columnInfosFromDynamicConfiguration2);
				}
			}
			return list;
		}

		public IEnumerable<IEnumerable<CellWriteInfo>> GetRows(List<ExcelColumnInfo> props, CancellationToken cancellationToken = default(CancellationToken))
		{
			while (_reader.Read())
			{
				cancellationToken.ThrowIfCancellationRequested();
				yield return GetRowValues(props);
			}
		}

		private IEnumerable<CellWriteInfo> GetRowValues(List<ExcelColumnInfo> props)
		{
			int i = 0;
			int column = 1;
			while (i < _reader.FieldCount)
			{
				if (_configuration.DynamicColumnFirst)
				{
					int ordinal = _reader.GetOrdinal(props[i].Key.ToString());
					yield return new CellWriteInfo(_reader.GetValue(ordinal), column, props[i]);
				}
				else
				{
					yield return new CellWriteInfo(_reader.GetValue(i), column, props[i]);
				}
				i++;
				column++;
			}
		}
	}
	internal class DataTableWriteAdapter : IMiniExcelWriteAdapter
	{
		private readonly DataTable _dataTable;

		private readonly Configuration _configuration;

		public DataTableWriteAdapter(DataTable dataTable, Configuration configuration)
		{
			_dataTable = dataTable;
			_configuration = configuration;
		}

		public bool TryGetKnownCount(out int count)
		{
			count = _dataTable.Rows.Count;
			return true;
		}

		public List<ExcelColumnInfo> GetColumns()
		{
			List<ExcelColumnInfo> list = new List<ExcelColumnInfo>();
			for (int i = 0; i < _dataTable.Columns.Count; i++)
			{
				ExcelColumnInfo columnInfosFromDynamicConfiguration = CustomPropertyHelper.GetColumnInfosFromDynamicConfiguration(_dataTable.Columns[i].Caption ?? _dataTable.Columns[i].ColumnName, _configuration);
				list.Add(columnInfosFromDynamicConfiguration);
			}
			return list;
		}

		public IEnumerable<IEnumerable<CellWriteInfo>> GetRows(List<ExcelColumnInfo> props, CancellationToken cancellationToken = default(CancellationToken))
		{
			for (int row = 0; row < _dataTable.Rows.Count; row++)
			{
				cancellationToken.ThrowIfCancellationRequested();
				yield return GetRowValues(row, props);
			}
		}

		private IEnumerable<CellWriteInfo> GetRowValues(int row, List<ExcelColumnInfo> props)
		{
			int i = 0;
			int column = 1;
			while (i < _dataTable.Columns.Count)
			{
				yield return new CellWriteInfo(_dataTable.Rows[row][i], column, props[i]);
				i++;
				column++;
			}
		}
	}
	internal class EnumerableWriteAdapter : IMiniExcelWriteAdapter
	{
		private readonly IEnumerable _values;

		private readonly Configuration _configuration;

		private readonly Type _genericType;

		private IEnumerator _enumerator;

		private bool _empty;

		public EnumerableWriteAdapter(IEnumerable values, Configuration configuration)
		{
			_values = values;
			_configuration = configuration;
			_genericType = TypeHelper.GetGenericIEnumerables(values).FirstOrDefault();
		}

		public bool TryGetKnownCount(out int count)
		{
			count = 0;
			if (_values is ICollection collection)
			{
				count = collection.Count;
				return true;
			}
			return false;
		}

		public List<ExcelColumnInfo> GetColumns()
		{
			if (CustomPropertyHelper.TryGetTypeColumnInfo(_genericType, _configuration, out var props))
			{
				return props;
			}
			_enumerator = _values.GetEnumerator();
			if (!_enumerator.MoveNext())
			{
				try
				{
					_empty = true;
					return null;
				}
				finally
				{
					(_enumerator as IDisposable)?.Dispose();
					_enumerator = null;
				}
			}
			return CustomPropertyHelper.GetColumnInfoFromValue(_enumerator.Current, _configuration);
		}

		public IEnumerable<IEnumerable<CellWriteInfo>> GetRows(List<ExcelColumnInfo> props, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (_empty)
			{
				yield break;
			}
			try
			{
				if (_enumerator == null)
				{
					_enumerator = _values.GetEnumerator();
					if (!_enumerator.MoveNext())
					{
						yield break;
					}
				}
				do
				{
					cancellationToken.ThrowIfCancellationRequested();
					yield return GetRowValues(_enumerator.Current, props);
				}
				while (_enumerator.MoveNext());
			}
			finally
			{
				EnumerableWriteAdapter enumerableWriteAdapter = this;
				(enumerableWriteAdapter._enumerator as IDisposable)?.Dispose();
				enumerableWriteAdapter._enumerator = null;
			}
		}

		public static IEnumerable<CellWriteInfo> GetRowValues(object currentValue, List<ExcelColumnInfo> props)
		{
			int column = 1;
			foreach (ExcelColumnInfo prop in props)
			{
				object value = ((prop == null) ? null : ((!(currentValue is IDictionary<string, object> dictionary)) ? ((!(currentValue is IDictionary dictionary2)) ? prop.Property.GetValue(currentValue) : dictionary2[prop.Key]) : dictionary[prop.Key.ToString()]));
				yield return new CellWriteInfo(value, column, prop);
				column++;
			}
		}
	}
	internal interface IAsyncMiniExcelWriteAdapter
	{
		Task<List<ExcelColumnInfo>> GetColumnsAsync();

		IAsyncEnumerable<IAsyncEnumerable<CellWriteInfo>> GetRowsAsync(List<ExcelColumnInfo> props, CancellationToken cancellationToken);
	}
	internal interface IMiniExcelWriteAdapter
	{
		bool TryGetKnownCount(out int count);

		List<ExcelColumnInfo> GetColumns();

		IEnumerable<IEnumerable<CellWriteInfo>> GetRows(List<ExcelColumnInfo> props, CancellationToken cancellationToken = default(CancellationToken));
	}
	internal readonly struct CellWriteInfo
	{
		public object Value { get; }

		public int CellIndex { get; }

		public ExcelColumnInfo Prop { get; }

		public CellWriteInfo(object value, int cellIndex, ExcelColumnInfo prop)
		{
			Value = value;
			CellIndex = cellIndex;
			Prop = prop;
		}
	}
	internal class MiniExcelDataReaderWriteAdapter : IAsyncMiniExcelWriteAdapter
	{
		private readonly IMiniExcelDataReader _reader;

		private readonly Configuration _configuration;

		public MiniExcelDataReaderWriteAdapter(IMiniExcelDataReader reader, Configuration configuration)
		{
			_reader = reader;
			_configuration = configuration;
		}

		public async Task<List<ExcelColumnInfo>> GetColumnsAsync()
		{
			List<ExcelColumnInfo> props = new List<ExcelColumnInfo>();
			for (int i = 0; i < _reader.FieldCount; i++)
			{
				string columnName = await _reader.GetNameAsync(i);
				if (!_configuration.DynamicColumnFirst)
				{
					ExcelColumnInfo columnInfosFromDynamicConfiguration = CustomPropertyHelper.GetColumnInfosFromDynamicConfiguration(columnName, _configuration);
					props.Add(columnInfosFromDynamicConfiguration);
				}
				else if (_configuration.DynamicColumns.Any((DynamicExcelColumn a) => string.Equals(a.Key, columnName, StringComparison.OrdinalIgnoreCase)))
				{
					ExcelColumnInfo columnInfosFromDynamicConfiguration2 = CustomPropertyHelper.GetColumnInfosFromDynamicConfiguration(columnName, _configuration);
					props.Add(columnInfosFromDynamicConfiguration2);
				}
			}
			return props;
		}

		public async IAsyncEnumerable<IAsyncEnumerable<CellWriteInfo>> GetRowsAsync(List<ExcelColumnInfo> props, [EnumeratorCancellation] CancellationToken cancellationToken)
		{
			while (await _reader.ReadAsync())
			{
				cancellationToken.ThrowIfCancellationRequested();
				yield return GetRowValuesAsync(props);
			}
		}

		private async IAsyncEnumerable<CellWriteInfo> GetRowValuesAsync(List<ExcelColumnInfo> props)
		{
			int i = 0;
			int column = 1;
			while (i < _reader.FieldCount)
			{
				if (_configuration.DynamicColumnFirst)
				{
					int ordinal = _reader.GetOrdinal(props[i].Key.ToString());
					yield return new CellWriteInfo(await _reader.GetValueAsync(ordinal), column, props[i]);
				}
				else
				{
					yield return new CellWriteInfo(await _reader.GetValueAsync(i), column, props[i]);
				}
				i++;
				column++;
			}
		}
	}
	internal static class MiniExcelWriteAdapterFactory
	{
		public static bool TryGetAsyncWriteAdapter(object values, Configuration configuration, out IAsyncMiniExcelWriteAdapter writeAdapter)
		{
			writeAdapter = null;
			if (values.GetType().IsAsyncEnumerable(out var genericArgument))
			{
				Type type = typeof(AsyncEnumerableWriteAdapter<>).MakeGenericType(genericArgument);
				writeAdapter = (IAsyncMiniExcelWriteAdapter)Activator.CreateInstance(type, values, configuration);
				return true;
			}
			if (values is IMiniExcelDataReader reader)
			{
				writeAdapter = new MiniExcelDataReaderWriteAdapter(reader, configuration);
				return true;
			}
			return false;
		}

		public static IMiniExcelWriteAdapter GetWriteAdapter(object values, Configuration configuration)
		{
			if (!(values is IDataReader reader))
			{
				if (!(values is IEnumerable values2))
				{
					if (values is DataTable dataTable)
					{
						return new DataTableWriteAdapter(dataTable, configuration);
					}
					throw new NotImplementedException();
				}
				return new EnumerableWriteAdapter(values2, configuration);
			}
			return new DataReaderWriteAdapter(reader, configuration);
		}
	}
}
namespace MiniExcelLibs.Utils
{
	internal static class AttributeExtension
	{
		internal static TValue GetAttributeValue<TAttribute, TValue>(this Type attrType, Func<TAttribute, TValue> selector) where TAttribute : Attribute
		{
			TAttribute attr = attrType.GetCustomAttributes(typeof(TAttribute), inherit: true).FirstOrDefault() as TAttribute;
			return GetValueOrDefault(selector, attr);
		}

		private static TValue GetValueOrDefault<TAttribute, TValue>(Func<TAttribute, TValue> selector, TAttribute attr) where TAttribute : Attribute
		{
			if (attr != null)
			{
				return selector(attr);
			}
			return default(TValue);
		}

		internal static TAttribute GetAttribute<TAttribute>(this PropertyInfo prop, bool isInherit = true) where TAttribute : Attribute
		{
			return prop.GetAttributeValue((TAttribute attr) => attr, isInherit);
		}

		internal static TValue GetAttributeValue<TAttribute, TValue>(this PropertyInfo prop, Func<TAttribute, TValue> selector, bool isInherit = true) where TAttribute : Attribute
		{
			TAttribute attr = Attribute.GetCustomAttribute(prop, typeof(TAttribute), isInherit) as TAttribute;
			return GetValueOrDefault(selector, attr);
		}

		internal static bool IsUseAttribute<TAttribute>(this PropertyInfo prop)
		{
			return Attribute.GetCustomAttribute(prop, typeof(TAttribute)) != null;
		}
	}
	internal static class CalcChainHelper
	{
		public static string GetCalcChainContent(List<string> cellRefs, int sheetIndex)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (string cellRef in cellRefs)
			{
				stringBuilder.Append($"<c r=\"{cellRef}\" i=\"{sheetIndex}\"/>");
			}
			return stringBuilder.ToString();
		}

		public static void GenerateCalcChainSheet(Stream calcChainStream, string calcChainContent)
		{
			using StreamWriter streamWriter = new StreamWriter(calcChainStream, Encoding.UTF8);
			streamWriter.Write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><calcChain xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" + calcChainContent + "</calcChain>");
		}
	}
	internal static class ColumnHelper
	{
		private const int GENERAL_COLUMN_INDEX = 255;

		private const int MAX_COLUMN_INDEX = 16383;

		private static int _IntMappingAlphabetCount;

		private static readonly ConcurrentDictionary<int, string> _IntMappingAlphabet;

		private static readonly ConcurrentDictionary<string, int> _AlphabetMappingInt;

		static ColumnHelper()
		{
			_IntMappingAlphabetCount = 0;
			_IntMappingAlphabet = new ConcurrentDictionary<int, string>();
			_AlphabetMappingInt = new ConcurrentDictionary<string, int>();
			_IntMappingAlphabetCount = _IntMappingAlphabet.Count;
			CheckAndSetMaxColumnIndex(255);
		}

		public static string GetAlphabetColumnName(int columnIndex)
		{
			CheckAndSetMaxColumnIndex(columnIndex);
			if (_IntMappingAlphabet.TryGetValue(columnIndex, out var value))
			{
				return value;
			}
			throw new KeyNotFoundException();
		}

		public static int GetColumnIndex(string columnName)
		{
			if (_AlphabetMappingInt.TryGetValue(columnName, out var value))
			{
				CheckAndSetMaxColumnIndex(value);
			}
			return value;
		}

		private static void CheckAndSetMaxColumnIndex(int columnIndex)
		{
			if (columnIndex < _IntMappingAlphabetCount)
			{
				return;
			}
			if (columnIndex > 16383)
			{
				throw new InvalidDataException($"ColumnIndex {columnIndex} over excel vaild max index.");
			}
			int i;
			for (i = _IntMappingAlphabet.Count; i <= columnIndex; i++)
			{
				_IntMappingAlphabet.AddOrUpdate(i, IntToLetters(i), (int a, string b) => IntToLetters(i));
				_AlphabetMappingInt.AddOrUpdate(IntToLetters(i), i, (string a, int b) => i);
			}
			_IntMappingAlphabetCount = _IntMappingAlphabet.Count;
		}

		internal static string IntToLetters(int value)
		{
			value++;
			string text = string.Empty;
			while (--value >= 0)
			{
				text = (char)(65 + value % 26) + text;
				value /= 26;
			}
			return text;
		}
	}
	internal class ExcelColumnInfo
	{
		public object Key { get; set; }

		public int? ExcelColumnIndex { get; set; }

		public string ExcelColumnName { get; set; }

		public string[] ExcelColumnAliases { get; set; }

		public Property Property { get; set; }

		public Type ExcludeNullableType { get; set; }

		public bool Nullable { get; internal set; }

		public string ExcelFormat { get; internal set; }

		public double? ExcelColumnWidth { get; internal set; }

		public string ExcelIndexName { get; internal set; }

		public bool ExcelIgnore { get; internal set; }

		public int ExcelFormatId { get; internal set; }

		public ColumnType ExcelColumnType { get; internal set; }

		public Func<object, object> CustomFormatter { get; set; }
	}
	internal class ExcellSheetInfo
	{
		public object Key { get; set; }

		public string ExcelSheetName { get; set; }

		public SheetState ExcelSheetState { get; set; }

		private string ExcelSheetStateAsString => ExcelSheetState.ToString().ToLower();

		public SheetDto ToDto(int sheetIndex)
		{
			return new SheetDto
			{
				Name = ExcelSheetName,
				SheetIdx = sheetIndex,
				State = ExcelSheetStateAsString
			};
		}
	}
	internal static class CustomPropertyHelper
	{
		internal static IDictionary<string, object> GetEmptyExpandoObject(int maxColumnIndex, int startCellIndex)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			for (int i = startCellIndex; i <= maxColumnIndex; i++)
			{
				string alphabetColumnName = ColumnHelper.GetAlphabetColumnName(i);
				if (!dictionary.ContainsKey(alphabetColumnName))
				{
					dictionary.Add(alphabetColumnName, null);
				}
			}
			return dictionary;
		}

		internal static IDictionary<string, object> GetEmptyExpandoObject(Dictionary<int, string> hearrows)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			foreach (KeyValuePair<int, string> hearrow in hearrows)
			{
				if (!dictionary.ContainsKey(hearrow.Value))
				{
					dictionary.Add(hearrow.Value, null);
				}
			}
			return dictionary;
		}

		internal static List<ExcelColumnInfo> GetSaveAsProperties(this Type type, Configuration configuration)
		{
			List<ExcelColumnInfo> list = (from prop in GetExcelPropertyInfo(type, BindingFlags.Instance | BindingFlags.Public, configuration)
				where prop.Property.CanRead
				select prop).ToList();
			if (list.Count == 0)
			{
				throw new InvalidOperationException(type.Name + " un-ignore properties count can't be 0");
			}
			return SortCustomProps(list);
		}

		internal static List<ExcelColumnInfo> SortCustomProps(List<ExcelColumnInfo> props)
		{
			List<ExcelColumnInfo> list = props.Where((ExcelColumnInfo w) => w.ExcelColumnIndex.HasValue && w.ExcelColumnIndex > -1).ToList();
			if ((from g in list
				group g by g.ExcelColumnIndex).Any((IGrouping<int?, ExcelColumnInfo> _) => _.Count() > 1))
			{
				throw new InvalidOperationException("Duplicate column name");
			}
			int num = props.Count - 1;
			if (list.Count != 0)
			{
				num = Math.Max(list.Max((ExcelColumnInfo w) => w.ExcelColumnIndex).Value, num);
			}
			List<ExcelColumnInfo> source = props.Where((ExcelColumnInfo w) => !w.ExcelColumnIndex.HasValue || w.ExcelColumnIndex.GetValueOrDefault() == -1).ToList();
			List<ExcelColumnInfo> list2 = new List<ExcelColumnInfo>();
			int num2 = 0;
			int i;
			for (i = 0; i <= num; i++)
			{
				ExcelColumnInfo excelColumnInfo = list.SingleOrDefault((ExcelColumnInfo s) => s.ExcelColumnIndex == i);
				if (excelColumnInfo != null)
				{
					list2.Add(excelColumnInfo);
					continue;
				}
				ExcelColumnInfo excelColumnInfo2 = source.ElementAtOrDefault(num2);
				if (excelColumnInfo2 == null)
				{
					list2.Add(null);
				}
				else
				{
					excelColumnInfo2.ExcelColumnIndex = i;
					list2.Add(excelColumnInfo2);
				}
				num2++;
			}
			return list2;
		}

		internal static List<ExcelColumnInfo> GetExcelCustomPropertyInfos(Type type, string[] keys, Configuration configuration)
		{
			List<ExcelColumnInfo> list = (from prop in GetExcelPropertyInfo(type, BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, configuration)
				where prop.Property.Info.GetSetMethod() != null && !prop.Property.Info.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore) && !prop.Property.Info.GetAttributeValue((ExcelColumnAttribute x) => x.Ignore)
				select prop).ToList();
			if (list.Count == 0)
			{
				throw new InvalidOperationException(type.Name + " un-ignore properties count can't be 0");
			}
			if ((from w in list
				where w.ExcelColumnIndex.HasValue && w.ExcelColumnIndex > -1
				select w into g
				group g by g.ExcelColumnIndex).Any((IGrouping<int?, ExcelColumnInfo> _) => _.Count() > 1))
			{
				throw new InvalidOperationException("Duplicate column name");
			}
			string text = keys.Last();
			int columnIndex = ColumnHelper.GetColumnIndex(text);
			foreach (ExcelColumnInfo item in list)
			{
				if (item.ExcelColumnIndex.HasValue)
				{
					if (item.ExcelColumnIndex > columnIndex)
					{
						throw new ArgumentException($"ExcelColumnIndex {item.ExcelColumnIndex} over haeder max index {text}");
					}
					if (item.ExcelColumnName == null)
					{
						throw new InvalidOperationException($"{item.Property.Info.DeclaringType.Name} {item.Property.Name}'s ExcelColumnIndex {item.ExcelColumnIndex} can't find excel column name");
					}
				}
			}
			return list;
		}

		internal static string DescriptionAttr(Type type, object source)
		{
			FieldInfo field = type.GetField(source.ToString());
			if (field == null)
			{
				return source.ToString();
			}
			DescriptionAttribute[] array = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), inherit: false);
			if (array != null && array.Length != 0)
			{
				return array[0].Description;
			}
			return source.ToString();
		}

		private static IEnumerable<ExcelColumnInfo> ConvertToExcelCustomPropertyInfo(PropertyInfo[] props, Configuration configuration)
		{
			return from _ in props.Select(delegate(PropertyInfo p)
				{
					Type underlyingType = Nullable.GetUnderlyingType(p.PropertyType);
					ExcelColumnNameAttribute attribute = p.GetAttribute<ExcelColumnNameAttribute>();
					Type excludeNullableType = underlyingType ?? p.PropertyType;
					string text = p.GetAttribute<ExcelFormatAttribute>()?.Format;
					ExcelColumnAttribute excelColumnAttribute = p.GetAttribute<ExcelColumnAttribute>();
					DynamicExcelColumn dynamicExcelColumn = configuration?.DynamicColumns?.SingleOrDefault((DynamicExcelColumn _) => _.Key == p.Name);
					if (dynamicExcelColumn != null)
					{
						excelColumnAttribute = dynamicExcelColumn;
					}
					if (!p.GetAttributeValue((ExcelIgnoreAttribute x) => x.ExcelIgnore) && !p.GetAttributeValue((ExcelColumnAttribute x) => x.Ignore) && (excelColumnAttribute == null || !excelColumnAttribute.Ignore))
					{
						int? num = ((excelColumnAttribute != null && excelColumnAttribute.Index > -1) ? new int?(excelColumnAttribute.Index) : null);
						ExcelColumnInfo obj = new ExcelColumnInfo
						{
							Property = new Property(p),
							ExcludeNullableType = excludeNullableType,
							Nullable = (underlyingType != null),
							ExcelColumnAliases = (attribute?.Aliases ?? excelColumnAttribute?.Aliases),
							ExcelColumnName = (attribute?.ExcelColumnName ?? p.GetAttribute<DisplayNameAttribute>()?.DisplayName ?? excelColumnAttribute?.Name ?? p.Name)
						};
						ExcelColumnIndexAttribute attribute2 = p.GetAttribute<ExcelColumnIndexAttribute>();
						obj.ExcelColumnIndex = ((attribute2 != null) ? new int?(attribute2.ExcelColumnIndex) : num);
						obj.ExcelIndexName = p.GetAttribute<ExcelColumnIndexAttribute>()?.ExcelXName ?? excelColumnAttribute?.IndexName;
						ExcelColumnWidthAttribute attribute3 = p.GetAttribute<ExcelColumnWidthAttribute>();
						obj.ExcelColumnWidth = ((attribute3 != null) ? new double?(attribute3.ExcelColumnWidth) : excelColumnAttribute?.Width);
						obj.ExcelFormat = text ?? excelColumnAttribute?.Format;
						obj.ExcelFormatId = excelColumnAttribute?.FormatId ?? (-1);
						obj.ExcelColumnType = excelColumnAttribute?.Type ?? ColumnType.Value;
						obj.CustomFormatter = dynamicExcelColumn?.CustomFormatter;
						return obj;
					}
					return null;
				})
				where _ != null
				select _;
		}

		private static IEnumerable<ExcelColumnInfo> GetExcelPropertyInfo(Type type, BindingFlags bindingFlags, Configuration configuration)
		{
			return ConvertToExcelCustomPropertyInfo(type.GetProperties(bindingFlags), configuration);
		}

		internal static ExcellSheetInfo GetExcellSheetInfo(Type type, Configuration configuration)
		{
			ExcellSheetInfo excellSheetInfo = new ExcellSheetInfo
			{
				Key = type.Name,
				ExcelSheetName = null,
				ExcelSheetState = SheetState.Visible
			};
			if (type.GetCustomAttribute(typeof(ExcelSheetAttribute)) is ExcelSheetAttribute excelSheetAttribute)
			{
				excellSheetInfo.ExcelSheetName = excelSheetAttribute.Name ?? type.Name;
				excellSheetInfo.ExcelSheetState = excelSheetAttribute.State;
			}
			if (configuration is OpenXmlConfiguration openXmlConfiguration && openXmlConfiguration.DynamicSheets != null && openXmlConfiguration.DynamicSheets.Length != 0)
			{
				DynamicExcelSheet dynamicExcelSheet = openXmlConfiguration.DynamicSheets.SingleOrDefault((DynamicExcelSheet _) => _.Key == type.Name);
				if (dynamicExcelSheet != null)
				{
					excellSheetInfo.ExcelSheetName = dynamicExcelSheet.Name;
					excellSheetInfo.ExcelSheetState = dynamicExcelSheet.State;
				}
			}
			return excellSheetInfo;
		}

		internal static List<ExcelColumnInfo> GetDictionaryColumnInfo(IDictionary<string, object> dicString, IDictionary dic, Configuration configuration)
		{
			List<ExcelColumnInfo> props = new List<ExcelColumnInfo>();
			if (dicString != null)
			{
				foreach (string key in dicString.Keys)
				{
					SetDictionaryColumnInfo(props, key, configuration);
				}
			}
			else
			{
				if (dic == null)
				{
					throw new NotSupportedException("SetDictionaryColumnInfo Error");
				}
				foreach (object key2 in dic.Keys)
				{
					SetDictionaryColumnInfo(props, key2, configuration);
				}
			}
			return SortCustomProps(props);
		}

		internal static void SetDictionaryColumnInfo(List<ExcelColumnInfo> _props, object key, Configuration configuration)
		{
			ExcelColumnInfo excelColumnInfo = new ExcelColumnInfo();
			excelColumnInfo.ExcelColumnName = key?.ToString();
			excelColumnInfo.Key = key;
			bool flag = false;
			if (configuration.DynamicColumns != null && configuration.DynamicColumns.Length != 0)
			{
				DynamicExcelColumn dynamicExcelColumn = configuration.DynamicColumns.SingleOrDefault((DynamicExcelColumn _) => _.Key == key.ToString());
				if (dynamicExcelColumn != null)
				{
					excelColumnInfo.Nullable = true;
					if (dynamicExcelColumn.Format != null)
					{
						excelColumnInfo.ExcelFormat = dynamicExcelColumn.Format;
						excelColumnInfo.ExcelFormatId = dynamicExcelColumn.FormatId;
					}
					if (dynamicExcelColumn.Aliases != null)
					{
						excelColumnInfo.ExcelColumnAliases = dynamicExcelColumn.Aliases;
					}
					if (dynamicExcelColumn.IndexName != null)
					{
						excelColumnInfo.ExcelIndexName = dynamicExcelColumn.IndexName;
					}
					excelColumnInfo.ExcelColumnIndex = dynamicExcelColumn.Index;
					if (dynamicExcelColumn.Name != null)
					{
						excelColumnInfo.ExcelColumnName = dynamicExcelColumn.Name;
					}
					flag = dynamicExcelColumn.Ignore;
					excelColumnInfo.ExcelColumnWidth = dynamicExcelColumn.Width;
					excelColumnInfo.ExcelColumnType = dynamicExcelColumn.Type;
					excelColumnInfo.CustomFormatter = dynamicExcelColumn.CustomFormatter;
				}
			}
			if (!flag)
			{
				_props.Add(excelColumnInfo);
			}
		}

		internal static bool TryGetTypeColumnInfo(Type type, Configuration configuration, out List<ExcelColumnInfo> props)
		{
			if (type == null)
			{
				props = null;
				return false;
			}
			if (type.IsValueType)
			{
				throw new NotImplementedException("MiniExcel not support only " + type.Name + " value generic type");
			}
			if (type == typeof(string) || type == typeof(DateTime) || type == typeof(Guid))
			{
				throw new NotImplementedException("MiniExcel not support only " + type.Name + " generic type");
			}
			if (ValueIsNeededToDetermineProperties(type))
			{
				props = null;
				return false;
			}
			props = type.GetSaveAsProperties(configuration);
			return true;
		}

		internal static List<ExcelColumnInfo> GetColumnInfoFromValue(object value, Configuration configuration)
		{
			if (!(value is IDictionary<string, object> dicString))
			{
				if (value is IDictionary dic)
				{
					return GetDictionaryColumnInfo(null, dic, configuration);
				}
				return value.GetType().GetSaveAsProperties(configuration);
			}
			return GetDictionaryColumnInfo(dicString, null, configuration);
		}

		private static bool ValueIsNeededToDetermineProperties(Type type)
		{
			if (!(type == typeof(object)) && !typeof(IDictionary<string, object>).IsAssignableFrom(type))
			{
				return typeof(IDictionary).IsAssignableFrom(type);
			}
			return true;
		}

		internal static ExcelColumnInfo GetColumnInfosFromDynamicConfiguration(string columnName, Configuration configuration)
		{
			ExcelColumnInfo excelColumnInfo = new ExcelColumnInfo
			{
				ExcelColumnName = columnName,
				Key = columnName
			};
			if (configuration.DynamicColumns == null || configuration.DynamicColumns.Length == 0)
			{
				return excelColumnInfo;
			}
			DynamicExcelColumn dynamicExcelColumn = configuration.DynamicColumns.SingleOrDefault((DynamicExcelColumn _) => string.Equals(_.Key, columnName, StringComparison.OrdinalIgnoreCase));
			if (dynamicExcelColumn == null || dynamicExcelColumn.Ignore)
			{
				return excelColumnInfo;
			}
			excelColumnInfo.Nullable = true;
			excelColumnInfo.ExcelIgnore = dynamicExcelColumn.Ignore;
			excelColumnInfo.ExcelColumnType = dynamicExcelColumn.Type;
			excelColumnInfo.ExcelColumnIndex = dynamicExcelColumn.Index;
			excelColumnInfo.ExcelColumnWidth = dynamicExcelColumn.Width;
			excelColumnInfo.CustomFormatter = dynamicExcelColumn.CustomFormatter;
			if (dynamicExcelColumn.Format != null)
			{
				excelColumnInfo.ExcelFormat = dynamicExcelColumn.Format;
				excelColumnInfo.ExcelFormatId = dynamicExcelColumn.FormatId;
			}
			if (dynamicExcelColumn.Aliases != null)
			{
				excelColumnInfo.ExcelColumnAliases = dynamicExcelColumn.Aliases;
			}
			if (dynamicExcelColumn.IndexName != null)
			{
				excelColumnInfo.ExcelIndexName = dynamicExcelColumn.IndexName;
			}
			if (dynamicExcelColumn.Name != null)
			{
				excelColumnInfo.ExcelColumnName = dynamicExcelColumn.Name;
			}
			return excelColumnInfo;
		}
	}
	internal static class DateTimeHelper
	{
		public const double OADateMinAsDouble = -657435.0;

		public const double OADateMaxAsDouble = 2958466.0;

		private const long TicksPerMillisecond = 10000L;

		private const long TicksPerSecond = 10000000L;

		private const long TicksPerMinute = 600000000L;

		private const long TicksPerHour = 36000000000L;

		private const long TicksPerDay = 864000000000L;

		private const int MillisPerSecond = 1000;

		private const int MillisPerMinute = 60000;

		private const int MillisPerHour = 3600000;

		private const int MillisPerDay = 86400000;

		private const int DaysPerYear = 365;

		private const int DaysPer4Years = 1461;

		private const int DaysPer100Years = 36524;

		private const int DaysPer400Years = 146097;

		private const int DaysTo1899 = 693593;

		private const int DaysTo10000 = 3652059;

		private const long MaxMillis = 315537897600000L;

		private const long DoubleDateOffset = 599264352000000000L;

		public static bool IsDateTimeFormat(string formatCode)
		{
			return new ExcelNumberFormat(formatCode).IsDateTimeFormat;
		}

		public static DateTime FromOADate(double d)
		{
			return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified);
		}

		internal static long DoubleDateToTicks(double value)
		{
			if (value >= 2958466.0 || value <= -657435.0)
			{
				throw new ArgumentException("Invalid OA Date");
			}
			long num = (long)(value * 86400000.0 + ((value >= 0.0) ? 0.5 : (-0.5)));
			if (num < 0)
			{
				num -= num % 86400000 * 2;
			}
			num += 59926435200000L;
			if (num < 0 || num >= 315537897600000L)
			{
				throw new ArgumentException("OA Date out of range");
			}
			return num * 10000;
		}

		public static double AdjustOADateTime(double value, bool date1904)
		{
			if (!date1904)
			{
				if (value >= 0.0 && value < 60.0)
				{
					return value + 1.0;
				}
				return value;
			}
			return value + 1462.0;
		}

		public static bool IsValidOADateTime(double value)
		{
			if (value > -657435.0)
			{
				return value < 2958466.0;
			}
			return false;
		}

		public static object ConvertFromOATime(double value, bool date1904)
		{
			double num = AdjustOADateTime(value, date1904);
			if (IsValidOADateTime(num))
			{
				return FromOADate(num);
			}
			return value;
		}
	}
	internal static class DictionaryHelper
	{
		public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
		{
			if (!dictionary.TryGetValue(key, out var value))
			{
				return defaultValue;
			}
			return value;
		}

		public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> defaultValueProvider)
		{
			if (!dictionary.TryGetValue(key, out var value))
			{
				return defaultValueProvider();
			}
			return value;
		}
	}
	internal class ExcelNumberFormat
	{
		public bool IsValid { get; }

		public string FormatString { get; }

		public bool IsDateTimeFormat { get; }

		public bool IsTimeSpanFormat { get; }

		internal List<Section> Sections { get; }

		public ExcelNumberFormat(string formatString)
		{
			bool syntaxError;
			List<Section> list = Parser.ParseSections(formatString, out syntaxError);
			IsValid = !syntaxError;
			FormatString = formatString;
			if (IsValid)
			{
				Sections = list;
				IsDateTimeFormat = Evaluator.GetFirstSection(Sections, SectionType.Date) != null;
				IsTimeSpanFormat = Evaluator.GetFirstSection(Sections, SectionType.Duration) != null;
			}
			else
			{
				Sections = new List<Section>();
			}
		}
	}
	internal static class Evaluator
	{
		public static Section GetSection(List<Section> sections, object value)
		{
			if (!(value is string))
			{
				if (value is DateTime)
				{
					_ = (DateTime)value;
					return GetFirstSection(sections, SectionType.Date);
				}
				if (!(value is TimeSpan timeSpan))
				{
					if (!(value is double value2))
					{
						if (!(value is int num))
						{
							if (value is short num2)
							{
								return GetNumericSection(sections, num2);
							}
							return null;
						}
						return GetNumericSection(sections, num);
					}
					return GetNumericSection(sections, value2);
				}
				return GetNumericSection(sections, timeSpan.TotalDays);
			}
			if (sections.Count >= 4)
			{
				return sections[3];
			}
			return null;
		}

		public static Section GetFirstSection(List<Section> sections, SectionType type)
		{
			foreach (Section section in sections)
			{
				if (section.Type == type)
				{
					return section;
				}
			}
			return null;
		}

		private static Section GetNumericSection(List<Section> sections, double value)
		{
			if (sections.Count < 3)
			{
				return null;
			}
			return sections[2];
		}
	}
	internal enum SectionType
	{
		General,
		Number,
		Fraction,
		Exponential,
		Date,
		Duration,
		Text
	}
	internal class Section
	{
		public int SectionIndex { get; set; }

		public SectionType Type { get; set; }

		public List<string> GeneralTextDateDurationParts { get; set; }
	}
	internal class FractionSection
	{
		public List<string> IntegerPart { get; set; }

		public List<string> Numerator { get; set; }

		public List<string> DenominatorPrefix { get; set; }

		public List<string> Denominator { get; set; }

		public int DenominatorConstant { get; set; }

		public List<string> DenominatorSuffix { get; set; }

		public List<string> FractionSuffix { get; set; }

		public static bool TryParse(List<string> tokens, out FractionSection format)
		{
			List<string> list = null;
			List<string> tokens2 = null;
			for (int i = 0; i < tokens.Count; i++)
			{
				if (tokens[i] == "/")
				{
					list = tokens.GetRange(0, i);
					i++;
					tokens2 = tokens.GetRange(i, tokens.Count - i);
					break;
				}
			}
			if (list == null)
			{
				format = null;
				return false;
			}
			GetNumerator(list, out var integerPart, out var numeratorPart);
			if (!TryGetDenominator(tokens2, out var denominatorPrefix, out var denominatorPart, out var denominatorConstant, out var denominatorSuffix, out var fractionSuffix))
			{
				format = null;
				return false;
			}
			format = new FractionSection
			{
				IntegerPart = integerPart,
				Numerator = numeratorPart,
				DenominatorPrefix = denominatorPrefix,
				Denominator = denominatorPart,
				DenominatorConstant = denominatorConstant,
				DenominatorSuffix = denominatorSuffix,
				FractionSuffix = fractionSuffix
			};
			return true;
		}

		private static void GetNumerator(List<string> tokens, out List<string> integerPart, out List<string> numeratorPart)
		{
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			int num = -1;
			for (int num2 = tokens.Count - 1; num2 >= 0; num2--)
			{
				if (Token.IsPlaceholder(tokens[num2]))
				{
					flag = true;
					if (flag2)
					{
						flag3 = true;
						break;
					}
				}
				else if (flag && !flag2)
				{
					flag2 = true;
					num = num2 + 1;
				}
			}
			if (flag3)
			{
				integerPart = tokens.GetRange(0, num);
				numeratorPart = tokens.GetRange(num, tokens.Count - num);
			}
			else
			{
				integerPart = null;
				numeratorPart = tokens;
			}
		}

		private static bool TryGetDenominator(List<string> tokens, out List<string> denominatorPrefix, out List<string> denominatorPart, out int denominatorConstant, out List<string> denominatorSuffix, out List<string> fractionSuffix)
		{
			int i = 0;
			bool flag = false;
			bool flag2 = false;
			StringBuilder stringBuilder = new StringBuilder();
			for (; i < tokens.Count; i++)
			{
				string token = tokens[i];
				if (Token.IsPlaceholder(token))
				{
					flag = true;
					break;
				}
				if (Token.IsDigit19(token))
				{
					flag2 = true;
					break;
				}
			}
			if (!flag && !flag2)
			{
				denominatorPrefix = null;
				denominatorPart = null;
				denominatorConstant = 0;
				denominatorSuffix = null;
				fractionSuffix = null;
				return false;
			}
			int num = i;
			for (; i < tokens.Count; i++)
			{
				string text = tokens[i];
				if (!flag || !Token.IsPlaceholder(text))
				{
					if (!flag2 || !Token.IsDigit09(text))
					{
						break;
					}
					stringBuilder.Append(text);
				}
			}
			int num2 = tokens.Count;
			while (num2 > i && !Token.IsPlaceholder(tokens[num2 - 1]))
			{
				num2--;
			}
			if (num > 0)
			{
				denominatorPrefix = tokens.GetRange(0, num);
			}
			else
			{
				denominatorPrefix = null;
			}
			if (flag2)
			{
				denominatorConstant = int.Parse(stringBuilder.ToString());
			}
			else
			{
				denominatorConstant = 0;
			}
			denominatorPart = tokens.GetRange(num, i - num);
			if (i < num2)
			{
				denominatorSuffix = tokens.GetRange(i, num2 - i);
			}
			else
			{
				denominatorSuffix = null;
			}
			if (num2 < tokens.Count)
			{
				fractionSuffix = tokens.GetRange(num2, tokens.Count - num2);
			}
			else
			{
				fractionSuffix = null;
			}
			return true;
		}
	}
	internal class ExponentialSection
	{
		public List<string> BeforeDecimal { get; set; }

		public bool DecimalSeparator { get; set; }

		public List<string> AfterDecimal { get; set; }

		public string ExponentialToken { get; set; }

		public List<string> Power { get; set; }

		public static bool TryParse(List<string> tokens, out ExponentialSection format)
		{
			format = null;
			List<string> beforeDecimal;
			bool decimalSeparator;
			List<string> afterDecimal;
			int num = Parser.ParseNumberTokens(tokens, 0, out beforeDecimal, out decimalSeparator, out afterDecimal);
			if (num == 0)
			{
				return false;
			}
			int num2 = num;
			if (num2 < tokens.Count && Token.IsExponent(tokens[num2]))
			{
				string exponentialToken = tokens[num2];
				num2++;
				format = new ExponentialSection
				{
					BeforeDecimal = beforeDecimal,
					DecimalSeparator = decimalSeparator,
					AfterDecimal = afterDecimal,
					ExponentialToken = exponentialToken,
					Power = tokens.GetRange(num2, tokens.Count - num2)
				};
				return true;
			}
			return false;
		}
	}
	internal class DecimalSection
	{
		public bool ThousandSeparator { get; set; }

		public double ThousandDivisor { get; set; }

		public double PercentMultiplier { get; set; }

		public List<string> BeforeDecimal { get; set; }

		public bool DecimalSeparator { get; set; }

		public List<string> AfterDecimal { get; set; }

		public static bool TryParse(List<string> tokens, out DecimalSection format)
		{
			if (Parser.ParseNumberTokens(tokens, 0, out var beforeDecimal, out var decimalSeparator, out var afterDecimal) == tokens.Count)
			{
				bool thousandSeparator;
				double trailingCommasDivisor = GetTrailingCommasDivisor(tokens, out thousandSeparator);
				double percentMultiplier = GetPercentMultiplier(tokens);
				format = new DecimalSection
				{
					BeforeDecimal = beforeDecimal,
					DecimalSeparator = decimalSeparator,
					AfterDecimal = afterDecimal,
					PercentMultiplier = percentMultiplier,
					ThousandDivisor = trailingCommasDivisor,
					ThousandSeparator = thousandSeparator
				};
				return true;
			}
			format = null;
			return false;
		}

		private static double GetPercentMultiplier(List<string> tokens)
		{
			foreach (string token in tokens)
			{
				if (token == "%")
				{
					return 100.0;
				}
			}
			return 1.0;
		}

		private static double GetTrailingCommasDivisor(List<string> tokens, out bool thousandSeparator)
		{
			bool flag = false;
			double num = 1.0;
			for (int i = 0; i < tokens.Count; i++)
			{
				int num2 = tokens.Count - 1 - i;
				string text = tokens[num2];
				if (!flag)
				{
					if (!Token.IsPlaceholder(text))
					{
						continue;
					}
					for (int j = num2 + 1; j < tokens.Count; j++)
					{
						text = tokens[j];
						if (!(text == ","))
						{
							break;
						}
						num *= 1000.0;
					}
					flag = true;
				}
				else if (text == ",")
				{
					thousandSeparator = true;
					return num;
				}
			}
			thousandSeparator = false;
			return num;
		}
	}
	internal class ExcelDateTime
	{
		private static DateTime Excel1900LeapMinDate = new DateTime(1900, 2, 28);

		private static DateTime Excel1900LeapMaxDate = new DateTime(1900, 3, 1);

		private static DateTime Excel1900ZeroethMinDate = new DateTime(1899, 12, 30);

		private static DateTime Excel1900ZeroethMaxDate = new DateTime(1899, 12, 31);

		private const long TicksPerMillisecond = 10000L;

		private const long TicksPerSecond = 10000000L;

		private const long TicksPerMinute = 600000000L;

		private const long TicksPerHour = 36000000000L;

		private const long TicksPerDay = 864000000000L;

		private const int MillisPerSecond = 1000;

		private const int MillisPerMinute = 60000;

		private const int MillisPerHour = 3600000;

		private const int MillisPerDay = 86400000;

		private const int DaysPerYear = 365;

		private const int DaysPer4Years = 1461;

		private const int DaysPer100Years = 36524;

		private const int DaysPer400Years = 146097;

		private const int DaysTo1899 = 693593;

		private const long DoubleDateOffset = 599264352000000000L;

		public DateTime AdjustedDateTime { get; }

		public int AdjustDaysPost { get; }

		public int Year => AdjustedDateTime.Year;

		public int Month => AdjustedDateTime.Month;

		public int Day => AdjustedDateTime.Day + AdjustDaysPost;

		public int Hour => AdjustedDateTime.Hour;

		public int Minute => AdjustedDateTime.Minute;

		public int Second => AdjustedDateTime.Second;

		public int Millisecond => AdjustedDateTime.Millisecond;

		public DayOfWeek DayOfWeek => AdjustedDateTime.DayOfWeek;

		public ExcelDateTime(double numericDate, bool isDate1904)
		{
			if (isDate1904)
			{
				numericDate += 1462.0;
				AdjustedDateTime = new DateTime(DoubleDateToTicks(numericDate), DateTimeKind.Unspecified);
				return;
			}
			DateTime dateTime = new DateTime(DoubleDateToTicks(numericDate), DateTimeKind.Unspecified);
			if (dateTime < Excel1900ZeroethMinDate)
			{
				AdjustDaysPost = 0;
				AdjustedDateTime = dateTime.AddDays(2.0);
			}
			else if (dateTime < Excel1900ZeroethMaxDate)
			{
				AdjustDaysPost = -1;
				AdjustedDateTime = dateTime.AddDays(2.0);
			}
			else if (dateTime < Excel1900LeapMinDate)
			{
				AdjustDaysPost = 0;
				AdjustedDateTime = dateTime.AddDays(1.0);
			}
			else if (dateTime < Excel1900LeapMaxDate)
			{
				AdjustDaysPost = 1;
				AdjustedDateTime = dateTime;
			}
			else
			{
				AdjustDaysPost = 0;
				AdjustedDateTime = dateTime;
			}
		}

		public ExcelDateTime(DateTime value)
		{
			AdjustedDateTime = value;
			AdjustDaysPost = 0;
		}

		public string ToString(string numberFormat, CultureInfo culture)
		{
			return AdjustedDateTime.ToString(numberFormat, culture);
		}

		public static bool TryConvert(object value, bool isDate1904, CultureInfo culture, out ExcelDateTime result)
		{
			if (value is double numericDate)
			{
				result = new ExcelDateTime(numericDate, isDate1904);
				return true;
			}
			if (value is int num)
			{
				result = new ExcelDateTime(num, isDate1904);
				return true;
			}
			if (value is short num2)
			{
				result = new ExcelDateTime(num2, isDate1904);
				return true;
			}
			if (value is DateTime value2)
			{
				result = new ExcelDateTime(value2);
				return true;
			}
			result = null;
			return false;
		}

		internal static long DoubleDateToTicks(double value)
		{
			long num = (long)(value * 86400000.0 + ((value >= 0.0) ? 0.5 : (-0.5)));
			if (num < 0)
			{
				num -= num % 86400000 * 2;
			}
			num += 59926435200000L;
			return num * 10000;
		}
	}
	internal static class Parser
	{
		public static List<Section> ParseSections(string formatString, out bool syntaxError)
		{
			Tokenizer reader = new Tokenizer(formatString);
			List<Section> list = new List<Section>();
			syntaxError = false;
			while (true)
			{
				bool syntaxError2;
				Section section = ParseSection(reader, list.Count, out syntaxError2);
				if (syntaxError2)
				{
					syntaxError = true;
				}
				if (section == null)
				{
					break;
				}
				list.Add(section);
			}
			return list;
		}

		private static Section ParseSection(Tokenizer reader, int index, out bool syntaxError)
		{
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			bool flag4 = false;
			bool flag5 = false;
			List<string> list = new List<string>();
			syntaxError = false;
			string text;
			while ((text = ReadToken(reader, out syntaxError)) != null && !(text == ";"))
			{
				flag5 |= Token.IsPlaceholder(text);
				if (Token.IsDatePart(text))
				{
					flag = flag || true;
					flag2 |= Token.IsDurationPart(text);
					list.Add(text);
				}
				else
				{
					list.Add(text);
				}
			}
			if (syntaxError || list.Count == 0)
			{
				return null;
			}
			if ((flag && (flag3 || flag4)) || (flag3 && (flag || flag4)) || (flag4 && (flag3 || flag)))
			{
				syntaxError = true;
				return null;
			}
			FractionSection format = null;
			ExponentialSection format2 = null;
			DecimalSection format3 = null;
			List<string> result = null;
			SectionType type;
			if (flag)
			{
				type = ((!flag2) ? SectionType.Date : SectionType.Duration);
				ParseMilliseconds(list, out result);
			}
			else if (flag3)
			{
				type = SectionType.General;
				result = list;
			}
			else if (flag4 || !flag5)
			{
				type = SectionType.Text;
				result = list;
			}
			else if (FractionSection.TryParse(list, out format))
			{
				type = SectionType.Fraction;
			}
			else if (ExponentialSection.TryParse(list, out format2))
			{
				type = SectionType.Exponential;
			}
			else
			{
				if (!DecimalSection.TryParse(list, out format3))
				{
					syntaxError = true;
					return null;
				}
				type = SectionType.Number;
			}
			return new Section
			{
				Type = type,
				SectionIndex = index,
				GeneralTextDateDurationParts = result
			};
		}

		internal static int ParseNumberTokens(List<string> tokens, int startPosition, out List<string> beforeDecimal, out bool decimalSeparator, out List<string> afterDecimal)
		{
			beforeDecimal = null;
			afterDecimal = null;
			decimalSeparator = false;
			List<string> list = new List<string>();
			int num = 0;
			for (num = 0; num < tokens.Count; num++)
			{
				string text = tokens[num];
				if (text == "." && beforeDecimal == null)
				{
					decimalSeparator = true;
					beforeDecimal = tokens.GetRange(0, num);
					list = new List<string>();
				}
				else if (Token.IsNumberLiteral(text))
				{
					list.Add(text);
				}
				else if (!text.StartsWith("["))
				{
					break;
				}
			}
			if (list.Count > 0)
			{
				if (beforeDecimal != null)
				{
					afterDecimal = list;
				}
				else
				{
					beforeDecimal = list;
				}
			}
			return num;
		}

		private static void ParseMilliseconds(List<string> tokens, out List<string> result)
		{
			result = new List<string>();
			for (int i = 0; i < tokens.Count; i++)
			{
				string text = tokens[i];
				if (text == ".")
				{
					int num = 0;
					while (i + 1 < tokens.Count && tokens[i + 1] == "0")
					{
						i++;
						num++;
					}
					if (num > 0)
					{
						result.Add("." + new string('0', num));
					}
					else
					{
						result.Add(".");
					}
				}
				else
				{
					result.Add(text);
				}
			}
		}

		private static string ReadToken(Tokenizer reader, out bool syntaxError)
		{
			int position = reader.Position;
			if (ReadLiteral(reader) || reader.ReadEnclosed('[', ']') || reader.ReadOneOf("#?,!&%+-$€£0123456789{}():;/.@ ") || reader.ReadString("e+", ignoreCase: true) || reader.ReadString("e-", ignoreCase: true) || reader.ReadString("General", ignoreCase: true) || reader.ReadString("am/pm", ignoreCase: true) || reader.ReadString("a/p", ignoreCase: true) || reader.ReadOneOrMore(121) || reader.ReadOneOrMore(89) || reader.ReadOneOrMore(109) || reader.ReadOneOrMore(77) || reader.ReadOneOrMore(100) || reader.ReadOneOrMore(68) || reader.ReadOneOrMore(104) || reader.ReadOneOrMore(72) || reader.ReadOneOrMore(115) || reader.ReadOneOrMore(83) || reader.ReadOneOrMore(103) || reader.ReadOneOrMore(71))
			{
				syntaxError = false;
				int length = reader.Position - position;
				return reader.Substring(position, length);
			}
			syntaxError = reader.Position < reader.Length;
			return null;
		}

		private static bool ReadLiteral(Tokenizer reader)
		{
			if (reader.Peek() == 92 || reader.Peek() == 42 || reader.Peek() == 95)
			{
				reader.Advance(2);
				return true;
			}
			if (reader.ReadEnclosed('"', '"'))
			{
				return true;
			}
			return false;
		}
	}
	internal class Tokenizer
	{
		private string formatString;

		private int formatStringPosition;

		public int Position => formatStringPosition;

		public int Length => formatString?.Length ?? 0;

		public Tokenizer(string fmt)
		{
			formatString = fmt;
		}

		public string Substring(int startIndex, int length)
		{
			return formatString.Substring(startIndex, length);
		}

		public int Peek(int offset = 0)
		{
			if (formatStringPosition + offset >= Length)
			{
				return -1;
			}
			return formatString[formatStringPosition + offset];
		}

		public int PeekUntil(int startOffset, int until)
		{
			int num = startOffset;
			while (true)
			{
				int num2 = Peek(num++);
				if (num2 == -1)
				{
					break;
				}
				if (num2 == until)
				{
					return num - startOffset;
				}
			}
			return 0;
		}

		public bool PeekOneOf(int offset, string s)
		{
			foreach (char c in s)
			{
				if (Peek(offset) == c)
				{
					return true;
				}
			}
			return false;
		}

		public void Advance(int characters = 1)
		{
			formatStringPosition = Math.Min(formatStringPosition + characters, formatString.Length);
		}

		public bool ReadOneOrMore(int c)
		{
			if (Peek() != c)
			{
				return false;
			}
			while (Peek() == c)
			{
				Advance();
			}
			return true;
		}

		public bool ReadOneOf(string s)
		{
			if (PeekOneOf(0, s))
			{
				Advance();
				return true;
			}
			return false;
		}

		public bool ReadString(string s, bool ignoreCase = false)
		{
			if (formatStringPosition + s.Length > Length)
			{
				return false;
			}
			for (int i = 0; i < s.Length; i++)
			{
				char c = s[i];
				char c2 = (char)Peek(i);
				if (ignoreCase)
				{
					if (char.ToLower(c) != char.ToLower(c2))
					{
						return false;
					}
				}
				else if (c != c2)
				{
					return false;
				}
			}
			Advance(s.Length);
			return true;
		}

		public bool ReadEnclosed(char open, char close)
		{
			if (Peek() == open)
			{
				int num = PeekUntil(1, close);
				if (num > 0)
				{
					Advance(1 + num);
					return true;
				}
			}
			return false;
		}
	}
	internal static class Token
	{
		public static bool IsExponent(string token)
		{
			if (string.Compare(token, "e+", StringComparison.OrdinalIgnoreCase) != 0)
			{
				return string.Compare(token, "e-", StringComparison.OrdinalIgnoreCase) == 0;
			}
			return true;
		}

		public static bool IsLiteral(string token)
		{
			if (!token.StartsWith("_", StringComparison.Ordinal) && !token.StartsWith("\\", StringComparison.Ordinal) && !token.StartsWith("\"", StringComparison.Ordinal) && !token.StartsWith("*", StringComparison.Ordinal))
			{
				switch (token)
				{
				default:
					return token == " ";
				case ",":
				case "!":
				case "&":
				case "%":
				case "+":
				case "-":
				case "$":
				case "€":
				case "£":
				case "1":
				case "2":
				case "3":
				case "4":
				case "5":
				case "6":
				case "7":
				case "8":
				case "9":
				case "{":
				case "}":
				case "(":
				case ")":
					break;
				}
			}
			return true;
		}

		public static bool IsNumberLiteral(string token)
		{
			if (!IsPlaceholder(token) && !IsLiteral(token))
			{
				return token == ".";
			}
			return true;
		}

		public static bool IsPlaceholder(string token)
		{
			if (!(token == "0") && !(token == "#"))
			{
				return token == "?";
			}
			return true;
		}

		public static bool IsGeneral(string token)
		{
			return string.Compare(token, "general", StringComparison.OrdinalIgnoreCase) == 0;
		}

		public static bool IsDatePart(string token)
		{
			if (!token.StartsWith("y", StringComparison.OrdinalIgnoreCase) && !token.StartsWith("m", StringComparison.OrdinalIgnoreCase) && !token.StartsWith("d", StringComparison.OrdinalIgnoreCase) && !token.StartsWith("s", StringComparison.OrdinalIgnoreCase) && !token.StartsWith("h", StringComparison.OrdinalIgnoreCase) && (!token.StartsWith("g", StringComparison.OrdinalIgnoreCase) || IsGeneral(token)) && string.Compare(token, "am/pm", StringComparison.OrdinalIgnoreCase) != 0 && string.Compare(token, "a/p", StringComparison.OrdinalIgnoreCase) != 0)
			{
				return IsDurationPart(token);
			}
			return true;
		}

		public static bool IsDurationPart(string token)
		{
			if (!token.StartsWith("[h", StringComparison.OrdinalIgnoreCase) && !token.StartsWith("[m", StringComparison.OrdinalIgnoreCase))
			{
				return token.StartsWith("[s", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		public static bool IsDigit09(string token)
		{
			if (!(token == "0"))
			{
				return IsDigit19(token);
			}
			return true;
		}

		public static bool IsDigit19(string token)
		{
			if (token != null)
			{
				int length = token.Length;
				if (length == 1)
				{
					switch (token[0])
					{
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						return true;
					}
				}
			}
			return false;
		}
	}
	public static class ExcelTypeHelper
	{
		internal static ExcelType GetExcelType(string filePath, ExcelType excelType)
		{
			if (excelType != ExcelType.UNKNOWN)
			{
				return excelType;
			}
			string text = Path.GetExtension(filePath).ToLowerInvariant();
			switch (text)
			{
			case ".csv":
				return ExcelType.CSV;
			case ".xlsx":
			case ".xlsm":
				return ExcelType.XLSX;
			default:
				throw new NotSupportedException("Extension : " + text + " not suppprt, or you can specify exceltype.");
			}
		}

		internal static ExcelType GetExcelType(Stream stream, ExcelType excelType)
		{
			if (excelType != ExcelType.UNKNOWN)
			{
				return excelType;
			}
			byte[] array = new byte[8];
			stream.Seek(0L, SeekOrigin.Begin);
			stream.Read(array, 0, array.Length);
			stream.Seek(0L, SeekOrigin.Begin);
			if (array[0] == 80 && array[1] == 75)
			{
				return ExcelType.XLSX;
			}
			throw new NotSupportedException("Stream cannot know the file type, please specify ExcelType manually");
		}
	}
	internal static class FileHelper
	{
		public static FileStream OpenSharedRead(string path)
		{
			return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
		}
	}
	internal class ImageHelper
	{
		public enum ImageFormat
		{
			bmp,
			jpg,
			gif,
			tiff,
			png,
			unknown
		}

		public static ImageFormat GetImageFormat(byte[] bytes)
		{
			byte[] value = new byte[2] { 66, 77 };
			byte[] value2 = new byte[3] { 71, 73, 70 };
			byte[] value3 = new byte[4] { 137, 80, 78, 71 };
			byte[] value4 = new byte[3] { 73, 73, 42 };
			byte[] value5 = new byte[3] { 77, 77, 42 };
			byte[] value6 = new byte[4] { 255, 216, 255, 224 };
			byte[] value7 = new byte[4] { 255, 216, 255, 225 };
			if (bytes.StartsWith(value))
			{
				return ImageFormat.bmp;
			}
			if (bytes.StartsWith(value2))
			{
				return ImageFormat.gif;
			}
			if (bytes.StartsWith(value3))
			{
				return ImageFormat.png;
			}
			if (bytes.StartsWith(value4))
			{
				return ImageFormat.tiff;
			}
			if (bytes.StartsWith(value5))
			{
				return ImageFormat.tiff;
			}
			if (bytes.StartsWith(value6))
			{
				return ImageFormat.jpg;
			}
			if (bytes.StartsWith(value7))
			{
				return ImageFormat.jpg;
			}
			return ImageFormat.unknown;
		}
	}
	public static class IEnumerableHelper
	{
		public static bool StartsWith<T>(this IList<T> span, IList<T> value) where T : IEquatable<T>
		{
			if (value.Count == 0)
			{
				return true;
			}
			int num = span.Take(value.Count).Count();
			if (num != value.Count)
			{
				return false;
			}
			for (int i = 0; i < num; i++)
			{
				if (!span[i].Equals(value[i]))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class ReferenceHelper
	{
		public static string GetCellNumber(string cell)
		{
			string text = string.Empty;
			for (int i = 0; i < cell.Length; i++)
			{
				if (char.IsDigit(cell[i]))
				{
					text += cell[i];
				}
			}
			return text;
		}

		public static string GetCellLetter(string cell)
		{
			string text = string.Empty;
			for (int i = 0; i < cell.Length; i++)
			{
				if (char.IsLetter(cell[i]))
				{
					text += cell[i];
				}
			}
			return text;
		}

		public static Tuple<int, int> ConvertCellToXY(string cell)
		{
			int num = 0;
			string cellLetter = GetCellLetter(cell);
			for (int i = 0; i < cellLetter.Length; i++)
			{
				num = num * 26 + " ABCDEFGHIJKLMNOPQRSTUVWXYZ".IndexOf(cellLetter[i]);
			}
			string cellNumber = GetCellNumber(cell);
			return Tuple.Create(num, int.Parse(cellNumber));
		}

		public static string ConvertXyToCell(int x, int y

BepInEx/plugins/com.binbin.DivinationLogger.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
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.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.binbin.DivinationLogger")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+4152efad598808e0268af6d8f82091eb4244cc43")]
[assembly: AssemblyProduct("DivinationLogger")]
[assembly: AssemblyTitle("com.binbin.DivinationLogger")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DivinationLogger
{
	[HarmonyPatch]
	public class DivinationLogger
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(AtOManager), "GoToTown")]
		public static void GoToTownPostfix(AtOManager __instance)
		{
			Plugin.LogDebug("GoToTownPostfix");
			if (Plugin.LogToLogOutput.Value)
			{
				LogDivinations(__instance);
			}
			WriteDivinationsToFile(__instance);
		}

		public static int GetDivinationTier(int divinationIndex)
		{
			Plugin.LogDebug("Divination Tier: " + divinationIndex);
			AtOManager instance = AtOManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.LogDebug("AtOManager is null");
				return 0;
			}
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			dictionary.Add(0, 2);
			dictionary.Add(1, 5);
			dictionary.Add(2, 6);
			dictionary.Add(3, 8);
			dictionary.Add(4, 10);
			return dictionary.ContainsKey(divinationIndex) ? dictionary[divinationIndex] : 0;
		}

		public static void LogDivinations(AtOManager atOManager)
		{
			Plugin.LogDebug("LogDivinations");
			int divinationsNumber = atOManager.divinationsNumber;
			int num = ((atOManager.GetTownTier() == 3) ? 2 : Math.Min(atOManager.GetTownTier(), 1));
			if (atOManager.GetTownTier() == 2)
			{
				num--;
			}
			int num2 = 3;
			int value = Plugin.DivinationsToLog.Value;
			Dictionary<int, string> dictionary = new Dictionary<int, string>();
			dictionary.Add(0, "Fast");
			dictionary.Add(1, "Basic");
			dictionary.Add(2, "Advanced");
			dictionary.Add(3, "Premium");
			dictionary.Add(4, "Supreme");
			if (atOManager.GetTeam() == null)
			{
				Plugin.LogDebug("Team is null");
				return;
			}
			Hero[] team = atOManager.GetTeam();
			for (int i = 0; i < num2; i++)
			{
				for (int j = 0; j < value; j++)
				{
					int num3 = j + divinationsNumber;
					Plugin.LogDebug($"Divination {num3} {dictionary[num + i]}");
					Dictionary<int, string[]> divinationDictForOneDivination = GetDivinationDictForOneDivination(atOManager, num + i, num3);
					if (divinationDictForOneDivination == null)
					{
						Plugin.LogDebug("cardsByOrder is null");
						return;
					}
					foreach (KeyValuePair<int, string[]> item in divinationDictForOneDivination)
					{
						if (item.Value == null || item.Value.Length == 0 || item.Key >= team.Length)
						{
							Plugin.LogDebug("Row is null");
							return;
						}
						List<string> list = new List<string>();
						for (int k = 0; k < item.Value.Length; k++)
						{
							CardData cardData = Globals.Instance.GetCardData(item.Value[k], false);
							if ((Object)(object)cardData == (Object)null)
							{
								list.Add("");
							}
							else
							{
								list.Add(GetCardName(cardData));
							}
						}
						Hero obj = team[item.Key];
						string arg = ((obj == null) ? null : ((Character)obj).SourceName?.ToString()) ?? "Unknown";
						Plugin.LogDebug(string.Format("Hero {0}, {1}. Cards: {2}", item.Key, arg, string.Join(", ", list)));
					}
				}
			}
		}

		public static void WriteDivinationsToFile(AtOManager atOManager)
		{
			Plugin.LogDebug("WriteDivinationsToFile");
			int divinationsNumber = atOManager.divinationsNumber;
			int num = Math.Min(Math.Max(atOManager.GetTownTier() - 1, 0), 2);
			int num2 = 3;
			int value = Plugin.DivinationsToLog.Value;
			Dictionary<int, string> dictionary = new Dictionary<int, string>();
			dictionary.Add(0, "Fast");
			dictionary.Add(1, "Basic");
			dictionary.Add(2, "Advanced");
			dictionary.Add(3, "Premium");
			dictionary.Add(4, "Supreme");
			List<string> list = new List<string>(1) { "Divination" };
			List<List<string>> list2 = new List<List<string>>();
			list2.Add(list);
			if (atOManager.GetTeam() == null)
			{
				Plugin.LogDebug("Team is null");
				return;
			}
			Hero[] team = atOManager.GetTeam();
			bool flag = true;
			for (int i = 0; i < num2; i++)
			{
				int num3 = 4;
				string arg = dictionary[num + i];
				for (int j = 0; j < num3; j++)
				{
					if (Plugin.AddSpaces.Value && flag)
					{
						list.Add("");
						flag = false;
					}
					list.Add($"{arg}: Card {j + 1}");
				}
				flag = true;
			}
			for (int k = 0; k < value; k++)
			{
				List<List<string>> list3 = new List<List<string>>();
				for (int l = 0; l < team.Count(); l++)
				{
					list3.Add(new List<string>());
				}
				flag = true;
				for (int m = 0; m < num2; m++)
				{
					int num4 = k + divinationsNumber;
					Plugin.LogDebug($"Divination {num4} {dictionary[num + m]}");
					Dictionary<int, string[]> divinationDictForOneDivination = GetDivinationDictForOneDivination(atOManager, num + m, num4);
					foreach (KeyValuePair<int, string[]> item3 in divinationDictForOneDivination)
					{
						int key = item3.Key;
						List<string> list4 = new List<string>();
						for (int n = 0; n < 4; n++)
						{
							if (Plugin.AddSpaces.Value && flag)
							{
								list4.Add("");
								flag = false;
							}
							if (n >= item3.Value.Length)
							{
								list4.Add("");
								continue;
							}
							CardData cardData = Globals.Instance.GetCardData(item3.Value[n], false);
							if ((Object)(object)cardData == (Object)null)
							{
								list4.Add("");
							}
							else
							{
								list4.Add(GetCardName(cardData));
							}
						}
						flag = true;
						if (m == 0)
						{
							string text = $"D{num4 + 1}: ";
							Hero obj = team[key];
							string item = text + (((obj == null) ? null : ((Character)obj).SourceName?.ToString()) ?? "Missing Hero");
							list4.Insert(0, item);
						}
						list3[key].AddRange(list4);
					}
				}
				int count = 0;
				foreach (List<string> item4 in list3)
				{
					list2.Add(item4);
					count = item4.Count();
				}
				if (Plugin.AddSpaces.Value)
				{
					List<string> item2 = Enumerable.Repeat("", count).ToList();
					list2.Add(item2);
				}
			}
			SaveDivinationsToFile(atOManager, list2);
		}

		public static void SaveDivinationsToFile(AtOManager atOManager, List<List<string>> divinationResults)
		{
			string path;
			if (Plugin.AbsoluteFolderPath.Value == "" || Plugin.AbsoluteFolderPath.Value == null)
			{
				string directoryName = Path.GetDirectoryName(SaveManager.PathSaveGameTurn(0));
				path = ((Plugin.SaveFolder.Value == "" || Plugin.SaveFolder.Value == null) ? Path.Combine(directoryName, atOManager.GetGameId()) : Path.Combine(directoryName, Plugin.SaveFolder.Value));
			}
			else
			{
				path = Plugin.AbsoluteFolderPath.Value;
			}
			string path2 = string.Format("DivinationResults_Act_{0}.csv", atOManager.GetActNumberForText(""));
			string path3 = string.Format("DivinationResults_Act_{0}.xlsx", atOManager.GetActNumberForText(""));
			if (Plugin.SaveToCSV.Value)
			{
				WriteDataToCSV(divinationResults, Path.Combine(path, path2));
			}
			if (Plugin.SaveToExcel.Value)
			{
				WriteDataToExcel(divinationResults, Path.Combine(path, path3));
			}
		}

		public static Dictionary<int, string[]> GetDivinationDictForOneDivination(AtOManager atOManager, int tierNum, int ndivinations)
		{
			//IL_016c: 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_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Invalid comparison between Unknown and I4
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Invalid comparison between Unknown and I4
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Invalid comparison between Unknown and I4
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Invalid comparison between Unknown and I4
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Invalid comparison between Unknown and I4
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Invalid comparison between Unknown and I4
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Invalid comparison between Unknown and I4
			//IL_0368: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Invalid comparison between Unknown and I4
			Random.InitState(Functions.GetDeterministicHashCode(AtOManager.Instance.GetGameId() + "_" + AtOManager.Instance.mapVisitedNodes.Count + "_" + AtOManager.Instance.currentMapNode + "_" + ndivinations));
			TierRewardData tierRewardData = Globals.Instance.GetTierRewardData(GetDivinationTier(tierNum));
			Dictionary<int, string[]> dictionary = new Dictionary<int, string[]>();
			int num = ((tierNum <= 1) ? 3 : 4);
			Hero[] team = AtOManager.Instance.GetTeam();
			if ((Object)(object)tierRewardData != (Object)null)
			{
				TierRewardData val = tierRewardData;
				int num2 = val.TierNum;
				AtOManager.Instance.currentRewardTier = num2;
				if (num2 < 0)
				{
					num2 = 0;
				}
				val = Globals.Instance.GetTierRewardData(num2);
				TierRewardData val2 = ((num2 <= 0) ? val : Globals.Instance.GetTierRewardData(num2 - 1));
				CardData val3 = null;
				for (int i = 0; i < team.Length; i++)
				{
					if (team[i] == null || (Object)(object)((Character)team[i]).HeroData == (Object)null)
					{
						dictionary[i] = new string[3] { "", "", "" };
						continue;
					}
					Hero val4 = team[i];
					CardClass result = (CardClass)11;
					Enum.TryParse<CardClass>(Enum.GetName(typeof(HeroClass), ((Character)val4).HeroData.HeroClass), out result);
					CardClass result2 = (CardClass)11;
					Enum.TryParse<CardClass>(Enum.GetName(typeof(HeroClass), ((Character)val4).HeroData.HeroSubClass.HeroClassSecondary), out result2);
					int num3 = num;
					if (num == 3 && (int)result2 != 11)
					{
						num3 = 4;
					}
					string[] array = new string[num3];
					List<string> list = Globals.Instance.CardListNotUpgradedByClass[result];
					List<string> list2 = (((int)result2 == 11) ? new List<string>() : Globals.Instance.CardListNotUpgradedByClass[result2]);
					for (int j = 0; j < num3; j++)
					{
						TierRewardData val5 = ((j != 0) ? val2 : val);
						int num4 = Random.Range(0, 100);
						bool flag = true;
						while (flag)
						{
							flag = false;
							bool flag2 = false;
							while (!flag2)
							{
								flag = false;
								val3 = Globals.Instance.GetCardData((j < 2 || (int)result2 == 11) ? list[Random.Range(0, list.Count)] : list2[Random.Range(0, list2.Count)], false);
								if (flag)
								{
									continue;
								}
								if (num4 < val5.Common)
								{
									if ((int)val3.CardRarity == 0)
									{
										flag2 = true;
									}
								}
								else if (num4 < val5.Common + val5.Uncommon)
								{
									if ((int)val3.CardRarity == 1)
									{
										flag2 = true;
									}
								}
								else if (num4 < val5.Common + val5.Uncommon + val5.Rare)
								{
									if ((int)val3.CardRarity == 2)
									{
										flag2 = true;
									}
								}
								else if (num4 < val5.Common + val5.Uncommon + val5.Rare + val5.Epic)
								{
									if ((int)val3.CardRarity == 3)
									{
										flag2 = true;
									}
								}
								else if ((int)val3.CardRarity == 4)
								{
									flag2 = true;
								}
							}
							int num5 = Random.Range(0, 100);
							string id = val3.Id;
							val3 = Globals.Instance.GetCardData(Functions.GetCardByRarity(num5, val3, false), false);
							if ((Object)(object)val3 == (Object)null)
							{
								flag = true;
								continue;
							}
							for (int k = 0; k < array.Length; k++)
							{
								if (array[k] == val3.Id)
								{
									flag = true;
									break;
								}
							}
						}
						array[j] = val3.Id;
					}
					dictionary[i] = Functions.ShuffleArray<string>(array);
				}
				return dictionary;
			}
			Plugin.LogDebug("No townDivinationTier");
			return null;
		}

		public static void WriteDataToCSV(List<List<string>> data, string filePath)
		{
			Plugin.LogDebug("WriteListToCsv");
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				foreach (List<string> datum in data)
				{
					stringBuilder.AppendLine(string.Join(",", datum.Select((string field) => (field.Contains(",") || field.Contains("\"")) ? ("\"" + field.Replace("\"", "\"\"") + "\"") : field)));
				}
				string directoryName = Path.GetDirectoryName(filePath);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				File.WriteAllText(filePath, stringBuilder.ToString());
				Plugin.LogDebug("CSV file successfully created at: " + filePath);
			}
			catch (Exception ex)
			{
				Plugin.LogError("An error occurred: " + ex.Message);
			}
		}

		public static void WriteDataToExcel(List<List<string>> data, string filePath)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			Plugin.LogDebug("WriteListToExcel");
			List<string> list = data.FirstOrDefault();
			if (list == null)
			{
				Plugin.LogError("headerRow is empty or null");
				return;
			}
			List<Dictionary<string, object>> list2 = new List<Dictionary<string, object>>();
			for (int i = 1; i < data.Count; i++)
			{
				List<string> list3 = data[i];
				Dictionary<string, object> dictionary = new Dictionary<string, object>();
				for (int j = 0; j < list.Count && j < list3.Count; j++)
				{
					dictionary.Add(list[j], list3[j]);
				}
				list2.Add(dictionary);
			}
			if (Plugin.AddFormatting.Value)
			{
				OpenXmlConfiguration val = new OpenXmlConfiguration
				{
					FastMode = true,
					EnableAutoWidth = true,
					FreezeColumnCount = 1,
					FreezeRowCount = 1
				};
				MiniExcel.SaveAs(filePath, (object)list2, true, "Sheet1", (ExcelType)2, (IConfiguration)(object)val, false);
			}
			Plugin.LogDebug("Excel file created at: " + filePath);
		}

		public static string GetCardName(CardData cardData)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			string text = cardData.CardName;
			if ((int)cardData.CardUpgraded == 1)
			{
				text += " (Blue)";
			}
			else if ((int)cardData.CardUpgraded == 2)
			{
				text += " (Yellow)";
			}
			else if ((int)cardData.CardUpgraded == 3)
			{
				text += " (Corrupted)";
			}
			return text;
		}
	}
	[BepInPlugin("com.binbin.DivinationLogger", "DivinationLogger", "1.2.0")]
	[BepInProcess("AcrossTheObelisk.exe")]
	public class Plugin : BaseUnityPlugin
	{
		internal int ModDate = int.Parse(DateTime.Today.ToString("yyyyMMdd"));

		private readonly Harmony harmony = new Harmony("com.binbin.DivinationLogger");

		internal static ManualLogSource Log;

		public static string debugBase = "com.binbin.DivinationLogger ";

		public static ConfigEntry<bool> EnableMod { get; set; }

		public static ConfigEntry<bool> EnableDebug { get; set; }

		public static ConfigEntry<string> SaveFolder { get; set; }

		public static ConfigEntry<bool> SaveToCSV { get; set; }

		public static ConfigEntry<bool> SaveToExcel { get; set; }

		public static ConfigEntry<bool> LogToLogOutput { get; set; }

		public static ConfigEntry<string> AbsoluteFolderPath { get; set; }

		public static ConfigEntry<int> DivinationsToLog { get; set; }

		public static ConfigEntry<bool> AddSpaces { get; set; }

		public static ConfigEntry<bool> AddFormatting { get; set; }

		private void Awake()
		{
			//IL_002c: 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_0047: Expected O, but got Unknown
			//IL_0047: Expected O, but got Unknown
			//IL_005d: 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_0078: Expected O, but got Unknown
			//IL_0078: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00a9: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00da: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_010b: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Expected O, but got Unknown
			//IL_0140: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Expected O, but got Unknown
			//IL_0175: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01a7: Expected O, but got Unknown
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			//IL_01d8: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Expected O, but got Unknown
			//IL_0209: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"com.binbin.DivinationLogger 1.2.0 has loaded!");
			EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("DivinationLogger", "Enable Mod"), true, new ConfigDescription("If false, disables the mod. Restart the game upon changing this setting.", (AcceptableValueBase)null, Array.Empty<object>()));
			EnableDebug = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("DivinationLogger", "Enable Debug"), true, new ConfigDescription("If true, Enables Debug Logging.", (AcceptableValueBase)null, Array.Empty<object>()));
			LogToLogOutput = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("DivinationLogger", "Log to LogOutput"), false, new ConfigDescription("If true, logs the divinations to the LogOutput.", (AcceptableValueBase)null, Array.Empty<object>()));
			SaveToCSV = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("DivinationLogger", "Save to CSV"), true, new ConfigDescription("If true, saves the divinations as a csv file.", (AcceptableValueBase)null, Array.Empty<object>()));
			SaveToExcel = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("DivinationLogger", "Save to Excel"), false, new ConfigDescription("If true, saves the divinations as an Excel file.", (AcceptableValueBase)null, Array.Empty<object>()));
			SaveFolder = ((BaseUnityPlugin)this).Config.Bind<string>(new ConfigDefinition("DivinationLogger", "Save Folder"), "", new ConfigDescription("Folder to Save to, if left blank, will write to the default save folder/your current seed", (AcceptableValueBase)null, Array.Empty<object>()));
			AbsoluteFolderPath = ((BaseUnityPlugin)this).Config.Bind<string>(new ConfigDefinition("DivinationLogger", "Absolute Folder Path"), "", new ConfigDescription("Absolute FilePath to save to. If left blank, will default to Save Folder. Overrides Save Folder", (AcceptableValueBase)null, Array.Empty<object>()));
			DivinationsToLog = ((BaseUnityPlugin)this).Config.Bind<int>(new ConfigDefinition("DivinationLogger", "Number of Divinations"), 10, new ConfigDescription("The number of divinations that will be automatically logged whenever you enter town.", (AcceptableValueBase)null, Array.Empty<object>()));
			AddSpaces = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("DivinationLogger", "Add Spaces to File"), false, new ConfigDescription("Adds blank rows/columns in between the divinations and divination types", (AcceptableValueBase)null, Array.Empty<object>()));
			AddFormatting = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("DivinationLogger", "Add Formatting to Excel"), false, new ConfigDescription("Adds formatting, coloring cells if they are upgraded, and adding borders.", (AcceptableValueBase)null, Array.Empty<object>()));
			if (EnableMod.Value)
			{
				LogDebug("Excuting Patches");
				harmony.PatchAll();
			}
		}

		internal static void LogDebug(string msg)
		{
			if (EnableDebug.Value)
			{
				Log.LogDebug((object)(debugBase + msg));
			}
		}

		internal static void LogInfo(string msg)
		{
			Log.LogInfo((object)(debugBase + msg));
		}

		internal static void LogError(string msg)
		{
			Log.LogError((object)(debugBase + msg));
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.binbin.DivinationLogger";

		public const string PLUGIN_NAME = "DivinationLogger";

		public const string PLUGIN_VERSION = "1.2.0";
	}
}

BepInEx/plugins/Microsoft.Bcl.AsyncInterfaces.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("PreferInbox", "True")]
[assembly: AssemblyDefaultAlias("Microsoft.Bcl.AsyncInterfaces")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyMetadata("IsTrimmable", "True")]
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyDescription("Provides the IAsyncEnumerable<T> and IAsyncDisposable interfaces and helper types for .NET Standard 2.0. This package is not required starting with .NET Standard 2.1 and .NET Core 3.0.")]
[assembly: AssemblyFileVersion("9.0.325.11113")]
[assembly: AssemblyInformationalVersion("9.0.3+831d23e56149cd59c40fc00c7feb7c5334bd19c4")]
[assembly: AssemblyProduct("Microsoft® .NET")]
[assembly: AssemblyTitle("Microsoft.Bcl.AsyncInterfaces")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/dotnet/runtime")]
[assembly: AssemblyVersion("9.0.0.3")]
[assembly: TypeForwardedTo(typeof(IAsyncEnumerable<>))]
[assembly: TypeForwardedTo(typeof(IAsyncEnumerator<>))]
[assembly: TypeForwardedTo(typeof(IAsyncDisposable))]
[assembly: TypeForwardedTo(typeof(AsyncIteratorMethodBuilder))]
[assembly: TypeForwardedTo(typeof(AsyncIteratorStateMachineAttribute))]
[assembly: TypeForwardedTo(typeof(ConfiguredAsyncDisposable))]
[assembly: TypeForwardedTo(typeof(ConfiguredCancelableAsyncEnumerable<>))]
[assembly: TypeForwardedTo(typeof(EnumeratorCancellationAttribute))]
[assembly: TypeForwardedTo(typeof(ManualResetValueTaskSourceCore<>))]
[assembly: TypeForwardedTo(typeof(TaskAsyncEnumerableExtensions))]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
}
namespace System.Runtime.InteropServices
{
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
	internal sealed class LibraryImportAttribute : Attribute
	{
		public string LibraryName { get; }

		public string EntryPoint { get; set; }

		public StringMarshalling StringMarshalling { get; set; }

		public Type StringMarshallingCustomType { get; set; }

		public bool SetLastError { get; set; }

		public LibraryImportAttribute(string libraryName)
		{
			LibraryName = libraryName;
		}
	}
	internal enum StringMarshalling
	{
		Custom,
		Utf8,
		Utf16
	}
}