Decompiled source of Bonelab bHaptics v3.5.0

Mods/Bonelab_bhaptics.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BoneLib;
using BoneLib.BoneMenu;
using Bonelab_bhaptics;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.VRMK;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using MyBhapticsTactsuit;
using UnityEngine;
using bHapticsLib;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(global::Bonelab_bhaptics.Bonelab_bhaptics), "Bonelab_bhaptics", "3.3.0", "Florian Fahrenberger/SoapyScripter", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Bonelab_bhaptics")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+51830e5c801fb53cbee071c5d6d44485adc5867c")]
[assembly: AssemblyProduct("Bonelab_bhaptics")]
[assembly: AssemblyTitle("Bonelab_bhaptics")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace MyBhapticsTactsuit
{
	public class TactsuitVR
	{
		public bool suitDisabled = true;

		public bool systemInitialized;

		public bool faceConnected;

		public bool armsConnected;

		private static ManualResetEvent HeartBeat_mrse = new ManualResetEvent(initialState: false);

		private static ManualResetEvent Water_mrse = new ManualResetEvent(initialState: false);

		private static ManualResetEvent Choking_mrse = new ManualResetEvent(initialState: false);

		public Dictionary<string, FileInfo> FeedbackMap = new Dictionary<string, FileInfo>();

		private static RotationOption defaultRotationOption = new RotationOption(0f, 0f);

		public void HeartBeatFunc()
		{
			while (true)
			{
				HeartBeat_mrse.WaitOne();
				bHapticsManager.PlayRegistered("HeartBeat");
				Thread.Sleep(1000);
			}
		}

		public TactsuitVR()
		{
			LOG("Initializing suit");
			if (!bHaptics.WasError)
			{
				suitDisabled = false;
			}
			RegisterAllTactFiles();
			LOG("Starting HeartBeat thread...");
			new Thread(HeartBeatFunc).Start();
			LOG("Check if face or arms are connected...");
			if (bHapticsManager.IsDeviceConnected((PositionID)4))
			{
				faceConnected = true;
			}
			if (bHapticsManager.IsDeviceConnected((PositionID)10) | bHapticsManager.IsDeviceConnected((PositionID)11))
			{
				armsConnected = true;
			}
		}

		public void LOG(string logStr)
		{
			MelonLogger.Msg(logStr);
		}

		private void RegisterAllTactFiles()
		{
			string path = MelonEnvironment.ModsDirectory + "\\bHaptics";
			if (!Directory.Exists(path))
			{
				LOG("Could not find tact files!");
				return;
			}
			FileInfo[] files = new DirectoryInfo(path).GetFiles("*.tact", SearchOption.AllDirectories);
			for (int i = 0; i < files.Length; i++)
			{
				string name = files[i].Name;
				string fullName = files[i].FullName;
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(name);
				if (!(name == ".") && !(name == ".."))
				{
					string text = File.ReadAllText(fullName);
					try
					{
						bHapticsManager.RegisterPatternFromJson(fileNameWithoutExtension, text);
						LOG("Pattern registered: " + fileNameWithoutExtension);
					}
					catch (Exception ex)
					{
						LOG(ex.ToString());
					}
					FeedbackMap.Add(fileNameWithoutExtension, files[i]);
				}
			}
			systemInitialized = true;
		}

		public void PlaybackHaptics(string key, float intensity = 1f, float duration = 1f)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			if (FeedbackMap.ContainsKey(key))
			{
				ScaleOption val = new ScaleOption(intensity, duration);
				bHapticsManager.PlayRegistered(key, key, val, defaultRotationOption);
			}
			else
			{
				LOG("Feedback not registered: " + key);
			}
		}

		public void PlayBackHit(string key, float xzAngle, float yShift)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			ScaleOption val = new ScaleOption(1f, 1f);
			RotationOption val2 = new RotationOption(xzAngle, yShift);
			bHapticsManager.PlayRegistered(key, key, val, val2);
		}

		public void GunRecoil(bool isRightHand, float intensity = 1f, bool twoHanded = false)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			float num = 1f;
			ScaleOption val = new ScaleOption(intensity, num);
			if (twoHanded)
			{
				val = new ScaleOption(intensity * 0.5f, num);
			}
			RotationOption val2 = new RotationOption(0f, 0f);
			string text = "_L";
			string text2 = "_R";
			if (isRightHand)
			{
				text = "_R";
				text2 = "_L";
			}
			string text3 = "Recoil" + text;
			string text4 = "RecoilVest" + text;
			string text5 = "RecoilHands" + text;
			string text6 = "Recoil" + text2;
			string text7 = "RecoilVest" + text2;
			string text8 = "RecoilHands" + text2;
			bHapticsManager.PlayRegistered(text5, text5, val, val2);
			bHapticsManager.PlayRegistered(text3, text3, val, val2);
			bHapticsManager.PlayRegistered(text4, text4, val, val2);
			if (twoHanded)
			{
				bHapticsManager.PlayRegistered(text8, text8, val, val2);
				bHapticsManager.PlayRegistered(text6, text6, val, val2);
				bHapticsManager.PlayRegistered(text7, text7, val, val2);
			}
		}

		public void SwordRecoil(bool isRightHand, float intensity = 1f)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			float num = 1f;
			ScaleOption val = new ScaleOption(intensity, num);
			RotationOption val2 = new RotationOption(0f, 0f);
			string text = "_L";
			if (isRightHand)
			{
				text = "_R";
			}
			string text2 = "Sword" + text;
			string text3 = "SwordVest" + text;
			string text4 = "RecoilHands" + text;
			bHapticsManager.PlayRegistered(text4, text4, val, val2);
			bHapticsManager.PlayRegistered(text2, text2, val, val2);
			bHapticsManager.PlayRegistered(text3, text3, val, val2);
		}

		public void HeadShot(float hitAngle)
		{
			if (bHapticsManager.IsDeviceConnected((PositionID)4))
			{
				if (hitAngle < 45f || hitAngle > 315f)
				{
					PlaybackHaptics("Headshot_F");
				}
				if (hitAngle > 45f && hitAngle < 135f)
				{
					PlaybackHaptics("Headshot_L");
				}
				if (hitAngle > 135f && hitAngle < 225f)
				{
					PlaybackHaptics("Headshot_B");
				}
				if (hitAngle > 225f && hitAngle < 315f)
				{
					PlaybackHaptics("Headshot_R");
				}
			}
			else
			{
				PlayBackHit("BulletHit", hitAngle, 0.5f);
			}
		}

		public void FootStep(bool isRightFoot)
		{
			if (!(!bHapticsManager.IsDeviceConnected((PositionID)8) | !bHapticsManager.IsDeviceConnected((PositionID)9)))
			{
				string text = "_L";
				if (isRightFoot)
				{
					text = "_R";
				}
				string key = "FootStep" + text;
				PlaybackHaptics(key);
			}
		}

		public void StartHeartBeat()
		{
			HeartBeat_mrse.Set();
		}

		public void StopHeartBeat()
		{
			HeartBeat_mrse.Reset();
		}

		public void StartWater()
		{
			Water_mrse.Set();
		}

		public void StopWater()
		{
			Water_mrse.Reset();
		}

		public void StartChoking()
		{
			Choking_mrse.Set();
		}

		public void StopChoking()
		{
			Choking_mrse.Reset();
			bHapticsManager.StopPlaying("TeleportOpened");
		}

		public bool IsPlaying(string effect)
		{
			return bHapticsManager.IsPlaying(effect);
		}

		public void StopHapticFeedback(string effect)
		{
			bHapticsManager.StopPlaying(effect);
		}

		public void StopAllHapticFeedback()
		{
			StopThreads();
			foreach (string key in FeedbackMap.Keys)
			{
				bHapticsManager.StopPlaying(key);
			}
		}

		public void StopThreads()
		{
			StopHeartBeat();
			StopWater();
			StopChoking();
		}
	}
}
namespace Bonelab_bhaptics
{
	public class Bonelab_bhaptics : MelonMod
	{
		[HarmonyPatch(typeof(PlayerDamageReceiver), "ReceiveAttack", new Type[] { typeof(Attack) })]
		public class bhaptics_ReceiveAttack
		{
			[HarmonyPostfix]
			public static void Postfix(PlayerDamageReceiver __instance, Attack attack)
			{
				//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_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Invalid comparison between Unknown and I4
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Invalid comparison between Unknown and I4
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Invalid comparison between Unknown and I4
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Invalid comparison between Unknown and I4
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Invalid comparison between Unknown and I4
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Invalid comparison between Unknown and I4
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b3: Invalid comparison between Unknown and I4
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bc: Invalid comparison between Unknown and I4
				//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ed: Invalid comparison between Unknown and I4
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Invalid comparison between Unknown and I4
				//IL_0155: Unknown result type (might be due to invalid IL or missing references)
				//IL_0141: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)Player.RigManager != (Object)null) || (Object)(object)__instance.health._rigManager != (Object)(object)Player.RigManager)
				{
					return;
				}
				bool flag = false;
				AttackType attackType = attack.attackType;
				string key;
				if ((int)attackType <= 2)
				{
					if ((int)attackType != 1)
					{
						if ((int)attackType != 2)
						{
							goto IL_0077;
						}
						key = "Impact";
					}
					else
					{
						key = "BulletHit";
					}
				}
				else if ((int)attackType != 8)
				{
					if ((int)attackType != 16)
					{
						if ((int)attackType != 32)
						{
							goto IL_0077;
						}
						key = "BulletHit";
					}
					else
					{
						key = "BladeHit";
					}
				}
				else
				{
					key = "LavaballHit";
				}
				goto IL_007d;
				IL_0077:
				key = "Impact";
				goto IL_007d;
				IL_007d:
				if ((int)__instance.bodyPart == 0 && tactsuitVr.faceConnected)
				{
					tactsuitVr.PlaybackHaptics("Headshot_F");
					flag = true;
				}
				if (((int)__instance.bodyPart == 6 || (int)__instance.bodyPart == 5) && tactsuitVr.armsConnected)
				{
					tactsuitVr.PlaybackHaptics("Recoil_L");
					flag = true;
				}
				if (((int)__instance.bodyPart == 9 || (int)__instance.bodyPart == 8) && tactsuitVr.armsConnected)
				{
					tactsuitVr.PlaybackHaptics("Recoil_R");
					flag = true;
				}
				if (!flag)
				{
					KeyValuePair<float, float> keyValuePair = ((!((Object)(object)attack.collider != (Object)null)) ? getAngleAndShift(((Component)__instance).transform, attack.origin) : getAngleAndShift(((Component)__instance).transform, ((Component)attack.collider).transform.position));
					tactsuitVr.PlayBackHit(key, keyValuePair.Key, keyValuePair.Value);
				}
			}
		}

