Decompiled source of DGLabPunish v0.6.1

BepInEx\plugins\DGLabPunish\DGLabPunish.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Net.Codecrete.QrCodeGenerator;
using Newtonsoft.Json;
using UnityEngine;
using WebSocketSharp;
using WebSocketSharp.Server;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DGLabPunish;

internal enum ContinuousStimState
{
	Idle,
	Walk,
	Run,
	Slide,
	Punish
}
internal sealed class StimOverlay
{
	public char Channel;

	public float StartTime;

	public int DurationMs;

	public int Strength;

	public int Frequency;

	public StimEnvelopeShape Shape;

	public double Phase;

	public int Priority;

	public int Generation;
}
internal sealed class ContinuousStimEngine
{
	private struct Sample
	{
		public int Strength;

		public int Frequency;

		public int BaseStrength;

		public int OverlayStrength;
	}

	private readonly DGLabSocketServer _server;

	private readonly StimDiagnostics _diagnostics;

	private readonly List<StimOverlay> _overlays;

	private float _lastSendTime;

	private float _lastActiveTime;

	private float _lastQueueUpdateTime;

	private float _lastStrengthTimeA;

	private float _lastStrengthTimeB;

	private bool _moving;

	private bool _sprinting;

	private bool _sliding;

	private float _speed;

	private bool _forceSend;

	private int _generation;

	private int _estimatedQueueMs;

	private int _lastStrengthA;

	private int _lastStrengthB;

	internal ContinuousStimEngine(DGLabSocketServer server, StimDiagnostics diagnostics)
	{
		_server = server;
		_diagnostics = diagnostics;
		_overlays = new List<StimOverlay>();
		_lastSendTime = -999f;
		_lastActiveTime = -999f;
		_lastQueueUpdateTime = -999f;
		_lastStrengthTimeA = -999f;
		_lastStrengthTimeB = -999f;
		_forceSend = false;
		_generation = 0;
		_estimatedQueueMs = 0;
		_lastStrengthA = -1;
		_lastStrengthB = -1;
	}

	internal void SetMovement(bool moving, bool sprinting, bool sliding, float speed)
	{
		if (moving != _moving || sprinting != _sprinting || sliding != _sliding)
		{
			_forceSend = true;
		}
		_moving = moving;
		_sprinting = sprinting;
		_sliding = sliding;
		_speed = speed;
		if (moving || sliding)
		{
			_lastActiveTime = Time.realtimeSinceStartup;
		}
	}

	internal void AddOverlay(char channel, int strength, int durationMs, int frequency, StimEnvelopeShape shape, double phase, int priority)
	{
		if (priority >= 80)
		{
			Interrupt(priority);
		}
		AddOverlayInternal(channel, strength, durationMs, frequency, shape, phase, priority);
	}

	private void AddOverlayInternal(char channel, int strength, int durationMs, int frequency, StimEnvelopeShape shape, double phase, int priority)
	{
		_overlays.Add(new StimOverlay
		{
			Channel = channel,
			StartTime = Time.realtimeSinceStartup,
			DurationMs = Mathf.Max(25, durationMs),
			Strength = Mathf.Max(0, strength),
			Frequency = Mathf.Clamp(frequency, 10, 1000),
			Shape = shape,
			Phase = phase,
			Priority = priority,
			Generation = _generation
		});
		_forceSend = true;
		_lastSendTime = -999f;
	}

	internal void AddOverlayBoth(int strengthA, int strengthB, int durationMs, int frequency, StimEnvelopeShape shape, int priority)
	{
		AddOverlayPair(strengthA, strengthB, durationMs, frequency, shape, 0.0, 0.18, priority);
	}

	internal void AddOverlayPair(int strengthA, int strengthB, int durationMs, int frequency, StimEnvelopeShape shape, double phaseA, double phaseB, int priority)
	{
		if (priority >= 80)
		{
			Interrupt(priority);
		}
		AddOverlayInternal('A', strengthA, durationMs, frequency, shape, phaseA, priority);
		AddOverlayInternal('B', strengthB, durationMs, frequency, shape, phaseB, priority);
	}

	internal void Clear()
	{
		_overlays.Clear();
		_lastSendTime = -999f;
		_lastActiveTime = -999f;
		_lastQueueUpdateTime = -999f;
		_forceSend = false;
		_generation++;
		_estimatedQueueMs = 0;
		_diagnostics.EstimatedQueueMs = 0;
		_diagnostics.ContinuousGeneration = _generation;
	}

	internal void Tick()
	{
		if (_server == null || !_server.IsBound || !ModConfig.Armed.Value || !ModConfig.ContinuousMode.Value)
		{
			return;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		UpdateEstimatedQueue(realtimeSinceStartup);
		PruneOverlays(realtimeSinceStartup);
		int num = Mathf.Clamp(ModConfig.ContinuousSendIntervalMs.Value, 50, 1000);
		if (!_forceSend && (realtimeSinceStartup - _lastSendTime) * 1000f < (float)num)
		{
			return;
		}
		ContinuousStimState continuousStimState = CurrentState(realtimeSinceStartup);
		_diagnostics.ContinuousState = continuousStimState.ToString();
		_diagnostics.ActiveOverlays = _overlays.Count;
		_diagnostics.EstimatedQueueMs = _estimatedQueueMs;
		_diagnostics.ContinuousGeneration = _generation;
		if (continuousStimState == ContinuousStimState.Idle && _overlays.Count == 0)
		{
			_diagnostics.ContinuousBaseA = 0;
			_diagnostics.ContinuousBaseB = 0;
			_diagnostics.ContinuousOverlayA = 0;
			_diagnostics.ContinuousOverlayB = 0;
			return;
		}
		int num2 = Mathf.Clamp(ModConfig.ContinuousLookaheadMs.Value, 100, 1500);
		int num3 = Mathf.Clamp(num2 / 2, 25, 80);
		if (!_forceSend && _estimatedQueueMs > num3)
		{
			_diagnostics.LastCommandResult = "队列水位足够,暂不补包";
			return;
		}
		List<int> list = new List<int>();
		List<int> list2 = new List<int>();
		List<int> list3 = new List<int>();
		List<int> list4 = new List<int>();
		int num4 = Mathf.Max(1, (int)Math.Ceiling((double)num2 / 25.0));
		int num5 = 0;
		int num6 = 0;
		int num7 = 0;
		int num8 = 0;
		int num9 = 0;
		int num10 = 0;
		for (int i = 0; i < num4; i++)
		{
			float sampleTime = realtimeSinceStartup + (float)i * 0.025f;
			Sample sample = SampleChannel('A', continuousStimState, sampleTime);
			Sample sample2 = SampleChannel('B', continuousStimState, sampleTime);
			list.Add(sample.Frequency);
			list2.Add(sample2.Frequency);
			list3.Add(sample.Strength);
			list4.Add(sample2.Strength);
			num5 = Mathf.Max(num5, sample.Strength);
			num6 = Mathf.Max(num6, sample2.Strength);
			num7 = Mathf.Max(num7, sample.BaseStrength);
			num8 = Mathf.Max(num8, sample2.BaseStrength);
			num9 = Mathf.Max(num9, sample.OverlayStrength);
			num10 = Mathf.Max(num10, sample2.OverlayStrength);
		}
		PrepareStrength('A', num5);
		PrepareStrength('B', num6);
		List<string> list5 = WaveformEncoder.Pulse(list, list3);
		List<string> list6 = WaveformEncoder.Pulse(list2, list4);
		bool flag = _server.SendPulse('A', list5);
		bool flag2 = _server.SendPulse('B', list6);
		_lastSendTime = realtimeSinceStartup;
		_forceSend = false;
		if (flag || flag2)
		{
			int num11 = Mathf.Max(flag ? list5.Count : 0, flag2 ? list6.Count : 0);
			_estimatedQueueMs = Mathf.Clamp(_estimatedQueueMs + num11 * 100, 0, 1000);
		}
		_diagnostics.ContinuousBaseA = num7;
		_diagnostics.ContinuousBaseB = num8;
		_diagnostics.ContinuousOverlayA = num9;
		_diagnostics.ContinuousOverlayB = num10;
		_diagnostics.ContinuousRefillCount++;
		_diagnostics.EstimatedQueueMs = _estimatedQueueMs;
		_diagnostics.ContinuousGeneration = _generation;
		_diagnostics.LastCommandResult = ((flag && flag2) ? ("连续补包已发送,队列约 " + _estimatedQueueMs + "ms") : "连续补包发送失败");
	}

	private ContinuousStimState CurrentState(float now)
	{
		if (_sliding)
		{
			return ContinuousStimState.Slide;
		}
		if (_sprinting && _moving)
		{
			return ContinuousStimState.Run;
		}
		if (_moving)
		{
			return ContinuousStimState.Walk;
		}
		int num = Mathf.Max(0, ModConfig.ContinuousFadeOutMs.Value);
		if (num > 0 && (now - _lastActiveTime) * 1000f < (float)num)
		{
			return ContinuousStimState.Walk;
		}
		if (_overlays.Count <= 0)
		{
			return ContinuousStimState.Idle;
		}
		return ContinuousStimState.Punish;
	}

	private Sample SampleChannel(char channel, ContinuousStimState state, float sampleTime)
	{
		int frequency = 180;
		int num = BaseStrength(state, sampleTime, out frequency);
		int num2 = 0;
		int num3 = frequency;
		for (int i = 0; i < _overlays.Count; i++)
		{
			StimOverlay stimOverlay = _overlays[i];
			if (stimOverlay.Channel != channel || stimOverlay.Generation != _generation)
			{
				continue;
			}
			double num4 = (double)(sampleTime - stimOverlay.StartTime) * 1000.0 / (double)stimOverlay.DurationMs;
			if (!(num4 < 0.0) && !(num4 > 1.0))
			{
				int num5 = (int)Math.Round((double)stimOverlay.Strength * WaveformEncoder.EvaluateEnvelope(stimOverlay.Shape, num4, stimOverlay.Phase));
				if (num5 > num2)
				{
					num2 = num5;
					num3 = stimOverlay.Frequency;
				}
			}
		}
		int strength = Mathf.Clamp(num + num2, 0, ModConfig.MaxWaveIntensity.Value);
		if (num2 > 0)
		{
			frequency = num3;
		}
		Sample result = default(Sample);
		result.Strength = strength;
		result.Frequency = Mathf.Clamp(frequency, 10, 1000);
		result.BaseStrength = num;
		result.OverlayStrength = num2;
		return result;
	}

	private int BaseStrength(ContinuousStimState state, float sampleTime, out int frequency)
	{
		frequency = 180;
		int num;
		StimEnvelopeShape shape;
		switch (state)
		{
		case ContinuousStimState.Idle:
		case ContinuousStimState.Punish:
			return 0;
		case ContinuousStimState.Run:
			num = ModConfig.RunBaseIntensity.Value;
			frequency = ModConfig.RunBaseFrequency.Value;
			shape = ModConfig.RunBaseShape.Value;
			break;
		case ContinuousStimState.Slide:
			num = ModConfig.SlideBaseIntensity.Value;
			frequency = ModConfig.SlideBaseFrequency.Value;
			shape = StimEnvelopeShape.Tremor;
			break;
		default:
			num = ModConfig.WalkBaseIntensity.Value;
			frequency = ModConfig.WalkBaseFrequency.Value;
			shape = ModConfig.WalkBaseShape.Value;
			break;
		}
		int num2 = Mathf.Max(1, ModConfig.ContinuousFadeOutMs.Value);
		if (!_moving && !_sliding)
		{
			float num3 = (sampleTime - _lastActiveTime) * 1000f;
			if (num3 >= (float)num2)
			{
				return 0;
			}
			num = (int)Math.Round((double)num * (1.0 - (double)(num3 / (float)num2)));
		}
		double t = (double)sampleTime * 1000.0 % 900.0 / 900.0;
		double num4 = WaveformEncoder.EvaluateEnvelope(shape, t, 0.0);
		double num5 = 0.55;
		return Mathf.Clamp((int)Math.Round((double)num * (num5 + (1.0 - num5) * num4)), 0, ModConfig.MaxWaveIntensity.Value);
	}

	private void PruneOverlays(float now)
	{
		for (int num = _overlays.Count - 1; num >= 0; num--)
		{
			StimOverlay stimOverlay = _overlays[num];
			if (stimOverlay.Generation != _generation || (now - stimOverlay.StartTime) * 1000f > (float)(stimOverlay.DurationMs + 100))
			{
				_overlays.RemoveAt(num);
			}
		}
	}

	private void Interrupt(int priority)
	{
		_generation++;
		for (int num = _overlays.Count - 1; num >= 0; num--)
		{
			if (_overlays[num].Priority <= priority)
			{
				_overlays.RemoveAt(num);
			}
		}
		_server.ClearAll();
		_estimatedQueueMs = 0;
		_lastQueueUpdateTime = Time.realtimeSinceStartup;
		_lastSendTime = -999f;
		_forceSend = true;
		_diagnostics.EstimatedQueueMs = 0;
		_diagnostics.ContinuousGeneration = _generation;
	}

	private void UpdateEstimatedQueue(float now)
	{
		if (_lastQueueUpdateTime < -100f)
		{
			_lastQueueUpdateTime = now;
			return;
		}
		int num = Mathf.Max(0, (int)Math.Round((now - _lastQueueUpdateTime) * 1000f));
		if (num > 0)
		{
			_estimatedQueueMs = Mathf.Max(0, _estimatedQueueMs - num);
			_lastQueueUpdateTime = now;
		}
	}

	private void PrepareStrength(char channel, int eventStrength)
	{
		AutoStrengthMode autoStrengthMode = ModConfig.AutoStrengthMode.Value;
		if (ModConfig.AllowStrengthControl.Value)
		{
			autoStrengthMode = AutoStrengthMode.EventScaled;
		}
		if (autoStrengthMode == AutoStrengthMode.Off || eventStrength <= 0)
		{
			return;
		}
		StrengthState strength = _server.Strength;
		int channel2 = ((channel == 'A') ? 1 : 2);
		int num = ((channel == 'A') ? strength.ACurrent : strength.BCurrent);
		int num2 = ((channel == 'A') ? strength.AMax : strength.BMax);
		int num3 = Mathf.Clamp(ModConfig.MinimumChannelStrength.Value, 0, 200);
		int num4 = ((autoStrengthMode == AutoStrengthMode.MinimumOnly) ? Mathf.Max(num, num3) : Mathf.Max(num3, eventStrength));
		if (num2 > 0)
		{
			num4 = Mathf.Min(num4, num2);
		}
		num4 = Mathf.Clamp(num4, 0, 200);
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		int num5 = ((channel == 'A') ? _lastStrengthA : _lastStrengthB);
		float num6 = ((channel == 'A') ? _lastStrengthTimeA : _lastStrengthTimeB);
		if (num5 < 0 || Mathf.Abs(num4 - num5) >= 2 || !(realtimeSinceStartup - num6 < 0.35f))
		{
			_server.SetStrength(channel2, num4);
			if (channel == 'A')
			{
				_lastStrengthA = num4;
				_lastStrengthTimeA = realtimeSinceStartup;
			}
			else
			{
				_lastStrengthB = num4;
				_lastStrengthTimeB = realtimeSinceStartup;
			}
		}
	}
}
internal sealed class ControlPanel
{
	private readonly DGLabSocketServer _server;

	private readonly StimController _stim;

	private Rect _window;

	private Vector2 _scroll;

	private Texture2D _qrTexture;

	private string _qrText;

	private bool _visible;

	private bool _cursorSaved;

	private bool _previousCursorVisible;

	private CursorLockMode _previousLockState;

	private bool _draftsInitialized;

	private string _hostDraft;

	private string _portDraft;

	private string _publishUriDraft;

	private string _remoteUriDraft;

	private string _remoteCodeDraft;

	private string _panelKeyDraft;

	private string _stopKeyDraft;

	private string _settingsMessage;

	private int _panelTab;

	private int _selectedProfileIndex;

	private int _selectedWaveIndex;

	private string _manualStrengthA;

	private string _manualStrengthB;

	internal bool Visible => _visible;

	internal ControlPanel(DGLabSocketServer server, StimController stim)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		_server = server;
		_stim = stim;
		_window = new Rect(40f, 40f, 560f, 760f);
		_scroll = Vector2.zero;
		_visible = false;
		_settingsMessage = "";
		_panelTab = 0;
		_selectedProfileIndex = 0;
		_selectedWaveIndex = 0;
		_manualStrengthA = "20";
		_manualStrengthB = "20";
	}

	internal void ToggleVisible()
	{
		SetVisible(!_visible);
	}