		[HarmonyPatch(typeof(InventorySlotReceiver), "OnHandGrab", new Type[] { typeof(Hand) })]
		public class bhaptics_SlotGrab
		{
			[HarmonyPostfix]
			public static void Postfix(InventorySlotReceiver __instance, Hand hand)
			{
				if (__instance.isInUIMode || (Object)(object)hand == (Object)null || !((Object)(object)Player.RigManager != (Object)null) || (Object)(object)hand.manager != (Object)(object)Player.RigManager)
				{
					return;
				}
				string text = "BackCt";
				foreach (SlotContainer item in (Il2CppArrayBase<SlotContainer>)(object)Player.RigManager.inventory.bodySlots)
				{
					if ((Object)(object)item.inventorySlotReceiver == (Object)(object)__instance)
					{
						text = ((Object)item).name;
						break;
					}
				}
				switch (text)
				{
				case "SideLf":
					tactsuitVr.PlaybackHaptics("StoreGun_L");
					break;
				case "SideRt":
					tactsuitVr.PlaybackHaptics("StoreGun_R");
					break;
				case "BackLf":
					tactsuitVr.PlaybackHaptics("ReceiveShoulder_L");
					break;
				case "BackRt":
					tactsuitVr.PlaybackHaptics("ReceiveShoulder_R");
					break;
				default:
					tactsuitVr.PlaybackHaptics("StoreGun_R");
					break;
				}
			}
		}