	internal void SetVisible(bool visible)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		if (_visible != visible)
		{
			_visible = visible;
			if (_visible)
			{
				InitDrafts();
				_previousCursorVisible = Cursor.visible;
				_previousLockState = Cursor.lockState;
				_cursorSaved = true;
				UnlockCursor();
			}
			else if (_cursorSaved)
			{
				Cursor.visible = _previousCursorVisible;
				Cursor.lockState = _previousLockState;
				_cursorSaved = false;
			}
		}
	}

	internal void UpdateCursor()
	{
		if (_visible)
		{
			UnlockCursor();
		}
	}

	private static void UnlockCursor()
	{
		Cursor.visible = true;
		Cursor.lockState = (CursorLockMode)0;
	}

	internal void Draw()
	{
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Expected O, but got Unknown
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		if (_visible)
		{
			float num = Mathf.Max(420f, (float)Screen.width - 20f);
			float num2 = Mathf.Max(360f, (float)Screen.height * 0.85f);
			((Rect)(ref _window)).width = Mathf.Min(((Rect)(ref _window)).width, num);
			((Rect)(ref _window)).height = Mathf.Min(((Rect)(ref _window)).height, num2);
			if (((Rect)(ref _window)).xMax > (float)Screen.width)
			{
				((Rect)(ref _window)).x = Mathf.Max(0f, (float)Screen.width - ((Rect)(ref _window)).width - 10f);
			}
			if (((Rect)(ref _window)).yMax > (float)Screen.height)
			{
				((Rect)(ref _window)).y = Mathf.Max(0f, (float)Screen.height - ((Rect)(ref _window)).height - 10f);
			}
			_window = GUI.Window(88991, _window, new WindowFunction(DrawWindow), "郊狼 3.0 连接面板");
		}
	}

	private void DrawWindow(int id)
	{
		//IL_0008: 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_0042: Unknown result type (might be due to invalid IL or missing references)
		InitDrafts();
		_scroll = GUILayout.BeginScrollView(_scroll, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(Mathf.Max(260f, ((Rect)(ref _window)).height - 34f)) });
		DrawTabs();
		if (_panelTab == 0)
		{
			DrawClientPage();
			FinishWindow();
			return;
		}
		if (_panelTab == 1)
		{
			DrawWaveLibraryPage();
			FinishWindow();
			return;
		}
		if (_panelTab == 2)
		{
			DrawEventMappingPage();
			FinishWindow();
			return;
		}
		if (_panelTab == 3)
		{
			DrawImportExportPage();
			FinishWindow();
			return;
		}
		Section("连接");
		GUILayout.Label("协议:DG-LAB 郊狼 3.0 App Socket", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("模式:" + _server.ConnectionModeText(), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("状态:" + _server.StatusText(), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (!string.IsNullOrEmpty(_server.LastRemoteEndpoint))
		{
			GUILayout.Label("连接来源/远程地址:" + _server.LastRemoteEndpoint, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		EnumCycle<SocketConnectionMode>("连接模式", ModConfig.ConnectionMode);
		GUILayout.Label("二维码地址(用于核对):", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.TextArea(_server.GetQrUrl(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(48f) });
		EnsureQrTexture(_server.GetQrUrl());
		if ((Object)(object)_qrTexture != (Object)null)
		{
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.FlexibleSpace();
			GUILayout.Box((Texture)(object)_qrTexture, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(180f),
				GUILayout.Height(180f)
			});
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
		}
		GUILayout.Label("检测到的电脑 IPv4:" + _server.LocalAddressSummary(), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		string[] localIPv4Addresses = _server.GetLocalIPv4Addresses();
		if (localIPv4Addresses.Length > 0)
		{
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			for (int i = 0; i < localIPv4Addresses.Length && i < 3; i++)
			{
				if (GUILayout.Button("使用 " + localIPv4Addresses[i], (GUILayoutOption[])(object)new GUILayoutOption[0]))
				{
					_hostDraft = localIPv4Addresses[i];
				}
			}
			GUILayout.EndHorizontal();
		}
		TextRow("局域网 IP/域名", ref _hostDraft);
		TextRow("本地端口", ref _portDraft);
		TextRow("公网 Socket URI", ref _publishUriDraft);
		TextRow("远程 Socket URI", ref _remoteUriDraft);
		TextRow("自建 Relay Code", ref _remoteCodeDraft);
		GUILayout.Label("说明:Relay Code 不是 DG-LAB App 原生远程口令,需要你自己的兼容 relay 服务。优先用公网/远程 Socket。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		TextRow("面板键", ref _panelKeyDraft);
		TextRow("急停键", ref _stopKeyDraft);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("保存连接/键位并重启", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			SavePanelSettings(restartServer: true);
		}
		if (GUILayout.Button(_server.IsRunning ? "重启服务" : "启动服务", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_server.Stop();
			_server.Start();
			RefreshQr();
		}
		GUILayout.EndHorizontal();
		if (GUILayout.Button("停止服务", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_server.Stop();
		}
		if (!string.IsNullOrEmpty(_settingsMessage))
		{
			GUILayout.Label(_settingsMessage, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		Section("状态与测试");
		GUILayout.Label("触发总开关:" + (ModConfig.Armed.Value ? "已启用" : "未启用") + "    绑定后自动启用:" + (ModConfig.AutoArmOnBind.Value ? "开启" : "关闭"), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (!ModConfig.Armed.Value)
		{
			GUILayout.Label("注意:真实游戏事件需要启用触发;下方模拟按钮会绕过此开关,只用于测试波形。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button(ModConfig.Armed.Value ? "解除触发" : "启用触发", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ModConfig.Armed.Value = !ModConfig.Armed.Value;
			SaveConfig();
		}
		if (GUILayout.Button("紧急停止", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.EmergencyStop();
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("测试 A", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SendTest('A');
		}
		if (GUILayout.Button("测试 B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SendTest('B');
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("模拟左脚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.TriggerFootstepForced(left: true);
		}
		if (GUILayout.Button("模拟右脚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.TriggerFootstepForced(left: false);
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("模拟奔跑左脚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateRunFootstep(left: true);
		}
		if (GUILayout.Button("模拟奔跑右脚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateRunFootstep(left: false);
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("模拟持续走路 2秒", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateContinuousMovement(run: false);
		}
		if (GUILayout.Button("模拟持续奔跑 2秒", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateContinuousMovement(run: true);
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("模拟跳跃", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateJump();
		}
		if (GUILayout.Button("模拟落地", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateLand();
		}
		if (GUILayout.Button("模拟滑行", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateSlide();
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("模拟包络受击", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateHurt(10);
		}
		if (GUILayout.Button("模拟死亡", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateDeath();
		}
		GUILayout.EndHorizontal();
		StrengthState strength = _server.Strength;
		GUILayout.Label("A 强度:" + strength.ACurrent + " / " + strength.AMax + "    B 强度:" + strength.BCurrent + " / " + strength.BMax, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if ((strength.ACurrent == 0 || strength.BCurrent == 0) && ModConfig.AutoStrengthMode.Value == AutoStrengthMode.Off && !ModConfig.AllowStrengthControl.Value)
		{
			GUILayout.Label("提示:有通道当前强度为 0,且自动调强关闭;该通道可能没有体感。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		StimDiagnostics diagnostics = _stim.Diagnostics;
		GUILayout.Label("连续:" + diagnostics.ContinuousState + "    补包:" + diagnostics.ContinuousRefillCount + "    队列估算:" + diagnostics.EstimatedQueueMs + "ms    Gen:" + diagnostics.ContinuousGeneration, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("Overlay:" + diagnostics.ActiveOverlays, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("连续强度:A 基础 " + diagnostics.ContinuousBaseA + " + " + diagnostics.ContinuousOverlayA + " / B 基础 " + diagnostics.ContinuousBaseB + " + " + diagnostics.ContinuousOverlayB, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("步态:" + diagnostics.MovementState + "    来源:" + diagnostics.LastFootstepSource + "    间隔:" + diagnostics.LastFootstepIntervalMs + "ms", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("计数:左脚 " + diagnostics.LeftFootsteps + " / 右脚 " + diagnostics.RightFootsteps + " / 动画脚步 " + diagnostics.AnimationFootsteps + " / 兜底 " + diagnostics.FallbackFootsteps, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("去重:" + diagnostics.DuplicateFootsteps + " / 奔跑补拍 " + diagnostics.RunSupplementFootsteps + " / 左右间隔 " + diagnostics.LastLeftRightDeltaMs + "ms", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("动作:跳跃 " + diagnostics.JumpCount + " / 落地 " + diagnostics.LandCount + " / 滑行 " + diagnostics.SlideCount + " / 敌脚 " + diagnostics.EnemyFootsteps, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("事件:受击 " + diagnostics.HurtCount + " / 死亡 " + diagnostics.DeathCount, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("最后事件:" + diagnostics.LastEvent + "    通道:" + diagnostics.LastChannel + "    结果:" + diagnostics.LastCommandResult, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("最后拦截:" + diagnostics.LastBlockedReason, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("下一步:" + (diagnostics.NextFootLeft ? "左脚" : "右脚"), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("重置下一步为配置的第一脚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.ResetFootToConfiguredFirst();
		}
		Section("事件开关");
		Toggle("本地玩家受击触发", ModConfig.HurtEnabled);
		Toggle("本地玩家死亡触发", ModConfig.DeathEnabled);
		Toggle("本地玩家脚步触发", ModConfig.LocalFootstepEnabled);
		Toggle("跳跃触发", ModConfig.JumpEnabled);
		Toggle("落地触发", ModConfig.LandEnabled);
		Toggle("滑行触发", ModConfig.SlideEnabled);
		Toggle("跳跃/落地/滑行总开关", ModConfig.LandJumpEnabled);
		Toggle("猎人脚步近距离提示", ModConfig.EnemyFootstepEnabled);
		Section("安全与自动强度");
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("舒适持续", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ApplyComfortPreset();
		}
		if (GUILayout.Button("标准游戏", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ApplyPreset(20, 24, 30, 45, 60, 30, 65);
		}
		if (GUILayout.Button("强惩罚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ApplyPreset(28, 36, 42, 65, 85, 35, 90);
		}
		if (GUILayout.Button("调试同步", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ApplyPreset(36, 45, 55, 70, 90, 35, 90);
		}
		GUILayout.EndHorizontal();
		Toggle("连续模式", ModConfig.ContinuousMode);
		IntSlider("补包间隔 ms", ModConfig.ContinuousSendIntervalMs, 50, 1000);
		IntSlider("Lookahead ms", ModConfig.ContinuousLookaheadMs, 100, 1500);
		IntSlider("停止淡出 ms", ModConfig.ContinuousFadeOutMs, 0, 1500);
		Toggle("绑定后自动启用触发", ModConfig.AutoArmOnBind);
		EnumCycle<AutoStrengthMode>("自动调强模式", ModConfig.AutoStrengthMode);
		Toggle("兼容旧自动调强开关", ModConfig.AllowStrengthControl);
		IntSlider("最低可感强度", ModConfig.MinimumChannelStrength, 0, 80);
		IntSlider("总强度上限", ModConfig.MaxWaveIntensity, 1, 100);
		IntSlider("测试强度", ModConfig.TestIntensity, 1, 100);
		IntSlider("最长持续 ms", ModConfig.MaxEventDurationMs, 100, 6000);
		IntSlider("Clear 延迟 ms", ModConfig.ClearDelayMs, 0, 1000);
		Section("脚步");
		Toggle("第一步为左脚", ModConfig.FirstFootLeft);
		EnumCycle<StimChannel>("左脚通道", ModConfig.LeftFootChannel);
		EnumCycle<StimChannel>("右脚通道", ModConfig.RightFootChannel);
		Toggle("站停后重置左右脚", ModConfig.ResetFootOnIdle);
		IntSlider("站停重置 ms", ModConfig.FootstepIdleResetMs, 100, 3000);
		IntSlider("脚步强度", ModConfig.FootstepIntensity, 1, 50);
		IntSlider("脚步持续 ms", ModConfig.FootstepDurationMs, 25, 600);
		IntSlider("脚步频率", ModConfig.FootstepFrequency, 10, 1000);
		EnumCycle<StimWaveShape>("脚步波形", ModConfig.FootstepWaveShape);
		IntSlider("走路基础强度", ModConfig.WalkBaseIntensity, 0, 50);
		IntSlider("走路基础频率", ModConfig.WalkBaseFrequency, 10, 1000);
		EnumCycle<StimEnvelopeShape>("走路基础波形", ModConfig.WalkBaseShape);
		IntSlider("走路脚步增量", ModConfig.WalkStepBumpIntensity, 0, 60);
		IntSlider("走路增量持续 ms", ModConfig.WalkStepBumpDurationMs, 25, 600);
		IntSlider("动画去重 ms", ModConfig.FootstepDuplicateWindowMs, 0, 200);
		IntSlider("走路最小间隔 ms", ModConfig.WalkFootstepMinIntervalMs, 20, 500);
		IntSlider("奔跑基础强度", ModConfig.RunBaseIntensity, 0, 60);
		IntSlider("奔跑基础频率", ModConfig.RunBaseFrequency, 10, 1000);
		EnumCycle<StimEnvelopeShape>("奔跑基础波形", ModConfig.RunBaseShape);
		IntSlider("奔跑脚步强度", ModConfig.RunFootstepIntensity, 1, 80);
		IntSlider("奔跑持续 ms", ModConfig.RunFootstepDurationMs, 25, 600);
		IntSlider("奔跑脚步增量", ModConfig.RunStepBumpIntensity, 0, 80);
		IntSlider("奔跑增量持续 ms", ModConfig.RunStepBumpDurationMs, 25, 600);
		IntSlider("奔跑最小间隔 ms", ModConfig.RunFootstepMinIntervalMs, 20, 500);
		Toggle("兜底脚步补发", ModConfig.FallbackFootstepSupplement);
		IntSlider("兜底等待 ms", ModConfig.FallbackFootstepNoAnimationMs, 100, 2000);
		Toggle("奔跑节奏补拍", ModConfig.RunCadenceSupplement);
		IntSlider("奔跑补拍间隔 ms", ModConfig.RunSupplementIntervalMs, 55, 500);
		Section("动作");
		EnumCycle<StimChannelMode>("跳跃通道", ModConfig.JumpChannelMode);
		IntSlider("跳跃强度", ModConfig.JumpIntensity, 1, 80);
		IntSlider("跳跃持续 ms", ModConfig.JumpDurationMs, 25, 1000);
		IntSlider("跳跃频率", ModConfig.JumpFrequency, 10, 1000);
		IntSlider("跳跃冷却 ms", ModConfig.JumpCooldownMs, 40, 2000);
		EnumCycle<StimChannelMode>("落地通道", ModConfig.LandChannelMode);
		IntSlider("落地强度", ModConfig.LandIntensity, 1, 80);
		IntSlider("落地持续 ms", ModConfig.LandDurationMs, 25, 1000);
		IntSlider("落地频率", ModConfig.LandFrequency, 10, 1000);
		EnumCycle<StimEnvelopeShape>("落地包络", ModConfig.LandEnvelope);
		IntSlider("落地冷却 ms", ModConfig.LandCooldownMs, 40, 2000);
		EnumCycle<StimChannelMode>("滑行通道", ModConfig.SlideChannelMode);
		IntSlider("滑行强度", ModConfig.SlideIntensity, 1, 80);
		IntSlider("滑行持续 ms", ModConfig.SlideDurationMs, 25, 1000);
		IntSlider("滑行频率", ModConfig.SlideFrequency, 10, 1000);
		EnumCycle<StimEnvelopeShape>("滑行包络", ModConfig.SlideEnvelope);
		IntSlider("滑行冷却 ms", ModConfig.SlideCooldownMs, 40, 2000);
		Section("受击");
		EnumCycle<StimChannelMode>("受击通道", ModConfig.HurtChannelMode);
		IntSlider("受击基础强度", ModConfig.HurtMinIntensity, 1, 100);
		IntSlider("受击最大强度", ModConfig.HurtMaxIntensity, 1, 100);
		FloatSlider("伤害倍率", ModConfig.HurtDamageMultiplier, 0f, 10f);
		FloatSlider("A 通道倍率", ModConfig.HurtAMultiplier, 0f, 2f);
		FloatSlider("B 通道倍率", ModConfig.HurtBMultiplier, 0f, 2f);
		IntSlider("受击最短 ms", ModConfig.HurtDurationMinMs, 25, 6000);
		IntSlider("受击最长 ms", ModConfig.HurtDurationMaxMs, 25, 6000);
		IntSlider("受击频率", ModConfig.HurtFrequency, 10, 1000);
		EnumCycle<StimEnvelopeShape>("受击包络", ModConfig.HurtEnvelope);
		IntSlider("受击冷却 ms", ModConfig.HurtCooldownMs, 100, 3000);
		Section("死亡");
		EnumCycle<StimChannelMode>("死亡通道", ModConfig.DeathChannelMode);
		EnumCycle<StimWaveShape>("死亡 A 波形", ModConfig.DeathAWaveShape);
		EnumCycle<StimWaveShape>("死亡 B 波形", ModConfig.DeathBWaveShape);
		EnumCycle<StimEnvelopeShape>("死亡包络", ModConfig.DeathEnvelope);
		Toggle("死亡前清空旧队列", ModConfig.DeathClearBeforePulse);
		IntSlider("死亡强度", ModConfig.DeathIntensity, 1, 100);
		IntSlider("死亡持续 ms", ModConfig.DeathDurationMs, 100, 6000);
		IntSlider("死亡频率", ModConfig.DeathFrequency, 10, 1000);
		IntSlider("死亡冷却 ms", ModConfig.DeathCooldownMs, 500, 10000);
		Section("说明");
		GUILayout.Label("电脑不需要蓝牙。手机连接郊狼 3.0,Mod 只负责 Socket。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("公网/远程模式请使用可被手机访问的 ws:// 或 wss:// 地址。正式远程建议 wss。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("DG-LAB App 原生远程口令不是 Socket v2 API,本 Mod 不把它作为稳定主线接入。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		FinishWindow();
	}

	private void FinishWindow()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.EndScrollView();
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 22f));
	}

	private void DrawTabs()
	{
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Toggle(_panelTab == 0, "客户端", GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_panelTab = 0;
		}
		if (GUILayout.Toggle(_panelTab == 1, "波形库", GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_panelTab = 1;
		}
		if (GUILayout.Toggle(_panelTab == 2, "事件映射", GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_panelTab = 2;
		}
		if (GUILayout.Toggle(_panelTab == 3, "导入/导出", GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_panelTab = 3;
		}
		if (GUILayout.Toggle(_panelTab == 4, "事件参数", GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_panelTab = 4;
		}
		GUILayout.EndHorizontal();
	}

	private void DrawClientPage()
	{
		Section("Socket 控制端");
		GUILayout.Label("协议:DG-LAB 郊狼 3.0 App Socket v2。电脑不需要蓝牙,手机 App 负责蓝牙连接主机。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("模式:" + _server.ConnectionModeText(), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("状态:" + _server.StatusText(), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (!string.IsNullOrEmpty(_server.LastRemoteEndpoint))
		{
			GUILayout.Label("连接来源/远程地址:" + _server.LastRemoteEndpoint, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		if (!string.IsNullOrEmpty(_server.LastError))
		{
			GUILayout.Label("最后错误:" + _server.LastError, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		GUILayout.Label("二维码地址:", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.TextArea(_server.GetQrUrl(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(48f) });
		EnsureQrTexture(_server.GetQrUrl());
		if ((Object)(object)_qrTexture != (Object)null)
		{
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.FlexibleSpace();
			GUILayout.Box((Texture)(object)_qrTexture, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(180f),
				GUILayout.Height(180f)
			});
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
		}
		GUILayout.Label("检测到的电脑 IPv4:" + _server.LocalAddressSummary(), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		string[] localIPv4Addresses = _server.GetLocalIPv4Addresses();
		if (localIPv4Addresses.Length > 0)
		{
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			for (int i = 0; i < localIPv4Addresses.Length && i < 3; i++)
			{
				if (GUILayout.Button("使用 " + localIPv4Addresses[i], (GUILayoutOption[])(object)new GUILayoutOption[0]))
				{
					_hostDraft = localIPv4Addresses[i];
				}
			}
			GUILayout.EndHorizontal();
		}
		EnumCycle<SocketConnectionMode>("连接模式", ModConfig.ConnectionMode);
		TextRow("局域网 IP/域名", ref _hostDraft);
		TextRow("本地端口", ref _portDraft);
		TextRow("公网 Socket URI", ref _publishUriDraft);
		TextRow("远程 Socket URI", ref _remoteUriDraft);
		TextRow("自建 Relay Code", ref _remoteCodeDraft);
		GUILayout.Label("Relay Code 是本 Mod 自建 relay 口令,不是 DG-LAB App 原生远程口令。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("保存连接/键位并重启", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			SavePanelSettings(restartServer: true);
		}
		if (GUILayout.Button(_server.IsRunning ? "重启服务" : "启动服务", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_server.Stop();
			_server.Start();
			RefreshQr();
		}
		if (GUILayout.Button("停止服务", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_server.Stop();
		}
		GUILayout.EndHorizontal();
		Section("强度控制");
		StrengthState strength = _server.Strength;
		GUILayout.Label("A 当前/上限:" + strength.ACurrent + " / " + strength.AMax + "    B 当前/上限:" + strength.BCurrent + " / " + strength.BMax, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		TextRow("手动 A 强度", ref _manualStrengthA);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("设置 A", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			SetManualStrength(1, _manualStrengthA);
		}
		if (GUILayout.Button("A -5", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			AdjustStrength(1, -5);
		}
		if (GUILayout.Button("A +5", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			AdjustStrength(1, 5);
		}
		if (GUILayout.Button("Clear A", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_server.ClearChannel(1);
		}
		GUILayout.EndHorizontal();
		TextRow("手动 B 强度", ref _manualStrengthB);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("设置 B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			SetManualStrength(2, _manualStrengthB);
		}
		if (GUILayout.Button("B -5", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			AdjustStrength(2, -5);
		}
		if (GUILayout.Button("B +5", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			AdjustStrength(2, 5);
		}
		if (GUILayout.Button("Clear B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_server.ClearChannel(2);
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("启用触发", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ModConfig.Armed.Value = true;
			SaveConfig();
		}
		if (GUILayout.Button("解除触发", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			ModConfig.Armed.Value = false;
			SaveConfig();
		}
		if (GUILayout.Button("紧急停止", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.EmergencyStop();
		}
		GUILayout.EndHorizontal();
		Section("快速测试");
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("测试 A", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SendTest('A');
		}
		if (GUILayout.Button("测试 B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SendTest('B');
		}
		GUILayout.EndHorizontal();
		WavePreset wavePreset = SelectedWave();
		GUILayout.Label("选中波形:" + ((wavePreset == null) ? "无" : StimProfileManager.DisplayName(wavePreset)), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("播放选中波形 A", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			StimProfileManager.SendWave(_server, wavePreset, 'A');
		}
		if (GUILayout.Button("播放选中波形 B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			StimProfileManager.SendWave(_server, wavePreset, 'B');
		}
		if (GUILayout.Button("Clear A/B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_server.ClearAll();
		}
		GUILayout.EndHorizontal();
		if (!string.IsNullOrEmpty(_settingsMessage))
		{
			GUILayout.Label(_settingsMessage, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		if (!string.IsNullOrEmpty(StimProfileManager.LastMessage))
		{
			GUILayout.Label(StimProfileManager.LastMessage, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
	}

	private void DrawWaveLibraryPage()
	{
		Section("波形包");
		DrawProfileSelector();
		StimProfile stimProfile = SelectedProfile();
		if (stimProfile == null)
		{
			GUILayout.Label("没有可用波形包。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			return;
		}
		GUILayout.Label("当前波形包:" + StimProfileManager.DisplayName(stimProfile) + "    版本:" + stimProfile.version + "    上限:" + stimProfile.maxWaveIntensity, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("应用此波形包", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			StimProfileManager.ApplyProfile(stimProfile);
			_settingsMessage = StimProfileManager.LastMessage;
		}
		if (GUILayout.Button("刷新波形包", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			StimProfileManager.RefreshProfiles();
			ClampSelections();
		}
		GUILayout.EndHorizontal();
		Section("波形列表");
		if (stimProfile.waves == null || stimProfile.waves.Count == 0)
		{
			GUILayout.Label("该波形包没有波形。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			return;
		}
		for (int i = 0; i < stimProfile.waves.Count; i++)
		{
			WavePreset wave = stimProfile.waves[i];
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (GUILayout.Toggle(_selectedWaveIndex == i, StimProfileManager.DisplayName(wave), GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) }))
			{
				_selectedWaveIndex = i;
			}
			GUILayout.Label(WaveSummary(wave), (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.EndHorizontal();
		}
		WavePreset wavePreset = SelectedWave();
		if (wavePreset != null)
		{
			Section("波形测试");
			GUILayout.Label("名称:" + StimProfileManager.DisplayName(wavePreset), (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("类型:" + wavePreset.type + " / " + wavePreset.shape + "    通道建议:" + wavePreset.channel, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("频率:" + wavePreset.frequency + "    强度:" + wavePreset.minStrength + "-" + wavePreset.maxStrength + "    时长:" + wavePreset.durationMs + "ms", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (GUILayout.Button("测试 A", (GUILayoutOption[])(object)new GUILayoutOption[0]))
			{
				StimProfileManager.SendWave(_server, wavePreset, 'A');
			}
			if (GUILayout.Button("测试 B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
			{
				StimProfileManager.SendWave(_server, wavePreset, 'B');
			}
			if (GUILayout.Button("测试 A+B", (GUILayoutOption[])(object)new GUILayoutOption[0]))
			{
				StimProfileManager.SendWave(_server, wavePreset, 'A');
				StimProfileManager.SendWave(_server, wavePreset, 'B');
			}
			GUILayout.EndHorizontal();
		}
		if (!string.IsNullOrEmpty(StimProfileManager.LastMessage))
		{
			GUILayout.Label(StimProfileManager.LastMessage, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
	}

	private void DrawEventMappingPage()
	{
		Section("事件映射");
		DrawProfileSelector();
		StimProfile stimProfile = SelectedProfile();
		if (stimProfile == null || stimProfile.events == null || stimProfile.events.Count == 0)
		{
			GUILayout.Label("当前波形包没有事件映射。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			return;
		}
		GUILayout.Label("这里展示波形包对事件的推荐映射;应用波形包会把持续状态参数写入配置。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		for (int i = 0; i < stimProfile.events.Count; i++)
		{
			EventRule eventRule = stimProfile.events[i];
			GUILayout.Label(eventRule.eventName + " -> " + eventRule.waveName + "    通道:" + eventRule.channelMode + "    倍率:" + eventRule.strengthMultiplier.ToString("0.00"), (GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (!string.IsNullOrEmpty(eventRule.note))
			{
				GUILayout.Label("  " + eventRule.note, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			}
		}
		Section("当前诊断");
		StimDiagnostics diagnostics = _stim.Diagnostics;
		GUILayout.Label("连续状态:" + diagnostics.ContinuousState + "    补包:" + diagnostics.ContinuousRefillCount + "    队列估算:" + diagnostics.EstimatedQueueMs + "ms    Gen:" + diagnostics.ContinuousGeneration, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("连续强度:A " + diagnostics.ContinuousBaseA + "+" + diagnostics.ContinuousOverlayA + " / B " + diagnostics.ContinuousBaseB + "+" + diagnostics.ContinuousOverlayB, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("脚步:左 " + diagnostics.LeftFootsteps + " / 右 " + diagnostics.RightFootsteps + " / 来源 " + diagnostics.LastFootstepSource + " / 下一步 " + (diagnostics.NextFootLeft ? "左" : "右"), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("动作:跳跃 " + diagnostics.JumpCount + " / 落地 " + diagnostics.LandCount + " / 滑行 " + diagnostics.SlideCount + " / 受击 " + diagnostics.HurtCount + " / 死亡 " + diagnostics.DeathCount, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		Section("模拟事件");
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("模拟左脚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.TriggerFootstepForced(left: true);
		}
		if (GUILayout.Button("模拟右脚", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.TriggerFootstepForced(left: false);
		}
		if (GUILayout.Button("模拟走路 2秒", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateContinuousMovement(run: false);
		}
		if (GUILayout.Button("模拟奔跑 2秒", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateContinuousMovement(run: true);
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("模拟跳跃", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateJump();
		}
		if (GUILayout.Button("模拟落地", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateLand();
		}
		if (GUILayout.Button("模拟滑行", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateSlide();
		}
		if (GUILayout.Button("模拟受击", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateHurt(10);
		}
		if (GUILayout.Button("模拟死亡", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			_stim.SimulateDeath();
		}
		GUILayout.EndHorizontal();
	}

	private void DrawImportExportPage()
	{
		Section("导入/导出");
		GUILayout.Label("导入目录:", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.TextArea(StimProfileManager.ProfilesDirectory, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) });
		GUILayout.Label("支持 DGLabPunishProfile.json、原始 HEX JSON 数组和 .pulse 文本。第三方项目建议只导入数据,不复制代码。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("HEX 示例:type=hex,hex=[\"0A0A0A0A64646464\"];.pulse 可每行写 16 位 HEX 或 frequency strength。", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("刷新导入目录", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			StimProfileManager.RefreshProfiles();
			ClampSelections();
		}
		if (GUILayout.Button("导出当前配置", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			try
			{
				StimProfileManager.ExportCurrentConfig();
			}
			catch (Exception ex)
			{
				StimProfileManager.LastMessage = "导出失败:" + ex.Message;
			}
		}
		GUILayout.EndHorizontal();
		DrawProfileSelector();
		if (GUILayout.Button("应用选中的导入/内置波形包", (GUILayoutOption[])(object)new GUILayoutOption[0]))
		{
			StimProfileManager.ApplyProfile(SelectedProfile());
			_settingsMessage = StimProfileManager.LastMessage;
		}
		if (!string.IsNullOrEmpty(_settingsMessage))
		{
			GUILayout.Label(_settingsMessage, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		if (!string.IsNullOrEmpty(StimProfileManager.LastMessage))
		{
			GUILayout.Label(StimProfileManager.LastMessage, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		Section("当前核心配置");
		GUILayout.Label("连续模式:" + ModConfig.ContinuousMode.Value + "    自动调强:" + ModConfig.AutoStrengthMode.Value, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("补包/Lookahead:" + ModConfig.ContinuousSendIntervalMs.Value + " / " + ModConfig.ContinuousLookaheadMs.Value + " ms", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("走路基础/增量:" + ModConfig.WalkBaseIntensity.Value + " / " + ModConfig.WalkStepBumpIntensity.Value, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("奔跑基础/增量:" + ModConfig.RunBaseIntensity.Value + " / " + ModConfig.RunStepBumpIntensity.Value, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("受击:" + ModConfig.HurtMinIntensity.Value + "-" + ModConfig.HurtMaxIntensity.Value + " / " + ModConfig.HurtDurationMaxMs.Value + "ms", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("死亡:" + ModConfig.DeathIntensity.Value + " / " + ModConfig.DeathDurationMs.Value + "ms", (GUILayoutOption[])(object)new GUILayoutOption[0]);
	}

	private void DrawProfileSelector()
	{
		ClampSelections();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("波形包", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
		if (GUILayout.Button("<", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(32f) }))
		{
			_selectedProfileIndex--;
			ClampSelections();
		}
		StimProfile stimProfile = SelectedProfile();
		GUILayout.Label((stimProfile == null) ? "无" : StimProfileManager.DisplayName(stimProfile), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) });
		if (GUILayout.Button(">", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(32f) }))
		{
			_selectedProfileIndex++;
			ClampSelections();
		}
		GUILayout.EndHorizontal();
	}

	private StimProfile SelectedProfile()
	{
		ClampSelections();
		if (StimProfileManager.Profiles.Count == 0)
		{
			return null;
		}
		return StimProfileManager.Profiles[_selectedProfileIndex];
	}

	private WavePreset SelectedWave()
	{
		StimProfile stimProfile = SelectedProfile();
		if (stimProfile == null || stimProfile.waves == null || stimProfile.waves.Count == 0)
		{
			return null;
		}
		ClampSelections();
		return stimProfile.waves[_selectedWaveIndex];
	}

	private void ClampSelections()
	{
		if (StimProfileManager.Profiles.Count == 0)
		{
			_selectedProfileIndex = 0;
			_selectedWaveIndex = 0;
			return;
		}
		if (_selectedProfileIndex < 0)
		{
			_selectedProfileIndex = StimProfileManager.Profiles.Count - 1;
		}
		if (_selectedProfileIndex >= StimProfileManager.Profiles.Count)
		{
			_selectedProfileIndex = 0;
		}
		StimProfile stimProfile = StimProfileManager.Profiles[_selectedProfileIndex];
		int num = ((stimProfile != null && stimProfile.waves != null) ? stimProfile.waves.Count : 0);
		if (num == 0)
		{
			_selectedWaveIndex = 0;
			return;
		}
		if (_selectedWaveIndex < 0)
		{
			_selectedWaveIndex = num - 1;
		}
		if (_selectedWaveIndex >= num)
		{
			_selectedWaveIndex = 0;
		}
	}

	private string WaveSummary(WavePreset wave)
	{
		if (wave == null)
		{
			return "";
		}
		if (wave.hex != null && wave.hex.Count > 0)
		{
			return "HEX " + wave.hex.Count + " 条 / 建议 " + wave.channel;
		}
		return wave.type + " " + wave.shape + " / " + wave.frequency + "Hz / " + wave.minStrength + "-" + wave.maxStrength + " / " + wave.durationMs + "ms";
	}

	private void SetManualStrength(int channel, string value)
	{
		if (!int.TryParse(value, out var result))
		{
			_settingsMessage = "强度必须是数字。";
			return;
		}
		result = Mathf.Clamp(result, 0, 200);
		bool flag = _server.SetStrength(channel, result);
		_settingsMessage = (flag ? ("已设置 " + ((channel == 1) ? "A" : "B") + " 强度为 " + result) : "设置失败:App 尚未绑定或连接不可用。");
	}

	private void AdjustStrength(int channel, int delta)
	{
		StrengthState strength = _server.Strength;
		int num = ((channel == 1) ? strength.ACurrent : strength.BCurrent);
		int num2 = Mathf.Clamp(num + delta, 0, 200);
		if (channel == 1)
		{
			_manualStrengthA = num2.ToString();
		}
		else
		{
			_manualStrengthB = num2.ToString();
		}
		bool flag = _server.SetStrength(channel, num2);
		_settingsMessage = (flag ? ("已调整 " + ((channel == 1) ? "A" : "B") + " 强度为 " + num2) : "调整失败:App 尚未绑定或连接不可用。");
	}

	private void InitDrafts()
	{
		//IL_0085: 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)
		if (!_draftsInitialized)
		{
			_hostDraft = ModConfig.AdvertiseHost.Value;
			if (string.IsNullOrEmpty(_hostDraft))
			{
				_hostDraft = _server.GetAdvertiseHost();
			}
			_portDraft = ModConfig.Port.Value.ToString();
			_publishUriDraft = ModConfig.PublishSocketUri.Value;
			_remoteUriDraft = ModConfig.RemoteServerUri.Value;
			_remoteCodeDraft = ModConfig.RemotePairCode.Value;
			_panelKeyDraft = ((object)ModConfig.PanelKey.Value).ToString();
			_stopKeyDraft = ((object)ModConfig.EmergencyStopKey.Value).ToString();
			_draftsInitialized = true;
		}
	}

	private void SavePanelSettings(bool restartServer)
	{
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		if (!int.TryParse(_portDraft, out var result) || result < 1 || result > 65535)
		{
			_settingsMessage = "端口无效,应为 1-65535。";
			return;
		}
		if (!TryParseKey(_panelKeyDraft, out var keyCode))
		{
			_settingsMessage = "面板键无效,例如 P、F8、Insert。";
			return;
		}
		if (!TryParseKey(_stopKeyDraft, out var keyCode2))
		{
			_settingsMessage = "急停键无效,例如 I、F9、BackQuote。";
			return;
		}
		ModConfig.AdvertiseHost.Value = (_hostDraft ?? "").Trim();
		ModConfig.Port.Value = result;
		ModConfig.PublishSocketUri.Value = (_publishUriDraft ?? "").Trim();
		ModConfig.RemoteServerUri.Value = (_remoteUriDraft ?? "").Trim();
		ModConfig.RemotePairCode.Value = (_remoteCodeDraft ?? "").Trim();
		ModConfig.PanelKey.Value = keyCode;
		ModConfig.EmergencyStopKey.Value = keyCode2;
		SaveConfig();
		RefreshQr();
		if (restartServer)
		{
			_server.Stop();
			_server.Start();
		}
		_settingsMessage = "设置已保存。当前二维码已刷新。";
	}

	private static bool TryParseKey(string value, out KeyCode keyCode)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected I4, but got Unknown
		try
		{
			keyCode = (KeyCode)(int)(KeyCode)Enum.Parse(typeof(KeyCode), (value ?? "").Trim(), ignoreCase: true);
			return true;
		}
		catch
		{
			keyCode = (KeyCode)0;
			return false;
		}
	}

	private static void SaveConfig()
	{
		try
		{
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				((BaseUnityPlugin)Plugin.Instance).Config.Save();
			}
		}
		catch
		{
		}
	}

	private static void Section(string label)
	{
		GUILayout.Space(8f);
		GUILayout.Label("=== " + label + " ===", (GUILayoutOption[])(object)new GUILayoutOption[0]);
	}

	private void TextRow(string label, ref string value)
	{
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
		value = GUILayout.TextField(value ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(360f) });
		GUILayout.EndHorizontal();
	}

	private void Toggle(string label, ConfigEntry<bool> entry)
	{
		bool flag = GUILayout.Toggle(entry.Value, label, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (flag != entry.Value)
		{
			entry.Value = flag;
			SaveConfig();
		}
	}

	private void ApplyPreset(int footstep, int slide, int jump, int land, int death, int minimum, int hurtMax)
	{
		ModConfig.AutoStrengthMode.Value = AutoStrengthMode.EventScaled;
		ModConfig.ContinuousMode.Value = true;
		ModConfig.MinimumChannelStrength.Value = minimum;
		ModConfig.MaxWaveIntensity.Value = Mathf.Max(hurtMax, death);
		ModConfig.FootstepIntensity.Value = footstep;
		ModConfig.FootstepDurationMs.Value = ((footstep >= 24) ? 320 : 250);
		ModConfig.FootstepWaveShape.Value = StimWaveShape.Sin;
		ModConfig.WalkBaseIntensity.Value = Mathf.Max(4, footstep / 2);
		ModConfig.WalkBaseFrequency.Value = 25;
		ModConfig.WalkBaseShape.Value = StimEnvelopeShape.Tremor;
		ModConfig.WalkStepBumpIntensity.Value = Mathf.Max(8, footstep - 4);
		ModConfig.WalkStepBumpDurationMs.Value = 160;
		ModConfig.WalkFootstepMinIntervalMs.Value = 90;
		ModConfig.RunBaseIntensity.Value = Mathf.Max(6, footstep / 2 + 5);
		ModConfig.RunBaseFrequency.Value = 260;
		ModConfig.RunBaseShape.Value = StimEnvelopeShape.SawBurst;
		ModConfig.RunFootstepIntensity.Value = Mathf.Max(footstep + 4, footstep);
		ModConfig.RunFootstepDurationMs.Value = ((footstep >= 28) ? 170 : 140);
		ModConfig.RunStepBumpIntensity.Value = Mathf.Max(12, footstep);
		ModConfig.RunStepBumpDurationMs.Value = 110;
		ModConfig.RunFootstepMinIntervalMs.Value = 55;
		ModConfig.SlideIntensity.Value = slide;
		ModConfig.JumpIntensity.Value = jump;
		ModConfig.LandIntensity.Value = land;
		ModConfig.HurtMaxIntensity.Value = hurtMax;
		ModConfig.HurtDurationMinMs.Value = ((hurtMax >= 80) ? 1800 : 1500);
		ModConfig.HurtDurationMaxMs.Value = ((hurtMax >= 80) ? 4500 : 3500);
		ModConfig.HurtFrequency.Value = 60;
		ModConfig.DeathIntensity.Value = death;
		ModConfig.DeathDurationMs.Value = ((death >= 80) ? 5000 : 4000);
		ModConfig.DeathFrequency.Value = 150;
		ModConfig.MaxEventDurationMs.Value = Mathf.Max(ModConfig.DeathDurationMs.Value, ModConfig.HurtDurationMaxMs.Value);
		ModConfig.MaxQueuedPulseItems.Value = ((death >= 80) ? 55 : 45);
		ModConfig.TestIntensity.Value = minimum;
		ModConfig.HurtEnvelope.Value = StimEnvelopeShape.RampUpHoldDown;
		ModConfig.LandEnvelope.Value = StimEnvelopeShape.SingleTap;
		ModConfig.SlideEnvelope.Value = StimEnvelopeShape.Tremor;
		ModConfig.DeathEnvelope.Value = StimEnvelopeShape.DeathWave;
		SaveConfig();
		_settingsMessage = "已应用预设,可继续微调各事件强度。";
	}

	private void ApplyComfortPreset()
	{
		ModConfig.AutoStrengthMode.Value = AutoStrengthMode.EventScaled;
		ModConfig.ContinuousMode.Value = true;
		ModConfig.MinimumChannelStrength.Value = 10;
		ModConfig.MaxWaveIntensity.Value = 40;
		ModConfig.MaxEventDurationMs.Value = 3500;
		ModConfig.MaxQueuedPulseItems.Value = 35;
		ModConfig.ContinuousSendIntervalMs.Value = 80;
		ModConfig.ContinuousLookaheadMs.Value = 120;
		ModConfig.ContinuousFadeOutMs.Value = 450;
		ModConfig.FootstepIntensity.Value = 12;
		ModConfig.FootstepDurationMs.Value = 220;
		ModConfig.FootstepWaveShape.Value = StimWaveShape.Sin;
		ModConfig.WalkBaseIntensity.Value = 10;
		ModConfig.WalkBaseFrequency.Value = 25;
		ModConfig.WalkBaseShape.Value = StimEnvelopeShape.Tremor;
		ModConfig.WalkStepBumpIntensity.Value = 8;
		ModConfig.WalkStepBumpDurationMs.Value = 150;
		ModConfig.WalkFootstepMinIntervalMs.Value = 90;
		ModConfig.RunBaseIntensity.Value = 12;
		ModConfig.RunBaseFrequency.Value = 240;
		ModConfig.RunBaseShape.Value = StimEnvelopeShape.SawBurst;
		ModConfig.RunFootstepIntensity.Value = 14;
		ModConfig.RunFootstepDurationMs.Value = 130;
		ModConfig.RunStepBumpIntensity.Value = 10;
		ModConfig.RunStepBumpDurationMs.Value = 100;
		ModConfig.RunFootstepMinIntervalMs.Value = 55;
		ModConfig.SlideIntensity.Value = 14;
		ModConfig.JumpIntensity.Value = 16;
		ModConfig.LandIntensity.Value = 18;
		ModConfig.HurtMinIntensity.Value = 10;
		ModConfig.HurtMaxIntensity.Value = 40;
		ModConfig.HurtDurationMinMs.Value = 1200;
		ModConfig.HurtDurationMaxMs.Value = 3000;
		ModConfig.HurtFrequency.Value = 60;
		ModConfig.DeathIntensity.Value = 40;
		ModConfig.DeathDurationMs.Value = 3500;
		ModConfig.DeathFrequency.Value = 150;
		ModConfig.TestIntensity.Value = 10;
		ModConfig.HurtEnvelope.Value = StimEnvelopeShape.RampUpHoldDown;
		ModConfig.LandEnvelope.Value = StimEnvelopeShape.SingleTap;
		ModConfig.SlideEnvelope.Value = StimEnvelopeShape.Tremor;
		ModConfig.DeathEnvelope.Value = StimEnvelopeShape.DeathWave;
		SaveConfig();
		_settingsMessage = "已应用舒适模式:最高 40,基础强度 10。";
	}

	private void IntSlider(string label, ConfigEntry<int> entry, int min, int max)
	{
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label(label + ":" + entry.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
		int num = (int)Math.Round(GUILayout.HorizontalSlider((float)entry.Value, (float)min, (float)max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) }));
		if (num != entry.Value)
		{
			entry.Value = num;
			SaveConfig();
		}
		GUILayout.EndHorizontal();
	}

	private void FloatSlider(string label, ConfigEntry<float> entry, float min, float max)
	{
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label(label + ":" + entry.Value.ToString("0.00"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
		float num = GUILayout.HorizontalSlider(entry.Value, min, max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
		num = (float)Math.Round(num, 2);
		if (Math.Abs(num - entry.Value) > 0.001f)
		{
			entry.Value = num;
			SaveConfig();
		}
		GUILayout.EndHorizontal();
	}

	private void EnumCycle<T>(string label, ConfigEntry<T> entry)
	{
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
		if (GUILayout.Button(entry.Value.ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) }))
		{
			T[] array = (T[])Enum.GetValues(typeof(T));
			int num = Array.IndexOf(array, entry.Value);
			if (num < 0)
			{
				num = 0;
			}
			entry.Value = array[(num + 1) % array.Length];
			SaveConfig();
			RefreshQr();
		}
		GUILayout.EndHorizontal();
	}

	private void RefreshQr()
	{
		_qrText = null;
		if ((Object)(object)_qrTexture != (Object)null)
		{
			Object.Destroy((Object)(object)_qrTexture);
			_qrTexture = null;
		}
	}

	private void EnsureQrTexture(string text)
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Expected O, but got Unknown
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_qrTexture != (Object)null && _qrText == text)
		{
			return;
		}
		RefreshQr();
		_qrText = text;
		try
		{
			QrCode val = QrCode.EncodeText(text, Ecc.Medium);
			int num = 4;
			int num2 = Math.Max(3, 180 / (val.Size + num * 2));
			int num3 = (val.Size + num * 2) * num2;
			Texture2D val2 = new Texture2D(num3, num3, (TextureFormat)4, false);
			Color32 val3 = default(Color32);
			((Color32)(ref val3))..ctor((byte)0, (byte)0, (byte)0, byte.MaxValue);
			Color32 val4 = default(Color32);
			((Color32)(ref val4))..ctor(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			for (int i = 0; i < num3; i++)
			{
				for (int j = 0; j < num3; j++)
				{
					int num4 = j / num2 - num;
					int num5 = i / num2 - num;
					bool flag = num4 >= 0 && num5 >= 0 && num4 < val.Size && num5 < val.Size && val.GetModule(num4, num5);
					val2.SetPixel(j, num3 - 1 - i, Color32.op_Implicit(flag ? val3 : val4));
				}
			}
			val2.Apply(false, true);
			_qrTexture = val2;
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to generate QR texture: " + ex.Message));
		}
	}
}
internal sealed class DgLabMessage
{
	[JsonProperty("type")]
	public string Type { get; set; }

	[JsonProperty("clientId")]
	public string ClientId { get; set; }

	[JsonProperty("targetId")]
	public string TargetId { get; set; }

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

	public static DgLabMessage Create(string type, string clientId, string targetId, string message)
	{
		DgLabMessage dgLabMessage = new DgLabMessage();
		dgLabMessage.Type = type;
		dgLabMessage.ClientId = clientId;
		dgLabMessage.TargetId = targetId;
		dgLabMessage.Message = message;
		return dgLabMessage;
	}

	public string ToJson()
	{
		return JsonConvert.SerializeObject((object)this);
	}
}
internal sealed class StrengthState
{
	public int ACurrent;

	public int BCurrent;

	public int AMax;

	public int BMax;

	public StrengthState Clone()
	{
		StrengthState strengthState = new StrengthState();
		strengthState.ACurrent = ACurrent;
		strengthState.BCurrent = BCurrent;
		strengthState.AMax = AMax;
		strengthState.BMax = BMax;
		return strengthState;
	}
}
internal sealed class DGLabSocketServer
{
	internal sealed class AppSocketBehavior : WebSocketBehavior
	{
		public DGLabSocketServer Owner { get; set; }

		public string RemoteEndpoint
		{
			get
			{
				try
				{
					return (((WebSocketBehavior)this).Context != null && ((WebSocketBehavior)this).Context.UserEndPoint != null) ? ((WebSocketBehavior)this).Context.UserEndPoint.ToString() : "";
				}
				catch
				{
					return "";
				}
			}
		}

		protected override void OnOpen()
		{
			Owner.OnOpen(this);
		}

		protected override void OnMessage(MessageEventArgs e)
		{
			Owner.OnMessage(this, e.Data);
		}

		protected override void OnClose(CloseEventArgs e)
		{
			Owner.OnClose(this);
		}

		public void SendText(string text)
		{
			((WebSocketBehavior)this).Send(text);
		}
	}

	private static readonly Regex StrengthRegex = new Regex("^strength-(\\d+)\\+(\\d+)\\+(\\d+)\\+(\\d+)$", RegexOptions.Compiled);

	private static readonly Regex SafeCodeRegex = new Regex("[^A-Za-z0-9_-]", RegexOptions.Compiled);

	private readonly object _sync = new object();

	private string _terminalId;

	private WebSocketServer _server;

	private WebSocket _remoteSocket;

	private AppSocketBehavior _session;

	private string _appId;

	private bool _bound;

	private bool _remoteConnected;

	private bool _remoteClientIdAssigned;

	private DateTime _lastHeartbeatUtc;

	private StrengthState _strength;

	private string _lastError;

	private string _lastRemoteEndpoint;

	private string _remoteStatus;

	internal string ClientId
	{
		get
		{
			lock (_sync)
			{
				return _terminalId;
			}
		}
	}

	internal bool IsRunning
	{
		get
		{
			if (IsRemoteMode())
			{
				lock (_sync)
				{
					return _remoteSocket != null && _remoteConnected;
				}
			}
			if (_server != null)
			{
				return _server.IsListening;
			}
			return false;
		}
	}

	internal bool IsConnected
	{
		get
		{
			lock (_sync)
			{
				if (IsRemoteMode())
				{
					return _remoteSocket != null && _remoteConnected;
				}
				return _session != null;
			}
		}
	}

	internal bool IsBound
	{
		get
		{
			lock (_sync)
			{
				return _bound && (IsRemoteMode() ? _remoteConnected : (_session != null));
			}
		}
	}

	internal StrengthState Strength
	{
		get
		{
			lock (_sync)
			{
				return _strength.Clone();
			}
		}
	}

	internal string LastError
	{
		get
		{
			lock (_sync)
			{
				return _lastError;
			}
		}
	}

	internal string LastRemoteEndpoint
	{
		get
		{
			lock (_sync)
			{
				return _lastRemoteEndpoint;
			}
		}
	}

	internal DGLabSocketServer()
	{
		_terminalId = Guid.NewGuid().ToString();
		_appId = "";
		_strength = new StrengthState();
		_lastError = "";
		_lastRemoteEndpoint = "";
		_remoteStatus = "";
	}

	internal void Start()
	{
		if (!IsRunning)
		{
			if (IsRemoteMode())
			{
				StartRemoteClient();
			}
			else
			{
				StartLocalServer();
			}
		}
	}

	private void StartLocalServer()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		int num = Clamp(ModConfig.Port.Value, 1, 65535);
		try
		{
			_server = new WebSocketServer(IPAddress.Any, num);
			_server.AddWebSocketService<AppSocketBehavior>("/", (Action<AppSocketBehavior>)delegate(AppSocketBehavior behavior)
			{
				behavior.Owner = this;
			});
			_server.AddWebSocketService<AppSocketBehavior>("/" + _terminalId, (Action<AppSocketBehavior>)delegate(AppSocketBehavior behavior)
			{
				behavior.Owner = this;
			});
			_server.Start();
			_lastHeartbeatUtc = DateTime.UtcNow;
			lock (_sync)
			{
				_lastError = "";
				_remoteStatus = "";
			}
			Plugin.Log.LogInfo((object)("DG-LAB local Socket server listening on port " + num + " with terminalId " + _terminalId));
		}
		catch (Exception ex)
		{
			_server = null;
			lock (_sync)
			{
				_lastError = ex.Message;
			}
			Plugin.Log.LogError((object)("Failed to start DG-LAB Socket server on port " + num + ": " + ex.Message));
		}
	}

	private void StartRemoteClient()
	{
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		string uri = NormalizeBaseUri(ModConfig.RemoteServerUri.Value);
		if (string.IsNullOrEmpty(uri))
		{
			lock (_sync)
			{
				_lastError = "远程 Socket 服务地址为空。";
				_remoteStatus = _lastError;
				return;
			}
		}
		if (ModConfig.ConnectionMode.Value == SocketConnectionMode.RelayCode)
		{
			string text = SafeRelayCode(ModConfig.RemotePairCode.Value);
			if (!string.IsNullOrEmpty(text))
			{
				lock (_sync)
				{
					_terminalId = text;
				}
			}
		}
		try
		{
			_remoteSocket = new WebSocket(uri, new string[0]);
			_remoteSocket.OnOpen += delegate
			{
				lock (_sync)
				{
					_remoteConnected = true;
					_remoteClientIdAssigned = ModConfig.ConnectionMode.Value == SocketConnectionMode.RelayCode && !string.IsNullOrEmpty(SafeRelayCode(ModConfig.RemotePairCode.Value));
					_bound = false;
					_appId = "";
					_lastError = "";
					_remoteStatus = "已连接远程服务,等待终端 ID/绑定。";
					_lastRemoteEndpoint = uri;
				}
				Plugin.Log.LogInfo((object)("Connected to remote DG-LAB Socket service: " + uri));
			};
			_remoteSocket.OnMessage += delegate(object sender, MessageEventArgs e)
			{
				HandleRemoteMessage(e.Data);
			};
			_remoteSocket.OnClose += delegate(object sender, CloseEventArgs e)
			{
				lock (_sync)
				{
					_remoteConnected = false;
					_remoteClientIdAssigned = false;
					_bound = false;
					_appId = "";
					_strength = new StrengthState();
					_remoteStatus = "远程服务已断开:" + e.Reason;
				}
				Plugin.Log.LogInfo((object)("Remote DG-LAB Socket closed: " + e.Reason));
			};
			_remoteSocket.OnError += delegate(object sender, ErrorEventArgs e)
			{
				lock (_sync)
				{
					_lastError = e.Message;
					_remoteStatus = "远程服务错误:" + e.Message;
				}
				Plugin.Log.LogWarning((object)("Remote DG-LAB Socket error: " + e.Message));
			};
			_remoteSocket.ConnectAsync();
		}
		catch (Exception ex)
		{
			_remoteSocket = null;
			lock (_sync)
			{
				_lastError = ex.Message;
				_remoteStatus = "远程服务启动失败:" + ex.Message;
			}
			Plugin.Log.LogError((object)("Failed to connect remote DG-LAB Socket service: " + ex.Message));
		}
	}

	internal void Stop()
	{
		lock (_sync)
		{
			_bound = false;
			_session = null;
			_appId = "";
			_lastRemoteEndpoint = "";
			_remoteConnected = false;
			_remoteClientIdAssigned = false;
		}
		if (_remoteSocket != null)
		{
			try
			{
				_remoteSocket.Close();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to close remote DG-LAB Socket: " + ex.Message));
			}
			_remoteSocket = null;
		}
		if (_server != null)
		{
			try
			{
				_server.Stop();
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("Failed to stop DG-LAB Socket server: " + ex2.Message));
			}
			_server = null;
		}
	}

	internal void Tick()
	{
		if (!IsBound)
		{
			return;
		}
		int num = Math.Max(5000, ModConfig.HeartbeatIntervalMs.Value);
		if ((DateTime.UtcNow - _lastHeartbeatUtc).TotalMilliseconds >= (double)num)
		{
			if (IsRemoteMode())
			{
				SendRemoteRaw("heartbeat", "200");
			}
			else
			{
				SendEnvelope("heartbeat", "200");
			}
			_lastHeartbeatUtc = DateTime.UtcNow;
		}
	}

	internal string GetQrUrl()
	{
		return "https://www.dungeon-lab.com/app-download.php#DGLAB-SOCKET#" + GetSocketBaseUri() + "/" + ClientId;
	}

	internal string GetSocketBaseUri()
	{
		SocketConnectionMode value = ModConfig.ConnectionMode.Value;
		if (value == SocketConnectionMode.RemoteServer || value == SocketConnectionMode.RelayCode)
		{
			string text = NormalizeBaseUri(ModConfig.RemoteServerUri.Value);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return "ws://127.0.0.1:" + Clamp(ModConfig.Port.Value, 1, 65535);
		}
		string text2 = NormalizeBaseUri(ModConfig.PublishSocketUri.Value);
		if (value == SocketConnectionMode.PublicSocket && !string.IsNullOrEmpty(text2))
		{
			return text2;
		}
		if (!string.IsNullOrEmpty(text2))
		{
			return text2;
		}
		return "ws://" + GetAdvertiseHost() + ":" + Clamp(ModConfig.Port.Value, 1, 65535);
	}

	internal string GetAdvertiseHost()
	{
		string value = ModConfig.AdvertiseHost.Value;
		if (!string.IsNullOrEmpty(value))
		{
			return value.Trim();
		}
		string[] localIPv4Addresses = GetLocalIPv4Addresses();
		if (localIPv4Addresses.Length > 0)
		{
			return localIPv4Addresses[0];
		}
		return "127.0.0.1";
	}

	internal string[] GetLocalIPv4Addresses()
	{
		List<string> list = new List<string>();
		try
		{
			IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
			foreach (IPAddress iPAddress in addressList)
			{
				if (iPAddress.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(iPAddress))
				{
					list.Add(iPAddress.ToString());
				}
			}
		}
		catch
		{
		}
		return list.ToArray();
	}

	internal string LocalAddressSummary()
	{
		StringBuilder stringBuilder = new StringBuilder();
		string[] localIPv4Addresses = GetLocalIPv4Addresses();
		for (int i = 0; i < localIPv4Addresses.Length; i++)
		{
			if (i > 0)
			{
				stringBuilder.Append(" / ");
			}
			stringBuilder.Append(localIPv4Addresses[i]);
		}
		if (stringBuilder.Length != 0)
		{
			return stringBuilder.ToString();
		}
		return "未检测到局域网 IPv4";
	}

	internal string StatusText()
	{
		if (IsRemoteMode())
		{
			string remoteStatus;
			string lastError;
			lock (_sync)
			{
				remoteStatus = _remoteStatus;
				lastError = _lastError;
			}
			if (IsBound)
			{
				return "远程 Socket 已绑定";
			}
			if (IsConnected)
			{
				if (!string.IsNullOrEmpty(remoteStatus))
				{
					return remoteStatus;
				}
				return "远程 Socket 已连接,等待绑定";
			}
			if (!string.IsNullOrEmpty(lastError))
			{
				return "远程 Socket 未连接:" + lastError;
			}
			return "远程 Socket 未连接";
		}
		if (!IsRunning)
		{
			string lastError2 = LastError;
			if (!string.IsNullOrEmpty(lastError2))
			{
				return "服务未启动:" + lastError2;
			}
			return "服务未启动";
		}
		if (IsBound)
		{
			return "已绑定";
		}
		if (IsConnected)
		{
			return "已连接,等待绑定";
		}
		return "等待手机 App 连接";
	}

	internal string ConnectionModeText()
	{
		return ModConfig.ConnectionMode.Value switch
		{
			SocketConnectionMode.LocalServer => "本地局域网", 
			SocketConnectionMode.PublicSocket => "公网/隧道地址", 
			SocketConnectionMode.RemoteServer => "远程 Socket 后端", 
			_ => "自建 Relay Code", 
		};
	}

	internal void OnOpen(AppSocketBehavior behavior)
	{
		lock (_sync)
		{
			if (_session != null && !object.ReferenceEquals(_session, behavior))
			{
				behavior.SendText(DgLabMessage.Create("error", "", "", "400").ToJson());
				return;
			}
			_session = behavior;
			_bound = false;
			_appId = Guid.NewGuid().ToString();
			_strength = new StrengthState();
			_lastRemoteEndpoint = behavior.RemoteEndpoint;
		}
		behavior.SendText(DgLabMessage.Create("bind", _appId, "", "targetId").ToJson());
		Plugin.Log.LogInfo((object)("DG-LAB app connected; assigned appId " + _appId + " from " + behavior.RemoteEndpoint));
	}

	internal void OnClose(AppSocketBehavior behavior)
	{
		lock (_sync)
		{
			if (object.ReferenceEquals(_session, behavior))
			{
				_session = null;
				_bound = false;
				_appId = "";
				_strength = new StrengthState();
				_lastRemoteEndpoint = "";
			}
		}
		Plugin.Log.LogInfo((object)"DG-LAB app disconnected.");
	}

	internal void OnMessage(AppSocketBehavior behavior, string raw)
	{
		DgLabMessage dgLabMessage;
		try
		{
			dgLabMessage = JsonConvert.DeserializeObject<DgLabMessage>(raw);
		}
		catch
		{
			behavior.SendText(DgLabMessage.Create("msg", "", "", "403").ToJson());
			return;
		}
		if (dgLabMessage == null || string.IsNullOrEmpty(dgLabMessage.Type))
		{
			behavior.SendText(DgLabMessage.Create("msg", "", "", "403").ToJson());
		}
		else if (dgLabMessage.Type == "bind")
		{
			HandleBind(behavior, dgLabMessage);
		}
		else if (dgLabMessage.Type == "msg")
		{
			HandleAppMessage(dgLabMessage);
		}
	}

	private void HandleBind(AppSocketBehavior behavior, DgLabMessage message)
	{
		bool flag;
		lock (_sync)
		{
			flag = object.ReferenceEquals(_session, behavior) && message.ClientId == _terminalId && message.TargetId == _appId;
			if (flag)
			{
				_bound = true;
			}
		}
		if (flag)
		{
			behavior.SendText(DgLabMessage.Create("bind", _terminalId, _appId, "200").ToJson());
			Plugin.Log.LogInfo((object)"DG-LAB app bound successfully.");
		}
		else
		{
			behavior.SendText(DgLabMessage.Create("bind", message.ClientId ?? "", message.TargetId ?? "", "400").ToJson());
		}
	}

	private void HandleRemoteMessage(string raw)
	{
		DgLabMessage dgLabMessage;
		try
		{
			dgLabMessage = JsonConvert.DeserializeObject<DgLabMessage>(raw);
		}
		catch
		{
			Plugin.Log.LogWarning((object)"Remote DG-LAB Socket sent invalid JSON.");
			return;
		}
		if (dgLabMessage == null || string.IsNullOrEmpty(dgLabMessage.Type))
		{
			return;
		}
		if (dgLabMessage.Type == "bind")
		{
			HandleRemoteBind(dgLabMessage);
		}
		else if (dgLabMessage.Type == "msg")
		{
			HandleAppMessage(dgLabMessage);
		}
		else if (dgLabMessage.Type == "break")
		{
			lock (_sync)
			{
				_bound = false;
				_appId = "";
				_remoteStatus = "远程配对已断开:" + dgLabMessage.Message;
			}
		}
	}

	private void HandleRemoteBind(DgLabMessage message)
	{
		lock (_sync)
		{
			if (message.Message == "targetId")
			{
				if ((ModConfig.ConnectionMode.Value != SocketConnectionMode.RelayCode || string.IsNullOrEmpty(SafeRelayCode(ModConfig.RemotePairCode.Value))) && !string.IsNullOrEmpty(message.ClientId))
				{
					_terminalId = message.ClientId;
				}
				_remoteClientIdAssigned = true;
				_remoteStatus = "已获取远程终端 ID,等待手机扫码绑定。";
			}
			else if (message.Message == "200")
			{
				_bound = true;
				_appId = message.TargetId ?? "";
				_lastHeartbeatUtc = DateTime.UtcNow;
				_remoteStatus = "远程 Socket 已绑定。";
				Plugin.Log.LogInfo((object)"Remote DG-LAB app bound successfully.");
			}
			else
			{
				_remoteStatus = "远程绑定失败:" + message.Message;
				_lastError = _remoteStatus;
			}
		}
	}

	private void HandleAppMessage(DgLabMessage message)
	{
		Match match = StrengthRegex.Match(message.Message ?? "");
		if (!match.Success)
		{
			return;
		}
		lock (_sync)
		{
			_strength.ACurrent = ParseInt(match.Groups[1].Value);
			_strength.BCurrent = ParseInt(match.Groups[2].Value);
			_strength.AMax = ParseInt(match.Groups[3].Value);
			_strength.BMax = ParseInt(match.Groups[4].Value);
		}
	}

	internal bool SendPulse(char channel, IList<string> pulses)
	{
		if (pulses == null || pulses.Count == 0)
		{
			return false;
		}
		int val = Clamp(ModConfig.MaxQueuedPulseItems.Value, 1, 100);
		int count = Math.Min(val, pulses.Count);
		string command = "pulse-" + channel + ":" + WaveformEncoder.ToJsonArray(pulses, count);
		return SendEnvelope("msg", command);
	}

	internal bool ClearChannel(int channel)
	{
		return SendEnvelope("msg", "clear-" + channel);
	}

	internal void ClearAll()
	{
		ClearChannel(1);
		ClearChannel(2);
	}

	internal bool SetStrength(int channel, int value)
	{
		int num = Clamp(value, 0, 200);
		return SendEnvelope("msg", "strength-" + channel + "+2+" + num);
	}

	private bool SendEnvelope(string type, string command)
	{
		if (IsRemoteMode())
		{
			if (type == "msg")
			{
				return SendRemoteDirect(command);
			}
			return SendRemoteRaw(type, command);
		}
		AppSocketBehavior session;
		string appId;
		lock (_sync)
		{
			if (_session == null || !_bound)
			{
				return false;
			}
			session = _session;
			appId = _appId;
		}
		if (command != null && command.Length > 1950)
		{
			Plugin.Log.LogWarning((object)"DG-LAB command was too long and has been dropped.");
			return false;
		}
		try
		{
			session.SendText(DgLabMessage.Create(type, _terminalId, appId, command).ToJson());
			return true;
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to send DG-LAB command: " + ex.Message));
			return false;
		}
	}

	private bool SendRemoteDirect(string command)
	{
		if (command != null && command.Length > 1950)
		{
			Plugin.Log.LogWarning((object)"DG-LAB command was too long and has been dropped.");
			return false;
		}
		WebSocket remoteSocket;
		string terminalId;
		string appId;
		lock (_sync)
		{
			if (_remoteSocket == null || !_remoteConnected || !_bound)
			{
				return false;
			}
			remoteSocket = _remoteSocket;
			terminalId = _terminalId;
			appId = _appId;
		}
		try
		{
			string text = JsonConvert.SerializeObject((object)new
			{
				type = 4,
				message = command,
				clientId = terminalId,
				targetId = appId
			});
			remoteSocket.Send(text);
			return true;
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to send remote DG-LAB command: " + ex.Message));
			return false;
		}
	}

	private bool SendRemoteRaw(string type, string command)
	{
		WebSocket remoteSocket;
		string terminalId;
		string appId;
		lock (_sync)
		{
			if (_remoteSocket == null || !_remoteConnected)
			{
				return false;
			}
			remoteSocket = _remoteSocket;
			terminalId = _terminalId;
			appId = _appId;
		}
		try
		{
			remoteSocket.Send(DgLabMessage.Create(type, terminalId, appId, command).ToJson());
			return true;
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to send remote DG-LAB raw message: " + ex.Message));
			return false;
		}
	}

	private bool IsRemoteMode()
	{
		SocketConnectionMode value = ModConfig.ConnectionMode.Value;
		if (value != SocketConnectionMode.RemoteServer)
		{
			return value == SocketConnectionMode.RelayCode;
		}
		return true;
	}

	private static string NormalizeBaseUri(string value)
	{
		string text = (value ?? "").Trim();
		while (text.EndsWith("/", StringComparison.Ordinal))
		{
			text = text.Substring(0, text.Length - 1);
		}
		return text;
	}

	private static string SafeRelayCode(string value)
	{
		string text = (value ?? "").Trim();
		if (string.IsNullOrEmpty(text))
		{
			return "";
		}
		return SafeCodeRegex.Replace(text, "");
	}

	private static int Clamp(int value, int min, int max)
	{
		if (value < min)
		{
			return min;
		}
		if (value > max)
		{
			return max;
		}
		return value;
	}

	private static int ParseInt(string value)
	{
		if (!int.TryParse(value, out var result))
		{
			return 0;
		}
		return result;
	}
}
internal enum SocketConnectionMode
{
	LocalServer,
	PublicSocket,
	RemoteServer,
	RelayCode
}
internal enum StimChannel
{
	A,
	B
}
internal enum StimChannelMode
{
	A,
	B,
	Both,
	Alternate
}
internal enum AutoStrengthMode
{
	Off,
	MinimumOnly,
	EventScaled
}
internal enum StimWaveShape
{
	Smooth,
	Gradient,
	Sin
}
internal enum StimEnvelopeShape
{
	SingleTap,
	DoubleTap,
	RampUpHoldDown,
	SawBurst,
	Tremor,
	DeathWave
}
internal static class ModConfig
{
	internal static ConfigEntry<bool> AutoStartServer;

	internal static ConfigEntry<SocketConnectionMode> ConnectionMode;

	internal static ConfigEntry<int> Port;

	internal static ConfigEntry<string> AdvertiseHost;

	internal static ConfigEntry<string> PublishSocketUri;

	internal static ConfigEntry<string> RemoteServerUri;

	internal static ConfigEntry<string> RemotePairCode;

	internal static ConfigEntry<int> HeartbeatIntervalMs;

	internal static ConfigEntry<bool> Armed;

	internal static ConfigEntry<bool> AutoArmOnBind;

	internal static ConfigEntry<bool> AllowStrengthControl;

	internal static ConfigEntry<AutoStrengthMode> AutoStrengthMode;

	internal static ConfigEntry<int> MinimumChannelStrength;

	internal static ConfigEntry<int> MaxWaveIntensity;

	internal static ConfigEntry<int> MaxEventDurationMs;

	internal static ConfigEntry<int> MaxQueuedPulseItems;

	internal static ConfigEntry<int> ClearDelayMs;

	internal static ConfigEntry<bool> ContinuousMode;

	internal static ConfigEntry<int> ContinuousSendIntervalMs;

	internal static ConfigEntry<int> ContinuousLookaheadMs;

	internal static ConfigEntry<int> ContinuousFadeOutMs;

	internal static ConfigEntry<KeyCode> PanelKey;

	internal static ConfigEntry<KeyCode> EmergencyStopKey;

	internal static ConfigEntry<bool> HurtEnabled;

	internal static ConfigEntry<bool> DeathEnabled;

	internal static ConfigEntry<bool> LocalFootstepEnabled;

	internal static ConfigEntry<bool> JumpEnabled;

	internal static ConfigEntry<bool> LandEnabled;

	internal static ConfigEntry<bool> SlideEnabled;

	internal static ConfigEntry<bool> LandJumpEnabled;

	internal static ConfigEntry<bool> EnemyFootstepEnabled;

	internal static ConfigEntry<int> HurtCooldownMs;

	internal static ConfigEntry<int> FootstepCooldownMs;

	internal static ConfigEntry<int> JumpCooldownMs;

	internal static ConfigEntry<int> LandCooldownMs;

	internal static ConfigEntry<int> SlideCooldownMs;

	internal static ConfigEntry<int> MovementCooldownMs;

	internal static ConfigEntry<int> DeathCooldownMs;

	internal static ConfigEntry<bool> FirstFootLeft;

	internal static ConfigEntry<StimChannel> LeftFootChannel;

	internal static ConfigEntry<StimChannel> RightFootChannel;

	internal static ConfigEntry<bool> ResetFootOnIdle;

	internal static ConfigEntry<int> FootstepIdleResetMs;

	internal static ConfigEntry<int> FootstepIntensity;

	internal static ConfigEntry<int> FootstepDurationMs;

	internal static ConfigEntry<int> FootstepFrequency;

	internal static ConfigEntry<StimWaveShape> FootstepWaveShape;

	internal static ConfigEntry<int> FootstepDuplicateWindowMs;

	internal static ConfigEntry<int> WalkFootstepMinIntervalMs;

	internal static ConfigEntry<int> RunFootstepIntensity;

	internal static ConfigEntry<int> RunFootstepDurationMs;

	internal static ConfigEntry<int> RunFootstepMinIntervalMs;

	internal static ConfigEntry<bool> FallbackFootstepSupplement;

	internal static ConfigEntry<int> FallbackFootstepNoAnimationMs;

	internal static ConfigEntry<bool> RunCadenceSupplement;

	internal static ConfigEntry<int> RunSupplementIntervalMs;

	internal static ConfigEntry<int> WalkBaseIntensity;

	internal static ConfigEntry<int> WalkBaseFrequency;

	internal static ConfigEntry<StimEnvelopeShape> WalkBaseShape;

	internal static ConfigEntry<int> WalkStepBumpIntensity;

	internal static ConfigEntry<int> WalkStepBumpDurationMs;

	internal static ConfigEntry<int> RunBaseIntensity;

	internal static ConfigEntry<int> RunBaseFrequency;

	internal static ConfigEntry<StimEnvelopeShape> RunBaseShape;

	internal static ConfigEntry<int> RunStepBumpIntensity;

	internal static ConfigEntry<int> RunStepBumpDurationMs;

	internal static ConfigEntry<int> JumpIntensity;

	internal static ConfigEntry<int> JumpDurationMs;

	internal static ConfigEntry<int> JumpFrequency;

	internal static ConfigEntry<StimChannelMode> JumpChannelMode;

	internal static ConfigEntry<int> LandIntensity;

	internal static ConfigEntry<int> LandDurationMs;

	internal static ConfigEntry<int> LandFrequency;

	internal static ConfigEntry<StimChannelMode> LandChannelMode;

	internal static ConfigEntry<StimEnvelopeShape> LandEnvelope;

	internal static ConfigEntry<int> SlideIntensity;

	internal static ConfigEntry<int> SlideDurationMs;

	internal static ConfigEntry<int> SlideFrequency;

	internal static ConfigEntry<StimChannelMode> SlideChannelMode;

	internal static ConfigEntry<StimEnvelopeShape> SlideEnvelope;

	internal static ConfigEntry<int> SlideBaseIntensity;

	internal static ConfigEntry<int> SlideBaseFrequency;

	internal static ConfigEntry<int> HurtMinIntensity;

	internal static ConfigEntry<int> HurtMaxIntensity;

	internal static ConfigEntry<float> HurtDamageMultiplier;

	internal static ConfigEntry<float> HurtAMultiplier;

	internal static ConfigEntry<float> HurtBMultiplier;

	internal static ConfigEntry<int> HurtDurationMinMs;

	internal static ConfigEntry<int> HurtDurationMaxMs;

	internal static ConfigEntry<int> HurtFrequency;

	internal static ConfigEntry<StimChannelMode> HurtChannelMode;

	internal static ConfigEntry<StimEnvelopeShape> HurtEnvelope;

	internal static ConfigEntry<int> DeathIntensity;

	internal static ConfigEntry<int> DeathDurationMs;

	internal static ConfigEntry<int> DeathFrequency;

	internal static ConfigEntry<StimChannelMode> DeathChannelMode;

	internal static ConfigEntry<StimWaveShape> DeathAWaveShape;

	internal static ConfigEntry<StimWaveShape> DeathBWaveShape;

	internal static ConfigEntry<StimEnvelopeShape> DeathEnvelope;

	internal static ConfigEntry<bool> DeathClearBeforePulse;

	internal static ConfigEntry<int> EnemyFootstepIntensity;

	internal static ConfigEntry<float> EnemyFootstepRange;

	internal static ConfigEntry<int> TestIntensity;

	internal static void Bind(ConfigFile config)
	{
		AutoStartServer = config.Bind<bool>("Connection", "AutoStartServer", true, "Mod 加载时自动启动 DG-LAB Socket 连接。");
		ConnectionMode = config.Bind<SocketConnectionMode>("Connection", "ConnectionMode", SocketConnectionMode.LocalServer, "LocalServer=本机监听;PublicSocket=本机监听但二维码使用公网地址;RemoteServer=连接公网 Socket v2 后端;RelayCode=自建 relay code 兼容模式。");
		Port = config.Bind<int>("Connection", "Port", 9999, "本机 DG-LAB App Socket 监听端口。");
		AdvertiseHost = config.Bind<string>("Connection", "AdvertiseHost", "", "局域网二维码里展示给手机连接的电脑 IP/域名。留空时自动选择局域网 IPv4。");
		PublishSocketUri = config.Bind<string>("Connection", "PublishSocketUri", "", "公网/隧道模式二维码使用的 WebSocket 基础地址,例如 wss://ws.example.com。留空时使用局域网地址。");
		RemoteServerUri = config.Bind<string>("Connection", "RemoteServerUri", "", "RemoteServer/RelayCode 模式连接的公网 DG-LAB Socket v2 后端地址,例如 wss://ws.example.com。");
		RemotePairCode = config.Bind<string>("Connection", "RemotePairCode", "", "RelayCode 模式使用的自定义终端码。该功能需要兼容自定义码的 relay 服务,不能直接填写 DG-LAB App 原生远程口令。");
		HeartbeatIntervalMs = config.Bind<int>("Connection", "HeartbeatIntervalMs", 60000, "发送给 DG-LAB App 或远程服务的心跳间隔,单位毫秒。");
		Armed = config.Bind<bool>("Safety", "Enabled", false, "为 false 时,游戏事件不会触发波形。可在面板里点击“启用触发”。");
		AutoArmOnBind = config.Bind<bool>("Safety", "AutoArmOnBind", true, "绑定 DG-LAB App 后自动启用游戏事件触发。关闭后需手动点击“启用触发”。");
		AllowStrengthControl = config.Bind<bool>("Safety", "AllowStrengthControl", false, "兼容旧配置:开启后等同于 EventScaled 自动调强。");
		AutoStrengthMode = config.Bind<AutoStrengthMode>("Safety", "AutoStrengthMode", DGLabPunish.AutoStrengthMode.EventScaled, "Off=不调强;MinimumOnly=只补到最低可感强度;EventScaled=按事件强度设置通道强度。");
		MinimumChannelStrength = config.Bind<int>("Safety", "MinimumChannelStrength", 30, "MinimumOnly 模式下 A/B 通道会被补到的最低强度。");
		MaxWaveIntensity = config.Bind<int>("Safety", "MaxWaveIntensity", 60, "本 Mod 使用的波形强度上限。DG-LAB 波形强度范围为 0-100。");
		MaxEventDurationMs = config.Bind<int>("Safety", "MaxEventDurationMs", 4000, "单次事件波形最长持续时间,单位毫秒。");
		MaxQueuedPulseItems = config.Bind<int>("Safety", "MaxQueuedPulseItems", 45, "单次事件最多发送多少条 100ms 波形数据。");
		ClearDelayMs = config.Bind<int>("Safety", "ClearDelayMs", 60, "高优先级事件 clear 后等待多久再发送新波形,单位毫秒。");
		ContinuousMode = config.Bind<bool>("Safety", "ContinuousMode", true, "开启后使用持续状态机:走路/跑步/滑行期间持续输出基础波形,事件叠加强度。关闭后使用旧版单发事件模式。");
		ContinuousSendIntervalMs = config.Bind<int>("Continuous", "SendIntervalMs", 70, "连续模式补包间隔,单位毫秒。");
		ContinuousLookaheadMs = config.Bind<int>("Continuous", "LookaheadMs", 100, "连续模式每次生成未来多久的波形,单位毫秒。");
		ContinuousFadeOutMs = config.Bind<int>("Continuous", "FadeOutMs", 450, "移动停止后的淡出时间,单位毫秒。");
		PanelKey = config.Bind<KeyCode>("Safety", "PanelKey", (KeyCode)112, "打开/关闭游戏内郊狼连接面板。");
		EmergencyStopKey = config.Bind<KeyCode>("Safety", "EmergencyStopKey", (KeyCode)105, "清空 A/B 波形队列并将 A/B 通道强度设为 0。");
		HurtEnabled = config.Bind<bool>("Events", "HurtEnabled", true, "本地玩家受击时触发波形。");
		DeathEnabled = config.Bind<bool>("Events", "DeathEnabled", true, "本地玩家死亡时触发波形。");
		LocalFootstepEnabled = config.Bind<bool>("Events", "LocalFootstepEnabled", true, "本地玩家脚步时触发低强度波形。");
		JumpEnabled = config.Bind<bool>("Events", "JumpEnabled", true, "本地玩家跳跃时触发低强度波形。");
		LandEnabled = config.Bind<bool>("Events", "LandEnabled", true, "本地玩家落地时触发低强度波形。");
		SlideEnabled = config.Bind<bool>("Events", "SlideEnabled", true, "本地玩家滑行时触发低强度波形。");
		LandJumpEnabled = config.Bind<bool>("Events", "LandJumpEnabled", true, "兼容旧配置:总开关,关闭后跳跃、落地、滑行都不触发。");
		EnemyFootstepEnabled = config.Bind<bool>("Events", "EnemyFootstepEnabled", false, "猎人敌人近距离脚步提示,默认关闭。");
		HurtCooldownMs = config.Bind<int>("Timing", "HurtCooldownMs", 450, "两次受击波形之间的最短间隔,单位毫秒。");
		FootstepCooldownMs = config.Bind<int>("Timing", "FootstepCooldownMs", 120, "两次脚步波形之间的最短间隔,单位毫秒。");
		JumpCooldownMs = config.Bind<int>("Timing", "JumpCooldownMs", 250, "两次跳跃波形之间的最短间隔,单位毫秒。");
		LandCooldownMs = config.Bind<int>("Timing", "LandCooldownMs", 250, "两次落地波形之间的最短间隔,单位毫秒。");
		SlideCooldownMs = config.Bind<int>("Timing", "SlideCooldownMs", 300, "两次滑行波形之间的最短间隔,单位毫秒。");
		MovementCooldownMs = config.Bind<int>("Timing", "MovementCooldownMs", 300, "兼容旧配置:旧版跳跃/落地/滑行冷却。");
		DeathCooldownMs = config.Bind<int>("Timing", "DeathCooldownMs", 5000, "两次死亡波形之间的最短间隔,单位毫秒。");
		FirstFootLeft = config.Bind<bool>("Footstep", "FirstFootLeft", true, "站停重置后第一步是否按左脚处理。默认左脚。");
		LeftFootChannel = config.Bind<StimChannel>("Footstep", "LeftFootChannel", StimChannel.A, "左脚对应通道。默认 A。");
		RightFootChannel = config.Bind<StimChannel>("Footstep", "RightFootChannel", StimChannel.B, "右脚对应通道。默认 B。");
		ResetFootOnIdle = config.Bind<bool>("Footstep", "ResetFootOnIdle", true, "长时间没有脚步后,下一步是否重置为 FirstFootLeft。");
		FootstepIdleResetMs = config.Bind<int>("Footstep", "FootstepIdleResetMs", 900, "多久没有脚步后重置左右脚,单位毫秒。");
		FootstepIntensity = config.Bind<int>("Footstep", "FootstepIntensity", 20, "本地脚步波形强度。");
		FootstepDurationMs = config.Bind<int>("Footstep", "FootstepDurationMs", 250, "本地脚步波形持续时间,单位毫秒。");
		FootstepFrequency = config.Bind<int>("Footstep", "FootstepFrequency", 180, "脚步波形频率值。");
		FootstepWaveShape = config.Bind<StimWaveShape>("Footstep", "FootstepWaveShape", StimWaveShape.Sin, "脚步波形形状。Sin 更像短促踩踏,Smooth 更平滑。");
		FootstepDuplicateWindowMs = config.Bind<int>("Footstep", "FootstepDuplicateWindowMs", 35, "极短时间内重复脚步事件的去重窗口,单位毫秒。");
		WalkFootstepMinIntervalMs = config.Bind<int>("Footstep", "WalkFootstepMinIntervalMs", 90, "走路脚步最小发送间隔,单位毫秒。");
		RunFootstepIntensity = config.Bind<int>("Footstep", "RunFootstepIntensity", 24, "奔跑脚步波形强度。");
		RunFootstepDurationMs = config.Bind<int>("Footstep", "RunFootstepDurationMs", 140, "奔跑脚步波形持续时间,单位毫秒。");
		RunFootstepMinIntervalMs = config.Bind<int>("Footstep", "RunFootstepMinIntervalMs", 55, "奔跑脚步最小发送间隔,单位毫秒。");
		FallbackFootstepSupplement = config.Bind<bool>("Footstep", "FallbackFootstepSupplement", false, "动画脚步长时间没有触发时,是否允许 PlayerAvatar.Footstep 兜底补发。默认关闭。");
		FallbackFootstepNoAnimationMs = config.Bind<int>("Footstep", "FallbackFootstepNoAnimationMs", 450, "多久没有动画脚步后允许兜底补发,单位毫秒。");
		RunCadenceSupplement = config.Bind<bool>("Footstep", "RunCadenceSupplement", false, "奔跑时如果动画脚步偏慢,是否按间隔补一拍。默认关闭。");
		RunSupplementIntervalMs = config.Bind<int>("Footstep", "RunSupplementIntervalMs", 170, "奔跑补拍间隔,单位毫秒。");
		WalkBaseIntensity = config.Bind<int>("ContinuousWalk", "WalkBaseIntensity", 10, "走路持续基础波形强度。");
		WalkBaseFrequency = config.Bind<int>("ContinuousWalk", "WalkBaseFrequency", 25, "走路持续基础波形频率。");
		WalkBaseShape = config.Bind<StimEnvelopeShape>("ContinuousWalk", "WalkBaseShape", StimEnvelopeShape.Tremor, "走路持续基础波形形状。");
		WalkStepBumpIntensity = config.Bind<int>("ContinuousWalk", "WalkStepBumpIntensity", 16, "走路每步叠加强度。");
		WalkStepBumpDurationMs = config.Bind<int>("ContinuousWalk", "WalkStepBumpDurationMs", 160, "走路每步叠加强度持续时间。");
		RunBaseIntensity = config.Bind<int>("ContinuousRun", "RunBaseIntensity", 15, "奔跑持续基础波形强度。");
		RunBaseFrequency = config.Bind<int>("ContinuousRun", "RunBaseFrequency", 260, "奔跑持续基础波形频率。");
		RunBaseShape = config.Bind<StimEnvelopeShape>("ContinuousRun", "RunBaseShape", StimEnvelopeShape.SawBurst, "奔跑持续基础波形形状。");
		RunStepBumpIntensity = config.Bind<int>("ContinuousRun", "RunStepBumpIntensity", 22, "奔跑每步叠加强度。");
		RunStepBumpDurationMs = config.Bind<int>("ContinuousRun", "RunStepBumpDurationMs", 110, "奔跑每步叠加强度持续时间。");
		JumpIntensity = config.Bind<int>("Actions", "JumpIntensity", 18, "跳跃波形强度。");
		JumpDurationMs = config.Bind<int>("Actions", "JumpDurationMs", 250, "跳跃波形持续时间,单位毫秒

BepInEx\plugins\DGLabPunish\QrCodeGenerator.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;

[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("Codecrete")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) Manuel Bleichenbacher and Project Nayuki (MIT License)")]
[assembly: AssemblyDescription("QR Code Generator for .NET – simple, compact and with many examples.\r\n\r\nCore features:\r\n- Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard\r\n- Output formats: Raw modules/pixels of the QR symbol, SVG, XAML path, PNG and BMP files. For other raster bitmap formats, see project home page.\r\n- Encodes numeric and special-alphanumeric text in less space than general text\r\n- Open source code under the permissive MIT License\r\n- Built for .NET Standard 2.0 and therefore runs on most modern .NET platforms (.NET Core, .NET Framework, Mono etc.).\r\n- Example code for WinForms, WPF, ASP.NET, ImageSharp, SkiaSharp and many more\r\n\r\nManual parameters:\r\n- You can specify the minimum and maximum version number allowed, and the library will automatically choose the smallest version in the range that fits the data.\r\n- You can specify the mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one.\r\n- You can specify an error correction level, or optionally allow the library to boost it if it doesn't increase the version number.\r\n- You can create a list of data segments manually and add ECI segments.\r\n\r\nOptional advanced features:\r\n- Long text can be split into multiple linked QR codes (aka Structured Append)\r\n- Encodes Japanese Unicode text in Kanji mode to save a lot of space compared to UTF-8 bytes\r\n- Computes optimal segment mode switching for text with mixed numeric/alphanumeric/general/kanji parts\r\n")]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: AssemblyInformationalVersion("2.1.0+d75ad20b2f2c04a41120c3e7c7326842fc837fcc")]
[assembly: AssemblyProduct("QR Code Generator for .NET")]
[assembly: AssemblyTitle("QrCodeGenerator")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/manuelbl/QrCodeGenerator")]
[assembly: AssemblyVersion("1.6.0.0")]
namespace Net.Codecrete.QrCodeGenerator;

public static class BitArrayExtensions
{
	public static void AppendBits(this BitArray bitArray, uint val, int len)
	{
		if (len < 0 || len > 31)
		{
			throw new ArgumentOutOfRangeException("len", "'len' out of range");
		}
		if (val >> len != 0)
		{
			throw new ArgumentOutOfRangeException("val", "'val' out of range");
		}
		int length = bitArray.Length;
		bitArray.Length = length + len;
		uint num = (uint)(1 << len - 1);
		for (int i = length; i < length + len; i++)
		{
			if ((val & num) != 0)
			{
				bitArray.Set(i, value: true);
			}
			num >>= 1;
		}
	}

	public static void AppendData(this BitArray bitArray, BitArray otherArray)
	{
		Objects.RequireNonNull(otherArray);
		int num = bitArray.Length;
		bitArray.Length = num + otherArray.Length;
		int num2 = 0;
		while (num2 < otherArray.Length)
		{
			if (otherArray[num2])
			{
				bitArray.Set(num, value: true);
			}
			num2++;
			num++;
		}
	}

	public static uint ExtractBits(this BitArray bitArray, int index, int len)
	{
		if (len < 0 || len > 31)
		{
			throw new ArgumentOutOfRangeException("len", "'len' out of range");
		}
		if (index < 0 || index + len > bitArray.Length)
		{
			throw new ArgumentOutOfRangeException("index", "'index' out of range");
		}
		uint num = 0u;
		for (int i = 0; i < len; i++)
		{
			num <<= 1;
			if (bitArray.Get(index + i))
			{
				num |= 1u;
			}
		}
		return num;
	}
}
public class DataTooLongException : ArgumentException
{
	public DataTooLongException(string message)
		: base(message)
	{
	}
}
internal class Graphics
{
	private readonly int _size;

	private readonly bool[,] _modules;

	internal Graphics(int size, bool[,] modules)
	{
		_size = size;
		_modules = modules;
	}

	internal string ToSvgString(int border, string foreground, string background)
	{
		if (border < 0)
		{
			throw new ArgumentOutOfRangeException("border", "Border must be non-negative");
		}
		int num = _size + border * 2;
		StringBuilder stringBuilder = new StringBuilder().Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n").Append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n").Append($"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 {num} {num}\" stroke=\"none\">\n")
			.Append("\t<rect width=\"100%\" height=\"100%\" fill=\"" + background + "\"/>\n")
			.Append("\t<path d=\"");
		bool[,] modules = CopyModules();
		CreatePath(stringBuilder, modules, border);
		return stringBuilder.Append("\" fill=\"" + foreground + "\"/>\n").Append("</svg>\n").ToString();
	}

	internal string ToGraphicsPath(int border)
	{
		if (border < 0)
		{
			throw new ArgumentOutOfRangeException("border", "Border must be non-negative");
		}
		bool[,] modules = CopyModules();
		StringBuilder stringBuilder = new StringBuilder();
		CreatePath(stringBuilder, modules, border);
		return stringBuilder.ToString();
	}

	internal byte[] ToBmpBitmap(int border, int scale, int foreground, int background)
	{
		if (scale < 1)
		{
			throw new ArgumentOutOfRangeException("scale", scale, "Scale must be greater than 0.");
		}
		if (border < 0)
		{
			throw new ArgumentOutOfRangeException("border", border, "Border must be non-negative.");
		}
		int num = (_size + 2 * border) * scale;
		if (num > 32767)
		{
			throw new ArgumentOutOfRangeException("scale", "Scale or border too large.");
		}
		int num2 = (num - 1 >> 3) + 1;
		int num3 = (num2 + 3) & -4;
		int num4 = 62 + num * num3;
		byte[] array = new byte[num4];
		array[0] = 66;
		array[1] = 77;
		array[2] = (byte)num4;
		array[3] = (byte)(num4 >> 8);
		array[4] = (byte)(num4 >> 16);
		array[5] = (byte)(num4 >> 24);
		array[10] = 62;
		array[14] = 40;
		array[18] = (byte)num;
		array[19] = (byte)(num >> 8);
		array[20] = (byte)(num >> 16);
		array[21] = (byte)(num >> 24);
		array[22] = array[18];
		array[23] = array[19];
		array[24] = array[20];
		array[25] = array[21];
		array[26] = 1;
		array[28] = 1;
		array[38] = 196;
		array[39] = 14;
		array[42] = array[38];
		array[43] = array[39];
		array[54] = (byte)foreground;
		array[55] = (byte)(foreground >> 8);
		array[56] = (byte)(foreground >> 16);
		array[58] = (byte)background;
		array[59] = (byte)(background >> 8);
		array[60] = (byte)(background >> 16);
		int num5 = border * scale;
		if (border > 0)
		{
			int num6 = _size * scale;
			for (int i = 0; i < num3; i++)
			{
				byte b = byte.MaxValue;
				if (i == num2 - 1)
				{
					b = (byte)(255 << (num2 << 3) - num);
				}
				else if (i >= num2)
				{
					b = 0;
				}
				for (int j = 0; j < num5; j++)
				{
					array[62 + i + j * num3] = b;
					array[62 + i + (j + num6 + num5) * num3] = b;
				}
			}
		}
		for (int j = 0; j < _size; j++)
		{
			int num7 = j * scale + num5;
			for (int i = 0; i < num3; i++)
			{
				byte b = 0;
				for (int k = 0; k < 8; k++)
				{
					int num8 = ((i << 3) + k) / scale;
					if (num8 < num)
					{
						b = ((num8 >= border && num8 < _size + border) ? ((byte)(b | (byte)((!_modules[_size - j - 1, num8 - border]) ? ((uint)(1 << 7 - k)) : 0u))) : ((byte)(b | (byte)(1 << 7 - k))));
					}
				}
				array[62 + i + num7 * num3] = b;
			}
			for (int i = 1; i <= scale - 1; i++)
			{
				for (int k = 0; k < num3; k++)
				{
					array[62 + k + (num7 + i) * num3] = array[62 + k + num7 * num3];
				}
			}
		}
		return array;
	}

	private static void CreatePath(StringBuilder path, bool[,] modules, int border)
	{
		int length = modules.GetLength(0);
		for (int i = 0; i < length; i++)
		{
			for (int j = 0; j < length; j++)
			{
				if (modules[i, j])
				{
					DrawLargestRectangle(path, modules, j, i, border);
				}
			}
		}
	}

	private static void DrawLargestRectangle(StringBuilder path, bool[,] modules, int x, int y, int border)
	{
		int length = modules.GetLength(0);
		int num = 1;
		int num2 = 1;
		int num3 = 1;
		int num4 = length;
		for (int i = y; i < length && modules[i, x]; i++)
		{
			int j;
			for (j = 0; x + j < num4 && modules[i, x + j]; j++)
			{
			}
			int num5 = j * (i - y + 1);
			if (num5 > num3)
			{
				num3 = num5;
				num = j;
				num2 = i - y + 1;
			}
			num4 = x + j;
		}
		if (x != 0 || y != 0)
		{
			path.Append(' ');
		}
		FormattableString formattableString = $"M{x + border},{y + border}h{num}v{num2}h{-num}z";
		path.Append(formattableString.ToString(CultureInfo.InvariantCulture));
		ClearRectangle(modules, x, y, num, num2);
	}

	private static void ClearRectangle(bool[,] modules, int x, int y, int width, int height)
	{
		for (int i = y; i < y + height; i++)
		{
			for (int j = x; j < x + width; j++)
			{
				modules[i, j] = false;
			}
		}
	}

	private bool[,] CopyModules()
	{
		bool[,] array = new bool[_size, _size];
		for (int i = 0; i < _size; i++)
		{
			for (int j = 0; j < _size; j++)
			{
				array[i, j] = _modules[i, j];
			}
		}
		return array;
	}
}
internal static class Objects
{
	internal static T RequireNonNull<T>(T arg)
	{
		if (arg == null)
		{
			throw new ArgumentNullException();
		}
		return arg;
	}
}
internal sealed class PngBuilder
{
	private static readonly byte[] Signature = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 };

	private static readonly uint[] CrcTable = new uint[256]
	{
		0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, 249268274u, 2044508324u,
		3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, 498536548u, 1789927666u, 4089016648u, 2227061214u,
		450548861u, 1843258603u, 4107580753u, 2211677639u, 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u,
		4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u,
		901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, 651767980u, 1373503546u,
		3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u,
		795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u,
		2680153253u, 3904427059u, 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u,
		1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u,
		2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, 1303535960u, 984961486u, 2747007092u, 3569037538u,
		1256170817u, 1037604311u, 2765210733u, 3554079995u, 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u,
		2852801631u, 3708648649u, 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u,
		1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, 3988292384u, 2596254646u,
		62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, 3814918930u, 2489596804u, 225274430u, 2053790376u,
		3826175755u, 2466906013u, 167816743u, 2097651377u, 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u,
		426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u,
		3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, 3624741850u, 2936675148u,
		906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u,
		3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u,
		752459403u, 1541320221u, 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u,
		2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u,
		1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, 2282248934u, 4279200368u, 1711684554u, 285281116u,
		2405801727u, 4167216745u, 1634467795u, 376229701u, 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u,
		1231636301u, 1047427035u, 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u,
		3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, 3009837614u, 3294710456u,
		1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u
	};

	private static readonly byte[] IHDR = new byte[4] { 73, 72, 68, 82 };

	private static readonly byte[] PLTE = new byte[4] { 80, 76, 84, 69 };

	private static readonly byte[] IDAT = new byte[4] { 73, 68, 65, 84 };

	private static readonly byte[] IEND = new byte[4] { 73, 69, 78, 68 };

	private readonly MemoryStream stream = new MemoryStream();

	internal static byte[] ToImage(QrCode qrCode, int scale, int border, int foreground, int background)
	{
		int num = (qrCode.Size + border * 2) * scale;
		PngBuilder pngBuilder = new PngBuilder();
		pngBuilder.WriteHeader(num, num, 1, 3);
		pngBuilder.WritePalette(new int[2] { background, foreground });
		pngBuilder.WriteData(CreateBitmap(qrCode, border, scale));
		pngBuilder.WriteEnd();
		return pngBuilder.GetBytes();
	}

	private static byte[] CreateBitmap(QrCode qrCode, int border, int scale)
	{
		int size = qrCode.Size;
		int num = (size + border * 2) * scale;
		int num2 = (num + 7) / 8 + 1;
		byte[] array = new byte[num2 * num];
		for (int i = 0; i < size; i++)
		{
			int num3 = (border + i) * scale * num2;
			for (int j = 0; j < size; j++)
			{
				if (qrCode.GetModule(j, i))
				{
					int k = (border + j) * scale;
					for (int num4 = k + scale; k < num4; k++)
					{
						int num5 = num3 + k / 8 + 1;
						array[num5] |= (byte)(128 >>> k % 8);
					}
				}
			}
			for (int l = 1; l < scale; l++)
			{
				Array.Copy(array, num3, array, num3 + l * num2, num2);
			}
		}
		return array;
	}

	private byte[] GetBytes()
	{
		byte[] array = stream.ToArray();
		SetCRC(array);
		return array;
	}

	private void WriteHeader(int width, int height, byte bitDepth, byte colorType)
	{
		stream.Write(Signature, 0, Signature.Length);
		WriteChunkStart(IHDR, 13);
		WriteIntBigEndian((uint)width);
		WriteIntBigEndian((uint)height);
		stream.WriteByte(bitDepth);
		stream.WriteByte(colorType);
		stream.WriteByte(0);
		stream.WriteByte(0);
		stream.WriteByte(0);
		WriteChunkEnd();
	}

	private void WritePalette(int[] palette)
	{
		WriteChunkStart(PLTE, palette.Length * 3);
		foreach (int num in palette)
		{
			stream.WriteByte((byte)((uint)(num >> 16) & 0xFFu));
			stream.WriteByte((byte)((uint)(num >> 8) & 0xFFu));
			stream.WriteByte((byte)((uint)num & 0xFFu));
		}
		WriteChunkEnd();
	}

	private void WriteData(byte[] data)
	{
		byte[] array = Deflate(data);
		WriteChunkStart(IDAT, array.Length + 6);
		stream.WriteByte(120);
		stream.WriteByte(156);
		stream.Write(array, 0, array.Length);
		uint value = CalcAdler32(data, 0, data.Length);
		WriteIntBigEndian(value);
		WriteChunkEnd();
	}

	private void WriteEnd()
	{
		WriteChunkStart(IEND, 0);
		WriteChunkEnd();
	}

	private static void SetCRC(byte[] bytes)
	{
		int num = Signature.Length;
		while (num < bytes.Length)
		{
			int num2 = (bytes[num] << 24) | (bytes[num + 1] << 16) | (bytes[num + 2] << 8) | bytes[num + 3];
			uint num3 = CalcCrc32(bytes, num + 4, num2 + 4);
			int num4 = num + 8 + num2;
			bytes[num4] = (byte)(num3 >> 24);
			bytes[num4 + 1] = (byte)(num3 >> 16);
			bytes[num4 + 2] = (byte)(num3 >> 8);
			bytes[num4 + 3] = (byte)num3;
			num = num4 + 4;
		}
	}

	private void WriteChunkStart(byte[] type, int length)
	{
		WriteIntBigEndian((uint)length);
		stream.Write(type, 0, 4);
	}

	private void WriteChunkEnd()
	{
		stream.SetLength(stream.Length + 4);
		stream.Position += 4L;
	}

	private void WriteIntBigEndian(uint value)
	{
		stream.WriteByte((byte)(value >> 24));
		stream.WriteByte((byte)(value >> 16));
		stream.WriteByte((byte)(value >> 8));
		stream.WriteByte((byte)value);
	}

	private static byte[] Deflate(byte[] data)
	{
		MemoryStream memoryStream = new MemoryStream();
		using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Optimal))
		{
			deflateStream.Write(data, 0, data.Length);
		}
		return memoryStream.ToArray();
	}

	private static uint CalcAdler32(byte[] data, int index, int length)
	{
		uint num = 1u;
		uint num2 = 0u;
		int num3 = index + length;
		for (int i = index; i < num3; i++)
		{
			num = (num + data[i]) % 65521;
			num2 = (num2 + num) % 65521;
		}
		return (num2 << 16) + num;
	}

	private static uint CalcCrc32(byte[] data, int index, int length)
	{
		uint num = uint.MaxValue;
		int num2 = index + length;
		for (int i = index; i < num2; i++)
		{
			num = CrcTable[(num ^ data[i]) & 0xFF] ^ (num >> 8);
		}
		return num ^ 0xFFFFFFFFu;
	}
}
public class QrCode
{
	private struct FinderPenalty
	{
		private readonly short[] _runHistory;

		private readonly int _size;

		public FinderPenalty(int size)
		{
			_size = size;
			_runHistory = new short[7];
		}

		internal int CountPatterns()
		{
			int num = _runHistory[1];
			bool flag = num > 0 && _runHistory[2] == num && _runHistory[3] == num * 3 && _runHistory[4] == num && _runHistory[5] == num;
			return ((flag && _runHistory[0] >= num * 4 && _runHistory[6] >= num) ? 1 : 0) + ((flag && _runHistory[6] >= num * 4 && _runHistory[0] >= num) ? 1 : 0);
		}

		internal int TerminateAndCount(bool currentRunColor, int currentRunLength)
		{
			if (currentRunColor)
			{
				AddHistory(currentRunLength);
				currentRunLength = 0;
			}
			currentRunLength += _size;
			AddHistory(currentRunLength);
			return CountPatterns();
		}

		internal void AddHistory(int currentRunLength)
		{
			if (_runHistory[0] == 0)
			{
				currentRunLength += _size;
			}
			Array.Copy(_runHistory, 0, _runHistory, 1, 6);
			_runHistory[0] = (short)currentRunLength;
		}
	}

	public sealed class Ecc
	{
		public static readonly Ecc Low = new Ecc(0, 1u);

		public static readonly Ecc Medium = new Ecc(1, 0u);

		public static readonly Ecc Quartile = new Ecc(2, 3u);

		public static readonly Ecc High = new Ecc(3, 2u);

		internal static readonly Ecc[] AllValues = new Ecc[4] { Low, Medium, Quartile, High };

		public int Ordinal { get; }

		internal uint FormatBits { get; }

		private Ecc(int ordinal, uint fb)
		{
			Ordinal = ordinal;
			FormatBits = fb;
		}
	}

	private readonly bool[,] _modules;

	private readonly bool[,] _isFunction;

	public const int MinVersion = 1;

	public const int MaxVersion = 40;

	private const int PenaltyN1 = 3;

	private const int PenaltyN2 = 3;

	private const int PenaltyN3 = 40;

	private const int PenaltyN4 = 10;

	private static readonly byte[,] EccCodewordsPerBlock = new byte[4, 41]
	{
		{
			255, 7, 10, 15, 20, 26, 18, 20, 24, 30,
			18, 20, 24, 26, 30, 22, 24, 28, 30, 28,
			28, 28, 28, 30, 30, 26, 28, 30, 30, 30,
			30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
			30
		},
		{
			255, 10, 16, 26, 18, 24, 16, 18, 22, 22,
			26, 30, 22, 22, 24, 24, 28, 28, 26, 26,
			26, 26, 28, 28, 28, 28, 28, 28, 28, 28,
			28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
			28
		},
		{
			255, 13, 22, 18, 26, 18, 24, 18, 22, 20,
			24, 28, 26, 24, 20, 30, 24, 28, 28, 26,
			30, 28, 30, 30, 30, 30, 28, 30, 30, 30,
			30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
			30
		},
		{
			255, 17, 28, 22, 16, 22, 28, 26, 26, 24,
			28, 24, 28, 22, 24, 24, 30, 28, 28, 26,
			28, 30, 24, 30, 30, 30, 30, 30, 30, 30,
			30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
			30
		}
	};

	private static readonly byte[,] NumErrorCorrectionBlocks = new byte[4, 41]
	{
		{
			255, 1, 1, 1, 1, 1, 2, 2, 2, 2,
			4, 4, 4, 4, 4, 6, 6, 6, 6, 7,
			8, 8, 9, 9, 10, 12, 12, 12, 13, 14,
			15, 16, 17, 18, 19, 19, 20, 21, 22, 24,
			25
		},
		{
			255, 1, 1, 1, 2, 2, 4, 4, 4, 5,
			5, 5, 8, 9, 9, 10, 10, 11, 13, 14,
			16, 17, 17, 18, 20, 21, 23, 25, 26, 28,
			29, 31, 33, 35, 37, 38, 40, 43, 45, 47,
			49
		},
		{
			255, 1, 1, 2, 2, 4, 4, 6, 6, 8,
			8, 8, 10, 12, 16, 12, 17, 16, 18, 21,
			20, 23, 23, 25, 27, 29, 34, 34, 35, 38,
			40, 43, 45, 48, 51, 53, 56, 59, 62, 65,
			68
		},
		{
			255, 1, 1, 2, 4, 4, 4, 5, 6, 8,
			8, 11, 11, 16, 16, 18, 16, 19, 21, 25,
			25, 25, 34, 30, 32, 35, 37, 40, 42, 45,
			48, 51, 54, 57, 60, 63, 66, 70, 74, 77,
			81
		}
	};

	public int Version { get; }

	public int Size { get; }

	public Ecc ErrorCorrectionLevel { get; }

	public int Mask { get; }

	public static QrCode EncodeText(string text, Ecc ecl)
	{
		Objects.RequireNonNull(text);
		Objects.RequireNonNull(ecl);
		return EncodeSegments(QrSegment.MakeSegments(text), ecl);
	}

	public static List<QrCode> EncodeTextInMultipleCodes(string text, Ecc ecl, int version = 29, bool boostEcl = true)
	{
		Objects.RequireNonNull(text);
		Objects.RequireNonNull(ecl);
		try
		{
			QrCode item = EncodeSegments(QrSegmentAdvanced.MakeSegmentsOptimally(text, ecl, version, version), ecl, version, version, -1, boostEcl);
			return new List<QrCode> { item };
		}
		catch (DataTooLongException)
		{
		}
		return (from segmentList in QrSegmentAdvanced.MakeSegmentsForMultipleCodes(text, ecl, version)
			select EncodeSegments(segmentList, ecl, version, version, -1, boostEcl)).ToList();
	}

	public static QrCode EncodeBinary(byte[] data, Ecc ecl)
	{
		Objects.RequireNonNull(data);
		Objects.RequireNonNull(ecl);
		QrSegment item = QrSegment.MakeBytes(data);
		return EncodeSegments(new List<QrSegment> { item }, ecl);
	}

	public static QrCode EncodeSegments(List<QrSegment> segments, Ecc ecl, int minVersion = 1, int maxVersion = 40, int mask = -1, bool boostEcl = true)
	{
		Objects.RequireNonNull(segments);
		Objects.RequireNonNull(ecl);
		if (minVersion < 1 || minVersion > maxVersion)
		{
			throw new ArgumentOutOfRangeException("minVersion", "Invalid value");
		}
		if (maxVersion > 40)
		{
			throw new ArgumentOutOfRangeException("maxVersion", "Invalid value");
		}
		if (mask < -1 || mask > 7)
		{
			throw new ArgumentOutOfRangeException("mask", "Invalid value");
		}
		int num = minVersion;
		int totalBits;
		while (true)
		{
			int num2 = GetNumDataCodewords(num, ecl) * 8;
			totalBits = QrSegment.GetTotalBits(segments, num);
			if (totalBits != -1 && totalBits <= num2)
			{
				break;
			}
			if (num >= maxVersion)
			{
				string message = "Segment too long";
				if (totalBits != -1)
				{
					message = $"Data length = {totalBits} bits, Max capacity = {num2} bits";
				}
				throw new DataTooLongException(message);
			}
			num++;
		}
		Ecc[] allValues = Ecc.AllValues;
		foreach (Ecc ecc in allValues)
		{
			if (boostEcl && totalBits <= GetNumDataCodewords(num, ecc) * 8)
			{
				ecl = ecc;
			}
		}
		BitArray bitArray = new BitArray(0);
		foreach (QrSegment segment in segments)
		{
			bitArray.AppendBits(segment.EncodingMode.ModeBits, 4);
			bitArray.AppendBits((uint)segment.NumChars, segment.EncodingMode.NumCharCountBits(num));
			bitArray.AppendData(segment.GetData());
		}
		int num3 = GetNumDataCodewords(num, ecl) * 8;
		bitArray.AppendBits(0u, Math.Min(4, num3 - bitArray.Length));
		bitArray.AppendBits(0u, (8 - bitArray.Length % 8) % 8);
		uint num4 = 236u;
		while (bitArray.Length < num3)
		{
			bitArray.AppendBits(num4, 8);
			num4 ^= 0xFDu;
		}
		byte[] array = new byte[bitArray.Length / 8];
		for (int j = 0; j < bitArray.Length; j++)
		{
			if (bitArray.Get(j))
			{
				array[j >> 3] |= (byte)(1 << 7 - (j & 7));
			}
		}
		return new QrCode(num, ecl, array, mask);
	}

	public QrCode(int version, Ecc ecl, byte[] dataCodewords, int mask = -1)
	{
		if (version < 1 || version > 40)
		{
			throw new ArgumentOutOfRangeException("version", "Version value out of range");
		}
		if (mask < -1 || mask > 7)
		{
			throw new ArgumentOutOfRangeException("mask", "Mask value out of range");
		}
		Version = version;
		Size = version * 4 + 17;
		Objects.RequireNonNull(ecl);
		ErrorCorrectionLevel = ecl;
		Objects.RequireNonNull(dataCodewords);
		_modules = new bool[Size, Size];
		_isFunction = new bool[Size, Size];
		DrawFunctionPatterns();
		byte[] data = AddEccAndInterleave(dataCodewords);
		DrawCodewords(data);
		if (mask == -1)
		{
			int num = int.MaxValue;
			for (uint num2 = 0u; num2 < 8; num2++)
			{
				ApplyMask(num2);
				DrawFormatBits(num2);
				int penaltyScore = GetPenaltyScore();
				if (penaltyScore < num)
				{
					mask = (int)num2;
					num = penaltyScore;
				}
				ApplyMask(num2);
			}
		}
		Mask = mask;
		ApplyMask((uint)mask);
		DrawFormatBits((uint)mask);
		_isFunction = null;
	}

	public bool GetModule(int x, int y)
	{
		if (0 <= x && x < Size && 0 <= y && y < Size)
		{
			return _modules[y, x];
		}
		return false;
	}

	public string ToSvgString(int border)
	{
		return ToSvgString(border, "#000000", "#ffffff");
	}

	public string ToSvgString(int border, string foreground, string background)
	{
		return AsGraphics().ToSvgString(border, foreground, background);
	}

	public string ToGraphicsPath(int border = 0)
	{
		return AsGraphics().ToGraphicsPath(border);
	}

	public byte[] ToBmpBitmap(int border, int scale, int foreground, int background)
	{
		return AsGraphics().ToBmpBitmap(border, scale, foreground, background);
	}

	public byte[] ToBmpBitmap(int border = 0, int scale = 1)
	{
		return ToBmpBitmap(border, scale, 0, 16777215);
	}

	public byte[] ToPngBitmap(int border, int scale, int foreground, int background)
	{
		return PngBuilder.ToImage(this, scale, border, foreground, background);
	}

	public byte[] ToPngBitmap(int border = 0, int scale = 1)
	{
		return PngBuilder.ToImage(this, scale, border, 0, 16777215);
	}

	public int RgbColor(byte red, byte green, byte blue)
	{
		return (red << 16) | (green << 8) | blue;
	}

	private void DrawFunctionPatterns()
	{
		for (int i = 0; i < Size; i++)
		{
			SetFunctionModule(6, i, i % 2 == 0);
			SetFunctionModule(i, 6, i % 2 == 0);
		}
		DrawFinderPattern(3, 3);
		DrawFinderPattern(Size - 4, 3);
		DrawFinderPattern(3, Size - 4);
		int[] alignmentPatternPositions = GetAlignmentPatternPositions();
		int num = alignmentPatternPositions.Length;
		for (int j = 0; j < num; j++)
		{
			for (int k = 0; k < num; k++)
			{
				if ((j != 0 || k != 0) && (j != 0 || k != num - 1) && (j != num - 1 || k != 0))
				{
					DrawAlignmentPattern(alignmentPatternPositions[j], alignmentPatternPositions[k]);
				}
			}
		}
		DrawFormatBits(0u);
		DrawVersion();
	}

	private void DrawFormatBits(uint mask)
	{
		uint num = (ErrorCorrectionLevel.FormatBits << 3) | mask;
		uint num2 = num;
		for (int i = 0; i < 10; i++)
		{
			num2 = (num2 << 1) ^ ((num2 >> 9) * 1335);
		}
		uint x = ((num << 10) | num2) ^ 0x5412u;
		for (int j = 0; j <= 5; j++)
		{
			SetFunctionModule(8, j, GetBit(x, j));
		}
		SetFunctionModule(8, 7, GetBit(x, 6));
		SetFunctionModule(8, 8, GetBit(x, 7));
		SetFunctionModule(7, 8, GetBit(x, 8));
		for (int k = 9; k < 15; k++)
		{
			SetFunctionModule(14 - k, 8, GetBit(x, k));
		}
		for (int l = 0; l < 8; l++)
		{
			SetFunctionModule(Size - 1 - l, 8, GetBit(x, l));
		}
		for (int m = 8; m < 15; m++)
		{
			SetFunctionModule(8, Size - 15 + m, GetBit(x, m));
		}
		SetFunctionModule(8, Size - 8, isDark: true);
	}

	private void DrawVersion()
	{
		if (Version >= 7)
		{
			uint num = (uint)Version;
			for (int i = 0; i < 12; i++)
			{
				num = (num << 1) ^ ((num >> 11) * 7973);
			}
			uint x = (uint)(Version << 12) | num;
			for (int j = 0; j < 18; j++)
			{
				bool bit = GetBit(x, j);
				int num2 = Size - 11 + j % 3;
				int num3 = j / 3;
				SetFunctionModule(num2, num3, bit);
				SetFunctionModule(num3, num2, bit);
			}
		}
	}

	private void DrawFinderPattern(int x, int y)
	{
		for (int i = -4; i <= 4; i++)
		{
			for (int j = -4; j <= 4; j++)
			{
				int num = Math.Max(Math.Abs(j), Math.Abs(i));
				int num2 = x + j;
				int num3 = y + i;
				if (0 <= num2 && num2 < Size && 0 <= num3 && num3 < Size)
				{
					SetFunctionModule(num2, num3, num != 2 && num != 4);
				}
			}
		}
	}

	private void DrawAlignmentPattern(int x, int y)
	{
		for (int i = -2; i <= 2; i++)
		{
			for (int j = -2; j <= 2; j++)
			{
				SetFunctionModule(x + j, y + i, Math.Max(Math.Abs(j), Math.Abs(i)) != 1);
			}
		}
	}

	private void SetFunctionModule(int x, int y, bool isDark)
	{
		_modules[y, x] = isDark;
		_isFunction[y, x] = true;
	}

	private Graphics AsGraphics()
	{
		return new Graphics(Size, _modules);
	}

	private byte[] AddEccAndInterleave(byte[] data)
	{
		Objects.RequireNonNull(data);
		if (data.Length != GetNumDataCodewords(Version, ErrorCorrectionLevel))
		{
			throw new ArgumentOutOfRangeException("data", "Length of data does not match version and ecl");
		}
		int num = NumErrorCorrectionBlocks[ErrorCorrectionLevel.Ordinal, Version];
		int num2 = EccCodewordsPerBlock[ErrorCorrectionLevel.Ordinal, Version];
		int num3 = GetNumRawDataModules(Version) / 8;
		int num4 = num - num3 % num;
		int num5 = num3 / num;
		byte[][] array = new byte[num][];
		ReedSolomonGenerator reedSolomonGenerator = new ReedSolomonGenerator(num2);
		int i = 0;
		int num6 = 0;
		for (; i < num; i++)
		{
			byte[] array2 = CopyOfRange(data, num6, num6 + num5 - num2 + ((i >= num4) ? 1 : 0));
			num6 += array2.Length;
			byte[] array3 = CopyOf(array2, num5 + 1);
			byte[] remainder = reedSolomonGenerator.GetRemainder(array2);
			Array.Copy(remainder, 0, array3, array3.Length - num2, remainder.Length);
			array[i] = array3;
		}
		byte[] array4 = new byte[num3];
		int j = 0;
		int num7 = 0;
		for (; j < array[0].Length; j++)
		{
			for (int k = 0; k < array.Length; k++)
			{
				if (j != num5 - num2 || k >= num4)
				{
					array4[num7] = array[k][j];
					num7++;
				}
			}
		}
		return array4;
	}

	private void DrawCodewords(byte[] data)
	{
		Objects.RequireNonNull(data);
		if (data.Length != GetNumRawDataModules(Version) / 8)
		{
			throw new ArgumentOutOfRangeException("data", "data length does not match version");
		}
		int num = 0;
		for (int num2 = Size - 1; num2 >= 1; num2 -= 2)
		{
			if (num2 == 6)
			{
				num2 = 5;
			}
			for (int i = 0; i < Size; i++)
			{
				for (int j = 0; j < 2; j++)
				{
					int num3 = num2 - j;
					int num4 = ((((num2 + 1) & 2) == 0) ? (Size - 1 - i) : i);
					if (!_isFunction[num4, num3] && num < data.Length * 8)
					{
						_modules[num4, num3] = GetBit(data[num >>> 3], 7 - (num & 7));
						num++;
					}
				}
			}
		}
	}

	private void ApplyMask(uint mask)
	{
		if (mask < 0 || mask > 7)
		{
			throw new ArgumentOutOfRangeException("mask", "Mask value out of range");
		}
		for (int i = 0; i < Size; i++)
		{
			for (int j = 0; j < Size; j++)
			{
				bool flag = false;
				switch (mask)
				{
				case 0u:
					flag = (j + i) % 2 == 0;
					break;
				case 1u:
					flag = i % 2 == 0;
					break;
				case 2u:
					flag = j % 3 == 0;
					break;
				case 3u:
					flag = (j + i) % 3 == 0;
					break;
				case 4u:
					flag = (j / 3 + i / 2) % 2 == 0;
					break;
				case 5u:
					flag = j * i % 2 + j * i % 3 == 0;
					break;
				case 6u:
					flag = (j * i % 2 + j * i % 3) % 2 == 0;
					break;
				case 7u:
					flag = ((j + i) % 2 + j * i % 3) % 2 == 0;
					break;
				}
				_modules[i, j] ^= flag && !_isFunction[i, j];
			}
		}
	}

	private int GetPenaltyScore()
	{
		int num = 0;
		for (int i = 0; i < Size; i++)
		{
			bool flag = false;
			int num2 = 0;
			FinderPenalty finderPenalty = new FinderPenalty(Size);
			for (int j = 0; j < Size; j++)
			{
				if (_modules[i, j] == flag)
				{
					num2++;
					if (num2 == 5)
					{
						num += 3;
					}
					else if (num2 > 5)
					{
						num++;
					}
				}
				else
				{
					finderPenalty.AddHistory(num2);
					if (!flag)
					{
						num += finderPenalty.CountPatterns() * 40;
					}
					flag = _modules[i, j];
					num2 = 1;
				}
			}
			num += finderPenalty.TerminateAndCount(flag, num2) * 40;
		}
		for (int k = 0; k < Size; k++)
		{
			bool flag2 = false;
			int num3 = 0;
			FinderPenalty finderPenalty2 = new FinderPenalty(Size);
			for (int l = 0; l < Size; l++)
			{
				if (_modules[l, k] == flag2)
				{
					num3++;
					if (num3 == 5)
					{
						num += 3;
					}
					else if (num3 > 5)
					{
						num++;
					}
				}
				else
				{
					finderPenalty2.AddHistory(num3);
					if (!flag2)
					{
						num += finderPenalty2.CountPatterns() * 40;
					}
					flag2 = _modules[l, k];
					num3 = 1;
				}
			}
			num += finderPenalty2.TerminateAndCount(flag2, num3) * 40;
		}
		for (int m = 0; m < Size - 1; m++)
		{
			for (int n = 0; n < Size - 1; n++)
			{
				bool flag3 = _modules[m, n];
				if (flag3 == _modules[m, n + 1] && flag3 == _modules[m + 1, n] && flag3 == _modules[m + 1, n + 1])
				{
					num += 3;
				}
			}
		}
		int num4 = 0;
		for (int num5 = 0; num5 < Size; num5++)
		{
			for (int num6 = 0; num6 < Size; num6++)
			{
				if (_modules[num5, num6])
				{
					num4++;
				}
			}
		}
		int num7 = Size * Size;
		int num8 = (Math.Abs(num4 * 20 - num7 * 10) + num7 - 1) / num7 - 1;
		return num + num8 * 10;
	}

	private int[] GetAlignmentPatternPositions()
	{
		if (Version == 1)
		{
			return Array.Empty<int>();
		}
		int num = Version / 7 + 2;
		int num2 = (Version * 8 + num * 3 + 5) / (num * 4 - 4) * 2;
		int[] array = new int[num];
		array[0] = 6;
		int num3 = array.Length - 1;
		int num4 = Size - 7;
		while (num3 >= 1)
		{
			array[num3] = num4;
			num3--;
			num4 -= num2;
		}
		return array;
	}

	private static int GetNumRawDataModules(int ver)
	{
		if (ver < 1 || ver > 40)
		{
			throw new ArgumentOutOfRangeException("ver", "Version number out of range");
		}
		int num = ver * 4 + 17;
		int num2 = num * num;
		num2 -= 192;
		num2 -= 31;
		num2 -= (num - 16) * 2;
		if (ver >= 2)
		{
			int num3 = ver / 7 + 2;
			num2 -= (num3 - 1) * (num3 - 1) * 25;
			num2 -= (num3 - 2) * 2 * 20;
			if (ver >= 7)
			{
				num2 -= 36;
			}
		}
		return num2;
	}

	public static int GetNumDataCodewords(int ver, Ecc ecl)
	{
		return GetNumRawDataModules(ver) / 8 - EccCodewordsPerBlock[ecl.Ordinal, ver] * NumErrorCorrectionBlocks[ecl.Ordinal, ver];
	}

	private static byte[] CopyOfRange(byte[] original, int from, int to)
	{
		byte[] array = new byte[to - from];
		Array.Copy(original, from, array, 0, to - from);
		return array;
	}

	private static byte[] CopyOf(byte[] original, int newLength)
	{
		byte[] array = new byte[newLength];
		Array.Copy(original, array, Math.Min(original.Length, newLength));
		return array;
	}

	private static bool GetBit(uint x, int i)
	{
		return ((x >> i) & 1) != 0;
	}
}
public class QrSegment
{
	public sealed class Mode
	{
		public static readonly Mode Numeric = new Mode(1u, 10, 12, 14);

		public static readonly Mode Alphanumeric = new Mode(2u, 9, 11, 13);

		public static readonly Mode Byte = new Mode(4u, 8, 16, 16);

		public static readonly Mode Kanji = new Mode(8u, 8, 10, 12);

		public static readonly Mode Eci = new Mode(7u, default(int), default(int), default(int));

		public static readonly Mode StructuredAppend = new Mode(3u, default(int), default(int), default(int));

		internal uint ModeBits { get; }

		private int[] NumBitsCharCount { get; }

		internal int NumCharCountBits(int ver)
		{
			return NumBitsCharCount[(ver + 7) / 17];
		}

		private Mode(uint modeBits, params int[] numBitsCharCount)
		{
			ModeBits = modeBits;
			NumBitsCharCount = numBitsCharCount;
		}
	}

	private readonly BitArray _data;

	private static readonly Regex NumericRegex = new Regex("^[0-9]*$", RegexOptions.Compiled);

	private static readonly Regex AlphanumericRegex = new Regex("^[A-Z0-9 $%*+./:-]*$", RegexOptions.Compiled);

	internal const string AlphanumericCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";

	public Mode EncodingMode { get; }

	public int NumChars { get; }

	public static QrSegment MakeBytes(byte[] data)
	{
		Objects.RequireNonNull(data);
		BitArray bitArray = new BitArray(0);
		foreach (byte val in data)
		{
			bitArray.AppendBits(val, 8);
		}
		return new QrSegment(Mode.Byte, data.Length, bitArray);
	}

	public static QrSegment MakeBytes(ArraySegment<byte> data)
	{
		Objects.RequireNonNull(data);
		BitArray bitArray = new BitArray(0);
		foreach (byte item in (IEnumerable<byte>)data)
		{
			bitArray.AppendBits(item, 8);
		}
		return new QrSegment(Mode.Byte, data.Count, bitArray);
	}

	public static QrSegment MakeNumeric(string digits)
	{
		Objects.RequireNonNull(digits);
		if (!IsNumeric(digits))
		{
			throw new ArgumentOutOfRangeException("digits", "String contains non-numeric characters");
		}
		BitArray bitArray = new BitArray(0);
		int num;
		for (int i = 0; i < digits.Length; i += num)
		{
			num = Math.Min(digits.Length - i, 3);
			bitArray.AppendBits(uint.Parse(digits.Substring(i, num)), num * 3 + 1);
		}
		return new QrSegment(Mode.Numeric, digits.Length, bitArray);
	}

	public static QrSegment MakeAlphanumeric(string text)
	{
		Objects.RequireNonNull(text);
		if (!IsAlphanumeric(text))
		{
			throw new ArgumentOutOfRangeException("text", "String contains unencodable characters in alphanumeric mode");
		}
		BitArray bitArray = new BitArray(0);
		int i;
		for (i = 0; i <= text.Length - 2; i += 2)
		{
			uint num = (uint)("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".IndexOf(text[i]) * 45);
			num += (uint)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".IndexOf(text[i + 1]);
			bitArray.AppendBits(num, 11);
		}
		if (i < text.Length)
		{
			bitArray.AppendBits((uint)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".IndexOf(text[i]), 6);
		}
		return new QrSegment(Mode.Alphanumeric, text.Length, bitArray);
	}

	internal static QrSegment MakeStructuredAppend(byte parity, int position, int total)
	{
		BitArray bitArray = new BitArray(0);
		bitArray.AppendBits((uint)(position - 1), 4);
		bitArray.AppendBits((uint)(total - 1), 4);
		bitArray.AppendBits(parity, 8);
		return new QrSegment(Mode.StructuredAppend, 0, bitArray);
	}

	public static List<QrSegment> MakeSegments(string text)
	{
		Objects.RequireNonNull(text);
		List<QrSegment> list = new List<QrSegment>();
		if (!(text == ""))
		{
			if (IsNumeric(text))
			{
				list.Add(MakeNumeric(text));
			}
			else if (IsAlphanumeric(text))
			{
				list.Add(MakeAlphanumeric(text));
			}
			else
			{
				list.Add(MakeBytes(Encoding.UTF8.GetBytes(text)));
			}
		}
		return list;
	}

	public static QrSegment MakeEci(int assignVal)
	{
		BitArray bitArray = new BitArray(0);
		if (assignVal < 0)
		{
			throw new ArgumentOutOfRangeException("assignVal", "ECI assignment value out of range");
		}
		if (assignVal < 128)
		{
			bitArray.AppendBits((uint)assignVal, 8);
		}
		else if (assignVal < 16384)
		{
			bitArray.AppendBits(2u, 2);
			bitArray.AppendBits((uint)assignVal, 14);
		}
		else
		{
			if (assignVal >= 1000000)
			{
				throw new ArgumentOutOfRangeException("assignVal", "ECI assignment value out of range");
			}
			bitArray.AppendBits(6u, 3);
			bitArray.AppendBits((uint)assignVal, 21);
		}
		return new QrSegment(Mode.Eci, 0, bitArray);
	}

	public static bool IsNumeric(string text)
	{
		return NumericRegex.IsMatch(text);
	}

	public static bool IsAlphanumeric(string text)
	{
		return AlphanumericRegex.IsMatch(text);
	}

	public QrSegment(Mode mode, int numChars, BitArray data)
	{
		EncodingMode = Objects.RequireNonNull(mode);
		Objects.RequireNonNull(data);
		if (numChars < 0)
		{
			throw new ArgumentOutOfRangeException("numChars", "Invalid value");
		}
		NumChars = numChars;
		_data = (BitArray)data.Clone();
	}

	public BitArray GetData()
	{
		return (BitArray)_data.Clone();
	}

	public string GetText()
	{
		StringBuilder stringBuilder = new StringBuilder();
		AppendText(stringBuilder);
		return stringBuilder.ToString();
	}

	public static string GetJoinedText(List<QrSegment> segments)
	{
		StringBuilder stringBuilder = new StringBuilder();
		foreach (QrSegment segment in segments)
		{
			segment.AppendText(stringBuilder);
		}
		return stringBuilder.ToString();
	}

	public static string GetJoinedText(List<List<QrSegment>> segments)
	{
		StringBuilder stringBuilder = new StringBuilder();
		foreach (List<QrSegment> segment in segments)
		{
			foreach (QrSegment item in segment)
			{
				item.AppendText(stringBuilder);
			}
		}
		return stringBuilder.ToString();
	}

	private void AppendText(StringBuilder builder)
	{
		if (EncodingMode == Mode.Numeric)
		{
			for (int i = 0; i < NumChars; i += 3)
			{
				int num = Math.Min(NumChars - i, 3);
				int index = i / 3 * 10;
				switch (num)
				{
				case 3:
				{
					uint num4 = _data.ExtractBits(index, 10);
					builder.Append((char)(48 + num4 / 100));
					builder.Append((char)(48 + num4 / 10 % 10));
					builder.Append((char)(48 + num4 % 10));
					break;
				}
				case 2:
				{
					uint num3 = _data.ExtractBits(index, 7);
					builder.Append((char)(48 + num3 / 10));
					builder.Append((char)(48 + num3 % 10));
					break;
				}
				case 1:
				{
					uint num2 = _data.ExtractBits(index, 4);
					builder.Append((char)(48 + num2));
					break;
				}
				}
			}
		}
		else if (EncodingMode == Mode.Alphanumeric)
		{
			for (int j = 0; j < NumChars; j += 2)
			{
				int num5 = Math.Min(NumChars - j, 2);
				int index2 = j / 2 * 11;
				if (num5 == 2)
				{
					int num6 = (int)_data.ExtractBits(index2, 11);
					builder.Append("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"[num6 / 45]);
					builder.Append("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"[num6 % 45]);
				}
				else
				{
					int index3 = (int)_data.ExtractBits(index2, 6);
					builder.Append("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"[index3]);
				}
			}
		}
		else if (EncodingMode == Mode.Byte)
		{
			byte[] array = new byte[NumChars];
			for (int k = 0; k < NumChars; k++)
			{
				array[k] = (byte)_data.ExtractBits(k * 8, 8);
			}
			builder.Append(Encoding.UTF8.GetString(array));
		}
	}

	internal static int GetTotalBits(List<QrSegment> segments, int version)
	{
		Objects.RequireNonNull(segments);
		long num = 0L;
		foreach (QrSegment segment in segments)
		{
			Objects.RequireNonNull(segment);
			int num2 = segment.EncodingMode.NumCharCountBits(version);
			if (segment.NumChars >= 1 << num2)
			{
				return -1;
			}
			num += 4L + (long)num2 + segment._data.Length;
			if (num > int.MaxValue)
			{
				return -1;
			}
		}
		return (int)num;
	}

	internal static int GetTotalBits(int numChars, Mode mode, int version)
	{
		int num = mode.NumCharCountBits(version);
		if (numChars >= 1 << num)
		{
			return -1;
		}
		int num2 = 0;
		if (mode == Mode.Numeric)
		{
			num2 = numChars / 3 * 10 + ((numChars % 3 != 0) ? (numChars % 3 * 3 + 1) : 0);
		}
		else if (mode == Mode.Alphanumeric)
		{
			num2 = numChars / 2 * 11 + ((numChars % 2 != 0) ? 6 : 0);
		}
		else if (mode == Mode.Byte)
		{
			num2 = numChars * 8;
		}
		else
		{
			if (mode != Mode.Kanji)
			{
				throw new ArgumentOutOfRangeException("mode", "Unsupported mode for this calculation");
			}
			num2 = numChars * 13;
		}
		return 4 + num + num2;
	}
}
public static class QrSegmentAdvanced
{
	private const string PackedQrKanjiToUnicode = "MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZAALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA/////////////////////////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBNME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDhMOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQmBCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQJRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32tfe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYgZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLsbTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CElFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKgdZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6rXydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOnZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtkmANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiVnfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/XYB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6lufhQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/Sge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZWXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJacl5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bbfL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333PfZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7egM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bjWMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oCiuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhYWVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLrW8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/DfQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGroXmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16cYBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851sTk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04HYWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5fUbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+KgACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHMW+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3vlzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/lUBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGTUZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQUw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaPVqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrjWtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yrXLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQYClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FYYVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KUYtdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTHZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2ZoZl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGgeaEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammyaa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzXbMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7Jbrdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3AwcD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKycsNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTydPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYwdjt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXogeh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuce5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5afnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAhgCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHCgbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMvgyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UYhSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZiF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tfi2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3bjcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEykTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNWk7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYuli+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJeml6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnYmdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uDm5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1knVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w==";

	private static readonly ushort[] UnicodeToQrKanji;

	public static List<QrSegment> MakeSegmentsOptimally(string text, QrCode.Ecc ecl, int minVersion = 1, int maxVersion = 40)
	{
		Objects.RequireNonNull(text);
		Objects.RequireNonNull(ecl);
		if (minVersion < 1 || minVersion > maxVersion)
		{
			throw new ArgumentOutOfRangeException("minVersion", "Invalid value");
		}
		if (maxVersion > 40)
		{
			throw new ArgumentOutOfRangeException("maxVersion", "Invalid value");
		}
		List<QrSegment> list = null;
		int[] codePoints = ToCodePoints(text);
		int num = 0;
		int num2 = 0;
		for (int i = minVersion; i <= maxVersion; i++)
		{
			if (i == minVersion || i == 10 || i == 27)
			{
				list = MakeSegmentsOptimally(codePoints, i);
			}
			num = QrCode.GetNumDataCodewords(i, ecl) * 8;
			num2 = QrSegment.GetTotalBits(list, i);
			if (num2 != -1 && num2 <= num)
			{
				return list;
			}
		}
		string message = "Segment too long";
		if (num2 != -1)
		{
			message = $"Data length = {num2} bits, Max capacity = {num} bits";
		}
		throw new DataTooLongException(message);
	}

	private static List<QrSegment> MakeSegmentsOptimally(IReadOnlyList<int> codePoints, int version)
	{
		if (codePoints.Count == 0)
		{
			return new List<QrSegment>();
		}
		QrSegment.Mode[] charModes = ComputeCharacterModes(codePoints, version);
		return SplitIntoSegments(codePoints, charModes);
	}

	private static int MeasureSegmentsOptimally(IReadOnlyList<int> codePoints, int version)
	{
		if (codePoints.Count == 0)
		{
			return 0;
		}
		QrSegment.Mode[] charModes = ComputeCharacterModes(codePoints, version);
		return MeasureSegments(codePoints, charModes, version);
	}

	private static QrSegment.Mode[] ComputeCharacterModes(IReadOnlyList<int> codePoints, int version)
	{
		if (codePoints.Count == 0)
		{
			throw new ArgumentOutOfRangeException("codePoints");
		}
		QrSegment.Mode[] array = new QrSegment.Mode[4]
		{
			QrSegment.Mode.Byte,
			QrSegment.Mode.Alphanumeric,
			QrSegment.Mode.Numeric,
			QrSegment.Mode.Kanji
		};
		int num = array.Length;
		int[] array2 = new int[num];
		for (int i = 0; i < num; i++)
		{
			array2[i] = (4 + array[i].NumCharCountBits(version)) * 6;
		}
		QrSegment.Mode[,] array3 = new QrSegment.Mode[codePoints.Count, num];
		int[] array4 = (int[])array2.Clone();
		for (int j = 0; j < codePoints.Count; j++)
		{
			int num2 = codePoints[j];
			int[] array5 = new int[num];
			array5[0] = array4[0] + CountUtf8Bytes(num2) * 8 * 6;
			array3[j, 0] = array[0];
			if (Enumerable.Contains("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:", (char)num2))
			{
				array5[1] = array4[1] + 33;
				array3[j, 1] = array[1];
			}
			if (48 <= num2 && num2 <= 57)
			{
				array5[2] = array4[2] + 20;
				array3[j, 2] = array[2];
			}
			if (IsKanji(num2))
			{
				array5[3] = array4[3] + 78;
				array3[j, 3] = array[3];
			}
			for (int k = 0; k < num; k++)
			{
				for (int l = 0; l < num; l++)
				{
					int num3 = (array5[l] + 5) / 6 * 6 + array2[k];
					if (array3[j, l] != null && (array3[j, k] == null || num3 < array5[k]))
					{
						array5[k] = num3;
						array3[j, k] = array[l];
					}
				}
			}
			array4 = array5;
		}
		QrSegment.Mode mode = null;
		int m = 0;
		int num4 = 0;
		for (; m < num; m++)
		{
			if (mode == null || array4[m] < num4)
			{
				num4 = array4[m];
				mode = array[m];
			}
		}
		QrSegment.Mode[] array6 = new QrSegment.Mode[codePoints.Count];
		for (int num5 = array6.Length - 1; num5 >= 0; num5--)
		{
			for (int n = 0; n < num; n++)
			{
				if (array[n] == mode)
				{
					mode = (array6[num5] = array3[num5, n]);
					break;
				}
			}
		}
		return array6;
	}

	private static List<QrSegment> SplitIntoSegments(IReadOnlyList<int> codePoints, IReadOnlyList<QrSegment.Mode> charModes)
	{
		if (codePoints.Count == 0)
		{
			throw new ArgumentOutOfRangeException("codePoints");
		}
		List<QrSegment> result = new List<QrSegment>();
		GroupConsecutiveModes(charModes, delegate(int startIndex, int endIndex, QrSegment.Mode mode)
		{
			string text = FromCodePoints(codePoints, startIndex, endIndex - startIndex);
			if (mode == QrSegment.Mode.Byte)
			{
				result.Add(QrSegment.MakeBytes(Encoding.UTF8.GetBytes(text)));
			}
			else if (mode == QrSegment.Mode.Numeric)
			{
				result.Add(QrSegment.MakeNumeric(text));
			}
			else if (mode == QrSegment.Mode.Alphanumeric)
			{
				result.Add(QrSegment.MakeAlphanumeric(text));
			}
			else if (mode == QrSegment.Mode.Kanji)
			{
				result.Add(MakeKanji(text));
			}
		});
		return result;
	}

	private static int MeasureSegments(IReadOnlyList<int> codePoints, IReadOnlyList<QrSegment.Mode> charModes, int version)
	{
		if (codePoints.Count == 0)
		{
			throw new ArgumentOutOfRangeException("codePoints");
		}
		int result = 0;
		GroupConsecutiveModes(charModes, delegate(int startIndex, int endIndex, QrSegment.Mode mode)
		{
			int num;
			if (mode == QrSegment.Mode.Byte)
			{
				num = 0;
				for (int i = startIndex; i < endIndex; i++)
				{
					num += CountUtf8Bytes(codePoints[i]);
				}
			}
			else
			{
				num = endIndex - startIndex;
			}
			result += QrSegment.GetTotalBits(num, mode, version);
		});
		return result;
	}

	private static string FromCodePoints(IReadOnlyList<int> codepoints, int startIndex, int count)
	{
		Encoding encoding = new UTF32Encoding(!BitConverter.IsLittleEndian, byteOrderMark: false, throwOnInvalidCharacters: true);
		byte[] array = new byte[count * 4];
		int num = startIndex;
		int num2 = 0;
		while (num < startIndex + count)
		{
			byte[] bytes = BitConverter.GetBytes(codepoints[num]);
			array[num2] = bytes[0];
			array[num2 + 1] = bytes[1];
			array[num2 + 2] = bytes[2];
			array[num2 + 3] = bytes[3];
			num++;
			num2 += 4;
		}
		return encoding.GetString(array);
	}

	private static int[] ToCodePoints(string s)
	{
		byte[] bytes = new UTF32Encoding(!BitConverter.IsLittleEndian, byteOrderMark: false, throwOnInvalidCharacters: true).GetBytes(s);
		int[] array = new int[bytes.Length / 4];
		int num = 0;
		int num2 = 0;
		while (num < bytes.Length)
		{
			array[num2] = BitConverter.ToInt32(bytes, num);
			num += 4;
			num2++;
		}
		return array;
	}

	private static int CountUtf8Bytes(int cp)
	{
		if (cp < 0)
		{
			throw new ArgumentOutOfRangeException("cp", "Invalid code point");
		}
		if (cp < 128)
		{
			return 1;
		}
		if (cp < 2048)
		{
			return 2;
		}
		if (cp < 65536)
		{
			return 3;
		}
		if (cp < 1114112)
		{
			return 4;
		}
		throw new ArgumentOutOfRangeException("cp", "Invalid code point");
	}

	public static QrSegment MakeKanji(string text)
	{
		Objects.RequireNonNull(text);
		BitArray bitArray = new BitArray(0);
		foreach (ushort item in text.Select((char t) => UnicodeToQrKanji[(uint)t]))
		{
			if (item == ushort.MaxValue)
			{
				throw new ArgumentOutOfRangeException("text", "String contains non-kanji-mode characters");
			}
			bitArray.AppendBits(item, 13);
		}
		return new QrSegment(QrSegment.Mode.Kanji, text.Length, bitArray);
	}

	public static bool IsEncodableAsKanji(string text)
	{
		Objects.RequireNonNull(text);
		return text.All((char t) => IsKanji(t));
	}

	private static bool IsKanji(int c)
	{
		if (c < UnicodeToQrKanji.Length)
		{
			return UnicodeToQrKanji[c] != ushort.MaxValue;
		}
		return false;
	}

	static QrSegmentAdvanced()
	{
		UnicodeToQrKanji = new ushort[65536];
		for (int i = 0; i < UnicodeToQrKanji.Length; i++)
		{
			UnicodeToQrKanji[i] = ushort.MaxValue;
		}
		byte[] array = Convert.FromBase64String("MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZAALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA/////////////////////////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBNME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDhMOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQmBCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQJRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32tfe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYgZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLsbTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CElFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKgdZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6rXydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOnZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtkmANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiVnfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/XYB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6lufhQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/Sge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZWXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJacl5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bbfL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333PfZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7egM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bjWMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oCiuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhYWVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLrW8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/DfQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGroXmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16cYBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851sTk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04HYWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5fUbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+KgACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHMW+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3vlzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/lUBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGTUZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQUw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaPVqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrjWtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yrXLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQYClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FYYVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KUYtdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTHZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2ZoZl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGgeaEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammyaa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzXbMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7Jbrdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3AwcD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKycsNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTydPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYwdjt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXogeh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuce5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5afnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAhgCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHCgbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMvgyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UYhSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZiF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tfi2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3bjcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEykTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNWk7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYuli+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJeml6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnYmdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uDm5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1knVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w==");
		for (int j = 0; j < array.Length; j += 2)
		{
			int num = (array[j] << 8) | array[j + 1];
			if (num != 65535)
			{
				UnicodeToQrKanji[num] = (ushort)(j / 2);
			}
		}
	}

	public static List<List<QrSegment>> MakeSegmentsForMultipleCodes(string text, QrCode.Ecc ecl, int version = 29)
	{
		Objects.RequireNonNull(text);
		Objects.RequireNonNull(ecl);
		if (version < 1 || version > 40)
		{
			throw new ArgumentOutOfRangeException("version", "Invalid value");
		}
		List<List<QrSegment>> list = SplitTextIntoMultipleCodes(text, ecl, version);
		byte parity = CalculateParity(text);
		for (int i = 0; i < list.Count; i++)
		{
			list[i].Insert(0, QrSegment.MakeStructuredAppend(parity, i + 1, list.Count));
		}
		return list;
	}

	private static List<List<QrSegment>> SplitTextIntoMultipleCodes(string text, QrCode.Ecc ecl, int version)
	{
		int[] array = ToCodePoints(text);
		int num = QrCode.GetNumDataCodewords(version, ecl) * 8 - 20;
		List<List<QrSegment>> list = new List<List<QrSegment>>();
		int num2 = 0;
		while (num2 < array.Length)
		{
			if (list.Count >= 16)
			{
				throw new DataTooLongException("The text is too long to fit into 16 QR codes");
			}
			int num3 = num2;
			int num4 = array.Length;
			while (num3 < num4)
			{
				int num5 = (num3 + num4 + 1) / 2;
				if (MeasureSegmentsOptimally(new ArraySegment<int>(array, num2, num5 - num2), version) <= num)
				{
					num3 = num5;
				}
				else
				{
					num4 = num5 - 1;
				}
			}
			if (num4 == num2)
			{
				throw new InvalidOperationException("QR code splitting: should not reach");
			}
			list.Add(MakeSegmentsOptimally(new ArraySegment<int>(array, num2, num4 - num2), version));
			num2 = num4;
		}
		return list;
	}

	private static byte CalculateParity(string text)
	{
		byte[] bytes = Encoding.UTF8.GetBytes(text);
		byte b = 0;
		byte[] array = bytes;
		foreach (byte b2 in array)
		{
			b ^= (byte)(b2 >> 8);
		}
		return b;
	}

	private static void GroupConsecutiveModes(IReadOnlyList<QrSegment.Mode> elements, Action<int, int, QrSegment.Mode> action)
	{
		int arg = 0;
		QrSegment.Mode mode = elements[0];
		int num = 0;
		while (true)
		{
			if (num == elements.Count || elements[num] != mode)
			{
				action(arg, num, mode);
				if (num == elements.Count)
				{
					break;
				}
				arg = num;
				mode = elements[num];
			}
			num++;
		}
	}
}
internal class ReedSolomonGenerator
{
	private readonly byte[] _coefficients;

	internal ReedSolomonGenerator(int degree)
	{
		if (degree < 1 || degree > 255)
		{
			throw new ArgumentOutOfRangeException("degree", "Degree out of range");
		}
		_coefficients = new byte[degree];
		_coefficients[degree - 1] = 1;
		uint num = 1u;
		for (int i = 0; i < degree; i++)
		{
			for (int j = 0; j < _coefficients.Length; j++)
			{
				_coefficients[j] = Multiply(_coefficients[j], num);
				if (j + 1 < _coefficients.Length)
				{
					_coefficients[j] ^= _coefficients[j + 1];
				}
			}
			num = Multiply(num, 2u);
		}
	}

	internal byte[] GetRemainder(byte[] data)
	{
		Objects.RequireNonNull(data);
		byte[] array = new byte[_coefficients.Length];
		for (int i = 0; i < data.Length; i++)
		{
			uint y = (uint)(data[i] ^ array[0]);
			Array.Copy(array, 1, array, 0, array.Length - 1);
			array[^1] = 0;
			for (int j = 0; j < array.Length; j++)
			{
				array[j] ^= Multiply(_coefficients[j], y);
			}
		}
		return array;
	}

	private static byte Multiply(uint x, uint y)
	{
		uint num = 0u;
		for (int num2 = 7; num2 >= 0; num2--)
		{
			num = (num << 1) ^ ((num >> 7) * 285);
			num ^= ((y >> num2) & 1) * x;
		}
		return (byte)num;
	}
}