		[HarmonyPatch(typeof(InventorySlotReceiver), "OnHandDrop", new Type[] { typeof(IGrippable) })]
		public class bhaptics_SlotInsert
		{
			[HarmonyPostfix]
			public static void Postfix(InventorySlotReceiver __instance, IGrippable host)
			{
				Hand lastHand = host.GetLastHand();
				if (__instance.isInUIMode || (Object)(object)lastHand == (Object)null || !((Object)(object)Player.RigManager != (Object)null) || (Object)(object)lastHand.manager != (Object)(object)Player.RigManager)
				{
					return;
				}
				string text = "BackCt";
				foreach (SlotContainer item in (Il2CppArrayBase<SlotContainer>)(object)Player.RigManager.inventory.bodySlots)
				{
					if ((Object)(object)item.inventorySlotReceiver == (Object)(object)__instance)
					{
						text = ((Object)item).name;
						break;
					}
				}
				switch (text)
				{
				case "SideLf":
					tactsuitVr.PlaybackHaptics("StoreGun_L");
					break;
				case "SideRt":
					tactsuitVr.PlaybackHaptics("StoreGun_R");
					break;
				case "BackLf":
					tactsuitVr.PlaybackHaptics("StoreShoulder_L");
					break;
				case "BackRt":
					tactsuitVr.PlaybackHaptics("StoreShoulder_R");
					break;
				default:
					tactsuitVr.PlaybackHaptics("StoreGun_R");
					break;
				}
			}
		}

		[HarmonyPatch(typeof(Player_Health), "UpdateHealth", new Type[] { typeof(float) })]
		public class bhaptics_PlayerHealthUpdate
		{
			[HarmonyPostfix]
			public static void Postfix(Player_Health __instance)
			{
				if ((Object)(object)Player.RigManager != (Object)null && !((Object)(object)((Health)__instance)._rigManager != (Object)(object)Player.RigManager))
				{
					if (((Health)__instance).curr_Health <= 0.3f * ((Health)__instance).max_Health)
					{
						tactsuitVr.StartHeartBeat();
					}
					else
					{
						tactsuitVr.StopHeartBeat();
					}
				}
			}
		}

		public static TactsuitVR tactsuitVr = null;

		public static bool playerRightHanded = true;

		public override void OnInitializeMelon()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			tactsuitVr = new TactsuitVR();
			Hooking.OnPostFireGun += OnPostFireGun;
			Hooking.OnPlayerDeath += OnPlayerDeath;
			Hooking.OnSwitchAvatarPostfix += OnSwitchAvatarPostfix;
			Page obj = Page.Root.CreatePage("bHaptics Mod", Color.yellow, 0, true);
			obj.CreateBool("Suit Connected", Color.white, !tactsuitVr.suitDisabled, (Action<bool>)delegate(bool value)
			{
				tactsuitVr.suitDisabled = value;
			});
			obj.CreateBool("Visor Connected", Color.white, tactsuitVr.faceConnected, (Action<bool>)delegate(bool value)
			{
				tactsuitVr.faceConnected = value;
			});
			obj.CreateBool("Sleeves Connected", Color.white, tactsuitVr.armsConnected, (Action<bool>)delegate(bool value)
			{
				tactsuitVr.armsConnected = value;
			});
			obj.CreateFunction("Create New Tactsuit", Color.yellow, (Action)delegate
			{
				tactsuitVr = new TactsuitVR();
			});
			obj.CreateFunction("Test Haptics", Color.yellow, (Action)delegate
			{
				tactsuitVr.PlaybackHaptics("SwitchAvatar");
			});
		}

		private void OnPostFireGun(Gun gun)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Invalid comparison between Unknown and I4
			bool isRightHand = false;
			bool flag = false;
			if ((Object)(object)gun == (Object)null || (Object)(object)gun.triggerGrip == (Object)null || (Object)(object)gun.chamberedCartridge == (Object)null)
			{
				return;
			}
			flag = gun.triggerGrip.attachedHands.Count > 1;
			Enumerator<Hand> enumerator = gun.triggerGrip.attachedHands.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Hand current = enumerator.Current;
				if ((Object)(object)Player.ControllerRig != (Object)(object)current.Controller.contRig)
				{
					return;
				}
				if ((int)current.handedness == 2)
				{
					isRightHand = true;
					break;
				}
			}
			if (!flag)
			{
				foreach (Grip item in (Il2CppArrayBase<Grip>)(object)gun.otherGrips)
				{
					if (!flag)
					{
						flag = item.attachedHands.Count > 0;
						break;
					}
				}
			}
			float intensity = Mathf.Min(gun.muzzleVelocity / 1000f, 1f);
			tactsuitVr.GunRecoil(isRightHand, intensity, flag);
		}

		private static KeyValuePair<float, float> getAngleAndShift(Transform player, Vector3 hit)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(0f, 0f, 1f);
			Vector3 val2 = hit - player.position;
			Quaternion rotation = player.rotation;
			Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
			Vector3 val3 = new Vector3(val2.x, 0f, val2.z);
			float num = Vector3.Angle(val3, val);
			if (Vector3.Cross(val3, val).y < 0f)
			{
				num *= -1f;
			}
			float num2 = num - eulerAngles.y;
			num2 *= -1f;
			if (num2 < 0f)
			{
				num2 = 360f + num2;
			}
			float y = val2.y;
			float num3 = 0.5f;
			float num4 = -0.5f;
			y = ((y > num3) ? 0.5f : ((!(y < num4)) ? ((y - num4) / (num3 - num4) - 0.5f) : (-0.5f)));
			return new KeyValuePair<float, float>(num2, y);
		}

		private void OnPlayerDeath(RigManager rm)
		{
			if ((Object)(object)Player.RigManager != (Object)null && !((Object)(object)rm != (Object)(object)Player.RigManager))
			{
				tactsuitVr.StopThreads();
			}
		}

		private void OnSwitchAvatarPostfix(Avatar avatar)
		{
			if ((Object)(object)Player.RigManager != (Object)null && !((Object)(object)avatar != (Object)(object)Player.Avatar))
			{
				tactsuitVr.PlaybackHaptics("SwitchAvatar");
			}
		}
	}
}